你的代碼有問題
中斷邏輯錯誤:定時器 0 中斷中使用if(flag=20)和if(flag=0)(賦值語句而非判斷語句),導致倒計時邏輯完全錯亂,無法正常遞減。
倒計時邊界處理缺失:未處理num減至 0 后的復位邏輯,且flag=60的賦值無意義,導致數值溢出或停滯。
動態掃描時序不合理:主函數中無延時直接切換數碼管位選,掃描頻率過快,肉眼無法識別,表現為 “不顯示” 或 “顯示模糊”。
數碼管段碼可能不匹配:若使用共陽極數碼管,當前段碼表(共陰極)會導致顯示異常,需確認硬件連接類型。
- #include"stc8.h"
- #include "intrins.h"
- #define uint unsigned int
- #define uchar unsigned char
- #define SEG P1 // 數碼管段選引腳
- sbit SCON1 = P3^7; // 個位數碼管位選
- sbit SCON2 = P3^6; // 十位數碼管位選
- sbit KEY = P3^2; // 按鍵(預留,可用于啟動/復位)
- uchar count = 0; // 數碼管掃描計數
- char num = 60; // 倒計時初始值(0-60)
- uchar ge, shi; // 個位、十位拆分值
- uchar flag = 0; // 定時器計數標志
- // 共陰極數碼管段碼表(0-9),若為共陽極需改為0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6
- uchar code table[] = {
- 0x03,/*0*/ 0x9F,/*1*/ 0x25,/*2*/ 0x0D,/*3*/ 0x99,/*4*/
- 0x49,/*5*/ 0x41,/*6*/ 0x1F,/*7*/ 0x01,/*8*/ 0x09,/*9*/
- };
- // 定時器0初始化:5毫秒@11.0592MHz(12T模式)
- void T0_init() {
- AUXR &= 0x7F; // 定時器時鐘12T模式
- TMOD &= 0xF0; // 清除定時器0模式
- TMOD |= 0x01; // 定時器0工作模式1(16位定時)
- TL0 = 0x00; // 定時5ms初始值(11.0592MHz計算得出)
- TH0 = 0xEE; // 重載值:TH0=0xEE, TL0=0x00,單次定時約5ms
- TF0 = 0; // 清除溢出標志
- TR0 = 1; // 啟動定時器0
- ET0 = 1; // 使能定時器0中斷
- EA = 1; // 開啟總中斷
- }
- // IO口初始化:P1推挽輸出(段選),P3準雙向(位選/按鍵)
- void IO_init() {
- P3M0 = 0x00; P3M1 = 0x00; // P3口準雙向模式
- P1M0 = 0xFF; P1M1 = 0x00; // P1口推挽輸出(驅動數碼管)
- SCON1 = 1; SCON2 = 1; // 初始位選關閉(避免串擾)
- }
- // 毫秒級延時函數(用于數碼管動態掃描,調整顯示清晰度)
- void Delay_ms(uint ms) {
- uint i, j;
- for(i = ms; i > 0; i--)
- for(j = 110; j > 0; j--);
- }
- // 定時器0中斷服務函數:5ms觸發一次,累計1秒遞減num
- void TM0_Isr() interrupt 1 {
- TL0 = 0x00; // 重新加載定時初始值
- TH0 = 0xEE;
- flag++; // 每5ms計數+1
-
- // 累計20次=100ms?修正:200次=1000ms(1秒),原邏輯計時過快
- if (flag == 200) {
- flag = 0; // 計數清零
- num--; // 每秒遞減1
- if (num < 0) { // 倒計時結束(0→-1),復位為60
- num = 60;
- }
- }
- }
- void main() {
- IO_init(); // IO口初始化
- T0_init(); // 定時器0初始化
-
- while (1) {
- // 拆分十位和個位(num范圍0-60)
- shi = num / 10; // 十位:60→6,0→0
- ge = num % 10; // 個位:60→0,9→9
-
- // 動態掃描顯示:個位→十位,每段延時5ms,避免閃爍
- switch (count) {
- case 0: // 顯示個位
- SCON1 = 0; // 開啟個位數碼管
- SCON2 = 1; // 關閉十位數碼管
- SEG = table[ge]; // 輸出個位段碼
- Delay_ms(5); // 保持顯示,確保肉眼識別
- break;
- case 1: // 顯示十位
- SCON1 = 1; // 關閉個位數碼管
- SCON2 = 0; // 開啟十位數碼管
- SEG = table[shi]; // 輸出十位段碼
- Delay_ms(5); // 保持顯示
- break;
- default:
- count = 0; // 重置掃描計數
- break;
- }
- count++;
- if (count > 1) {
- count = 0; // 僅兩位數碼管,循環掃描
- }
- }
- }
復制代碼
1. 修復中斷邏輯錯誤
將中斷中的if(flag=20)改為if(flag==200)(判斷語句而非賦值),且修正計時邏輯:5ms×200=1000ms(1 秒),確保每秒遞減 1。
增加num<0的邊界處理,倒計時結束后自動復位為 60,實現循環倒計時。
2. 優化數碼管動態掃描
新增Delay_ms()函數,在每位數碼管顯示后延時 5ms,降低掃描頻率,使肉眼能清晰識別數字(原代碼無延時,掃描過快導致 “不顯示”)。
初始位選設置為SCON1=1、SCON2=1(關閉狀態),避免初始化時數碼管串擾。
3. 修正數碼管段碼適配
段碼表標注共陰極 / 共陽極差異,若硬件使用共陽極數碼管,需替換段碼表(注釋中已給出共陽極段碼),否則會出現 “全亮” 或 “不顯示”。
4. 完善 IO 口初始化
明確 P1 口為推挽輸出(驅動數碼管段選),P3 口為準雙向模式(位選和按鍵輸入),匹配硬件驅動需求。 |