|
以前我寫過一個電子時鐘程序,動態掃描里面使用了這樣的代碼序列:
P2 = 0xff; // 先關閉所有數碼管
P2 = dis_digit; // | LEDMASK;
P0 = dis_buf[dis_index]; // 從第0個數碼管開始,即最左邊開始
由于每個數碼管都有數字要顯示,沒發現有什么問題.
但是今天寫ADC0804程序時應用這個動態掃描函數卻發現了一點問題,
那就是我不想顯示的數碼管一直都顯示著一個模糊的數字,并且跟它往前相鄰的數字一樣.
猜測和調試了很久,最后才發現問題出在代碼的執行順序上.
正確的代碼執行序列應該是關燈后立刻把內容準備好,再開燈,這樣才能沒有副作用.
所以對P0的賦值要夾在對P2的兩次賦值之間.
PS:
電子時鐘.c
/*邏輯已經修改清晰,使用時分秒三個變量獨立處理,并配有相應函數*/
#include <reg51.h>
#include <intrins.h>
#define PUSH(Key) !Key //XL600都是按下為低電平的,高電平時作為輸入
#define LEDMASK 0x24 //00100100 --- 1的地方不亮
#define MIDDLINE 10
#define BALCK 11
#define ISKEY(pos) (key & (1 << pos)) //檢測是第幾個按鍵,從0開始起
sbit KeyPP = P3 ^ 2; //Key Play and Pause
sbit KeyHourAdd = P3 ^ 3; //Key Hour Add
sbit KeyMinAdd = P3 ^ 4; //Key Min Add
//sbit KEYSET = P3 ^ 5;
enum { KEYPP = 0, KEYHOURADD = 1, KEYMINADD = 2, KEYSET = 3};
unsigned char code Led7Tab[12] = { 0x28, 0x7E, 0xA2, 0x62, 0x74, //0 1 2 3 4
0x61, 0x21, 0x7A, 0x20, 0x60, //5 6 7 8 9
0xF7, //中間短橫線 MIDDLINE
0xFF}; //不顯示,全黑 BALCK
unsigned char dis_buf[8], hour, min, sec, start;
void clr_time();
void timetick();
void UpdateTime();
void delayms(unsigned char ms);
void proc_key(unsigned char key);
void PART2LED(unsigned char part, unsigned char pos);
void ToThenCarry(unsigned char *src, unsigned char top, unsigned char *dest);
unsigned char scan_key();
void main(void)
{
P0 = 0xff;
P2 = 0xff;
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x17;
IE = 0x82;
TR0 = 1;
clr_time();
while(1)
{
unsigned char key;
if(scan_key() != 0)
{
delayms(10);
if((key = scan_key()) != 0)
{
while(scan_key() != 0)
;
proc_key(key);
}
}
else if(start)
{
timetick();
}
}
}
unsigned char scan_key()
{
unsigned char key = 0, keyPos; //由于按鍵類型是sbit,不可以成為<<運算符的左值,
//故將其裝換為新的unsigned char變量,然后移位
key |= (keyPos= ~KeyPP) << 0;
key |= (keyPos= ~KeyHourAdd) << 1;
key |= (keyPos= ~KeyMinAdd) << 2;
//這里就可以擴展以后的按鍵了
return (key);
}
void proc_key(unsigned char key)
{
if(ISKEY(KEYPP))
{
start = !start;
}
else if(ISKEY(KEYHOURADD))
{
++hour;
if(hour == 24)
hour = 0;
UpdateTime();
}
else if(ISKEY(KEYMINADD))
{
++min;
if(min == 60)
min = 0;
UpdateTime();
}
}
void clr_time() //全部清零
{
hour = min = sec = 0;
dis_buf[2] = dis_buf[5] = Led7Tab[MIDDLINE];
UpdateTime();
}
void UpdateTime()
{
PART2LED(hour, 1);
PART2LED(min, 4);
PART2LED(sec, 7);
}
void PART2LED(unsigned char part, unsigned char pos)
{
dis_buf[pos] = Led7Tab[part % 10];
dis_buf[pos - 1] = Led7Tab[(part / 10)];
}
void ToThenCarry(unsigned char *src, unsigned char top, unsigned char *dest)
{
if(*src >= top)
{
*src = 0;
++(*dest);
}
}
void timetick()
{
delayms(255);
++sec;
ToThenCarry(&sec, 60, &min);
ToThenCarry(&min, 60, &hour);
if(hour == 24)
{
clr_time();
}
UpdateTime();
dis_buf[2] = dis_buf[5] ^= 0x08; //技巧:F7 -- FF 互變,用 00001000 異或即可
}
void Display() interrupt 1 //動態掃描顯示數碼管,放在中斷里就是最好的方案,搞得我想了半天其它方法
{
static unsigned char data dis_digit = 0xFE; // P2的二進制掩碼選通第幾個數碼管,從0位即最左邊掃描起
static unsigned char dis_index = 0; // 邏輯第幾個數碼管
TH0 = 0xFC;
TL0 = 0x17;
P2 = 0xff; // 先關閉所有數碼管
P0 = dis_buf[dis_index]; // 從第0個數碼管開始,即最左邊開始
// P0的賦值要夾在這中間,也就是緊跟在燈全滅之后,
// 否則,它會模糊地顯示上一個數字,即它之前的那個數字,
// 這個bug直到今天寫ADC0804程序才發現.
// Apr. 4, 2009
P2 = dis_digit;
dis_digit = _crol_(dis_digit, 1); // 循環左移
dis_index++;
dis_index &= 0x07; // 技巧: 掩碼:0111,當1000時變成0
}
void delayms(unsigned char ms)
{
unsigned int i;
while(--ms)
{
for ( i = 0; i < 320; i++)
;
}
}
ADC0804.c
#include "..\mcu.h"
#define ADCDATA P1
sbit ADC0804_WR = P3 ^ 6;
sbit ADC0804_RD = P3 ^ 7;
unsigned char dis_buf[8];
void Number2Led(unsigned char number);
void ClearDisplay(void);
void main(void)
{
unsigned char value;
TMOD = 0x02;
TH0 = 0xF0;
TL0 = 0xF0;
IE = 0x82;
TR0 = 1;
ADCDATA = 0xFF;
ClearDisplay();
while(1)
{
ADC0804_WR = 0;
ADC0804_WR = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ADC0804_RD = 1;
ADC0804_RD = 0;
value = ADCDATA;
value = ~value;
Number2Led(value);
}
}
void Number2Led(unsigned char number)
{
unsigned char i, j;
i = 7;
while(1)
{
dis_buf = LED7TAB[number % 10];
if(number > 10)
{
number /= 10;
}
else
{
break;
}
}
for(j = 1; j <= i; j++)
{
dis_buf[j] = 0xFF;
}
}
void Display() interrupt 1 //動態掃描顯示數碼管,放在中斷里就是最好的方案,搞得我想了半天其它方法
{
static unsigned char dis_digit = 0xFE; // P2的二進制掩碼選通第幾個數碼管,從0位即最左邊掃描起
static unsigned char dis_index = 0; // 邏輯第幾個數碼管
P2 = 0xff; // 先關閉所有數碼管
P0 = dis_buf[dis_index]; // 從第0個數碼管開始,即最左邊開始
P2 = dis_digit; // | LEDMASK;
dis_digit = _crol_(dis_digit, 1); // 循環左移
dis_index++;
dis_index &= 0x07; // 技巧: 掩碼:0111,當1000時變成0
}
void ClearDisplay(void)
{
unsigned char index;
for(index = 0; index < 8; index++)
{
dis_buf[index] = 0xFF;
}
}
|
|