1 系統框圖
2 實驗現象
一上電,數碼管顯示時間為00-00-00,即分鐘-秒鐘-Mini秒,范圍為00-00-00——59-59-99,計時精度為0.01秒,能正確地進行計時,同時能記錄一次時間,并在下一次計時后對上一次計時時間進行查詢。當按鍵Key1按下時,秒表開始運行,再按下時,秒表停止;每按下一次,狀態翻轉一次;當按鍵Key2按下時,數碼管顯示時間清0;當按鍵Key3按下時,單片機將數碼管顯示的數值保存在AT24C02中,掉電不丟失;當按鍵Key4被按下時,單片機從AT24C02中讀取數據,并顯示在數碼管上。
3 參考程序
3.1 主程序
#include #include 'timer0.h' #include 'key.h' #include 'Nixie.h' #include 'delayms.h' #include 'at24c02.h' unsigned char KeyNum; unsigned char Min,Sec,MiniSec; unsigned char RunFlag; void main() { timer0_init(); while(1) { KeyNum=key(); if(KeyNum==1) //K1按鍵按下 { RunFlag=!RunFlag; //啟動標識位翻轉 } if(KeyNum==2) //K2按鍵按下 { Min=0; //時間清0 Sec=0; MiniSec=0; } if(KeyNum==3) //K3按鍵按下 { AT24C02_WriteByte(0,Min); //將分寫入AT24C02的地址0 delayms(5); AT24C02_WriteByte(1,Sec); //將秒寫入AT24C02的地址1 delayms(5); AT24C02_WriteByte(2,MiniSec);//將Mini秒寫入AT24C02的地址2 delayms(5); } if(KeyNum==4) //K3按鍵按下 { Min=AT24C02_ReadByte(0); //讀出AT24C02數據 Sec=AT24C02_ReadByte(1); MiniSec=AT24C02_ReadByte(2); } Nixie_SetBuf(1,Min/10); //設置顯示緩存,顯示數據 Nixie_SetBuf(2,Min%10); Nixie_SetBuf(3,11); Nixie_SetBuf(4,Sec/10); Nixie_SetBuf(5,Sec%10); Nixie_SetBuf(6,11); Nixie_SetBuf(7,MiniSec/10); Nixie_SetBuf(8,MiniSec%10); } } /** * @brief 秒表驅動函數,時間運行,在中斷中調用 * @param 無,MiniSec:0-99, Sec:0-59, Min:0-59 * @retval 無 */ void Sec_Loop(void) { if(RunFlag) { MiniSec++; if(MiniSec>=100) { MiniSec=0; Sec++; if(Sec>=60) { Sec=0; Min++; if(Min>=60) { Min=0; } } } } } void timer0_routine() interrupt 1 { static unsigned int T0Count1,T0Count2,T0Count3; TL0=0x66; //設置定時初始值,1ms,@11.0592MHz TH0=0xFC; //設置定時初始值,1ms,@11.0592MHz T0Count1++; if(T0Count1>=20) { T0Count1=0; key_loop(); //20ms調用一次按鍵驅動函數 } T0Count2++; if(T0Count2>=2) { T0Count2=0; Nixie_Loop(); //2ms調用一次數碼管驅動函數 } T0Count3++; if(T0Count3>=10) { T0Count3=0; Sec_Loop(); //10ms調用一次數秒表驅動函數 } } 3.2 按鍵掃描函數(定時器掃描按鍵,20ms一次,不斷掃描) #include #include 'delayms.h' sbit key1 = P3^1; sbit key2 = P3^0; sbit key3 = P3^2; sbit key4 = P3^3; unsigned char Key_Num; /** * @brief 獲取按鍵鍵碼 * @param 無 * @retval 按下按鍵的鍵碼,范圍:0,1~4,0表示無按鍵按下 */ unsigned char key(void) { unsigned char Temp=0; Temp=Key_Num; Key_Num=0; return Temp; } /** * @brief 獲取獨立按鍵鍵碼 * @param 無 * @retval 按下按鍵的鍵碼,范圍:0~4,無按鍵按下時返回值為0 */ unsigned char key_getstate() { unsigned char KeyNumber = 0; if(key1==0){KeyNumber=1;} if(key2==0){KeyNumber=2;} if(key3==0){KeyNumber=3;} if(key4==0){KeyNumber=4;} return KeyNumber; } /** * @brief 按鍵驅動函數,在中斷中調用 * @param 無 * @retval 無 */ void key_loop(void) { static unsigned char NowState,LastState; LastState=NowState; //按鍵狀態更新 NowState=key_getstate(); //獲取按鍵當前狀態 //如果上個時間點按鍵按下,當前時間點未按下,則是按鍵釋放瞬間,以此避免消抖和松手檢測 if(LastState==1 && NowState==0) { Key_Num=1; } if(LastState==2 && NowState==0) { Key_Num=2; } if(LastState==3 && NowState==0) { Key_Num=3; } if(LastState==4 && NowState==0) { Key_Num=4; } } #ifndef _key_h_ #define _key_h_ unsigned char key(); void key_loop(void); #endif 3.3 數碼管驅動函數(定時器掃描數碼管,2ms不斷掃描) #include #include 'delayms.h' //數碼管顯示緩存區,其中10為不顯示,對應Nixietable[10]=0x00 unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10}; //數碼管段碼表,0-9,不顯示,- unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40}; /** * @brief 設置顯示緩存區 * @param Location 要設置的位置,范圍:1~8 * @param Number 要設置的數字,范圍:段碼表索引范圍 * @retval 無 */ void Nixie_SetBuf(unsigned char Location,Number) { Nixie_Buf[Location]=Number; } /** * @brief 數碼管掃描顯示 * @param Location 要顯示的位置,范圍:1~8 * @param Number 要顯示的數字,范圍:段碼表索引范圍 * @retval 無 */ void Nixie_Scan(unsigned char Location,Number) { P0=0x00; //段碼清0,消影 switch(Location) //位碼輸出 { case 1:P2_4=1;P2_3=1;P2_2=1;break; case 2:P2_4=1;P2_3=1;P2_2=0;break; case 3:P2_4=1;P2_3=0;P2_2=1;break; case 4:P2_4=1;P2_3=0;P2_2=0;break; case 5:P2_4=0;P2_3=1;P2_2=1;break; case 6:P2_4=0;P2_3=1;P2_2=0;break; case 7:P2_4=0;P2_3=0;P2_2=1;break; case 8:P2_4=0;P2_3=0;P2_2=0;break; } P0=NixieTable[Number]; //段碼輸出 } /** * @brief 數碼管驅動函數,在中斷中調用 * @param 無 * @retval 無 */ void Nixie_Loop(void) { static unsigned char i=1; Nixie_Scan(i,Nixie_Buf[i]); i++; if(i>=9){i=1;} } #ifndef __NIXIE_H__ #define __NIXIE_H__ void Nixie_SetBuf(unsigned char Location,Number); void Nixie_Scan(unsigned char Location,Number); void Nixie_Loop(void); #endif 3.4 定時器函數(T0) #include /** * @brief 定時器0初始化,1毫秒@11.0592MHz * @param 無 * @retval 無 */ void timer0_init(void) //1毫秒@11.0592MHz { TMOD &= 0xF0; //設置定時器模式,1111_0000,&,高四位保留,低四位清零 TMOD |= 0x01; //設置定時器模式,0000_0001,|,高四位保留,設置模式為T0 TL0 = 0x66; //設置定時初始值,1ms,@11.0592MHz TH0 = 0xFC; //設置定時初始值,1ms,@11.0592MHz TF0 = 0; //清除TF0標志 TR0 = 1; //定時器0開始計時 ET0=1; //打開定時器T0中斷開關 EA=1; //打開中斷系統總開關 PT0=0; //設置T0中斷優先級,低 } #ifndef _timer0_h_ #define _timer0_h_ void timer0_init(void); #endif 3.5 I2C驅動函數 #include sbit I2C_SCL=P2^1; sbit I2C_SDA=P2^0; /** * @brief I2C通信開始 * @param 無 * @retval 無 */ void I2C_Start(void) { I2C_SCL=1; //空閑狀態 I2C_SDA=1; //空閑狀態 I2C_SDA=0; I2C_SCL=0; } /** * @brief I2C通信結束 * @param 無 * @retval 無 */ void I2C_Stop(void) { I2C_SDA=0; I2C_SCL=1; //回到空閑狀態 I2C_SDA=1; //回到空閑狀態 } /** * @brief I2C主機向從機發送一個字節,SCL為同步信號,低電平寫數據 * @param Byte 要發送的字節 * @retval 無 */ void I2C_SendByte(unsigned char Byte) { unsigned char i; for(i=0;i<8;i++) //一個字節,8bit { I2C_SDA=Byte&(0x80>>i); //SCL為低電平,主機為發送器,寫數據 I2C_SCL=1; //SCL為高電平,從機為接收器,讀數據
設計資源 培訓 開發板 精華推薦
- LT1172HVCT、5V/1.25A 正降壓轉換器的典型應用
- 【訓練營】四條腿機器狗
- SG3525A 推挽式脈寬調制器控制電路的典型應用
- LT1108CS8-12掌上電腦邏輯電源微功率DC/DC轉換器典型應用電路
- AM2M-1515DH30-NZ ±15 Vout、2W 雙路輸出 DC-DC 轉換器的典型應用
- LTC2945HMS 具有高達 200V 浪涌保護的堅固型 4V 至 70V 高壓側功率監視器的典型應用
- 常用MCU全能燒錄器
- 【航順訓練營】國產航順MCU開發學習板
- LTC3624EMSE-25 5V 輸出電壓、2A 同步降壓型穩壓器的典型應用,具有 1MHz、突發模式操作
- 具有備用電源監控功能的 LTC4420IMSE 18V 雙輸入微電源路徑優先器的典型應用電路
- 意法半導體緊湊型可配置車規負載驅動器具備安全引腳
- 美光宣布在美投資增至 2000 億美元,加建晶圓廠和 HBM 封裝設施
- AMD舉辦Advancing AI 2025大會:Instinct MI350系列GPU發布,35倍推理性能提升
- 特斯拉起訴前Optimus機器人工程師,指控其竊取商業機密
- Nordic Semiconductor將在MWC上海2025上展示前沿蜂窩物聯網解決方案
- SiC 市場的下一個爆點:共源共柵(cascode)結構詳解
- 香港科技大學工學院推出擬人化自動駕駛系統
- 現代摩比斯推出新型安全技術 防止追尾碰撞
- 研究人員開發新型機器人系統 利用AI賦能機器人技術
- 研究人員開發具有突破性觸覺靈敏度的機械手 可實現類人靈巧操作