hjl 发表于 2025-4-25 15:25:54

AI8H2K32U PWM 问题




#include "pwm.h"

PWMn xdata PWM_CLANNL[PWM_CLANNL_NUM];
unsigned int xdata *pP;
/******************** 主函数 **************************/
void PWM_INIT(void)
{

    P_SW2 |= 0x80;                              //使能XFR访问

    //PWMA 配置
    PWMA_ENO = 0x00;
    PWMA_ENO |= ENO4P;//使能输出
    PWMA_PS = 0x00;//高级 PWM 通道输出脚选择位
    PWMA_PS |= PWM4_1;//选择 PWM4_4 通道
    PWMA_CNTR = 0;//清计数
    PWMA_PSCR = 23;//24M主频24分频为1M
    PWMA_BKR = 0x80;//使能主输出
    PWMA_CR1 |= 0x01;//开始计时
    PWMA_SR1 = 0;
    //PWMB 配置

    // PWMB_ENO = 0x00;
    // PWMB_ENO |= ENO5P;//使能输出
    // PWMB_PS = 0x00;//高级 PWM 通道输出脚选择位
    // PWMB_PS |= PWM5_2;//选择 PWM1_2 通道
    // PWMB_CNTR = 0;//清计数
    // PWMB_PSCRH = 0;
    // PWMB_PSCRL = 23;//24M主频24分频为1M
    // PWMB_BKR = 0x80;//使能主输出
    // PWMB_CR1 |= 0x01;//开始计时
    // PWMB_SR1 = 0;

   IP2 |= 0X04;      //最高优先级
      IP2H|=0X04;

}
//清除计数
void clear_pwm_count(PWMn *p)
{
    p->plsr_count = 0;
    p->pulse_count = 0;
    p->count_mm = 0;
    p->pulseoffset_count = 0;
    p->period_count = 0;
    p->duty_count = 0;
}
/************* 发送脉冲函数 **************/
/*u8 dj_cut选择通道 ,u8 sw开始停止PWM*/
/*u8 dj_cut选择通道 ,u8 sw开始停止PWM*/
void TxPulse(u8 channl,u16 HZ,u16 zkb)
{

    u16 hz_temp, zkb_temp;

    if (HZ > HIGHSPEED) HZ = HIGHSPEED;
    if (HZ < LOWSPEED) HZ = LOWSPEED;
    if (zkb > PWM_ZKB) zkb = PWM_ZKB / 2;
    hz_temp = HZ;
    //delaynms(1);
    zkb_temp = (u32) hz_temp * zkb / PWM_ZKB;
    //参数限制
    printf("hz_temp=%d,zkb_temp=%d\n",hz_temp,zkb_temp);


    switch (channl)
    {
      case PWMA_CLANNL_1P:
      PWMA_ARR = hz_temp;
      PWMA_CCR1 = zkb_temp;
      PWMA_CCER1 &= ~OC1P_EN;
      PWMA_SR1 &= ~CC1IE_EN;    //设置频率//设置占空比时间: hz_temp/2    //写 CCMRx 前必须先清零 CCxE    关闭通道

      PWMA_CCMR1 = PWM_OC1M_MODE1;//设置 PWM 模式1 输出//使能 CC1p通道, 高电平有    效//使能捕获/比较 1中断
      PWMA_CCER1 |= OC1P_EN;
      PWMA_IER |= CC1IE_EN;

      break;
      case PWMA_CLANNL_1N:
      PWMA_ARR = hz_temp;
      PWMA_CCR1 = zkb_temp;
      PWMA_CCER1 &= ~OC1N_EN;
      PWMA_SR1 &= ~CC1IE_EN;

      PWMA_CCMR1 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有    效//使能捕获/比较 1中断
      PWMA_CCER1 |= OC1N_EN;
      PWMA_IER |= CC1IE_EN;

    break;
    case PWMA_CLANNL_2P:
    PWMA_ARR = hz_temp;
    PWMA_CCR2 = zkb_temp;
    PWMA_CCER1 &= ~OC2P_EN;
    PWMA_SR1 &= ~CC2IE_EN;

    PWMA_CCMR2 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER1 |= OC2P_EN;
    PWMA_IER |= CC2IE_EN;

    break;
    case PWMA_CLANNL_2N:
    PWMA_ARR = hz_temp;
    PWMA_CCR2 = zkb_temp;
    PWMA_CCER1 &= ~OC2N_EN;
    PWMA_SR1 &= ~CC2IE_EN;

    PWMA_CCMR2 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER1 |= OC2N_EN;
    PWMA_IER |= CC2IE_EN;

    break;
    case PWMA_CLANNL_3P:
    PWMA_ARR = hz_temp;
    PWMA_CCR3 = zkb_temp;
    PWMA_CCER2 &= ~OC3P_EN;
    PWMA_SR1 &= ~CC3IE_EN;

    PWMA_CCMR3 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER2 |= OC3P_EN;
    PWMA_IER |= CC3IE_EN;


    break;
    case PWMA_CLANNL_3N:
    PWMA_ARR = hz_temp;
    PWMA_CCR3 = zkb_temp;
    PWMA_CCER2 &= ~OC3N_EN;
    PWMA_SR1 &= ~CC3IE_EN;

    PWMA_CCMR3 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER2 |= OC3N_EN;
    PWMA_IER |= CC3IE_EN;

    break;
    case PWMA_CLANNL_4P:
    PWMA_ARR = hz_temp;
    PWMA_CCR4 = zkb_temp;
    PWMA_CCER2 &= ~OC4P_EN;
    PWMA_SR1 &= ~CC4IE_EN;

    PWMA_CCMR4 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER2 |= OC4P_EN;
    PWMA_IER |= CC4IE_EN;

    break;
    case PWMA_CLANNL_4N:
    PWMA_ARR = hz_temp;
    PWMA_CCR4 = zkb_temp;
    PWMA_CCER2 &= ~OC4N_EN;
    PWMA_SR1 &= ~CC4IE_EN;

    PWMA_CCMR4 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有效//使能捕获/比较 1中断
    PWMA_CCER2 |= OC4N_EN;
    PWMA_IER |= CC4IE_EN;

    break;
    case PWMB_CLANNL_5P:
    PWMB_ARR = hz_temp;
    PWMB_CCR5 = zkb_temp;
    PWMB_CCER1 &= ~OC5_EN;
    PWMB_SR1 &= ~CC5IE_EN;

    PWMB_CCMR1 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有   效//使能捕获/比较 1中断
    PWMB_CCER1 |= OC5_EN;
    PWMB_IER |= CC5IE_EN;

    break;
    case PWMB_CLANNL_6P:
    PWMB_ARR = hz_temp;
    PWMB_CCR6 = zkb_temp;
    PWMB_CCER1 &= ~OC6_EN;
    PWMB_SR1 &= ~CC6IE_EN;

    PWMB_CCMR2 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有   效//使能捕获/比较 1中断
    PWMB_CCER1 |= OC6_EN;
    PWMB_IER |= CC6IE_EN;

    break;
    case PWMB_CLANNL_7P:
    PWMB_ARR = hz_temp;
    PWMB_CCR7 = zkb_temp;
    PWMB_CCER2 &= ~OC7_EN;
    PWMB_SR1 &= ~CC7IE_EN;

    PWMB_CCMR3 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有   效//使能捕获/比较 1中断
    PWMB_CCER2 |= OC7_EN;
    PWMB_IER |= CC7IE_EN;

    break;
    case PWMB_CLANNL_8P:
    PWMB_ARR = hz_temp;
    PWMB_CCR8 = zkb_temp;
    PWMB_CCER2 &= ~OC8_EN;
    PWMB_SR1 &= ~CC8IE_EN;

    PWMB_CCMR4 = PWM_OC1M_MODE1;    //设置 PWM 模式1 输出//使能 CC1p通道, 高电平有   效//使能捕获/比较 1中断
    PWMB_CCER2 |= OC8_EN;
    PWMB_IER |= CC8IE_EN;

    break;
    default:
    break;
}


    clear_pwm_count(&PWM_CLANNL[channl]);
    PWM_CLANNL[channl].channl = channl;
    PWM_CLANNL[channl].period = HZ;
    PWM_CLANNL[channl].duty = zkb;


}

void TxPulse_stop(u8 channl)
{
    switch (channl)
    {
      case PWMA_CLANNL_1P:
      PWMA_CCER1 &= ~OC1P_EN;
      PWMA_SR1 &= ~CC1IE_EN;
      PWMA_CCMR1 = PWM_OC1M_invalid;
      PWMA_CCER1 |= OC1P_EN;
      PWMA_IER &= ~CC1IE_EN;
      break;
      case PWMA_CLANNL_1N:
      PWMA_CCER1 &= ~OC1N_EN;
      PWMA_SR1 &= ~CC1IE_EN;
      PWMA_CCMR1 = PWM_OC1M_invalid;
      PWMA_CCER1 |= OC1N_EN;
      PWMA_IER &= ~CC1IE_EN;
      break;
      case PWMA_CLANNL_2P:
      PWMA_CCER1 &= ~OC2P_EN;
      PWMA_SR1 &= ~CC2IE_EN;
      PWMA_CCMR2 = PWM_OC1M_invalid;
      PWMA_CCER1 |= OC2P_EN;
      PWMA_IER &= ~CC2IE_EN;
      break;
      case PWMA_CLANNL_2N:
      PWMA_CCER1 &= ~OC2N_EN;
      PWMA_SR1 &= ~CC2IE_EN;
      PWMA_CCMR2 = PWM_OC1M_invalid;
      PWMA_CCER1 |= OC2N_EN;
      PWMA_IER &= ~CC2IE_EN;
      break;
      case PWMA_CLANNL_3P:
      PWMA_CCER2 &= ~OC3P_EN;
      PWMA_SR1 &= ~CC3IE_EN;
      PWMA_CCMR3 = PWM_OC1M_invalid;
      PWMA_CCER2 |= OC3P_EN;
      PWMA_IER &= ~CC3IE_EN;
      break;
      case PWMA_CLANNL_3N:
      PWMA_CCER2 &= ~OC3N_EN;
      PWMA_SR1 &= ~CC3IE_EN;
      PWMA_CCMR3 = PWM_OC1M_invalid;
      PWMA_CCER2 |= OC3N_EN;
      PWMA_IER &= ~CC3IE_EN;
      break;
      case PWMA_CLANNL_4P:
      PWMA_CCER2 &= ~OC4P_EN;
      PWMA_SR1 &= ~CC4IE_EN;
      PWMA_CCMR4 = PWM_OC1M_invalid;
      PWMA_CCER2 |= OC4P_EN;
      PWMA_IER &= ~CC4IE_EN;
      break;
      case PWMA_CLANNL_4N:
      PWMA_CCER2 &= ~OC4N_EN;
      PWMA_SR1 &= ~CC4IE_EN;
      PWMA_CCMR4 = PWM_OC1M_invalid;
      PWMA_CCER2 |= OC4N_EN;
      PWMA_IER &= ~CC4IE_EN;
      break;


      case PWMB_CLANNL_5P:
      PWMB_CCER1 &= ~OC5_EN;
      PWMB_SR1 &= ~CC5IE_EN;
      PWMB_CCMR1 = PWM_OC1M_invalid;
      PWMB_CCER1 |= OC5_EN;
      PWMB_IER &= ~CC5IE_EN;
      break;
      case PWMB_CLANNL_6P:
      PWMB_CCER1 &= ~OC6_EN;
      PWMB_SR1 &= ~CC6IE_EN;
      PWMB_CCMR2 = PWM_OC1M_invalid;
      PWMB_CCER1 |= OC6_EN;
      PWMB_IER &= ~CC6IE_EN;
      break;
      case PWMB_CLANNL_7P:
      PWMB_CCER2 &= ~OC7_EN;
      PWMB_SR1 &= ~CC7IE_EN;
      PWMB_CCMR3 = PWM_OC1M_invalid;
      PWMB_CCER2 |= OC7_EN;
      PWMB_IER &= ~CC7IE_EN;
      break;
      case PWMB_CLANNL_8P:
      PWMB_CCER2 &= ~OC8_EN;
      PWMB_SR1 &= ~CC8IE_EN;
      PWMB_CCMR4 = PWM_OC1M_invalid;
      PWMB_CCER2 |= OC8_EN;
      PWMB_IER &= ~CC8IE_EN;
      break;
      default:
      break;
    }
    clear_pwm_count(&PWM_CLANNL[channl]);
}

/*去改变占空比 和频率(可在定时器调用)*/
void pwm_tim(u8 channl,u16 hz,u16 zkb)
{
    if(channl < PWM_CLANNL_NUM)
    {

      if (hz > HIGHSPEED) hz = HIGHSPEED;
      if (hz < LOWSPEED) hz = LOWSPEED;
      PWM_CLANNL[channl].period_count = 1000000UL / hz;
      PWM_CLANNL[channl].duty_count = (u32) PWM_CLANNL[channl].period_count * zkb / PWM_ZKB;

      if (channl == 0||channl == 1) pP = &PWMA_CCR1;
      else if (channl == 2||channl == 3) pP = &PWMA_CCR2;
      else if (channl == 4||channl == 5) pP = &PWMA_CCR3;
      else if (channl == 6||channl == 7) pP = &PWMA_CCR4;
      else if (channl == 8) pP = &PWMB_CCR5;
      else if (channl == 9) pP = &PWMB_CCR6;
      else if (channl == 10) pP = &PWMB_CCR7;
      else if (channl == 11) pP = &PWMB_CCR8;
      if(channl<8) PWMA_ARR = PWM_CLANNL[channl].period_count;
      else PWMB_ARR = PWM_CLANNL[channl].period_count;
      *pP = PWM_CLANNL[channl].duty_count;
    }

}




// /******************* PWM中断函数 ********************/
INTERRUPT(PWMA_ISR,26)
{
    PWMA_SR1 = 0;

    printf("PWMA_ARR=%d,PWMA_CCR4=%d,PWMA_PSCR=%d\n",PWMA_ARR,PWMA_CCR4,PWMA_PSCR);
}
INTERRUPT(PWMB_ISR,27)
{

    PWMB_SR1 = 0;

}




国芯人工智能 发表于 2025-4-25 15:38:00

在分析您提供的代码片段时,我们可以看出这是一个与PWM(脉宽调制)相关的初始化函数。以下是对代码的详细解析和优化建议:

代码解析

1. 头文件引入:
   c
   #include "pwmh"
   这行代码引入了名为 pwmh 的头文件,通常该文件会包含与PWM相关的函数和宏定义。

2. 全局变量声明:
   c
   PWMn xdata PWMCLANNL;
   unsigned int xdata pP;
PWMCLANNL 是一个数组,用于存储PWM通道的相关数据,PWMCLANNLNUM 是通道的数量。
pP 是一个无符号整型变量,可能用于存储PWM的周期或其他参数。

3. PWM初始化函数:
   c
   void PWMINIT(void)
   {
       PSW2 |= 0x80;// 使能XFR访问
   }
PSW2 |= 0x80; 这行代码通过设置 PSW2 寄存器的最高位来使能XFR(外部功能寄存器)访问。这通常是为了访问某些特殊功能寄存器或扩展功能。

优化建议

1. 代码注释:
建议在代码中添加更多注释,特别是对于关键寄存器的设置和功能描述,以便于后续维护和理解。

2. 寄存器操作:
在操作寄存器时,建议使用宏定义或常量来代替硬编码的数值,以提高代码的可读性和可维护性。例如:
   c
   #define XFRENABLE 0x80
   PSW2 |= XFRENABLE;

3. 函数扩展:
当前的 PWMINIT 函数仅使能了XFR访问,建议在该函数中进一步配置PWM模块的相关寄存器,如设置PWM周期、占空比、通道使能等。

4. 错误处理:
在初始化过程中,建议添加错误处理机制,以确保配置的正确性。例如,检查寄存器设置是否成功。

示例代码

以下是一个扩展后的 PWMINIT 函数示例:

c
include "pwmh"

define XFRENABLE 0x80
define PWMPERIOD 1000// 假设PWM周期为1000

PWMn xdata PWMCLANNL;
unsigned int xdata pP;

void PWMINIT(void)
{
    // 使能XFR访问
    PSW2 |= XFRENABLE;

    // 配置PWM周期
    PWMAPERIOD = PWMPERIOD;

    // 配置PWM占空比(假设为50%)
    for (int i = 0; i < PWMCLANNLNUM; i++) {
      PWMCLANNL.DUTY = PWMPERIOD / 2;
    }

    // 使能PWM通道
    PWMAENO = 0xFF;// 假设使能所有通道
}

总结

通过上述分析和优化,我们可以使代码更加清晰、可维护,并且功能更加完善。在实际开发中,建议根据具体硬件平台和需求进一步调整和优化代码。

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

梁工 发表于 2025-4-26 13:33:11

贴了代码,有什么问题吗?请用文字详细描述一下问题所在。

hjl 发表于 2025-4-27 09:10:44

梁工 发表于 2025-4-26 13:33
贴了代码,有什么问题吗?请用文字详细描述一下问题所在。

我的晶振频率是24M ,PWMA_PSCR设置了23,PWMA_ARR设置500 ,PWMA_CCR4设置250,理论上输出2k 占空比50%的方波,并设置了输出比较中断,但printf函数在中断里运行,打印间隔却是15秒,同样设置过其他分频系数,比如PWMA_PSCR=0,打印间隔0.5秒,所以,是哪里的问题?

梁工 发表于 2025-4-27 10:19:05

hjl 发表于 2025-4-27 09:10
我的晶振频率是24M ,PWMA_PSCR设置了23,PWMA_ARR设置500 ,PWMA_CCR4设置250,理论上输出2k 占空比50%的 ...

不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。
你在中断里取反一个IO指示中断。你输出的PWM正常了吗?

hjl 发表于 2025-4-27 11:41:13

梁工 发表于 2025-4-27 10:19
不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。
你在中断里取反一 ...
删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一致,切换3n输出通道 是io P15端口也是一样的现象

hjl 发表于 2025-4-27 14:22:11

hjl 发表于 2025-4-27 11:41
删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一 ...

解决了,是SDCC大小端的问题,导致对16位的寄存器复制出现错误,真是麻烦了

梁工 发表于 2025-4-27 15:31:48

hjl 发表于 2025-4-27 14:22
解决了,是SDCC大小端的问题,导致对16位的寄存器复制出现错误,真是麻烦了 ...

C51、C251都是大端模式,这个要注意。电脑是小端模式,ARM也是小端模式。
页: [1]
查看完整版本: AI8H2K32U PWM 问题