|
#include <reg51.h> #include <absacc.h> // 8255端口地址定義(基于P2.5=A0, P2.6=A1, P2.7=CS,低有效) #define PA8255 XBYTE[0x0000] // A口:P2.7=0, P2.6=0, P2.5=0 #define PB8255 XBYTE[0x2000] // B口:P2.7=0, P2.6=0, P2.5=1 #define PC8255 XBYTE[0x4000] // C口:P2.7=0, P2.6=1, P2.5=0 #define COM8255 XBYTE[0x6000] // 控制口:P2.7=0, P2.6=1, P2.5=1 // 共陰極數碼管段碼表(0-9,空白) code unsigned char seg_code[] = { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 0x00 // 空白 }; // 按鍵位定義(PC0~PC5) #define KEY_START_PAUSE 0x01 #define KEY_RESET 0x02 #define KEY_SAVE 0x04 #define KEY_QUERY 0x08 #define KEY_PREV 0x10 #define KEY_NEXT 0x20 // 全局變量 unsigned long count = 0; // 改為long型,支持0~9分59.99秒,避免溢出 bit running = 0; // 計時運行標志 unsigned long record[10] = {0}; // 記錄數組同步改為long型,保存分鐘+秒信息 unsigned char record_count = 0; // 已存記錄數(0~10) bit mode = 0; // 0=計時模式,1=查詢模式 unsigned char query_index = 0; // 當前查詢的記錄索引(0~9) unsigned char display_buffer[8]; // 顯示緩沖區 // 按鍵掃描相關 unsigned char key_prev = 0; bit key_scan_flag = 0; // 10ms掃描標志 // 定時器0中斷服務程序(10ms) void timer0_isr(void) interrupt 1 { TH0 = 0xD8; // 12MHz,10ms初值 TL0 = 0xF0; if (running) { count++; // 取消99.99秒清零,累計為分鐘,最大支持9分59.99秒 if (count >= 5999) {} } key_scan_flag = 1; // 通知主循環掃描按鍵 } // 定時器0初始化 void timer_init() { TMOD &= 0xF0; TMOD |= 0x01; // 定時器0,模式1 TH0 = 0xD8; TL0 = 0xF0; ET0 = 1; EA = 1; TR0 = 1; } // 更新顯示緩沖區(核心修改:分鐘位加分隔符,分·秒清晰區分) void update_display() { unsigned char i; unsigned char buf[8]; unsigned char minute; // 分鐘(1位,0~9) unsigned int sec_total; // 剩余秒數(0~5999,對應00.00~59.99秒) unsigned int int_part, frac_part; // 秒的整數部分、小數部分 unsigned char tens, ones, tenths, hundredths; unsigned long val; for (i = 0; i < 8; i++) buf[i] = 0x00; // 先全滅 if (mode == 0) { // 計時模式 // 第1、2位:已存記錄數(兩位,不足補零) buf[0] = seg_code[record_count / 10]; buf[1] = seg_code[record_count % 10]; buf[2] = 0x00; // 第3位空白 // 計算分鐘和剩余秒數 minute = count / 6000; // 6000個0.01秒=60秒=1分鐘,取個位分鐘 sec_total = count % 6000; // 剩余秒數(0~5999) // 拆分剩余秒數:整數部分(秒)=sec_total/100,小數部分=sec_total%100 int_part = sec_total / 100; frac_part = sec_total % 100; tens = int_part / 10; // 秒的十位(0~5) ones = int_part % 10; // 秒的個位(0~9) tenths = frac_part / 10; // 秒的十分位 hundredths = frac_part % 10;// 秒的百分位 // 第4~8位:分鐘(1位+分隔符)+ 秒(99.99格式)【核心修改】 buf[3] = seg_code[minute] | 0x80; // 分鐘位+右側小數點(分隔符),分·秒 buf[4] = seg_code[tens]; // 第5位:秒十位 buf[5] = seg_code[ones] | 0x80; // 第6位:秒個位+小數點 buf[6] = seg_code[tenths]; // 第7位:秒十分位 buf[7] = seg_code[hundredths]; // 第8位:秒百分位 } else { // 查詢模式【同步修改分鐘位分隔符】 if (record_count > 0) { // 顯示當前記錄序號(從1開始) buf[0] = seg_code[(query_index + 1) / 10]; buf[1] = seg_code[(query_index + 1) % 10]; buf[2] = 0x00; // 顯示記錄值(同步支持分鐘+分隔符) val = record[query_index]; minute = val / 6000; // 記錄的分鐘 sec_total = val % 6000; // 記錄的剩余秒數 // 拆分剩余秒數 int_part = sec_total / 100; frac_part = sec_total % 100; tens = int_part / 10; ones = int_part % 10; tenths = frac_part / 10; hundredths = frac_part % 10; buf[3] = seg_code[minute] | 0x80; // 分鐘位+分隔符(和計時模式一致) buf[4] = seg_code[tens]; buf[5] = seg_code[ones] | 0x80; buf[6] = seg_code[tenths]; buf[7] = seg_code[hundredths]; } else { // 如果沒有記錄,返回計時模式 mode = 0; } } // 復制到全局顯示緩沖區 for (i = 0; i < 8; i++) display_buffer[i] = buf[i]; } // 動態掃描顯示(位選低電平有效,無修改) void display() { unsigned char i; unsigned int j; for (i = 0; i < 8; i++) { PB8255 = 0xFF; // 消隱,關閉所有位 PA8255 = display_buffer[i]; // 送段碼 PB8255 = ~(1 << i); // 選中第i位(i=0對應最左邊) // 短暫延時 for (j = 0; j < 100; j++); } } // 按鍵掃描 void scan_key() { unsigned char key_current, key_down; unsigned char i; key_current = ~PC8255 & 0x3F; // 讀PC0~PC5,取反得按下為1 key_down = key_current & (key_current ^ key_prev); key_prev = key_current; // 處理按鍵事件 if (key_down & KEY_START_PAUSE) { if (mode == 0) { running = !running; // 計時模式下開始/暫停 } } // 復位按鍵 if (key_down & KEY_RESET) { running = 0; // 停止計時 count = 0; // 清零當前值(分鐘+秒都清零) if (mode == 1) { // 如果在查詢模式,退出查詢 mode = 0; } else { // 在計時模式下,清除所有記錄 record_count = 0; for (i = 0; i < 10; i++) { record[i] = 0; } } } // 保存按鍵 if (key_down & KEY_SAVE) { if (mode == 0) { // 計時模式下保存 if (record_count < 10) { record[record_count] = count; // 保存當前count(含分鐘信息) record_count++; } } else { // 查詢模式下清除所有記錄 record_count = 0; mode = 0; // 退出查詢 } } // 查詢按鍵 - 修改為點擊一次直接進入查詢模式 if (key_down & KEY_QUERY) { if (mode == 0) { // 當前在計時模式 if (record_count > 0) { // 有記錄可查 mode = 1; // 直接切換到查詢模式 query_index = 0; // 指向第一個記錄 } } else { // 當前在查詢模式 mode = 0; // 退出查詢,返回計時模式 } } // 上一個按鍵 if (key_down & KEY_PREV) { if (mode == 1 && record_count > 0) { // 查詢模式下切換上一個記錄 if (query_index == 0) query_index = record_count - 1; else query_index--; } } // 下一個按鍵 if (key_down & KEY_NEXT) { if (mode == 1 && record_count > 0) { // 查詢模式下切換下一個記錄 query_index = (query_index + 1) % record_count; } } } // 主函數(無修改) void main() { // 初始化8255:方式0,A口輸出,B口輸出,C口輸入 COM8255 = 0x89; // 1000 1001B timer_init(); // 初始化定時器 // 初始狀態 count = 0; running = 0; record_count = 0; mode = 0; key_prev = 0; while (1) { if (key_scan_flag) { // 每10ms掃描一次按鍵 key_scan_flag = 0; scan_key(); } update_display(); // 更新顯示內容 display(); // 動態掃描顯示 } } |