 |
#include <at89x52.h>
#define _BV(n) (1 << (n))
sbit PL = P3^0; // 置數端 sbit MR = P3^1; // 清零端 sbit TCU = P3^2; // 進位端 sbit TCD = P3^3; // 借位端 sbit CPD = P3^4; // 倒計時端 sbit CPU = P3^5; // 計時端
unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
void LS193_Clear(void) { MR = 1; MR = 0; }
unsigned char LS193_Read(void) { return (P1 & 0x0f); // 輸出端接P1低4位 }
void LS193_Write(unsigned char dat) { P1 = ((dat & 0x0f) << 4) | 0x0f; // 置數輸入端接P1高4位 PL = 0; PL = 1; }
// 進位、借位信號出現的時間很短 // 這樣的判斷方法不可靠 /* // 判斷是否進位 bit LS193_Carry(void) { TCU = 1; return (TCU == 0); }
// 判斷是否借位 bit LS193_Borrow(void) { TCD = 1; return (TCD == 0); } */
// 向上計數 void LS193_Up(void) { CPU = 0; CPU = 1; }
// 向下計數 void LS193_Down(void) { CPD = 0; CPD = 1; }
void seg_scan(void) { unsigned char i; unsigned char n = LS193_Read(); for (i = 7; i >= 6; i--) // 掃描第7、6個數碼管,從低位到高位 { P2 = 0xff; P0 = seg8[n % 10]; P2 = ~_BV(i); delay(5); n /= 10; } }
int main(void) { unsigned char i, j; P1 = 0x0f; LS193_Clear(); // 上電先清零 IT0 = 1; // 下降沿觸發 EX0 = 1; IT1 = 1; EX1 = 1; EA = 1; // 把外中斷的觸發方式改為低電平觸發(ITx=0)也沒有問題 // 因為進位、借位信號持續的時間極短(相應的時鐘為低電平時才會出現) while (1) { for (j = 0; j < 32; j++) { for (i = 0; i < 40; i++) seg_scan(); LS193_Up(); } for (j = 0; j < 32; j++) { for (i = 0; i < 40; i++) seg_scan(); LS193_Down(); } } }
void et0(void) interrupt 0 { LS193_Write(2); // 進位時預置數2 }
void et1(void) interrupt 2 { LS193_Write(10); // 借位時預置數10 }
|
 |
/* 延長進、借位信號持續時間的方法 */ /* 副作用: 每次進/退位會產生一短一長兩次脈衝, 且切換計數方向時計數值不變 */ #include <at89x52.h>
#define _BV(n) (1 << (n))
// 清零端(14)恆接低電平, 通電時計數值為隨機數 sbit TCU = P1^0; // 進位端(12) sbit TCD = P1^1; // 借位端(13) sbit CPD = P1^2; // 倒計時端(4) sbit CPU = P1^3; // 計時端(5)
unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
unsigned char LS193_Read(void) { P3 |= 0x0f; return (P3 & 0x0f); // 輸出端接P3低4位 }
// 判斷是否進位 bit LS193_Carry(void) { TCU = 1; return (TCU == 0); }
// 判斷是否借位 bit LS193_Borrow(void) { TCD = 1; return (TCD == 0); }
// 向上計數 void LS193_Up(void) { CPD = 1; // 使向下計數無效, 副作用: 會產生一次向下計數,使得最終本次數字沒有變 CPU = 0; CPU = 1; // 產生上升沿 CPU = 0; // =0時進位信號才能長期保持 }
// 向下計數 void LS193_Down(void) { CPU = 1; // 使向上計數無效, 副作用:會產生一次向上計數 CPD = 0; CPD = 1; // 產生上升沿 CPD = 0; // =0時借位信號才能長期保持 }
void seg_scan(void) { unsigned char i; unsigned char n = LS193_Read(); for (i = 7; i >= 6; i--) // 掃描第7、6個數碼管,從低位到高位 { P2 = 0xff; P0 = seg8[n % 10]; P2 = ~_BV(i); delay(5); n /= 10; } // 若有進位則顯示小寫c if (LS193_Carry()) { P2 = 0xff; P0 = 0xa7; P2 = ~_BV(0); } delay(5); // 若有借位則顯示小寫b if (LS193_Borrow()) { P2 = 0xff; P0 = 0x83; P2 = ~_BV(1); } delay(5); }
int main(void) { unsigned char i, j; while (1) { // 正計時 // 等於15時進位燈亮 for (j = 0; j < 32; j++) { for (i = 0; i < 40; i++) seg_scan(); LS193_Up(); } // 倒計時 // 等於0時借位燈亮 for (j = 0; j < 32; j++) { for (i = 0; i < 40; i++) seg_scan(); LS193_Down(); } } }
|
 |
/* 脈衝產生個數測試 */ #include <at89x52.h>
#define _BV(n) (1 << (n))
// 清零端(14)恆接低電平, 通電時計數值為隨機數 sbit TCU = P3^2; // 進位端(12), 外部中斷0 sbit TCD = P3^3; // 借位端(13), 外部中斷1 sbit CPD = P1^2; // 倒計時端(4) sbit CPU = P1^3; // 計時端(5)
unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; unsigned char num = 0; // 下降沿個數
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
unsigned char LS193_Read(void) { P1 |= 0xf0; return (P1 >> 4) & 0x0f; // 輸出端接P1高4位 }
// 向上計數 void LS193_Up(void) { CPD = 1; // 使向下計數無效, 副作用: 會產生一次向下計數,使得最終本次數字沒有變 CPU = 0; CPU = 1; // 產生上升沿 CPU = 0; // =0時進位信號才能長期保持 }
// 向下計數 void LS193_Down(void) { CPU = 1; // 使向上計數無效, 副作用:會產生一次向上計數 CPD = 0; CPD = 1; // 產生上升沿 CPD = 0; // =0時借位信號才能長期保持 }
void seg_scan(void) { char i; unsigned char n = LS193_Read(); for (i = 7; i >= 6; i--) // 掃描第7、6個數碼管,從低位到高位 { P2 = 0xff; P0 = seg8[n % 10]; P2 = ~_BV(i); delay(5); n /= 10; } n = num; for (i = 2; i >= 0; i--) // 掃描第2~0個數碼管,從低位到高位 { P2 = 0xff; P0 = seg8[n % 10]; P2 = ~_BV(i); delay(5); n /= 10; } }
int main(void) { unsigned char i, j; IT0 = 1; EX0 = 1; IT1 = 1; EX1 = 1; EA = 1; while (1) { // 正計時 for (j = 0; j < 32; j++) { for (i = 0; i < 80; i++) seg_scan(); LS193_Up(); } // 倒計時 for (j = 0; j < 32; j++) { for (i = 0; i < 80; i++) seg_scan(); LS193_Down(); } } }
void et0(void) interrupt IE0_VECTOR { num++; }
void et1(void) interrupt IE1_VECTOR { num += 10; }
// 正計時時,從14到15, num+1,說明產生了一個下降沿 // 倒計時時,從01到00,再到15,都要加10,num一共加了20, 說明產生了兩個下降沿
|
 |
在第一個程序中,當計數值為14且為向上計數的時候,時鐘CPU先置0後置1,也就是先下降沿後上升沿,最後計數值變成15。CPU=0時計數值為14,所以無進位信號。
當從15跳變到0時,因為進位信號只會出現在CPU=0時,且此時計數值為15,所以產生進位信號。因為CPU=0持續的時間極短,大約只有一個時鐘周期,所以進位信號有效的時間也極短。如果不使用中斷的話基本上檢測不出來。
這大大提高了系統的可靠性,使得在置數的時候可以保證不出現計數值=0的情況,直接跳變至指定的數字。
|