|
假設函數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){;}
}
|
|