|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2012-11-23 23:14:10
|
显示全部楼层
coleyao 发表于 2012-11-21 11:48 ![](static/image/common/back.gif)
不客气,如果对速度有要求,不怕麻烦就用CPLD或数字电路,怕麻烦的话就用高频率的单片机,如stm32 CM0内 ...
以下是我学习您的代码,得出的分析 及 代码添加的注释:
1. 最大响应频率为2K,所以必须小于2K(实际上可能远小于2K,正确识别估计可能在1K左右)。
2. 原理: 是通过定时器不断(125us定时中断, 故允许的最大响应频率=4K)的扫描来检测AB相引脚上的电平变化(把上电首次(且只有首次才会)与对比成功后这一时刻的状态,同当前的检测状态作对比,以判断AB相电平是否发生变化);发生变化后,再判断B相电平与之前保存的A相电平的关系,来判断是右转(B==A时),还是左转(B !=A 时)。
但我感觉好像分别在AB相脉冲的上升沿,下降沿都有在计数,这样在A和B相的1个脉冲的上下沿共计数了4次? 这么做有点不是很理解。后面的计数中是不是对计数有除以4处理?
coleyao 大侠 ,您看我的理解正确么?
另外,有个问题想请教,对于抗干扰的处理。
1. 假如,在对比状态时,B相上现一次干扰,在低电平时突然有一个干扰脉冲, 会不会引起判断错误?
2. 我在想,可不可通过对 AB相电平变化的顺列来做抗干扰处理,如:右转是AB: 10 - 11 - 01 - 00,相当于一个完整脉冲周期(360度)才认为有效。
/*给个实例吧,用起来没问题的,不存在多次来回低速抖动时计数不准的现象,
当然有软解码的通病:速度上不去(for mega128 at 8M)。
*/
#pragma interrupt_handler TIMER3_OVF_ISR: 30
void TIMER3_OVF_ISR(void)
{
TCNT3=0xfc41; // 125uS
if(!Comparing){ // Comparing == 0, 首次对比(这一部分是针对刚上电时的情况)
PulAPol = PINE; // 读取AB相引脚电平状态(A相-PINE6,B相-PINE7)
PulLastState = PulAPol; // 记录下本次的AB相引脚电平状态
Comparing++; // 标志进入连续对比状态
PulAPol &= 0x40; // 记录下本次A相(PINE6)引脚电平状态
PulLastState &= 0xc0; // 记录下本次的AB相(只保留 B相-PINE7,A相-PINE6引脚)电平状态
PulAPol >>= 6; // 把A相状态位右移到第1位
}
if(Comparing) // Comparing >= 1, 第2..N次, 连续对比状态
{
PulBPol = PINE; // 再次读取AB相引脚电平状态(A相-PINE6,B相-PINE7)
PulState = PulBPol; // 记录下当前AB相位引脚电平状态
PulState &= 0xc0; // 记录下当前的AB相(只保留 B相-PINE7,A相-PINE6引脚)电平状态
PulBPol &= 0x80; // 记录下当前的B相(PINE7)引脚电平状态
PulBPol >>= 7; // 把B相状态位右移到第1位
if(PulState != PulLastState){ // 把当前状态与前一次对比是否发生变化? 无变化则继续在对比状态.
if(PulBPol == PulAPol){ // 已经发生了变化, 通过对比A、B相引脚电平的关系,判断是右转,还是左转?
RunRight = 1; // 相同: 则为右转
BMQCounterTotal--;
}
else{ // 不同: 则为左转
RunRight = 0;
BMQCounterTotal++;
}
Comparing = 0; // 标志进入保存当前(对比成功后的)状态
}
}
if(!Comparing){ // 记录下当前(对比成功后的)A相状态,及AB相的引脚电平状态,
PulAPol = PulState; // 以供后续检测,对比电平状态的变化。
PulLastState = PulAPol;
Comparing++;
PulAPol &= 0x40;
PulLastState &= 0xc0;
PulAPol >>= 6;
}
} |
|