stc8h8k64u 同时使用多个高速脉冲功能时,丢中断的情况探求
问题描述:同时使用三个高速脉冲输出功能时(PWMA_CCR4、PWMA_CCR3、PWMA_CCR2),发生中断标志位丢失的情况。按附录代码运行可观测到以下现象:
1、通过逻辑分析仪检测P34脚(PWMA_4P),可检测到高速脉冲不连续,脉冲中断的时长约32.8ms;
2、补全相关USB代码部分,打印输出ccr4_err_cnt变量,该值发生变化;
通过检测该值判断中断是否被响应的原理如下:
1)P34脚的硬件反转早于中断响应;
2)在中断函数中,翻转自定义标志位ccr4f,正常过程中,ccr4f 的值应与P34的值一致;
3)当ccr4f与P34的值不一致时,表示有一次中断函数未被执行,ccr4_err_cnt加1;
4)通过观测ccr4_err_cnt的值变化,分析未响应中断函数的次数。
代码中清除中断标志位的代码如下
t=PWMA_SR1; PWMA_SR1 =0; //清楚中断标志
若使用PWMA_SR1 &= ~0x10 的方式清楚中断标志,ccr4_err_cnt的变化速录会更快,也就是在单位时间内,未响应的中断函数次数更多。
补充说明:
发生中断未响应时,通过逻辑分析仪可观测到丢失中断的PWM管脚滞后其他管脚约1.5us。例如PWMA3N的管脚使用P15,当P15发生硬件翻转时,若在1.5us左右P34(PWMA4P)管脚发生硬件翻转,则在PWMA的中断函数中,PWMA4的中断函数会发生无法响应的情况。
上述现象将导致通过脉冲控制多个步进电机时,电机运行速度不稳定,并且该现象可能存在于其他中断标志位在片外RAM的中断响应中。
代码片段如下:
//pwm代码
#include "STC8H.h"
#define FOSC 24000000L
#include "intrins.h"
#define PWM1_1 0x00 //P:P1.0N:P1.1
#define PWM1_2 0x01 //P:P2.0N:P2.1
#define PWM1_3 0x02 //P:P6.0N:P6.1
#define PWM2_1 0x00 //P:P1.2/P5.4N:P1.3
#define PWM2_2 0x04 //P:P2.2N:P2.3
#define PWM2_3 0x08 //P:P6.2N:P6.3
#define PWM3_1 0x00 //P:P1.4N:P1.5
#define PWM3_2 0x10 //P:P2.4N:P2.5
#define PWM3_3 0x20 //P:P6.4N:P6.5
#define PWM4_1 0x00 //P:P1.6N:P1.7
#define PWM4_2 0x40 //P:P2.6N:P2.7
#define PWM4_3 0x80 //P:P6.6N:P6.7
#define PWM4_4 0xC0 //P:P3.4N:P3.3
#define ENO1P 0x01
#define ENO1N 0x02
#define ENO2P 0x04
#define ENO2N 0x08
#define ENO3P 0x10
#define ENO3N 0x20
#define ENO4P 0x40
#define ENO4N 0x80
bit ccr4f=0;
uint data ccr4_err_cnt=0;
uint PWMA_CCR3_set;
uint PWMA_CCR2_set;
uint PWMA_CCR4_set;
void PWMA_cfg()
{
IP2=0x04;IP2H=0x04;//将中断设为最高优先级,最高优先级的中断只有这一个
PWMA_ENO=0;
//使能PWMA输出
PWMA_PSCR=(FOSC/2000000)-1; //计数器时钟(FOCS/(PWMB_PSCR+1))
PWMA_ARR = 0xffff; //设置周期时间
PWMA_CCER1 = 0x00; //写CCMRx前必须先清零CCERx关闭通道
PWMA_CCER2 = 0x00; //写CCMRx前必须先清零CCERx关闭通道
PWMA_CCMR1 = 0; //冻结CCR1
PWMA_CCMR2 = 0x30; //设置CCR2为翻转输出模式
PWMA_CCMR3 = 0x30; //设置CCR3为翻转输出模式
PWMA_CCMR4 = 0x30; //设置CCR4为翻转输出模式
PWMA_CCER1 = 0x10; //禁用CC1通道
PWMA_CCER2 = 0x14; //使能CCR4P通道比较,//使能CCR3N通道比较
PWMA_CCR2_set = 100;
PWMA_CCR2 = PWMA_CCR2_set; //设置占空比时间
PWMA_CCR2_set += 100;
PWMA_CCR3_set = 100;
PWMA_CCR3 = PWMA_CCR3_set; //设置占空比时间
PWMA_CCR3_set += 100;
PWMA_CCR4_set = 100;
PWMA_CCR4 = PWMA_CCR4_set; //设置占空比时间
PWMA_CCR4_set += 100;
PWMA_IER = 0x18; //允许PWM4/3 中断
//设置PWM3/PWM4输出口
PWMA_PS = PWM4_4; //高级 PWM 通道输出脚选择位
PWMA_BKR = 0x80; //使能主输出
PWMA_CR1 = 0x01; //开始计时
}
void PWMA_ISR() interrupt 26 //PWMA中断
{
uchar data t;
//消除 中断标志位
t=PWMA_SR1;
PWMA_SR1 =0; //清楚其他中断标志
if((t&0x10)>0)
{
PWMA_CCR4 = PWMA_CCR4_set;
for(t=0;t<3;t++); //模拟其他指令时长
PWMA_ENO |= ENO4P;
PWMA_CCR4_set += 49;
ccr4f = !ccr4f;
if(ccr4f != P34) {ccr4f=P34;ccr4_err_cnt++;}
}
if((t&0x08)>0)
{
PWMA_CCR3 = PWMA_CCR3_set;
for(t=0;t<8;t++); //模拟其他指令时长
PWMA_CCR3_set += 70;
}
}
可按如下结构补全为可运行代码
void main()
{
//其他初始化代码
PWMA_cfg() ;
while(1);
}
//补全后
多轴控制,一定得用插补,否则不会太平稳的. 单个高速脉冲输出时,是啥情况 看来这里面有坑啊,要小心了。
t=PWMA_SR1;
PWMA_SR1 =0; //清楚其他中断标志
假如在这两句代码之间,PWMA_SR1 出现了新的标志,那么它就会被误杀,我暂时没想到办法,楼主测试一下看是不是这个原因。
页:
[1]