第43節(jié):通過串口用計數(shù)延時方式發(fā)送一串?dāng)?shù)據(jù)
上一節(jié)講了通過串口用delay延時方式發(fā)送一串?dāng)?shù)據(jù),這種方式要求發(fā)送一串?dāng)?shù)據(jù)的時候一氣呵成,期間不能執(zhí)行其它任務(wù),由于delay(400)這個時間還不算很長,所以可以應(yīng)用在很多簡單任務(wù)的系統(tǒng)中。但是在某些任務(wù)量很多的系統(tǒng)中,實時運行的主任務(wù)不允許被長時間和經(jīng)常性地中斷,這個時候就需要用計數(shù)延時來替代delay延時。本節(jié)要教會大家兩個知識點:
第一個:用計數(shù)延時方式發(fā)送一串?dāng)?shù)據(jù)的程序框架。
第二個:環(huán)形消息隊列的程序框架。
具體內(nèi)容,請看源代碼講解。
(1)硬件平臺:
基于朱兆祺51單片機學(xué)習(xí)板。
(2)實現(xiàn)功能:
波特率是:9600.
用朱兆祺51單片機學(xué)習(xí)板中的S1,S5,S9,S13作為獨立按鍵。
按一次按鍵S1,發(fā)送EB 00 55 01 00 00 00 00 41
按一次按鍵S5,發(fā)送EB 00 55 02 00 00 00 00 42
按一次按鍵S9,發(fā)送EB 00 55 03 00 00 00 00 43
按一次按鍵S13,發(fā)送EB 00 55 04 00 00 00 00 44
(3)源代碼講解如下:
- #include "REG52.H"
- #define const_send_time100//累計主循環(huán)次數(shù)的計數(shù)延時 請根據(jù)項目實際情況來調(diào)整此數(shù)據(jù)大小
- #define const_send_size10//串口發(fā)送數(shù)據(jù)的緩沖區(qū)數(shù)組大小
- #define const_Message_size10//環(huán)形消息隊列的緩沖區(qū)數(shù)組大小
- #define const_key_time120 //按鍵去抖動延時的時間
- #define const_key_time220 //按鍵去抖動延時的時間
- #define const_key_time320 //按鍵去抖動延時的時間
- #define const_key_time420 //按鍵去抖動延時的時間
- #define const_voice_short40 //蜂鳴器短叫的持續(xù)時間
- void initial_myself(void);
- void initial_peripheral(void);
- //void delay_short(unsigned int uiDelayshort);
- void delay_long(unsigned int uiDelaylong);
- void eusart_send(unsigned char ucSendData);//發(fā)送一個字節(jié),內(nèi)部沒有每個字節(jié)之間的延時
- void send_service(void);//利用累計主循環(huán)次數(shù)的計數(shù)延時方式來發(fā)送一串?dāng)?shù)據(jù)
- void T0_time(void);//定時中斷函數(shù)
- void usart_receive(void); //串口接收中斷函數(shù)
- void key_service(void); //按鍵服務(wù)的應(yīng)用程序
- void key_scan(void); //按鍵掃描函數(shù) 放在定時中斷里
- void insert_message(unsigned char ucMessageTemp);//插入新的消息到環(huán)形消息隊列里
- unsigned char get_message(void);//從環(huán)形消息隊列里提取消息
- sbit led_dr=P3^5;//Led的驅(qū)動IO口
- sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動IO口
- sbit key_sr1=P0^0; //對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
- sbit key_sr2=P0^1; //對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
- sbit key_sr3=P0^2; //對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
- sbit key_sr4=P0^3; //對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
- sbit key_gnd_dr=P0^4; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
- unsigned char ucSendregBuf[const_send_size]; //串口發(fā)送數(shù)據(jù)的緩沖區(qū)數(shù)組
- unsigned char ucMessageBuf[const_Message_size]; //環(huán)形消息隊列的緩沖區(qū)數(shù)據(jù)
- unsigned intuiMessageCurrent=0;//環(huán)形消息隊列的取數(shù)據(jù)當(dāng)前位置
- unsigned intuiMessageInsert=0;//環(huán)形消息隊列的插入新消息時候的位置
- unsigned intuiMessageCnt=0;//統(tǒng)計環(huán)形消息隊列的消息數(shù)量等于0時表示消息隊列里沒有消息
- unsigned char ucMessage=0; //當(dāng)前獲取到的消息
- unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時間計數(shù)器
- unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
- unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
- unsigned intuiKeyTimeCnt1=0; //按鍵去抖動延時計數(shù)器
- unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned intuiKeyTimeCnt2=0; //按鍵去抖動延時計數(shù)器
- unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned intuiKeyTimeCnt3=0; //按鍵去抖動延時計數(shù)器
- unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned intuiKeyTimeCnt4=0; //按鍵去抖動延時計數(shù)器
- unsigned char ucKeyLock4=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned char ucSendStep=0;//發(fā)送一串?dāng)?shù)據(jù)的運行步驟
- unsigned intuiSendTimeCnt=0; //累計主循環(huán)次數(shù)的計數(shù)延時器
- unsigned int uiSendCnt=0; //發(fā)送數(shù)據(jù)時的中間變量
- void main()
- {
- initial_myself();
- delay_long(100);
- initial_peripheral();
- while(1)
- {
- key_service(); //按鍵服務(wù)的應(yīng)用程序
- send_service();//利用累計主循環(huán)次數(shù)的計數(shù)延時方式來發(fā)送一串?dāng)?shù)據(jù)
- }
- }
- /* 注釋一:
- * 通過判斷數(shù)組下標(biāo)是否超范圍的條件,把一個數(shù)組的首尾連接起來,就像一個環(huán)形,
- * 因此命名為環(huán)形消息隊列。環(huán)形消息隊列有插入消息,獲取消息兩個核心函數(shù),以及一個
- * 統(tǒng)計消息總數(shù)的uiMessageCnt核心變量,通過此變量,我們可以知道消息隊列里面是否有消息需要處理.
- * 我在做項目中很少用消息隊列的,印象中我只在兩個項目中用過消息隊列這種方法。大部分的單片機
- * 項目其實直接用一兩個中間變量就可以起到傳遞消息的作用,就能滿足系統(tǒng)的要求。以下是各變量的含義:
- * #define const_Message_size10//環(huán)形消息隊列的緩沖區(qū)數(shù)組大小
- * unsigned char ucMessageBuf[const_Message_size]; //環(huán)形消息隊列的緩沖區(qū)數(shù)據(jù)
- * unsigned intuiMessageCurrent=0;//環(huán)形消息隊列的取數(shù)據(jù)當(dāng)前位置
- * unsigned intuiMessageInsert=0;//環(huán)形消息隊列的插入新消息時候的位置
- * unsigned intuiMessageCnt=0;//統(tǒng)計環(huán)形消息隊列的消息數(shù)量等于0時表示消息隊列里沒有消息
- */
- void insert_message(unsigned char ucMessageTemp)//插入新的消息到環(huán)形消息隊列里
- {
- if(uiMessageCnt
- {
- ucMessageBuf[uiMessageInsert]=ucMessageTemp;
- uiMessageInsert++;//插入新消息時候的位置
- if(uiMessageInsert>=const_Message_size) //到了緩沖區(qū)末尾,則從緩沖區(qū)的開頭重新開始。數(shù)組的首尾連接,看起來就像環(huán)形
- {
- uiMessageInsert=0;
- }
- uiMessageCnt++; //消息數(shù)量累加等于0時表示消息隊列里沒有消息
- }
- }
- unsigned char get_message(void)//從環(huán)形消息隊列里提取消息
- {
- unsigned char ucMessageTemp=0;//返回的消息中間變量,默認(rèn)為0
- if(uiMessageCnt>0)//只有消息數(shù)量大于0時才可以提取消息
- {
- ucMessageTemp=ucMessageBuf[uiMessageCurrent];
- uiMessageCurrent++;//環(huán)形消息隊列的取數(shù)據(jù)當(dāng)前位置
- if(uiMessageCurrent>=const_Message_size) //到了緩沖區(qū)末尾,則從緩沖區(qū)的開頭重新開始。數(shù)組的首尾連接,看起來就像環(huán)形
- {
- uiMessageCurrent=0;
- }
- uiMessageCnt--; //每提取一次,消息數(shù)量就減一等于0時表示消息隊列里沒有消息
- }
- return ucMessageTemp;
- }
- void send_service(void)//利用累計主循環(huán)次數(shù)的計數(shù)延時方式來發(fā)送一串?dāng)?shù)據(jù)
- {
- switch(ucSendStep)//發(fā)送一串?dāng)?shù)據(jù)的運行步驟
- {
- case 0: //從環(huán)形消息隊列里提取消息
- if(uiMessageCnt>0)//說明有消息需要處理
- {
- ucMessage=get_message();
- switch(ucMessage) //消息處理
- {
- case 1:
- ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
- ucSendregBuf[1]=0x00;
- ucSendregBuf[2]=0x55;
- ucSendregBuf[3]=0x01; //01代表1號鍵
- ucSendregBuf[4]=0x00;
- ucSendregBuf[5]=0x00;
- ucSendregBuf[6]=0x00;
- ucSendregBuf[7]=0x00;
- ucSendregBuf[8]=0x41;
- uiSendCnt=0; //發(fā)送數(shù)據(jù)的中間變量清零
- uiSendTimeCnt=0; //累計主循環(huán)次數(shù)的計數(shù)延時器清零
- ucSendStep=1; //切換到下一步發(fā)送一串?dāng)?shù)據(jù)
- break;
- case 2:
- ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
- ucSendregBuf[1]=0x00;
- ucSendregBuf[2]=0x55;
- ucSendregBuf[3]=0x02; //02代表2號鍵
- ucSendregBuf[4]=0x00;
- ucSendregBuf[5]=0x00;
- ucSendregBuf[6]=0x00;
- ucSendregBuf[7]=0x00;
- ucSendregBuf[8]=0x42;
- uiSendCnt=0; //發(fā)送數(shù)據(jù)的中間變量清零
- uiSendTimeCnt=0; //累計主循環(huán)次數(shù)的計數(shù)延時器清零
- ucSendStep=1; //切換到下一步發(fā)送一串?dāng)?shù)據(jù)
- break;
- case 3:
- ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
- ucSendregBuf[1]=0x00;
- ucSendregBuf[2]=0x55;
- ucSendregBuf[3]=0x03; //03代表3號鍵
- ucSendregBuf[4]=0x00;
- ucSendregBuf[5]=0x00;
- ucSendregBuf[6]=0x00;
- ucSendregBuf[7]=0x00;
- ucSendregBuf[8]=0x43;
- uiSendCnt=0; //發(fā)送數(shù)據(jù)的中間變量清零
- uiSendTimeCnt=0; //累計主循環(huán)次數(shù)的計數(shù)延時器清零
- ucSendStep=1; //切換到下一步發(fā)送一串?dāng)?shù)據(jù)
- break;
- case 4:
- ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
- ucSendregBuf[1]=0x00;
- ucSendregBuf[2]=0x55;
- ucSendregBuf[3]=0x04; //04代表4號鍵
- ucSendregBuf[4]=0x00;
- ucSendregBuf[5]=0x00;
- ucSendregBuf[6]=0x00;
- ucSendregBuf[7]=0x00;
- ucSendregBuf[8]=0x44;
- uiSendCnt=0; //發(fā)送數(shù)據(jù)的中間變量清零
- uiSendTimeCnt=0; //累計主循環(huán)次數(shù)的計數(shù)延時器清零
- ucSendStep=1; //切換到下一步發(fā)送一串?dāng)?shù)據(jù)
- break;
- default://如果沒有符合要求的消息,則不處理
- ucSendStep=0; //維持現(xiàn)狀,不切換
- break;
- }
- }
- break;
- case 1://利用累加主循環(huán)次數(shù)的計數(shù)延時方式來發(fā)送一串?dāng)?shù)據(jù)
- /* 注釋二:
- * 這里的計數(shù)延時為什么不用累計定時中斷次數(shù)的延時,而用累計主循環(huán)次數(shù)的計數(shù)延時?
- * 因為本程序定時器中斷一次需要500個指令時間,時間分辨率太低,不方便微調(diào)時間。因此我
- * 就用累計主循環(huán)次數(shù)的計數(shù)延時方式,在做項目的時候,各位讀者應(yīng)該根據(jù)系統(tǒng)的實際情況
- * 來調(diào)整const_send_time的大小。
- */
- uiSendTimeCnt++;//累計主循環(huán)次數(shù)的計數(shù)延時,為每個字節(jié)之間增加延時,
- if(uiSendTimeCnt>const_send_time)//請根據(jù)實際系統(tǒng)的情況,調(diào)整const_send_time的大小
- {
- uiSendTimeCnt=0;
- eusart_send(ucSendregBuf[uiSendCnt]);//發(fā)送一串?dāng)?shù)據(jù)給上位機
- uiSendCnt++;
- if(uiSendCnt>=9) //說明數(shù)據(jù)已經(jīng)發(fā)送完畢
- {
- uiSendCnt=0;
- ucSendStep=0; //返回到上一步,處理其它未處理的消息
- }
- }
- break;
- }
- }
- void eusart_send(unsigned char ucSendData)
- {
- ES = 0; //關(guān)串口中斷
- TI = 0; //清零串口發(fā)送完成中斷請求標(biāo)志
- SBUF =ucSendData; //發(fā)送一個字節(jié)
- /* 注釋三:
- * 根據(jù)我個人的經(jīng)驗,在發(fā)送一串?dāng)?shù)據(jù)中,每個字節(jié)之間必須添加一個延時,用來等待串口發(fā)送完成。
- * 當(dāng)然,也有一些朋友可能不增加延時,直接靠單片機自帶的發(fā)送完成標(biāo)志位來判斷,但是我以前
- * 在做項目中,感覺單單靠發(fā)送完成標(biāo)志位來判斷還是容易出錯(當(dāng)然也有可能是我自身程序的問題),
- * 所以后來在大部分的項目中我就干脆靠延時來等待它發(fā)送完成。我在51,PIC單片機中都是這么做的。
- * 但是,憑我的經(jīng)驗,在stm32單片機中,可以不增加延時,直接靠單片機自帶的標(biāo)志位來判斷就很可靠。
- */
- //delay_short(400);//因為外部在每個發(fā)送字節(jié)之間用了累計主循環(huán)次數(shù)的計數(shù)延時,因此不要此行的delay延時
- TI = 0; //清零串口發(fā)送完成中斷請求標(biāo)志
- ES = 1; //允許串口中斷
- }
- void key_scan(void)//按鍵掃描函數(shù) 放在定時中斷里
- {
- if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標(biāo)志位
- {
- ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt1=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
- }
- else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt1++; //累加定時中斷次數(shù)
- if(uiKeyTimeCnt1>const_key_time1)
- {
- uiKeyTimeCnt1=0;
- ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=1; //觸發(fā)1號鍵
- }
- }
- if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標(biāo)志位
- {
- ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt2=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
- }
- else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt2++; //累加定時中斷次數(shù)
- if(uiKeyTimeCnt2>const_key_time2)
- {
- uiKeyTimeCnt2=0;
- ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=2; //觸發(fā)2號鍵
- }
- }
- if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標(biāo)志位
- {
- ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt3=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
- }
- else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt3++; //累加定時中斷次數(shù)
- if(uiKeyTimeCnt3>const_key_time3)
- {
- uiKeyTimeCnt3=0;
- ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=3; //觸發(fā)3號鍵
- }
- }
- if(key_sr4==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標(biāo)志位
- {
- ucKeyLock4=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt4=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
- }
- else if(ucKeyLock4==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt4++; //累加定時中斷次數(shù)
- if(uiKeyTimeCnt4>const_key_time4)
- {
- uiKeyTimeCnt4=0;
- ucKeyLock4=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=4; //觸發(fā)4號鍵
- }
- }
- }
- void key_service(void) //第三區(qū) 按鍵服務(wù)的應(yīng)用程序
- {
- switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
- {
- case 1:// 1號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
- insert_message(0x01);//把新消息插入到環(huán)形消息隊列里等待處理
- ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數(shù)的共享數(shù)據(jù)
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0; //原子鎖解鎖
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
- break;
- case 2:// 2號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
- insert_message(0x02);//把新消息插入到環(huán)形消息隊列里等待處理
- ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數(shù)的共享數(shù)據(jù)
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0; //原子鎖解鎖
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
- break;
- case 3:// 3號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
- insert_message(0x03);//把新消息插入到環(huán)形消息隊列里等待處理
- ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數(shù)的共享數(shù)據(jù)
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0; //原子鎖解鎖
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
- break;
- case 4:// 4號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
- insert_message(0x04);//把新消息插入到環(huán)形消息隊列里等待處理
- ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數(shù)的共享數(shù)據(jù)
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0; //原子鎖解鎖
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
- break;
- }
- }
- void T0_time(void) interrupt 1 //定時中斷
- {
- TF0=0;//清除中斷標(biāo)志
- TR0=0; //關(guān)中斷
- /* 注釋四:
- * 此處多增加一個原子鎖,作為中斷與主函數(shù)共享數(shù)據(jù)的保護,實際上是借鑒了"紅金龍吸味"關(guān)于原子鎖的建議.
- */
- if(ucVoiceLock==0) //原子鎖判斷
- {
- if(uiVoiceCnt!=0)
- {
- uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
- beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
- }
- else
- {
- ; //此處多加一個空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
- beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
- }
- }
- key_scan();//按鍵掃描函數(shù)
- TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
- TL0=0x0b;
- TR0=1;//開中斷
- }
- void usart_receive(void) interrupt 4 //串口中斷
- {
- if(RI==1)
- {
- RI = 0; //接收中斷,及時把接收中斷標(biāo)志位清零
- }
- else
- {
- TI = 0; //發(fā)送中斷,及時把發(fā)送中斷標(biāo)志位清零
- }
- }
- //void delay_short(unsigned int uiDelayShort)
- //{
- // unsigned int i;
- // for(i=0;i
- // {
- // ; //一個分號相當(dāng)于執(zhí)行一條空語句
- // }
- //}
- void delay_long(unsigned int uiDelayLong)
- {
- unsigned int i;
- unsigned int j;
- for(i=0;i
- {
- for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
- {
- ; //一個分號相當(dāng)于執(zhí)行一條空語句
- }
- }
- }
- void initial_myself(void)//第一區(qū) 初始化單片機
- {
- /* 注釋五:
- * 矩陣鍵盤也可以做獨立按鍵,前提是把某一根公共輸出線輸出低電平,
- * 模擬獨立按鍵的觸發(fā)地,本程序中,把key_gnd_dr輸出低電平。
- * 朱兆祺51學(xué)習(xí)板的S1和S5兩個按鍵就是本程序中用到的兩個獨立按鍵。
- */
- key_gnd_dr=0; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
- led_dr=0; //關(guān)Led燈
- beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
- //配置定時器
- TMOD=0x01;//設(shè)置定時器0為工作方式1
- TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
- TL0=0x0b;
- //配置串口
- SCON=0x50;
- TMOD=0X21;
- TH1=TL1=-(11059200L/12/32/9600);//串口波特率9600。
- TR1=1;
- }
- void initial_peripheral(void) //第二區(qū) 初始化外圍
- {
- EA=1; //開總中斷
- ES=1; //允許串口中斷
- ET0=1; //允許定時中斷
- TR0=1; //啟動定時中斷
- }
總結(jié)陳詞:
前面幾個章節(jié)中,每個章節(jié)要么獨立地講解串口收數(shù)據(jù),要么獨立地講解發(fā)數(shù)據(jù),實際上在大部分的項目中,串口都需要“一收一應(yīng)答”的握手協(xié)議,上位機作為主機,單片機作為從機,主機先發(fā)一串?dāng)?shù)據(jù),從機收到數(shù)據(jù)后進行校驗判斷,如果校驗正確則返回正確應(yīng)答指令,如果校驗錯誤則返回錯誤應(yīng)答指令,主機收到應(yīng)答指令后,如果發(fā)現(xiàn)是正確應(yīng)答指令則繼續(xù)發(fā)送其它的新數(shù)據(jù),如果發(fā)現(xiàn)是錯誤應(yīng)答指令,或者超時沒有接收到任何應(yīng)答指令,則繼續(xù)重發(fā),如果連續(xù)重發(fā)三次都是錯誤應(yīng)答或者無應(yīng)答,主機就進行報錯處理。讀者只要把我的串口收發(fā)程序結(jié)合起來,就很容易實現(xiàn)這樣的功能,我就不再詳細(xì)講解了。從下一節(jié)開始我講解單片機掉電后數(shù)據(jù)保存的內(nèi)容,欲知詳情,請聽下回分解-----利用AT24C02進行掉電后的數(shù)據(jù)保存。
評論