找回密码
 立即注册
查看: 71|回复: 7

AI8H2K32U PWM 问题

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-04-27 09:10:44
已绑定手机

1

主题

3

回帖

23

积分

新手上路

积分
23
发表于 6 天前 | 显示全部楼层 |阅读模式
截图202504251518171201.jpg


#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;

}

截图202504251525117271.jpg



截图202504251517585884.jpg
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 6 天前 | 显示全部楼层
在分析您提供的代码片段时,我们可以看出这是一个与PWM(脉宽调制)相关的初始化函数。以下是对代码的详细解析和优化建议:

代码解析

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

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

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

优化建议

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

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

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

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

示例代码

以下是一个扩展后的 PWMINIT 函数示例:
  1. c
  2. include "pwmh"
  3. define XFRENABLE 0x80
  4. define PWMPERIOD 1000  // 假设PWM周期为1000
  5. PWMn xdata PWMCLANNL[PWMCLANNLNUM];
  6. unsigned int xdata pP;
  7. void PWMINIT(void)
  8. {
  9.     // 使能XFR访问
  10.     PSW2 |= XFRENABLE;
  11.     // 配置PWM周期
  12.     PWMAPERIOD = PWMPERIOD;
  13.     // 配置PWM占空比(假设为50%)
  14.     for (int i = 0; i < PWMCLANNLNUM; i++) {
  15.         PWMCLANNL[i].DUTY = PWMPERIOD / 2;
  16.     }
  17.     // 使能PWM通道
  18.     PWMAENO = 0xFF;  // 假设使能所有通道
  19. }
复制代码

总结

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

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 5 天前 | 显示全部楼层
贴了代码,有什么问题吗?请用文字详细描述一下问题所在。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-04-27 09:10:44
已绑定手机

1

主题

3

回帖

23

积分

新手上路

积分
23
发表于 4 天前 | 显示全部楼层
梁*** 发表于 2025-4-26 13:33
贴了代码,有什么问题吗?请用文字详细描述一下问题所在。

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

点评

不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。 你在中断里取反一个IO指示中断。你输出的PWM正常了吗?  详情 回复 发表于 4 天前
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 4 天前 | 显示全部楼层
hj*** 发表于 2025-4-27 09:10
我的晶振频率是24M ,PWMA_PSCR设置了23,PWMA_ARR设置500 ,PWMA_CCR4设置250,理论上输出2k 占空比50%的 ...

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

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-04-27 09:10:44
已绑定手机

1

主题

3

回帖

23

积分

新手上路

积分
23
发表于 4 天前 | 显示全部楼层
梁*** 发表于 2025-4-27 10:19
不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。
你在中断里取反一 ...

删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一致,切换3n输出通道 是io P15端口也是一样的现象
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-04-27 09:10:44
已绑定手机

1

主题

3

回帖

23

积分

新手上路

积分
23
发表于 4 天前 | 显示全部楼层
hj*** 发表于 2025-4-27 11:41
删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一 ...

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

点评

C51、C251都是大端模式,这个要注意。电脑是小端模式,ARM也是小端模式。  详情 回复 发表于 4 天前
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 4 天前 | 显示全部楼层
hj*** 发表于 2025-4-27 14:22
解决了,是SDCC大小端的问题,导致对16位的寄存器复制出现错误,真是麻烦了 ...

C51、C251都是大端模式,这个要注意。电脑是小端模式,ARM也是小端模式。
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 22:08 , Processed in 0.149805 second(s), 102 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表