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;
}
在分析您提供的代码片段时,我们可以看出这是一个与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
贴了代码,有什么问题吗?请用文字详细描述一下问题所在。
我的晶振频率是24M ,PWMA_PSCR设置了23,PWMA_ARR设置500 ,PWMA_CCR4设置250,理论上输出2k 占空比50%的方波,并设置了输出比较中断,但printf函数在中断里运行,打印间隔却是15秒,同样设置过其他分频系数,比如PWMA_PSCR=0,打印间隔0.5秒,所以,是哪里的问题?
hjl 发表于 2025-4-27 09:10
我的晶振频率是24M ,PWMA_PSCR设置了23,PWMA_ARR设置500 ,PWMA_CCR4设置250,理论上输出2k 占空比50%的 ...
不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。
你在中断里取反一个IO指示中断。你输出的PWM正常了吗? 梁工 发表于 2025-4-27 10:19
不要用print()函数打印,特别是在任何中断里不要使用,因为printf()函数时查询方式的。
你在中断里取反一 ...
删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一致,切换3n输出通道 是io P15端口也是一样的现象
hjl 发表于 2025-4-27 11:41
删掉了print 试了试,
原本的输出通道 就是4p 是io P16端口,现象是灯亮4秒多,灭10秒多,
示波器测跟灯一 ...
解决了,是SDCC大小端的问题,导致对16位的寄存器复制出现错误,真是麻烦了 hjl 发表于 2025-4-27 14:22
解决了,是SDCC大小端的问题,导致对16位的寄存器复制出现错误,真是麻烦了 ...
C51、C251都是大端模式,这个要注意。电脑是小端模式,ARM也是小端模式。
页:
[1]