使用外部中斷接收ENCODER

這是幫朋友寫的一個程式,主要是用int0來接收encoder正轉,int1來接收encoder反轉,再將encoder的值顯示在3顆七段顯示器上,由於接了74LS47,所以編碼跟一般七段不一樣

這裡有幾個重點要備忘:

1.ITX未設定時,預設為0即負觸發,只要一接收到0,中斷副程式中的變數就狂累加,將ITX設成1即可變為負緣觸發

2.掃描碼跟七段編碼在同一個PORT位:

先上掃描碼之後將七段編碼OR上去即可

3.假設encoder值為599,我們要如何顯示成59.9

將599%10取餘數=9存入counter[0]陣列

將579%100取餘數/10取商數=7存入counter[1]陣列

將579/100取商數=5存入counter[2]陣列

再用七段編碼的陣列代入counter即可

例:P2=seven_seg[counter[0]] =>調出counter[0]中的值來當作seven_seg的[指標]

counter[0]現在是9,於是資料指向seven_seg[9]=0x40

於是P2就被設成0x40

4.P2的配置及原始碼

P2_0~P2_2為電晶體PNP所以掃描碼為00000110 ,0000101 ,00000011....... 因七段為共陽P2_7為0導通

5.程式配置

timer0中斷副程式 負責將Encoder現在的值分成小數點,個位數,十位數,並做七段顯示

int0中斷副程式 負責接收正轉的Encoder信號

int1中斷副程式 負責接收反轉的Encoder信號

main主程式 限制記錄ENCODER步數的變數(steps)上限為3位數999

6.完成圖(使用74LS47最大好處就是只用了P2就可以做3位數顯示了)

點圖可以放大

6.電路圖

點圖可以放大

===========原始碼說明=============

#include<regx51.h>

code seven_seg[10]={0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48}; //74LS47編碼IC對應0~9

code scan[3]={0x06,0x05,0x03}; //掃描碼FOR 74LS47 S1 ,S2 ,S3

unsigned char counter[3]={0,0,0}; //存放十位數,個位數,小數點第一位

unsigned char i;

int steps; //記錄encoder的步數

unsigned int temp; //給計時器工作用

void timer0_initialize(void) //初始化計時器0

{

EA=0; //關閉中斷功能(所有中斷副程式失效)

ET0=1; //開啟計時器0中斷功能

EX0=1; /* 設定接受INT0的中斷 */

EX1=1; /* 設定接受INT1的中斷 */

IT0=1; //設INT0為負緣觸發*(避免一次訊號累加,造成錯步)*

IT1=1; //設INT1為負緣觸發*(避免一次訊號累加,造成錯步)*

PX0=1; //INT0中斷優先處理

PX1=1; //INT0中斷優先處理

PT0=0; //timer0中斷延後處理*(避免遺漏encoder的訊號)*

TMOD|=0x01; //設定計時器模式

temp=65536-8333; //設定中斷一次的時間

TH0=temp/256; //填入高八位

TL0=temp%256; //填入低八位

TR0=1; //啟動計時器

EA=1; //開啟中斷功能(中斷副程式可以執行)

}

void timer0_isr(void) interrupt TF0_VECTOR using 1 //計時器中斷副程式,計時器中斷一次即執行*(此程式中每秒中斷120次)*

{

TR0=0; //停止計時器

TH0=temp/256; //重新埴入高八位

TL0=temp%256; //重新埴入低八位

TR0=1; //啟動計時器

counter[0]=steps%10; //取steps的小數點第一位

counter[1]=steps%100/10; //取steps的個位數

counter[2]=steps/100; //取steps的十位數

P2=scan[i]; //先上掃描碼導通小數點第一位的七段

P2|=seven_seg[counter[i]]; //將小數點第一位的七段碼OR進P2,以免破壞掃描碼

if(i==1)P2_7=0; //掃描到個位數七段加上小數點

else P2_7=1; //若不是個位數不用加小數點

i++; //導通下一顆七段

if(i>2)i=0; //掃描到十位數後重新從小數第一位開始掃描

}

static void xint0_isr(void) interrupt IE0_VECTOR //INT0中斷副程式

{

if(steps<999)steps++; //ENCODER步數+1

}

static void xint1_isr(void) interrupt IE1_VECTOR //INT1中斷副程式

{

if(steps>0)steps--; //ENCODER步數-1

}

void main(void) //主程式

{

timer0_initialize(); //呼叫一次計時器初始化

while(1);

}