evhe 发表于 2025-9-11 20:35:59

AI8H PWM输出的问题 求助!

AI8H8K64U-TSSOP20使用PWM的方式P1.6端口点亮LED,没有驱动点亮,用IO低电平输出的方式能点亮
请看完整代码


#define MAIN_Fosc                24000000L      // 主时钟:24MHz(文档6.1.3章节,内部IRC)
#include      "STC8H.h"

// -------------------------- 文档对应参数定义 --------------------------
// PWM频率1KHz(人眼无闪烁),公式:频率=MAIN_Fosc/[(PSCR+1)*(ARR+1)](文档22.5.7章节)
#define PWMA_PSCR_VAL      0x0000                // 预分频=0(不分频,PWM时钟=24MHz)
#define PWMA_ARR_VAL      (MAIN_Fosc/(PWMA_PSCR_VAL+1)/1000 - 1)      // ARR=23999(周期1ms)
#define BREATH_STEP                20                        // 占空比渐变步长(平滑呼吸)
#define BREATH_DELAY      10                        // 渐变间隔(ms,控制呼吸速度)

// -------------------------- 全局变量 --------------------------
unsigned int g_ccr4_val = 0;                // PWMA_CCR4值(0~23999,对应低电平占空比0%~100%)
bit g_duty_inc = 1;                              // 占空比递增/递减标志(1=递增:LED变亮)

// -------------------------- 函数声明 --------------------------
void PWMA_Init(void);                              // 初始化PWMA_CCR4(P1.6 PWM输出)
void Delay_ms(unsigned int ms);                // 毫秒延时(文档6.1.3章节时钟校准)
void Breath_Loop(void);                              // 呼吸灯占空比渐变逻辑

// -------------------------- 主函数 --------------------------
void main(void)
{
      PWMA_Init();      // 初始化PWMA_CCR4(P1.6),启动PWM输出
      
      while(1)
      {
                Breath_Loop();      // 循环执行呼吸逻辑
      }
}

// -------------------------- PWMA初始化(P1.6=PWMA_CCR4,文档22.7章节) --------------------------
void PWMA_Init(void)
{
      // 1. 使能扩展SFR访问(文档8.2.8章节:必须先使能才能访问PWMA寄存器)
      P_SW2 |= 0x80;
      
      // 2. 配置PWM时钟与周期(文档22.7.20/22.7.22章节)
      PWMA_PSCR = PWMA_PSCR_VAL;      // 预分频=0
      PWMA_ARR = PWMA_ARR_VAL;      // 自动重装载值=23999(1KHz周期)
      
      // 3. 配置PWMA_CCR4为PWM模式1(低电平占空比随CCR4增大而增加,文档22.7.13章节)
      // CCMR2控制CCR4通道,高8位=0x60(PWM模式1),低8位无意义
      PWMA_CCMR2 = 0x6000;
      
      // 4. 配置P1.6为PWM4P输出(默认映射,文档2.5.4章节)
      // PWMA_IOAUX=0x00:CCR4默认映射P1.6,无需额外切换
      PWMA_IOAUX = 0x00;
      
      // 5. 使能CCR4输出+设置极性(文档22.7.16章节)
      // CC4E=1(使能输出),CC4P=0(低电平有效,符合LED低电平点亮)
      PWMA_CCER1 = 0x0080;
      
      // 6. 使能P1.6 PWM输出(文档22.7.2章节:输出允许寄存器)
      // ENO4P=1(使能PWM4P输出,对应P1.6)
      PWMA_ENO = 0x04;
      
      // 7. 初始占空比(0%低电平→LED灭,文档22.7.27章节)
      PWMA_CCR4 = g_ccr4_val;
      
      // 8. 主输出使能+启动PWMA计数器(文档22.7.33/22.7.4章节)
      PWMA_BKR = 0x80;      // MOE=1(主输出使能,PWMA所有通道输出总开关)
      PWMA_CR1 = 0x81;      // CEN=1(启动计数器),ARPE=1(允许ARR缓冲)
      
      // 9. 关闭扩展SFR访问(文档8.2.8章节:配置完成后恢复)
      P_SW2 &= ~0x80;
}

// -------------------------- 毫秒延时函数(基于24MHz时钟,文档6.1.3章节精度) --------------------------
void Delay_ms(unsigned int ms)
{
      unsigned int i, j;
      for(i = ms; i > 0; i--)
      {
                // 24MHz时钟下,j=2400≈1ms(文档6.1.3章节:1机器周期=1/24MHz≈41.67ns)
                for(j = 2400; j > 0; j--);
      }
}

// -------------------------- 呼吸灯逻辑(低电平占空比渐变,文档22.5.7章节) --------------------------
void Breath_Loop(void)
{
      // 使能扩展SFR访问(修改CCR4需重新使能)
      P_SW2 |= 0x80;
      
      // 占空比渐变:0%→100%(亮)→0%(灭)循环
      if(g_duty_inc)
      {
                g_ccr4_val += BREATH_STEP;
                if(g_ccr4_val >= PWMA_ARR_VAL)      // 达到最大占空比(100%低电平→LED最亮)
                {
                        g_ccr4_val = PWMA_ARR_VAL;
                        g_duty_inc = 0;      // 切换为递减
                }
      }
      else
      {
                g_ccr4_val -= BREATH_STEP;
                if(g_ccr4_val <= 0)      // 达到最小占空比(0%低电平→LED灭)
                {
                        g_ccr4_val = 0;
                        g_duty_inc = 1;      // 切换为递增
                }
      }
      
      // 更新CCR4值,改变PWM占空比(文档22.7.27章节)
      PWMA_CCR4 = g_ccr4_val;
      
      // 恢复扩展SFR访问状态
      P_SW2 &= ~0x80;
      
      // 延时平滑渐变(控制呼吸速度)
      Delay_ms(BREATH_DELAY);
}

国芯人工智能 发表于 2025-9-11 20:38:00

您好,关于您在使用 STC8H8K64U-TSSOP20 芯片进行 PWM 输出控制 LED 的问题,您提到使用 IO口低电平输出 可以点亮LED,但通过 PWM方式控制P16端口 无法点亮,下面我将从硬件配置、寄存器设置、引脚复用功能、PWM模式选择等多个角度为您分析可能的原因,并提供相应的修改建议。

一、问题简述
目标:使用STC8H8K64U的P16引脚输出PWM波控制LED亮度(呼吸灯效果)。
现象:
使用普通IO口低电平输出,LED可以点亮。
使用PWM输出,LED不亮。
代码片段:您提供了PWM初始化部分的代码,但未提供完整的PWM中断处理、占空比更新和主循环逻辑。

二、初步分析

1. 引脚功能复用配置是否正确?

在STC8H系列中,P16默认是ADC6输入通道,不是PWM输出通道。必须通过 端口复用寄存器 P1M1/P1M0 设置其为 第二功能(即PWM输出)。

示例配置:

c
P1M1 = 0x00;        // 设置P1口为推挽输出
P1M0 = 0xFF;

// 设置P16为PWM输出(第二功能)
P1M1 &= ~0x40;        // P1M1.6 = 0
P1M0 |=0x40;        // P1M0.6 = 1 → 第二功能(PWM)

若未配置P16为PWM功能,该引脚将始终作为普通IO或ADC使用,导致PWM输出无效。

2. PWM模块初始化是否正确?

您提供的代码片段中定义了PWM的ARR和PSCR参数,但未提供完整的PWM初始化函数。以下是标准的 PWMA初始化流程:

示例代码:

c
void PWMAInit(void)
{
    PWMAPSCR = PWMAPSCRVAL;        // 设置预分频值
    PWMAARR= PWMAARRVAL;        // 设置自动重载寄存器(周期)
    PWMACCR4 = 0;                                // 初始占空比为0
    PWMACR1= 0x80;                        // 启动PWM时钟
    PWMACR2= 0x00;                        // 边沿对齐模式
    PWMABKR= 0x80;                        // 主输出使能
    PWMAOER= 0x10;                        // 使能PWMA通道4输出
    PWMACR1 |= 0x01;                        // 启动PWM
}
注意:PWMA通道4对应的引脚为P16,需确保PWMAOER寄存器位设置正确。

3. PWM输出极性是否正确?

PWM输出的极性决定了输出是高电平有效还是低电平有效。如果LED是阳极接VCC、阴极接地的方式,PWM输出应为低电平有效。

设置低电平有效的寄存器如下:

c
PWMACMR4 = 0x60;        // PWM模式1,低电平有效

如果设置为高电平有效,LED可能无法正确点亮。

4. PWM中断或主循环是否更新了占空比?

在呼吸灯实现中,需要在主循环或定时器中断中动态修改PWMACCR4的值:

示例:

```c
void main(void)
{
    PWMAInit();

    while (1)
    {
      if (gdutyinc)
      {
            gccr4val += BREATHSTEP;
            if (gccr4val >= PWMAARRVAL)
            {
                gdutyinc = 0;
            }
      }
      else
      {
            gccr4val -= BREATHSTEP;
            if (gccr4val = PWMAARRVAL)
            {
                gdutyinc = 0;
            }
      }
      else
      {
            gccr4val -= BREATHSTEP;
            if (gccr4val

[本文内容由国芯人工智能辅助生成,仅供参考]

网老四 发表于 2025-9-11 21:11:20

基本就是没有初始化管脚的IO模式,
默认上电高阻抗.所以无法输出PWM波形

乘风飞扬 发表于 2025-9-12 17:30:36

可参考8H实验箱例程包里面的PWM例子:23-高级PWM1-PWM2-PWM3-PWM4,驱动P6口呼吸灯实验程序
只要修改例子里面的PWM选择通道即可。
例程包下载地址:https://www.stcai.com/syx
页: [1]
查看完整版本: AI8H PWM输出的问题 求助!