一、使用proteus繪制簡單的電路圖,用于后續仿真
二、編寫程序
/********************************************************************************************************************
---- @Project: USART
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200720
---- @ModifiedTime: 20200720
---- @Description: 實現功能:
---- 顯示和獨立按鍵部分根據數碼管顯示的程序來改編,用S1,S5,S9,S13作為獨立按鍵。
---- 一共有4個窗口。每個窗口顯示一個參數。有兩種更改參數的方式:
---- 第一種:按鍵更改參數:
---- 第8,7,6,5位數碼管顯示當前窗口,P-1代表第1個窗口,P-2代表第2個窗口,P-3代表第3個窗口,P-4代表第1個窗口。
---- 第4,3,2,1位數碼管顯示當前窗口被設置的參數。范圍是從0到9999。S1是加按鍵,按下此按鍵會依次增加當前窗口的參數。S5是減按鍵,按下此按鍵會依次減少當前窗口的參數。S9是切換窗口按鍵,按下此按鍵會依次循環切換不同的窗口。S13是啟動發送數據和復位按鍵,當系統處于待機狀態時,按下此按鍵會啟動發送數據;當通訊超時蜂鳴器報警時,可以按下此鍵清除報警,返回到待機的狀態。
----
---- 第二:通過串口把更改的參數發送給從機。
---- 波特率是:9600.
---- 通訊協議:EB 00 55 GG 00 02 XX XX CY
---- 其中第1,2,3位EB 00 55就是數據頭
---- 其中第4位GG就是數據類型。01代表更改參數1,02代表更改參數2,03代表更改參數3,04代表更改參數4,
---- 其中第5,6位00 02就是有效數據長度。高位在左,低位在右。
---- 其中從第7,8位XX XX是被更改的參數。高位在左,低位在右。
---- 第9位CY是累加和,前面所有字節的累加。
---- 一個完整的通訊必須發送完4串數據,每串數據之間的間隔時間不能超過10秒鐘,否則認為通訊超時主機會重發數據,如果連續三次都沒有返回,則引發蜂鳴器報警。如果接收到得數據校驗正確,主機繼續發送新的一串數據,直到把4串數據發送完畢為止。
----
---- 系統處于待機狀態時,LED燈一直亮,
---- 系統處于非待機狀態時,LED燈閃爍,
---- 系統處于出錯狀態時,LED燈閃爍,并且蜂鳴器間歇鳴叫報警。
----
---- 通過電腦的串口助手來模擬從機,返回不同的應答
---- 從機返回校驗正確應答:eb 00 55 f5 00 00 35
---- 從機返回校驗出錯應答:eb 00 55 fa 00 00 3a
---- 單片機:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定義——————*/
#define FOSC 11059200L
#define BAUD 9600
#define T1MS (65536-FOSC/12/500) /*0.5ms timer calculation method in 12Tmode*/
#define const_key_time1 9 /*按鍵去抖動延時的時間*/
#define const_key_time2 9 /*按鍵去抖動延時的時間*/
#define const_key_time3 9 /*按鍵去抖動延時的時間*/
#define const_key_time4 9 /*按鍵去抖動延時的時間*/
#define const_led_0_5s 32 /*大概0.5秒的時間*/
#define const_led_1s 64 /*大概1秒的時間*/
#define const_send_time_out 640 /*通訊超時出錯的時間 大概10秒*/
#define const_rc_size 20 /*接收串口中斷數據的緩沖區數組大小*/
#define const_receive_time 5 /*如果超過這個時間沒有串口數據過來,就認為一串數據已經全部接收完,這個時間根據實際情況來調整大小*/
#define const_send_size 10 /*串口發送數據的緩沖區數組大小*/
#define const_voice_short 20 /*蜂鳴器短叫的持續時間*/
/*——————變量函數定義及聲明——————*/
/*蜂鳴器的驅動IO口*/
sbit BEEP = P2^7;
/*LED*/
sbit LED = P3^5;
/*按鍵*/
sbit Key_S1 = P0^0; /*對應S1鍵,加鍵*/
sbit Key_S2 = P0^1; /*對應S5鍵,減鍵*/
sbit Key_S3 = P0^2; /*對應S9鍵,切換窗口*/
sbit Key_S4 = P0^3; /*對應S13鍵,復位*/
sbit Key_Gnd = P0^4;
/*數碼管*/
sbit Dig_Hc595_Sh = P2^0;
sbit Dig_Hc595_St = P2^1;
sbit Dig_Hc595_Ds = P2^2;
unsigned char ucSendregBuf[const_send_size]; /*發送的緩沖區數組*/
unsigned int uiSendCnt = 0; /*用來識別串口是否接收完一串數據的計時器*/
unsigned char ucSendLock = 1; /*串口服務程序的自鎖變量,每次接收完一串數據只處理一次*/
unsigned int uiRcregTotal = 0; /*代表當前緩沖區已經接收了多少個數據*/
unsigned char ucRcregBuf[const_rc_size]; /*接收串口中斷數據的緩沖區數組*/
unsigned int uiRcMoveIndex = 0; /*用來解析數據協議的中間變量*/
unsigned char ucSendCntLock = 0; /*串口計時器的原子鎖*/
unsigned char ucRcType = 0; /*數據類型*/
unsigned int uiRcSize = 0; /*數據長度*/
unsigned char ucRcCy = 0; /*校驗累加和*/
unsigned char ucLedLock = 0; /*原子鎖*/
unsigned int uiLedCnt = 0; /*控制Led閃爍的延時計時器*/
unsigned int uiSendTimeOutCnt = 0; /*用來識別接收數據超時的計時器*/
unsigned char ucSendTimeOutLock = 0; /*原子鎖*/
unsigned char ucStatus = 0; /*當前狀態變量 0代表待機 1代表正在通訊過程 2代表發送出錯*/
unsigned char ucSendStep = 0; /*發送數據的過程步驟*/
unsigned char ucErrorCnt = 0; /*累計錯誤總數*/
unsigned char ucSendTotal = 0; /*記錄當前已經發送了多少串數據*/
unsigned char ucReceiveStatus = 0; /*返回的數據狀態 0代表待機 1代表校驗正確 2代表校驗出錯*/
unsigned char ucKeySec = 0; /*被觸發的按鍵編號*/
unsigned int uiKeyTimeCnt1 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock1 = 0; /*按鍵觸發后自鎖的變量標志*/
unsigned int uiKeyTimeCnt2 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock2 = 0; /*按鍵觸發后自鎖的變量標志*/
unsigned int uiKeyTimeCnt3 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock3 = 0; /*按鍵觸發后自鎖的變量標志*/
unsigned int uiKeyTimeCnt4 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock4 = 0; /*按鍵觸發后自鎖的變量標志*/
unsigned int uiVoiceCnt = 0; /*蜂鳴器鳴叫的持續時間計數器*/
unsigned char ucVoiceLock = 0; /*蜂鳴器鳴叫的原子鎖*/
unsigned char ucDigShow8; /*第8位數碼管要顯示的內容*/
unsigned char ucDigShow7; /*第7位數碼管要顯示的內容*/
unsigned char ucDigShow6; /*第6位數碼管要顯示的內容*/
unsigned char ucDigShow5; /*第5位數碼管要顯示的內容*/
unsigned char ucDigShow4; /*第4位數碼管要顯示的內容*/
unsigned char ucDigShow3; /*第3位數碼管要顯示的內容*/
unsigned char ucDigShow2; /*第2位數碼管要顯示的內容*/
unsigned char ucDigShow1; /*第1位數碼管要顯示的內容*/
unsigned char ucDigDot8; /*數碼管8的小數點是否顯示的標志*/
unsigned char ucDigDot7; /*數碼管7的小數點是否顯示的標志*/
unsigned char ucDigDot6; /*數碼管6的小數點是否顯示的標志*/
unsigned char ucDigDot5; /*數碼管5的小數點是否顯示的標志*/
unsigned char ucDigDot4; /*數碼管4的小數點是否顯示的標志*/
unsigned char ucDigDot3; /*數碼管3的小數點是否顯示的標志*/
unsigned char ucDigDot2; /*數碼管2的小數點是否顯示的標志*/
unsigned char ucDigDot1; /*數碼管1的小數點是否顯示的標志*/
unsigned char ucDigShowTemp = 0; /*臨時中間變量*/
unsigned char ucDisplayDriveStep = 1; /*動態掃描數碼管的步驟變量*/
unsigned char ucWd1Update = 1; /*窗口1更新顯示標志*/
unsigned char ucWd2Update = 0; /*窗口2更新顯示標志*/
unsigned char ucWd3Update = 0; /*窗口3更新顯示標志*/
unsigned char ucWd4Update = 0; /*窗口4更新顯示標志*/
unsigned char ucWd = 1; /*本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。*/
unsigned int uiSetData1 = 0; /*本程序中需要被設置的參數1*/
unsigned int uiSetData2 = 0; /*本程序中需要被設置的參數2*/
unsigned int uiSetData3 = 0; /*本程序中需要被設置的參數3*/
unsigned int uiSetData4 = 0; /*本程序中需要被設置的參數4*/
unsigned char ucTemp1 = 0; /*中間過渡變量*/
unsigned char ucTemp2 = 0; /*中間過渡變量*/
unsigned char ucTemp3 = 0; /*中間過渡變量*/
unsigned char ucTemp4 = 0; /*中間過渡變量*/
void Dig_Hc595_Drive(unsigned char, unsigned char);
/*根據原理圖得出的共陰數碼管字模表*/
code unsigned char Dig_Table[] =
{
0x3f, /*0 序號0*/
0x06, /*1 序號1*/
0x5b, /*2 序號2*/
0x4f, /*3 序號3*/
0x66, /*4 序號4*/
0x6d, /*5 序號5*/
0x7d, /*6 序號6*/
0x07, /*7 序號7*/
0x7f, /*8 序號8*/
0x6f, /*9 序號9*/
0x00, /*不顯示 序號10*/
0x40, /*- 序號11*/
0x73, /*P 序號12*/
};
/**
* @brief 定時器0初始化函數
* @param 無
* @retval 初始化T0
**/
void Init_T0(void)
{
TMOD = 0x01; /*set timer0 as mode1 (16-bit)*/
TL0 = T1MS; /*initial timer0 low byte*/
TH0 = T1MS >> 8; /*initial timer0 high byte*/
}
/**
* @brief 串口初始化函數
* @param 無
* @retval 初始化T0
**/
void Init_USART(void)
{
SCON = 0x50;
TMOD = 0x21;
TH1=TL1=-(FOSC/12/32/BAUD);
}
/**
* @brief 外圍初始化函數
* @param 無
* @retval 初始化外圍
* 讓數碼管顯示的內容轉移到以下幾個變量接口上,方便以后編寫更上一層的窗口程序。
* 只要更改以下對應變量的內容,就可以顯示你想顯示的數字。
**/
void Init_Peripheral(void)
{
ucDigDot8 = 0;
ucDigDot7 = 0;
ucDigDot6 = 0;
ucDigDot5 = 0;
ucDigDot4 = 0;
ucDigDot3 = 0;
ucDigDot2 = 0;
ucDigDot1 = 0;
ET0 = 1;/*允許定時中斷*/
TR0 = 1;/*啟動定時中斷*/
TR1 = 1;
ES = 1; /*允許串口中斷*/
EA = 1;/*開總中斷*/
}
/**
* @brief 初始化函數
* @param 無
* @retval 初始化單片機
**/
void Init(void)
{
LED = 0;
BEEP = 1;
Key_Gnd = 0;
Dig_Hc595_Drive(0x00, 0x00); /*關閉所有經過另外兩個74HC595驅動的LED燈*/
Init_T0();
Init_USART();
/*
* 為了保證串口中斷接收的數據不丟失,必須設置IP = 0x10,相當于把串口中斷設置為最高優先級,
* 這個時候,串口中斷可以打斷任何其他的中斷服務函數實現嵌套,
*/
IP = 0x10; /*把串口中斷設置為最高優先級,必須的。*/
}
/**
* @brief 延時函數
* @param 無
* @retval 無
**/
void Delay_Long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i for(j=0;j<500;j++) /*內嵌循環的空指令數量*/ { ; /*一個分號相當于執行一條空語句*/ } } } /** * @brief 延時函數 * @param 無 * @retval 無 **/ void Delay_Short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i ; /*一個分號相當于執行一條空語句*/ } } /** * @brief 串口發送函數 * @param ucSendData * @retval 在發送一串數據中,每個字節之間必須添加一個延時,用來等待串口發送完成。 * 不增加延時,單單靠發送完成標志位來判斷還是容易出錯,在51,PIC單片機中都是這么做。 * 在stm32單片機中,可以不增加延時,直接靠單片機自帶的標志位來判斷就很可靠。 **/ void eusart_send(unsigned char ucSendData) { ES = 0; /*關串口中斷*/ TI = 0; /*清零串口發送完成中斷請求標志*/ SBUF = ucSendData; /*發送一個字節*/ Delay_Short(400); /*每個字節之間的延時,這里非常關鍵,也是最容易出錯的地方。延時的大小請根據實際項目來調整*/ TI = 0; /*清零串口發送完成中斷請求標志*/ ES = 1; /*允許串口中斷*/ } /** * @brief 一發一收的通訊服務程序 * @param 無 * @retval 無 **/ void communication_service(void) { unsigned int i; if(ucStatus == 1) /*處于正在通訊的過程中*/ { switch(ucSendStep) { case 0: /*通訊過程0 發送一串數據*/ switch(ucSendTotal) /*根據當前已經發送到第幾條數據來決定發送哪些參數*/ { case 0: /*發送參數1*/ ucSendregBuf[0] = 0xeb; ucSendregBuf[1] = 0x00; ucSendregBuf[2] = 0x55; ucSendregBuf[3] = 0x01; ucSendregBuf[4] = 0x00; ucSendregBuf[5] = 0x02; ucSendregBuf[6] = uiSetData1 >> 8; /*把int類型的參數分解成兩個字節的數據*/ ucSendregBuf[7] = uiSetData1; break; case 1: /*發送參數2*/ ucSendregBuf[0] = 0xeb; ucSendregBuf[1] = 0x00; ucSendregBuf[2] = 0x55; ucSendregBuf[3] = 0x02; ucSendregBuf[4] = 0x00; ucSendregBuf[5] = 0x02; ucSendregBuf[6] = uiSetData2 >> 8; /*把int類型的參數分解成兩個字節的數據*/ ucSendregBuf[7] = uiSetData2; break; case 2: /*發送參數3*/ ucSendregBuf[0] = 0xeb; ucSendregBuf[1] = 0x00; ucSendregBuf[2] = 0x55; ucSendregBuf[3] = 0x03; ucSendregBuf[4] = 0x00; ucSendregBuf[5] = 0x02; ucSendregBuf[6] = uiSetData3 >> 8; /*把int類型的參數分解成兩個字節的數據*/ ucSendregBuf[7] = uiSetData3;
上一篇:51單片機實現利用AT24C02進行掉電后的數據保存
下一篇:51單片機實現從機的串口收發
推薦閱讀最新更新時間:2025-04-25 07:13

設計資源 培訓 開發板 精華推薦
- 高通攜手中國“汽車朋友圈”亮相2025上海車展: 加速駕駛輔助普惠,推動艙駕創新升級
- 工業市場正在快速回暖,德州儀器如何重塑電力電子市場?
- 特斯拉:美國交付的Model Y/3電池包已實現100%美國生產
- 地平線與博世深化合作,攜手為多家車企提供輔助駕駛產品
- 強化中國市場戰略布局,德州儀器正靈活應對全球關稅挑戰
- Molex莫仕通過本地合作和創新加強支持中國汽車行業
- 貿澤開售Texas Instruments適用于高分辨率AR HUD的 全新DLP4620S-Q1 0.46"汽車數字微鏡器件
- ROHM推出高功率密度的新型SiC模塊,將實現車載充電器小型化!
- 用上車規級UFS 4.0,讓出行變得高效且可靠
- 車載測試技術解析:聚焦高帶寬、多通道同步采集與協議分析
- 看專題答題贏好禮!PI 穩定可靠的TOPSwitch-JX開關電源IC
- TI 有獎直播 | 使用基于 Arm 的 AM6xA 處理器設計智能化樓宇
- 報名有禮:【TI C2000在實時控制系統中的新特性】網絡直播誠邀您參與!
- 億佰特免費提供藍牙,4G DTU,WiFi,lora多種模塊,想玩的快來!
- 下載贏禮 | 雅特生 PMBus 接口非隔離數字 DC-DC 轉換器
- 免費試用+優惠購+任務解鎖贏好禮!這個夏天pyboardCN V2暢玩走起!
- Microchip 直播|多相降壓電源控制技術的發展與探討
- 有獎直播 是德科技全新光通信測試方案介紹
- 有獎直播 是德科技全新光通信測試方案介紹
- 有獎直播:NXP 汽車系統電源管理開講啦,從功能安全架構到新品FS26,預約有禮~