久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4416|回復: 4
打印 上一主題 下一主題
收起左側

基于狀態機與時間片輪的51單片機電子鐘設計 程序Proteus仿真

  [復制鏈接]
跳轉到指定樓層
樓主
## 一、概述
在對分層思想、時間片輪轉和狀態機思想進行[簡單應用](http://www.zg4o1577.cn/bbs/dpj-214415-1.html)后,我想對其進行更進一步的應用——使用這三種思想對我本人在2020年的一個[51電子鐘項目](http://www.zg4o1577.cn/bbs/dpj-215488-1.html)進行重構使其運行效率更高更好的利用單片機的各種資源。

仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)


## 二、主函數
主函數如下:
整個主函數的中心任務為功能選擇切換任務,負責切換顯示內容,控制ui變化等,其余任務函數除提醒任務外都是通過全局變量的形式給功能選擇切換任務提供資源或從該任務獲取內容。
```c
#include "sys.h"
#include "task.h"
//系統時鐘為12MHZ
void main()
{
        u8 key = 0;
        //各類初始化任務
        TimerInit();
        DS1302_Init();
        DS18B20_ConvertT();
        while(1)
        {
                LCD_Task();//顯示任務,按照給定的內容進行顯示
                SHOW_CTRl_Task();//功能選擇切換任務
                TEMP_Task();//溫度讀取任務
                ReadKey_Task();//按鍵讀取任務
                ALM_Task();//鬧鐘提醒任務
                TMR_Task();//倒計時提醒任務
        }
}
```
## 三、顯示任務
由于顯示任務涉及到了多個層級的函數,從最底層寫命令、寫數據,到中間層顯示和初始化等函數。再到最頂層控制多行的顯示。故使用了多級狀態機的形式來完成lcd任務的狀態機內容。由于C語言順序執行的特性。規定同一層級使用同一個狀態機,可以有效減少狀態機的數量同時也能保證系統的穩定運行。
### 頂層代碼如下
```c
void LCD_Task()
{        //顯示初始化狀態
        if(LCD_STATE == 0)
        {
                if(LCD_Init() == 1)
                {
                        LCD_STATE =1;
                }
        }
        //顯示第一行狀態  可能還需細分,視需求而定
        if(LCD_STATE == 1)
        {
                if(LCD_ShowString(1,Column1,LCD_SHOW_1) == 1)
                {
                        LCD_STATE =2;
                }
        }
        if(LCD_STATE == 2)
        {
                if(LCD_ShowString(2,Column2,LCD_SHOW_2) == 1)
                {
                        LCD_STATE =3;
                }
        }
        //顯示暫停狀態
        if(LCD_STATE == 3)
        {
        }
}
```
### 中間層代碼如下:
```c
u8 LCD_Init()
{        
        if(LCD_STATE_1 == 0)
        {
                //八位數據接口,兩行顯示,5*7點陣
                if(LCD_WriteCommand(0x38) == 1)
                {
                        LCD_STATE_1 = 1;
                }
        }
        
        if(LCD_STATE_1 == 1)
        {
                //顯示開,光標關,閃爍關
                if(LCD_WriteCommand(0x0c) == 1)
                {
                        LCD_STATE_1 = 2;
                }
        }
        
        if(LCD_STATE_1 == 2)
        {
                //數據讀寫操作后,光標自動加一,畫面不動
                if(LCD_WriteCommand(0x06) == 1)
                {
                        LCD_STATE_1 = 3;
                }
        }
        
        if(LCD_STATE_1 == 3)
        {
                //光標復位,清屏
                if(LCD_WriteCommand(0x01) == 1)
                {
                        LCD_STATE_1 = 0;
                        return 1;
                }
        }
        return 0;
}
/**
  * @brief  在LCD1602指定位置上顯示一個字符
  * @param  Line 行位置,范圍:1~2
  * @param  Column 列位置,范圍:1~16
  * @param  Char 要顯示的字符
  * @retval 0:顯示字符未完成
        *         1:顯示字符完成
  */
u8 LCD_ShowChar(u8 Line,u8 Column,char Char)
{
        if(LCD_STATE_1 == 0)
        {
                if(LCD_SetCursor(Line,Column) == 1)
                        LCD_STATE_1 = 1;
        }
        if(LCD_STATE_1 == 1)
        {
                if(LCD_WriteData(Char) == 1)
                {
                        LCD_STATE_1 = 0;
                        return 1;
                }
        }
        return 0;
}
```
### 底層代碼如下:
```c
/**
  * @brief  LCD1602寫命令
  * @param  Command 要寫入的命令
  * @retval 無
  */
u8 LCD_WriteCommand(u8 Command)
{
        if(LCD_STATE_0==0)
        {
                LCD_RS=0;
                LCD_RW=0;
                LCD_DataPort=Command;
                LCD_EN=1;
                LCD_DELAY = TimeRef + NUM_1MS;
                LCD_STATE_0 = 1;
        }
        if(LCD_STATE_0 == 1)
        {
                if(TimeRef >= LCD_DELAY)
                {
                        LCD_EN=0;
                        LCD_DELAY = TimeRef + NUM_1MS;
                        LCD_STATE_0 = 2;
                }
        }
        if(LCD_STATE_0 == 2)
        {
                if(TimeRef >= LCD_DELAY)
                {
                        LCD_STATE_0 = 0;
                        return 1;
                }
        }
        return 0;
}

/**
  * @brief  LCD1602寫數據
  * @param  Data 要寫入的數據
  * @retval 0:未寫入完成
        *         1:寫入完成
  */
u8 LCD_WriteData(u8 Data)
{
        if(LCD_STATE_0==0)
        {
                LCD_RS=1;
                LCD_RW=0;
                LCD_DataPort=Data;
                LCD_EN=1;
                LCD_DELAY = TimeRef + NUM_1MS;
                LCD_STATE_0 = 1;
        }
        if(LCD_STATE_0 == 1)
        {
                if(TimeRef >= LCD_DELAY)
                {
                        LCD_EN=0;
                        LCD_DELAY = TimeRef + NUM_1MS;
                        LCD_STATE_0 = 2;
                }
        }
        if(LCD_STATE_0 == 2)
        {
                if(TimeRef >= LCD_DELAY)
                {
                        LCD_STATE_0 = 0;
                        return 1;
                }
        }
        return 0;
}
```
## 四、溫度獲取任務
溫度獲取任務主要分為初始化獲取和循環獲取。初始化獲取用于立刻獲取溫度值防止出現剛開機時不顯示溫度的情況。循環獲取用于間隔一段時間獲取一次溫度,實現較為實時的溫度顯示。基本代碼如下
```c
//函數定義:
/**
  * @brief  溫度獲取任務
  * @param  無
  * @retval 無
  */
void TEMP_Task()
{        //初始化狀態
        if(TEMP_STATE == 0)
        {
                if(DS18B20_ConvertT() == 1)
                {
                        TEMP_DELAY = TimeRef + NUM_1000MS;
                        TEMP_STATE = 1;
                }
        }
        //延時狀態
        if(TEMP_STATE == 1)
        {
                if(TimeRef >= TEMP_DELAY)
                {
                        TEMP_STATE=2;
                }
        }
        //轉換狀態
        if(TEMP_STATE == 2)
        {
                if(DS18B20_ConvertT() == 1)
                {
                        TEMP_STATE = 3;
                }
        }
        if(TEMP_STATE == 3)
        {
                Temp = DS18B20_ReadT();
                TEMP_DELAY = TimeRef + (u32)NUM_1000MS*1800;
                TEMP_STATE =1;
        }
}
```
該線程所需的驅動并未實現完全的狀態機化由于單總線所需的延時較為精準在嘗試了進行狀態機化后發現會出現讀取亂碼的情況,且部分函數所需的延時時間太短甚至需要關閉定時器中斷以對該延時進行保護,可對標操作系統的臨界區保護。
## 五、按鍵獲取任務
按鍵獲取任務基本架構、分層與[按鍵控制數碼管項目](http://www.zg4o1577.cn/bbs/dpj-214415-1.html)類似,但由于本項目的功能較多且針對于項目的顯示內容使用了現態的方式進行控制,即按鍵任務無法得知完成顯示任務前的狀態(功能),故引入過去態和未來態,前者供需要在現態中進行狀態轉換的任務標記其源頭,后者用于在使用完相應的資源后跳轉到相應的任務上。故按鍵對于當前功能界面的判斷使用了過去態的方式,同時配合行號和列號完成相應功能。具體代碼如下:

```c
void ReadKey_Task()
{
        if(ReadKeyEN)
        {
                ReadKeyValue = ReadKeyDat();
                //記錄狀態機的次態、現態、下態,在根據次態確認按下按鍵執行的內容
                if(SHOW_CTRl_P_STATE == 4)//功能選擇頁面的按鍵選擇
                {
                        switch(ReadKeyValue)
                        {
                                case 0:;break;
                                case 1:{
                                        Key_F_STATE_C = 6;
                                        FSD_Line = 1;
                                        FSD_Colu = 1;
                                }break;
                                case 2:Key_F_STATE_C = 7;break;
                                case 3:Key_F_STATE_C = 8;break;
                                case 4:Key_F_STATE_C = 9;break;
                                case 5:SHOW_CTRl_N_STATE = Key_F_STATE_C ;break;
                        }
                }
                if(SHOW_CTRl_P_STATE == 6)//鬧鐘設置頁面的按鍵
                {
                        switch(ReadKeyValue)
                        {
                                case 0:;break;
                                case 1:{
                                        switch(ALM_STA)
                                        {
                                                case 0:{
                                                        FSD_Line==1?FSD_Line=1:FSD_Line--;
                                                        SHOW_CTRl_N_STATE = 6;
                                                }break;
                                                case 1:{
                                                        ALM_TIME[FSD_Line-1][FSD_Colu-1]--;
                                                        if(ALM_TIME[FSD_Line-1][FSD_Colu-1]<48)
                                                        {
                                                                ALM_TIME[FSD_Line-1][FSD_Colu-1]=48;
                                                        }
                                                        SHOW_CTRl_N_STATE = 6;
                                                }break;
                                        }
                                }break;
                                case 2:{
                                        switch(ALM_STA)
                                        {
                                                case 0:{
                                                        FSD_Line==2?FSD_Line=2:FSD_Line++;
                                                        SHOW_CTRl_N_STATE = 6;
                                                }break;
                                                case 1:{
                                                        ALM_TIME[FSD_Line-1][FSD_Colu-1]++;
                                                        if((FSD_Colu-1)==0)
                                                        {
                                                                if(ALM_TIME[FSD_Line-1][FSD_Colu-1]>=50)
                                                                {
                                                                        ALM_TIME[FSD_Line-1][FSD_Colu-1]=50;
                                                                        if(ALM_TIME[FSD_Line-1][1] >= 52)
                                                                                ALM_TIME[FSD_Line-1][1]=52;
                                                                }
                                                        }else if((FSD_Colu-1)==1)
                                                        {
                                                                if(ALM_TIME[FSD_Line-1][0]==50)
                                                                {
                                                                        if(ALM_TIME[FSD_Line-1][FSD_Colu-1]>52)
                                                                                ALM_TIME[FSD_Line-1][FSD_Colu-1]=52;
                                                                }
                                                        }else if((FSD_Colu-1)==2)
                                                        {
                                                                if(ALM_TIME[FSD_Line-1][2]>=53)
                                                                {
                                                                        ALM_TIME[FSD_Line-1][2]=53;
                                                                }
                                                        }
                                                        if(ALM_TIME[FSD_Line-1][FSD_Colu-1]>=57)
                                                        {
                                                                ALM_TIME[FSD_Line-1][FSD_Colu-1]=57;
                                                        }
                                                        SHOW_CTRl_N_STATE = 6;
                                                }break;
                                        }
                                }break;
                                case 3:{
                                        switch(ALM_STA)
                                        {
                                                case 0:{
                                                }break;
                                                case 1:{
                                                        FSD_Colu == 1?FSD_Colu=1:FSD_Colu--;
                                                }break;
                                        }
                                }break;
                                case 4:{
                                        switch(ALM_STA)
                                        {
                                                case 0:{
                                                        ALM_STA = 1;
                                                }break;
                                                case 1:{
                                                        FSD_Colu >= 5?FSD_Colu=5:FSD_Colu++;
                                                }break;
                                        }
                                }break;
                                case 5:{
                                        switch(ALM_STA)
                                        {
                                                case 0:{
                                                        SHOW_CTRl_N_STATE = 2;
                                                }break;
                                                case 1:{
                                                        ALM_STA = 0;
                                                }break;
                                        }
                                }break;
                        }
                }
                if(SHOW_CTRl_P_STATE == 7)//倒計時頁面的按鍵
                {
                        switch(ReadKeyValue)
                        {
                                case 0:;break;//無按鍵按下
                                
                                case 1:{//up
                                        switch(TMR_STA)
                                        {
                                                case 0:{//切換倒計時
                                                        FSD_Line==1?FSD_Line=1:FSD_Line--;
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                                case 1:{//設置倒計時狀態
                                                        switch(FSD_Colu)
                                                        {
                                                                case 0:;break;
                                                                case 1:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]>=600)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]-=600;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]-=600;
                                                                        }
                                                                }break;
                                                                case 2:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]>=60)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]-=60;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]-=60;
                                                                        }
                                                                }break;
                                                                case 3:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]>=10)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]-=10;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]-=10;
                                                                        }
                                                                }break;
                                                                case 4:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]>=1)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]-=1;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]-=1;
                                                                        }
                                                                }break;
                                                                case 5:{
                                                                        TMR_S_S|=(0x01<<(FSD_Line-1));
                                                                        TMR_STA = 2;
                                                                }break;
                                                                case 6:;break;
                                                        }
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                                case 2:{//倒計時中狀態
                                                        switch(FSD_Colu)
                                                        {
                                                                case 4:{//切換第幾個倒計時
                                                                        FSD_Line==1?FSD_Line=1:FSD_Line--;
                                                                        SHOW_CTRl_N_STATE = 7;
                                                                }break;
                                                                case 5:TMR_S_S|=(0x01<<(FSD_Line-1));break;
                                                                case 6:;break;
                                                        }
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                        }
                                }break;
                                
                                case 2:{//down
                                        switch(TMR_STA)
                                        {
                                                case 0:{//切換倒計時
                                                        FSD_Line==2?FSD_Line=2:FSD_Line++;
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                                case 1:{//設置倒計時狀態
                                                        switch(FSD_Colu)
                                                        {
                                                                case 0:;break;
                                                                case 1:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]<=5399)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]+=600;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]+=600;
                                                                        }
                                                                }break;
                                                                case 2:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]<=5939)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]+=60 ;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]+=60;
                                                                        }
                                                                }break;
                                                                case 3:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]<=5989)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]+=10 ;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]+=10;
                                                                        }
                                                                }break;
                                                                case 4:{
                                                                        if(TMR_SHOW_NUM[FSD_Line-1]<=5998)
                                                                        {
                                                                                TMR_SHOW_NUM[FSD_Line-1]+=1 ;
                                                                                TMR_SHOW_NUM_RST[FSD_Line-1]+=1;
                                                                        }
                                                                }break;
                                                                case 5:TMR_S_S&=(!(0x01<<(FSD_Line-1)));break;
                                                                case 6:;break;
                                                        }
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                                case 2:{//倒計時中狀態
                                                        switch(FSD_Colu)
                                                        {
                                                                case 4:{
                                                                        FSD_Line==2?FSD_Line=2:FSD_Line++;
                                                                        SHOW_CTRl_N_STATE = 7;
                                                                }break;
                                                                case 5:TMR_S_S&=(!(0x01<<(FSD_Line-1)));break;
                                                                case 6:;break;
                                                        }
                                                        SHOW_CTRl_N_STATE = 7;
                                                }break;
                                        }
                                }break;
                                
                                case 3:{//left
                                        switch(TMR_STA)
                                        {
                                                case 0:{//切換倒計時
                                                }break;
                                                case 1:{//設置倒計時狀態
                                                        FSD_Colu == 1?FSD_Colu=1:FSD_Colu--;
                                                }break;
                                                case 2:{//倒計時中狀態
                                                        FSD_Colu == 5?FSD_Colu=5:FSD_Colu--;
                                                }break;
                                        }
                                }break;
                                
                                case 4:{//right
                                        switch(TMR_STA)
                                        {
                                                case 0:{//切換倒計時
                                                        if(TMR_S_S &(0x01<<(FSD_Line-1)))//判斷該倒計時是否開啟中
                                                        {
                                                                TMR_STA = 2;//從切換倒計時狀態變為設置倒計時狀態
                                                                FSD_Colu =5;
                                                        }else
                                                        {
                                                                TMR_STA = 1;//從切換倒計時狀態變為設置倒計時狀態
                                                                FSD_Colu =1;
                                                        }
                                                }break;
                                                case 1:{//設置倒計時狀態
                                                        if(FSD_Colu >= 6)
                                                        {
                                                                FSD_Colu=6;
                                                                SHOW_CTRl_N_STATE = 7;
                                                        }else
                                                        {
                                                                FSD_Colu++;
                                                        }
                                                }break;
                                                case 2:{//倒計時中狀態
                                                        if(FSD_Colu >= 6)
                                                        {
                                                                FSD_Colu=6;
                                                                SHOW_CTRl_N_STATE = 7;
                                                        }else
                                                        {
                                                                FSD_Colu++;
                                                        }
                                                }break;
                                        }
                                }break;
                                
                                case 5:{//confirm
                                        switch(TMR_STA)
                                        {
                                                case 0:{ //切換倒計時
                                                        SHOW_CTRl_P_STATE = 2;//切換為時間顯示態
                                                        SHOW_CTRl_N_STATE = 2;//切換為時間顯示態
                                                }break;
                                                case 1:{//設置倒計時狀態
                                                        TMR_STA = 0;//切換為切換狀態
                                                }break;
                                                case 2:{//倒計時中狀態
                                                        if(FSD_Colu == 6)
                                                        {
                                                                TMR_SHOW_NUM[FSD_Line-1] = TMR_SHOW_NUM_RST[FSD_Line-1];
                                                        }else
                                                        {
                                                                TMR_STA = 0;//切換為切換狀態
                                                        }
                                                }break;
                                        }
                                }break;
                        }
                }
                if(SHOW_CTRl_P_STATE == 8)//秒表頁面的按鍵
                {
                        switch(ReadKeyValue)
                        {
                                case 0:;break;//無按鍵按下
                                case 1:{//上
                                        switch(STW_STA)
                                        {
                                                case 0:{//計時中
                                                        switch(FSD_Colu)
                                                        {
                                                                case 1:{
                                                                        STW_STA = 1;
                                                                        STW_SPT_NUM_i = 0;
                                                                        STW_SHOW_NUM_SPT[0] = STW_SHOW_NUM;
                                                                        SHOW_CTRl_N_STATE = 8;
                                                                }break;
                                                                case 2:{
                                                                }break;
                                                                case 3:{
                                                                }break;
                                                        }
                                                }break;
                                                case 1:{//計時暫停
                                                        switch(FSD_Colu)
                                                        {
                                                                case 1:{//不變
                                                                }break;
                                                                case 2:{//清除
                                                                }break;
                                                                case 3:{//翻看記錄
                                                                        
                                                                        if(STW_SPT_NUM_i>0)//限位
                                                                                STW_SPT_NUM_i--;
                                                                        STW_SHOW_NUM = STW_SHOW_NUM_SPT[STW_SPT_NUM_i];
                                                                        SHOW_CTRl_N_STATE = 8;
                                                                }break;
                                                        }
                                                }break;
                                        }
                                };break;
                                case 2:{//下
                                        switch(STW_STA)
                                        {
                                                case 0:{//計時中
                                                        switch(FSD_Colu)
                                                        {
                                                                case 1:{
                                                                }break;
                                                                case 2:{//記錄
                                                                        if(STW_SPT_NUM<STWSetNum-1)
                                                                        {
                                                                                STW_SPT_NUM++;
                                                                        }
                                                                        STW_SHOW_NUM_SPT[STW_SPT_NUM] = STW_SHOW_NUM;
                                                                }break;
                                                                case 3:{
                                                                }break;
                                                        }
                                                }break;
                                                case 1:{//計時暫停
                                                        switch(FSD_Colu)
                                                        {
                                                                case 1:{
                                                                        STW_STA = 0;
                                                                        SHOW_CTRl_N_STATE = 8;
                                                                }break;
                                                                case 2:{//清除
                                                                        STW_SHOW_NUM = 0;
                                                                        STW_SPT_NUM = 0;
                                                                        SHOW_CTRl_N_STATE = 8;
                                                                        //若后臺有倒計時會對其有一定影響
                                                                        TH1=0x3c;//50ms中斷一次
                                                                        TL1=0xAF;
                                                                }break;
                                                                case 3:{//翻看記錄
                                                                        STW_SPT_NUM_i++;
                                                                        if(STW_SPT_NUM_i>=STW_SPT_NUM)//限位
                                                                                STW_SPT_NUM_i=STW_SPT_NUM;
                                                                        STW_SHOW_NUM = STW_SHOW_NUM_SPT[STW_SPT_NUM_i];
                                                                        SHOW_CTRl_N_STATE = 8;
                                                                }break;
                                                        }
                                                }break;
                                        }
                                };break;
                                case 3:{//左
                                        if(FSD_Colu>0)
                                        {
                                                FSD_Colu--;
                                        }
                                };break;
                                case 4:{//右
                                        if(FSD_Colu<3)
                                        {
                                                FSD_Colu++;
                                        }
                                };break;
                                case 5:{//確認
                                        SHOW_CTRl_P_STATE = 2;//切換為時間顯示態
                                        SHOW_CTRl_N_STATE = 2;//切換為時間顯示態
                                };break;
                        }
                }
                if(SHOW_CTRl_P_STATE == 9)//24/12時頁面的按鍵
                {
                        switch(ReadKeyValue)
                        {
                                case 0:;break;
                                case 1:Tim_12_24_Set = 0;SHOW_CTRl_N_STATE=9;break;
                                case 2:Tim_12_24_Set = 1;SHOW_CTRl_N_STATE=9;break;
                                case 5:SHOW_CTRl_N_STATE = 2; ;break;
                        }
                }
               
        }
}
```
## 六、鬧鐘任務
鬧鐘任務鐘主要使用鬧鐘的有效值判斷鬧鐘是否開啟,若開啟則將設置的鬧鐘值與當前時間進行比較,當當前時間與設置的鬧鐘時間一致時則led燈亮。具體代碼如下:

```c
/**函數定義:
  * @brief  鬧鐘任務
  * @param  無
  * @retval 無
  */
void ALM_Task()
{
        if(ALM_TIME[0][4]%2)
        {
                if(DS1302_Time[3]==((ALM_TIME[0][0]-48)*10+ALM_TIME[0][1]-48) && DS1302_Time[4]==((ALM_TIME[0][2]-48)*10+ALM_TIME[0][3]-48))
                {
                        led=0;
                        return;
                }
        }
        
        if(ALM_TIME[1][4]%2)
        {
                if(DS1302_Time[3]==((ALM_TIME[1][0]-48)*10+ALM_TIME[1][1]-48) && DS1302_Time[4]==((ALM_TIME[1][2]-48)*10+ALM_TIME[1][3]-48))
                {
                        led=0;
                        return;
                }
        }
        led =1;
}
```
## 七、倒計時任務
倒計時任務與鬧鐘任務類似,也是比較后燈亮具體代碼如下

```c
/**函數定義:
  * @brief  倒計時任務
  * @param  無
  * @retval 無
  */
idata u8 TMR_P_TIME=0;
idata u8 TMR_FLAG =0;
void TMR_Task()
{
        if(TMR_FLAG == 1)
        {
                if(DS1302_Time[5]<TMR_P_TIME)
                {
                        led=0;
                        return;
                }
        }        
        led =1;
        TMR_FLAG=0;
}
```
## 八、功能選擇任務
功能選擇任務為整個項目的核心。它控制著整個項目的狀態機變換方向,同時針對外部按鍵做出的狀態賦值。完成相應的顯示內容切換和狀態轉換。具體代碼如下:

```c
//根據頁面設計相應的狀態機,需要統一延時態返回到上一狀態
void SHOW_CTRl_Task()
{
        //初始化狀態
        if(SHOW_CTRl_N_STATE == 0)
        {
                if(LCD_STATE == 3)
                {
                        SHOW_CTRl_DELAY = TimeRef + NUM_1000MS;
                        SHOW_CTRl_N_STATE = 1;//切換到延時態
                        SHOW_CTRl_F_STATE = 2;//延時態結束后切換到時間顯示態
                }
        }
        //延時態
        if(SHOW_CTRl_N_STATE == 1)
        {
                if(TimeRef >= SHOW_CTRl_DELAY)
                {
                        SHOW_CTRl_N_STATE = SHOW_CTRl_F_STATE;
                }
        }
        //時間顯示態
        if(SHOW_CTRl_N_STATE == 2)
        {
                LCD_ShowBase();
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE =2;
        }
        //等待顯示完成
        if(SHOW_CTRl_N_STATE == 3)
        {
                if(LCD_STATE == 3)
                {
                        SHOW_CTRl_N_STATE = SHOW_CTRl_F_STATE;
                }
        }
        //外部觸發動作,功能選擇態
        if(SHOW_CTRl_N_STATE == 4)
        {
                //出現需要按下兩次功能選擇按鍵才能正常顯示的現象,疑似與lcd狀態機有關,需要進行修改
                strcpy(LCD_SHOW_1,"U:RLM L:STW     ");
                strcpy(LCD_SHOW_2,"D:TMR R:24/12   ");
                Column1 = 1;   
                LCD_STATE = 1;
                Column2 = 1;
                //初始化該變量以防在多個功能使用時出現問題。
                FSD_Line=1;//功能設置顯示行
                FSD_Colu=1;//功能設置顯示列
                STW_SPT_NUM = 0;
                //狀態設置
                SHOW_CTRl_P_STATE = 4;
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE = 5;
                ReadKeyEN = 1;
                Key_F_STATE_C = SHOW_CTRl_F_STATE;//初始化按鍵狀態防止狀態機被意外改變
        }
        //顯示暫停態
        if(SHOW_CTRl_N_STATE == 5)
        {
                SHOW_CTRl_N_STATE = SHOW_CTRl_F_STATE;
        }
        //鬧鐘設置狀態
        if(SHOW_CTRl_N_STATE == 6)
        {
                strcpy(LCD_SHOW_1,"     RLMSet     ");
                strcpy(LCD_SHOW_2,"A  00:00        ");
                LCD_SHOW_2[1] = FSD_Line +'0';
                LCD_SHOW_2[3] = ALM_TIME[FSD_Line-1][0];
                LCD_SHOW_2[4] = ALM_TIME[FSD_Line-1][1];
                LCD_SHOW_2[6] = ALM_TIME[FSD_Line-1][2];
                LCD_SHOW_2[7] = ALM_TIME[FSD_Line-1][3];
               
                if(ALM_TIME[FSD_Line-1][4]%2)
                {
                        LCD_SHOW_2[9] = 'O';
                        LCD_SHOW_2[10] = 'N';
                        LCD_SHOW_2[11] = ' ';
                }else
                {
                        LCD_SHOW_2[9] = 'O';
                        LCD_SHOW_2[10] = 'F';
                        LCD_SHOW_2[11] = 'F';
                }
                Column1 = 1;   
                LCD_STATE = 1;
                Column2 = 1;
                SHOW_CTRl_P_STATE = 6;
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE = 5;
        }
                //倒計時狀態(開啟關閉重置)
        if(SHOW_CTRl_N_STATE == 7)
        {
                strcpy(LCD_SHOW_1,"     TMRSet     ");
                strcpy(LCD_SHOW_2,"T    :       R  ");
                //只負責顯示
                LCD_SHOW_2[1] = FSD_Line +'0';
                LCD_SHOW_2[3] = TMR_SHOW_NUM[FSD_Line-1]/600 +'0';
                LCD_SHOW_2[4] = TMR_SHOW_NUM[FSD_Line-1]/60%10+'0';
                LCD_SHOW_2[6] = TMR_SHOW_NUM[FSD_Line-1]%60/10+'0';
                LCD_SHOW_2[7] = TMR_SHOW_NUM[FSD_Line-1]%10+'0';
                //判斷倒計時是否開啟
                if(TMR_S_S &(0x01<<(FSD_Line-1)))//開啟
                {
                        LCD_SHOW_2[9] = 'O';
                        LCD_SHOW_2[10] = 'N';
                        LCD_SHOW_2[11] = ' ';
                        if(TMR_S_S==0x01||TMR_S_S==0x02)//第一次開啟
                        {
                                TH1=0x3c;//50ms 中斷一次
                                TL1=0xAF;
                                TR1=1;
                        }
                }else
                {
                        LCD_SHOW_2[9] = 'O';
                        LCD_SHOW_2[10] = 'F';
                        LCD_SHOW_2[11] = 'F';
                        if(TMR_S_S==0)//最后一次關閉
                        {
                                TR1=0;
                        }
                }
                //倒計時是否重置顯示內容
                if(FSD_Colu == 6)
                {
                        LCD_SHOW_2[15] = '?';
                }else
                {
                        LCD_SHOW_2[15] = ' ';
                }
                Column1 = 1;   
                LCD_STATE = 1;
                Column2 = 1;
                SHOW_CTRl_P_STATE = 7;
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE = 5;
        }
                //秒表設置狀態
        if(SHOW_CTRl_N_STATE == 8)
        {
                strcpy(LCD_SHOW_1,"     STWSet     ");
                strcpy(LCD_SHOW_2,"   :  :  OFF RES");        
                //只負責顯示
                LCD_SHOW_2[1] = STW_SHOW_NUM/6000+'0';
                LCD_SHOW_2[2] = STW_SHOW_NUM/600%10+'0';
                LCD_SHOW_2[4] = STW_SHOW_NUM/100%10+'0';
                LCD_SHOW_2[5] = STW_SHOW_NUM/10%10+'0';
                LCD_SHOW_2[7] = STW_SHOW_NUM%10+'0';
                if(STW_STA)
                {
                        LCD_SHOW_2[9] ='O';
                        LCD_SHOW_2[10]='F';
                        LCD_SHOW_2[11]='F';
                        LCD_SHOW_2[13]='R';
                        LCD_SHOW_2[14]='S';
                        LCD_SHOW_2[15]='T';
                        //在按下RST鍵時重新寫入定時器值
                }else
                {
                        LCD_SHOW_2[9] ='O';
                        LCD_SHOW_2[10]='N';
                        LCD_SHOW_2[11]=' ';
                        
                        LCD_SHOW_2[13]='S';
                        LCD_SHOW_2[14]='P';
                        LCD_SHOW_2[15]='T';
                        TR1=1;                        
                }
                Column1 = 1;   
                LCD_STATE = 1;
                Column2 = 1;
               
                SHOW_CTRl_P_STATE = 8;
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE = 5;
        }
                //12/24設置狀態
        if(SHOW_CTRl_N_STATE == 9)
        {
                strcpy(LCD_SHOW_1,"    24/12Set    ");
                strcpy(LCD_SHOW_2,"                ");
                if(Tim_12_24_Set)
                {
                        LCD_SHOW_2[4] = '1';
                        LCD_SHOW_2[5] = '2';
                        LCD_SHOW_2[6] = 'H';
                }else
                {
                        LCD_SHOW_2[4] = '2';
                        LCD_SHOW_2[5] = '4';
                        LCD_SHOW_2[6] = 'H';
                }
                Column1 = 1;   
                LCD_STATE = 1;
                Column2 = 1;
               
                SHOW_CTRl_P_STATE = 9;
                SHOW_CTRl_N_STATE = 3;
                SHOW_CTRl_F_STATE = 5;
        }
}
```
## 九、總結
本項目使用了分層、時間片輪、狀態機思想完成了51電子鐘的設計。其主要功能包含基本時間顯示、溫度顯示、倒計時、秒表、鬧鐘、24h/12h選擇,使用按鍵選擇和設置相應的功能。本項目的代碼對于狀態機思想進行了比較深入的運用希望各位能夠在其中有所收獲。同時也歡迎大家留言討論共同進步。

Keil代碼與Proteus8.8仿真下載: 仿真程序.7z (124.09 KB, 下載次數: 101)

評分

參與人數 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏17 分享淘帖 頂5 踩
回復

使用道具 舉報

沙發
ID:137736 發表于 2022-10-20 11:45 | 只看該作者
本帖最后由 zmc419 于 2022-10-20 11:54 編輯

原主程序太長了,模塊化后效果很好,sys.h只要一個文件就行,不要sys.c。
回復

使用道具 舉報

板凳
ID:137736 發表于 2022-10-20 11:48 | 只看該作者
很好,已經模塊化了
回復

使用道具 舉報

地板
ID:1049576 發表于 2022-10-28 16:48 | 只看該作者
感謝,剛好用的上
回復

使用道具 舉報

5#
ID:1049825 發表于 2022-10-30 22:06 | 只看該作者
高手,膜拜!!
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 中文字幕亚洲国产 | 日韩欧美不卡 | 亚洲一区二区三区视频免费观看 | 羞羞网站在线免费观看 | 国产一二区视频 | 成人网在线 | 亚洲视频免费在线 | 欧美九九 | 日韩精品一区二区三区中文字幕 | 亚洲国产一区视频 | 国产农村妇女毛片精品久久麻豆 | 99成人 | 国产精品一区二区免费 | av黄色在线观看 | 毛片一区二区 | 国产精品国产精品 | 国产欧美日韩在线播放 | 在线成人av| 中文字幕欧美一区二区 | 亚洲人成免费 | 久久久亚洲一区 | 美女露尿口视频 | 久热免费 | 日韩视频在线观看 | 亚洲欧洲小视频 | 中文字幕日韩一区 | 91天堂网| 久久69精品久久久久久国产越南 | 国产一区二区精品在线观看 | 亚洲欧美日韩精品久久亚洲区 | 日韩av免费在线观看 | 亚洲精品国产精品国自产在线 | 在线欧美日韩 | 亚洲成人日韩 | av黄色在线观看 | 91人人爽 | 精品美女久久久久久免费 | 久久久久久久久久久久一区二区 | 日日夜夜精品视频 | 国产精品婷婷 | 91久久久久久久 |