stm32萬年歷
本設計是利用單片機實現一個簡易萬年歷系統,能夠準確顯示時、分、秒信息。用戶可通過特定按鍵對時間進行設置調整,具備基本的時間校準功能,可滿足日常簡易計時需求。運用了stm32單片機模塊內部定時器 / 計數器功能來實現精確計時。單片機通過編程,可對輸入輸出端口進行控制,并通過按鍵模塊讀取按鍵狀態并驅動數碼管顯示時間信息。當按鍵按下時,改變對應引腳的電平狀態,單片機通過掃描引腳電平變化來識別按鍵操作,進而執行相應的時間調整功能。另外還有數碼管顯示模塊:使用共陰極,與單片機的輸出引腳相連。通過單片機輸出不同的段碼和位碼,控制數碼管的各個段點亮或熄滅,從而顯示出對應的數字,實現時間的可視化呈現。計時方案:利用單片機內部定時器產生精確的定時中斷,以 1 秒為時間基準進行計時累加。通過設置定時器的初值和計數模式,使其每隔一定時間(如 50ms)產生一次中斷,在中斷服務程序中對計時變量進行累加,當達到 1 秒時,對秒計數變量加 1 ,并進行分、時的進位處理。按鍵處理方案:采用軟件消抖的方式處理按鍵信號。當檢測到按鍵按下時,延遲一定時間(如 10ms)再次檢測按鍵狀態,若仍為按下狀態,則確認按鍵有效。根據不同按鍵的功能定義,對時間進行相應的調整,如秒的清零、分和時的增減等操作。顯示方案:采用動態掃描顯示方式,將數碼管分為位選和段選。單片機按照一定的時間間隔依次選通各個數碼管的位選引腳,同時輸出對應的段碼,使人眼產生視覺暫留效果,從而實現穩定的時間顯示。
題目:簡易萬年歷設計
要求:采用單片機自帶的定時器,實現萬年歷功能。要求包含“年月日”和“時分秒”顯示,通過數碼管顯示,要求初始值顯示為“25-06-19”“23-58-XX”。請結合自身能力選擇以下難度系數進行設計:
(1)通過數碼管切屏顯示,每隔1S切換一次。
(2)增加按鍵實現“年月日”和“時分秒”的切換顯示。
(3)實現時間初值設置功能。
#include "stm32f10x.h"
#include "Delay.h"
#include "MAX7219.h"
#include "Timer.h"
#include "LED.h"
#include "Key.h"// 時間數據結構
typedef struct
{uint8_t year; // 年 (0-99)uint8_t month; // 月 (1-12)uint8_t day; // 日 (1-31)uint8_t hour; // 時 (0-23)uint8_t minute; // 分 (0-59)uint8_t second; // 秒 (0-59)
} DateTime;DateTime currentTime = {25, 6, 19, 23, 58, 0}; // 初始時間 25-06-19 23:58:00// 數碼管顯示緩沖區
uint8_t displayDigits[8] = {0};// 顯示模式:0 - 年月日,1 - 時分秒
uint8_t displayMode = 1;
uint8_t flag;
// 時間設置狀態:0-正常模式,1-設置年,2-設置月,3-設置日,4-設置時,5-設置分,6-設置秒
uint8_t settingMode = 0;
uint8_t blinkCounter = 0;// 更新時間設置
void UpdateTimeSetting(uint8_t key)
{switch (settingMode){case 1: // 設置年if (key == 3) // 按鍵PB11增加{currentTime.year = (currentTime.year + 1) % 100;}else if (key == 4) // 按鍵PB12減少{currentTime.year = (currentTime.year - 1 + 100) % 100;}break;case 2: // 設置月if (key == 3){currentTime.month = (currentTime.month + 1 > 12) ? 1 : currentTime.month + 1;}else if (key == 4){currentTime.month = (currentTime.month - 1 < 1) ? 12 : currentTime.month - 1;}break;case 3: // 設置日if (key == 3){currentTime.day = (currentTime.day + 1 > 31) ? 1 : currentTime.day + 1;}else if (key == 4){currentTime.day = (currentTime.day - 1 < 1) ? 31 : currentTime.day - 1;}break;case 4: // 設置時if (key == 3){currentTime.hour = (currentTime.hour + 1 > 23) ? 0 : currentTime.hour + 1;}else if (key == 4){currentTime.hour = (currentTime.hour - 1 < 0) ? 23 : currentTime.hour - 1;}break;case 5: // 設置分if (key == 3){currentTime.minute = (currentTime.minute + 1 > 59) ? 0 : currentTime.minute + 1;}else if (key == 4){currentTime.minute = (currentTime.minute - 1 < 0) ? 59 : currentTime.minute - 1;}break;case 6: // 設置秒if (key == 3){currentTime.second = (currentTime.second + 1 > 59) ? 0 : currentTime.second + 1;}else if (key == 4){currentTime.second = (currentTime.second - 1 < 0) ? 59 : currentTime.second - 1;}break;default:break;}
}// 更新數碼管顯示
void UpdateDisplay(void)
{if (displayMode == 0){// 日期顯示: DD-MM-YYdisplayDigits[0] = currentTime.year / 10;displayDigits[1] = currentTime.year % 10;displayDigits[2] = 0x0A; // '-'符號displayDigits[3] = currentTime.month / 10;displayDigits[4] = currentTime.month % 10;displayDigits[5] = 0x0A; // '-'符號displayDigits[6] = currentTime.day / 10;displayDigits[7] = currentTime.day % 10;}else{// 時間顯示: HH-MM-SSdisplayDigits[0] = currentTime.hour / 10;displayDigits[1] = currentTime.hour % 10;displayDigits[2] = 0x0A; // ':'符號displayDigits[3] = currentTime.minute / 10;displayDigits[4] = currentTime.minute % 10;displayDigits[5] = 0x0A; // ':'符號displayDigits[6] = currentTime.second / 10;displayDigits[7] = currentTime.second % 10;}for (int i = 0; i < 8; i++){MAX7219_ShowNum(i + 1, displayDigits[i], 0);}
}// 更新時間
void UpdateTime(void)
{// 秒數加5currentTime.second+=5;// 判斷秒數是否達到60秒if (currentTime.second >= 60){currentTime.second = 0;currentTime.minute++;// 判斷分鐘數是否達到60分鐘if (currentTime.minute >= 60){currentTime.minute = 0;currentTime.hour++;// 判斷小時數是否達到24小時if (currentTime.hour >= 24){currentTime.hour = 0;currentTime.day++;// 簡單日期處理(不考慮月份天數差異)if (currentTime.day > 31){currentTime.day = 1;currentTime.month++;// 判斷月份是否超過12月if (currentTime.month > 12){currentTime.month = 1;currentTime.year++;}}}}}// 更新數碼管顯示UpdateDisplay();
}int main(void)
{Timer_Init();MAX7219_Init(0xFF, 0x0F, 8); // 初始化MAX7219,全開BCD譯碼,亮度最大,顯示所有數碼管Key_Init(); // 初始化按鍵// 初始顯示UpdateDisplay();while (1){uint8_t key = Key_GetNum();blinkCounter = (blinkCounter + 1) % 20; // 用于閃爍計時if (flag){flag = 0;if (settingMode == 0){ // 僅在非設置模式下更新時間UpdateTime();}}if (key == 1){ // 按鍵PB6切換顯示模式displayMode = !displayMode;UpdateDisplay();}else if (key == 2){ // 按鍵PB9進入/退出設置模式if (settingMode == 0){settingMode = 1; // 進入設置模式,從年開始}else{settingMode = 0; // 退出設置模式}UpdateDisplay();}else if (key == 3 || key == 4){if (settingMode > 0 && settingMode <= 6){UpdateTimeSetting(key);UpdateDisplay();}}else if (key == 5) // 新增按鍵PB13處理邏輯{if (settingMode > 0 && settingMode <= 6){settingMode = (settingMode % 6) + 1; // 自動跳轉到下一設置項UpdateDisplay();}}}
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){static int count=0;count++;if(count>=5){flag = 1;count=0;}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
在該電路中,數碼管與 MAX219 芯片相連,MAX219 芯片的各引腳(如 DIG0 - DIG7、DOUT 等)通過線路連接到相應位置 ,并通過 R2(10k)電阻進行相關配置。STM32F103C8 芯片的 PA15 引腳連接到 MAX219 的 LOAD 引腳,PB 端口(PB0 - PB15 )連接多個按鍵用于功能操作(如顯示切換、設置等 )。NRST 引腳通過 R1(10k)電阻和 C3(10μF)電容組成復位電路 ,PC13 - RTC、PC14 - OSC32_IN 等引腳也有對應連接,實現系統相關功能。
?
單片機定制(vx):yeyu_zx8888