|
假设函数IS_PIN_A_HIGH()和IS_PIN_B_HIGH()是读取A,B两个引脚的状态
假设有两个外中断INT0和INT1都已经配置为双边沿触发模式,则解码如下:- //! 编码计数器
- static volatile uint32_t s_wQDCounter = 0;
- ISR(INT0_vect)
- {
- if (IS_PIN_A_HIGH() && IS_PIN_B_HIGH()) {
- s_wQDCounter++;
- } else {
- s_wQDCounter--;
- }
- }
- ISR(INT1_vect)
- {
- if (IS_PIN_A_HIGH() && IS_PIN_B_HIGH()) {
- s_wQDCounter--;
- } else {
- s_wQDCounter++;
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
读取全局变量s_wQDCounter的时候别忘记加入中断保护。如果要追求效率,可以将计数器类型修改为uint16_t。
--------------------------
以上就是中断法,可以用引脚电平变化中断来做。上面的代码是4倍频。如果要2倍频,去掉任何一个中断处理程序即可。
如果要单倍频,选择任意一个外中断,并选择只对某个边沿触发即可。
多年测试,稳定可靠~
记住一句口诀:
在任意边沿触发模式下,A和B进行电平比较:
对A触发的中断:同加异减
对B触发的中断:同减异加
反之亦然
总结到最后,就是 同加异减,同减异加
| 附工程
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int flag=0;
unsigned char count=0;
unsigned int num=0;
unsigned int GrayData=0;
unsigned int Hdata=0;
unsigned int Ldata=0;
#define set_bit(x,y) ((x)|=(1<<(y)))
#define clr_bit(x,y) ((x)&=~(1<<(y)))
#define PUL PORTA ^= (1 << PA2)
static volatile unsigned int s_wQDCounter = 0;
// unsigned int s_wQDCounter = 0;
/*unsigned int GtoB(unsigned int num)
{
num ^= num >> 16;
num ^= num >> 8;
num ^= num >> 4;
num ^= num >> 2;
//num ^= num >> 1;
return num^(num >> 1);
} */
unsigned int GraytoDecimal(unsigned int x)
{
unsigned int y = x;
while(x>>=1)
y ^= x;
return y;
}
unsigned int DecimaltoGray(unsigned int x)
{
return x^(x>>1);
}
unsigned int BinToInt(char *bin)
{
unsigned int Value=0;
while(*bin)
{
Value=Value<<1;
Value += (*bin)-'0';
bin++;
};
return Value;
}
//==================================================
const unsigned char seg[]={ 0xC0, // 0
0xF9, // 1
0xA4, // 2
0xB0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xF8, // 7
0x80, // 8
0x90 // 9
};
//==================================================
//IO端口初始化
void PortInit(void)
{
DDRA=0XFF;
PORTA=0XFF;
DDRB=0XFF;
PORTB=0XFF;
DDRC=0XFF;
PORTC=0XFF;
DDRD=0x00;
PORTD=0XFF;
//set_bit(PORTA,PA0);
}
//Timer0初始化
void Timer0Init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x06; //set count
OCR0 = 0xFA; //set compare
TCCR0 = 0x03; //start timer
}
void int_init(void)//配置外部中断
{
MCUCR |= 0x05;
MCUCSR|= 0x00;
GICR |= 0xC0;
}
//==================================================
//定时器0溢出中断服务程序
ISR(TIMER0_OVF_vect) //4ms刷新显示一次
{
TCNT0=0X06;
flag++;
count++;
switch(count)
{
case 1:if(num/1000){PORTA=0X01;PORTB=seg[num/1000];}else PORTB=0XFF;break;
case 2:if(((num/1000)+(num%1000/100))){PORTA=0X02;PORTB=seg[num%1000/100];}else PORTB=0XFF;break;
case 3:if(((num/1000)+(num%1000/100)+(num%100/10))){PORTA=0X04;PORTB=seg[num%100/10];}else PORTB=0XFF;break;
case 4:PORTA=0X08;PORTB=seg[num%10];break;
case 5:count=0;break;
default:break;
}
num=s_wQDCounter;
}
unsigned char IS_PIN_A_HIGH(void) //PD2 CHA //编码器A相
{
if ((PIND&(1<<PD2))==0)return 1;
else return 0;
}
unsigned char IS_PIN_B_HIGH(void) //PD3 CHB 编码器B相
{
if ((PIND&(1<<PD3))==0)return 1;
else return 0;
}
ISR(INT0_vect)
{
cli();
if (IS_PIN_A_HIGH() && IS_PIN_B_HIGH()) {
s_wQDCounter++;
} else {
s_wQDCounter--;
}
sei();
}
ISR(INT1_vect)
{
cli();
if (IS_PIN_A_HIGH() && IS_PIN_B_HIGH()) {
s_wQDCounter--;
} else {
s_wQDCounter++;
}
sei();
}
//==================================================
//主函数
int main(void)
{
cli();
TIMSK = 0x01; //timer interrupt sources
PortInit();
Timer0Init();
int_init();
sei();
while (1){;}
}
|
|