<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 第44節(jié):從機(jī)的串口收發(fā)綜合程序框架

          第44節(jié):從機(jī)的串口收發(fā)綜合程序框架

          作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
          開場白:
          根據(jù)上一節(jié)的預(yù)告,本來這一節(jié)內(nèi)容打算講“利用AT24C02進(jìn)行掉電后的數(shù)據(jù)保存”的,但是由于網(wǎng)友“261854681”強(qiáng)烈建議我講一個(gè)完整的串口收發(fā)程序?qū)嵗?,因此我決定再花兩節(jié)篇幅講講這方面的內(nèi)容。
          實(shí)際上在大部分的項(xiàng)目中,串口都需要“一收一應(yīng)答”的握手協(xié)議,上位機(jī)作為主機(jī),單片機(jī)作為從機(jī),主機(jī)先發(fā)一串?dāng)?shù)據(jù),從機(jī)收到數(shù)據(jù)后進(jìn)行校驗(yàn)判斷,如果校驗(yàn)正確則返回正確應(yīng)答指令,如果校驗(yàn)錯(cuò)誤則返回錯(cuò)誤應(yīng)答指令,主機(jī)收到應(yīng)答指令后,如果發(fā)現(xiàn)是正確應(yīng)答指令則繼續(xù)發(fā)送其它的新數(shù)據(jù),如果發(fā)現(xiàn)是錯(cuò)誤應(yīng)答指令,或者超時(shí)沒有接收到任何應(yīng)答指令,則繼續(xù)重發(fā),如果連續(xù)重發(fā)三次都是錯(cuò)誤應(yīng)答或者無應(yīng)答,主機(jī)就進(jìn)行報(bào)錯(cuò)處理。
          這節(jié)先講從機(jī)的收發(fā)端程序?qū)嵗?。要教?huì)大家三個(gè)知識(shí)點(diǎn):
          第一個(gè):為了保證串口中斷接收的數(shù)據(jù)不丟失,在初始化時(shí)必須設(shè)置IP = 0x10,相當(dāng)于把串口中斷設(shè)置為最高優(yōu)先級(jí),這個(gè)時(shí)候,串口中斷可以打斷任何其他的中斷服務(wù)函數(shù),實(shí)現(xiàn)中斷嵌套。
          第二個(gè):從機(jī)端的收發(fā)端程序框架
          第三個(gè):從機(jī)的狀態(tài)指示程序框架。可以指示待機(jī),通訊中,超時(shí)出錯(cuò)三種狀態(tài)。

          具體內(nèi)容,請(qǐng)看源代碼講解。

          (1)硬件平臺(tái):
          基于朱兆祺51單片機(jī)學(xué)習(xí)板

          (2)實(shí)現(xiàn)功能:
          顯示和獨(dú)立按鍵部分根據(jù)第29節(jié)的程序來改編,用朱兆祺51單片機(jī)學(xué)習(xí)板中的S1,S5,S9,S13作為獨(dú)立按鍵。
          一共有4個(gè)窗口。每個(gè)窗口顯示一個(gè)參數(shù)。有兩種更改參數(shù)的方式:
          第一種:按鍵更改參數(shù):
          第8,7,6,5位數(shù)碼管顯示當(dāng)前窗口,P-1代表第1個(gè)窗口,P-2代表第2個(gè)窗口,P-3代表第3個(gè)窗口,P-4代表第1個(gè)窗口。
          第4,3,2,1位數(shù)碼管顯示當(dāng)前窗口被設(shè)置的參數(shù)。范圍是從0到9999。S1是加按鍵,按下此按鍵會(huì)依次增加當(dāng)前窗口的參數(shù)。S5是減按鍵,按下此按鍵會(huì)依次減少當(dāng)前窗口的參數(shù)。S9是切換窗口按鍵,按下此按鍵會(huì)依次循環(huán)切換不同的窗口。S13是復(fù)位按鍵,當(dāng)通訊超時(shí)蜂鳴器報(bào)警時(shí),可以按下此鍵清除報(bào)警。

          第二種:通過串口來更改參數(shù):
          波特率是:9600.
          通訊協(xié)議:EB 00 55GG 00 02 XX XXCY
          其中第1,2,3位EB 00 55就是數(shù)據(jù)頭
          其中第4位GG就是數(shù)據(jù)類型。01代表更改參數(shù)1,02代表更改參數(shù)2,03代表更改參數(shù)3,04代表更改參數(shù)4,
          其中第5,6位00 02就是有效數(shù)據(jù)長度。高位在左,低位在右。
          其中從第7,8位XX XX是被更改的參數(shù)。高位在左,低位在右。
          第9位CY是累加和,前面所有字節(jié)的累加。
          一個(gè)完整的通訊必須接收完4串?dāng)?shù)據(jù),每串?dāng)?shù)據(jù)之間的間隔時(shí)間不能超過10秒鐘,否則認(rèn)為通訊超時(shí)出錯(cuò)引發(fā)蜂鳴器報(bào)警。如果接收到得數(shù)據(jù)校驗(yàn)正確,
          則返回校驗(yàn)正確應(yīng)答:eb 00 55 f5 00 00 35,
          否則返回校驗(yàn)出錯(cuò)應(yīng)答::eb 00 55 fa 00 00 3a。
          系統(tǒng)處于待機(jī)狀態(tài)時(shí),LED燈一直亮,
          系統(tǒng)處于非待機(jī)狀態(tài)時(shí),LED燈閃爍,
          系統(tǒng)處于通訊超時(shí)出錯(cuò)狀態(tài)時(shí),LED燈閃爍,并且蜂鳴器間歇鳴叫報(bào)警。


          通過電腦的串口助手,依次發(fā)送以下測試數(shù)據(jù),將會(huì)分別更改參數(shù)1,參數(shù)2,參數(shù)3,參數(shù)4。注意,每串?dāng)?shù)據(jù)之間的時(shí)間最大不能超過10秒,否則系統(tǒng)認(rèn)為通訊超時(shí)報(bào)警。
          把參數(shù)1更改為十進(jìn)制的1: eb 00 55 01 00 02 00 01 44
          把參數(shù)2更改為十進(jìn)制的12:eb 00 55 02 00 02 00 0c 50
          把參數(shù)3更改為十進(jìn)制的123: eb 00 55 03 00 02 00 7b c0
          把參數(shù)4更改為十進(jìn)制的1234:eb 00 55 04 00 02 04 d2 1c

          (3)源代碼講解如下:
          1. #include "REG52.H"
          2. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時(shí)間
          3. #define const_key_time120 //按鍵去抖動(dòng)延時(shí)的時(shí)間
          4. #define const_key_time220 //按鍵去抖動(dòng)延時(shí)的時(shí)間
          5. #define const_key_time320 //按鍵去抖動(dòng)延時(shí)的時(shí)間
          6. #define const_key_time420 //按鍵去抖動(dòng)延時(shí)的時(shí)間
          7. #define const_led_0_5s200 //大概0.5秒的時(shí)間
          8. #define const_led_1s 400 //大概1秒的時(shí)間
          9. #define const_send_time_out 4000//通訊超時(shí)出錯(cuò)的時(shí)間 大概10秒
          10. #define const_rc_size20//接收串口中斷數(shù)據(jù)的緩沖區(qū)數(shù)組大小
          11. #define const_receive_time5//如果超過這個(gè)時(shí)間沒有串口數(shù)據(jù)過來,就認(rèn)為一串?dāng)?shù)據(jù)已經(jīng)全部接收完,這個(gè)時(shí)間根據(jù)實(shí)際情況來調(diào)整大小
          12. #define const_send_size10//串口發(fā)送數(shù)據(jù)的緩沖區(qū)數(shù)組大小
          13. void initial_myself(void);
          14. void initial_peripheral(void);
          15. void delay_short(unsigned int uiDelayShort);
          16. void delay_long(unsigned int uiDelaylong);
          17. //驅(qū)動(dòng)數(shù)碼管的74HC595
          18. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
          19. void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
          20. void display_service(void); //顯示的窗口菜單服務(wù)程序
          21. //驅(qū)動(dòng)LED的74HC595
          22. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
          23. void T0_time(void);//定時(shí)中斷函數(shù)
          24. void usart_receive(void); //串口接收中斷函數(shù)
          25. void usart_service(void);//串口服務(wù)程序,在main函數(shù)里
          26. void eusart_send(unsigned char ucSendData); //發(fā)送一個(gè)字節(jié),內(nèi)部自帶每個(gè)字節(jié)之間的delay延時(shí)
          27. void key_service(void); //按鍵服務(wù)的應(yīng)用程序
          28. void key_scan(void);//按鍵掃描函數(shù) 放在定時(shí)中斷里
          29. void status_service(void);//狀態(tài)顯示的應(yīng)用程序
          30. sbit key_sr1=P0^0; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
          31. sbit key_sr2=P0^1; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
          32. sbit key_sr3=P0^2; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
          33. sbit key_sr4=P0^3; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
          34. sbit key_gnd_dr=P0^4; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
          35. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口
          36. sbit led_dr=P3^5;//作為狀態(tài)指示燈 亮的時(shí)候表示待機(jī)狀態(tài).閃爍表示非待機(jī)狀態(tài),處于正在發(fā)送數(shù)據(jù)或者出錯(cuò)的狀態(tài)
          37. sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的74HC595程序
          38. sbit dig_hc595_st_dr=P2^1;
          39. sbit dig_hc595_ds_dr=P2^2;
          40. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
          41. sbit hc595_st_dr=P2^4;
          42. sbit hc595_ds_dr=P2^5;
          43. unsigned char ucSendregBuf[const_send_size]; //發(fā)送的緩沖區(qū)數(shù)組
          44. unsigned intuiSendCnt=0; //用來識(shí)別串口是否接收完一串?dāng)?shù)據(jù)的計(jì)時(shí)器
          45. unsigned char ucSendLock=1; //串口服務(wù)程序的自鎖變量,每次接收完一串?dāng)?shù)據(jù)只處理一次
          46. unsigned intuiRcregTotal=0;//代表當(dāng)前緩沖區(qū)已經(jīng)接收了多少個(gè)數(shù)據(jù)
          47. unsigned char ucRcregBuf[const_rc_size]; //接收串口中斷數(shù)據(jù)的緩沖區(qū)數(shù)組
          48. unsigned intuiRcMoveIndex=0;//用來解析數(shù)據(jù)協(xié)議的中間變量
          49. unsigned charucSendCntLock=0; //串口計(jì)時(shí)器的原子鎖
          50. unsigned char ucRcType=0;//數(shù)據(jù)類型
          51. unsigned intuiRcSize=0;//數(shù)據(jù)長度
          52. unsigned char ucRcCy=0;//校驗(yàn)累加和
          53. unsigned intuiLedCnt=0;//控制Led閃爍的延時(shí)計(jì)時(shí)器
          54. unsigned intuiSendTimeOutCnt=0; //用來識(shí)別接收數(shù)據(jù)超時(shí)的計(jì)時(shí)器
          55. unsigned char ucSendTimeOutLock=0; //原子鎖
          56. unsigned char ucStatus=0; //當(dāng)前狀態(tài)變量 0代表待機(jī) 1代表正在通訊過程 2代表發(fā)送出錯(cuò)
          57. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號(hào)
          58. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
          59. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
          60. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
          61. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
          62. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
          63. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
          64. unsigned intuiKeyTimeCnt4=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
          65. unsigned char ucKeyLock4=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
          66. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時(shí)間計(jì)數(shù)器
          67. unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
          68. unsigned char ucDigShow8;//第8位數(shù)碼管要顯示的內(nèi)容
          69. unsigned char ucDigShow7;//第7位數(shù)碼管要顯示的內(nèi)容
          70. unsigned char ucDigShow6;//第6位數(shù)碼管要顯示的內(nèi)容
          71. unsigned char ucDigShow5;//第5位數(shù)碼管要顯示的內(nèi)容
          72. unsigned char ucDigShow4;//第4位數(shù)碼管要顯示的內(nèi)容
          73. unsigned char ucDigShow3;//第3位數(shù)碼管要顯示的內(nèi)容
          74. unsigned char ucDigShow2;//第2位數(shù)碼管要顯示的內(nèi)容
          75. unsigned char ucDigShow1;//第1位數(shù)碼管要顯示的內(nèi)容
          76. unsigned char ucDigDot8;//數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志
          77. unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志
          78. unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志
          79. unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志
          80. unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志
          81. unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志
          82. unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志
          83. unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志
          84. unsigned char ucDigShowTemp=0; //臨時(shí)中間變量
          85. unsigned char ucDisplayDriveStep=1;//動(dòng)態(tài)掃描數(shù)碼管的步驟變量
          86. unsigned char ucWd1Update=1; //窗口1更新顯示標(biāo)志
          87. unsigned char ucWd2Update=0; //窗口2更新顯示標(biāo)志
          88. unsigned char ucWd3Update=0; //窗口3更新顯示標(biāo)志
          89. unsigned char ucWd4Update=0; //窗口4更新顯示標(biāo)志
          90. unsigned char ucWd=1;//本程序的核心變量,窗口顯示變量。類似于一級(jí)菜單的變量。代表顯示不同的窗口。
          91. unsigned intuiSetData1=0;//本程序中需要被設(shè)置的參數(shù)1
          92. unsigned intuiSetData2=0;//本程序中需要被設(shè)置的參數(shù)2
          93. unsigned intuiSetData3=0;//本程序中需要被設(shè)置的參數(shù)3
          94. unsigned intuiSetData4=0;//本程序中需要被設(shè)置的參數(shù)4
          95. unsigned char ucTemp1=0;//中間過渡變量
          96. unsigned char ucTemp2=0;//中間過渡變量
          97. unsigned char ucTemp3=0;//中間過渡變量
          98. unsigned char ucTemp4=0;//中間過渡變量
          99. //根據(jù)原理圖得出的共陰數(shù)碼管字模表
          100. code unsigned char dig_table[]=
          101. {
          102. 0x3f,//0 序號(hào)0
          103. 0x06,//1 序號(hào)1
          104. 0x5b,//2 序號(hào)2
          105. 0x4f,//3 序號(hào)3
          106. 0x66,//4 序號(hào)4
          107. 0x6d,//5 序號(hào)5
          108. 0x7d,//6 序號(hào)6
          109. 0x07,//7 序號(hào)7
          110. 0x7f,//8 序號(hào)8
          111. 0x6f,//9 序號(hào)9
          112. 0x00,//無 序號(hào)10
          113. 0x40,//- 序號(hào)11
          114. 0x73,//P 序號(hào)12
          115. };
          116. void main()
          117. {
          118. initial_myself();
          119. delay_long(100);
          120. initial_peripheral();
          121. while(1)
          122. {
          123. key_service(); //按鍵服務(wù)的應(yīng)用程序
          124. usart_service();//串口服務(wù)程序
          125. display_service(); //顯示的窗口菜單服務(wù)程序
          126. status_service();//狀態(tài)顯示的應(yīng)用程序
          127. }
          128. }
          129. void status_service(void)//狀態(tài)顯示的應(yīng)用程序
          130. {
          131. if(ucStatus!=0) //處于非待機(jī)的狀態(tài),Led閃爍
          132. {
          133. if(uiLedCnt
          134. {
          135. led_dr=1;//前半秒亮
          136. if(ucStatus==2)//處于發(fā)送數(shù)據(jù)出錯(cuò)的狀態(tài),則蜂鳴器間歇鳴叫報(bào)警
          137. {
          138. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          139. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          140. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          141. }
          142. }
          143. else if(uiLedCnt
          144. {
          145. led_dr=0; //前半秒滅
          146. }
          147. else
          148. {
          149. uiLedCnt=0; //延時(shí)計(jì)時(shí)器清零,讓Led燈處于閃爍的反復(fù)循環(huán)中
          150. }
          151. }
          152. else//處于待機(jī)狀態(tài),Led一直亮
          153. {
          154. led_dr=1;
          155. }
          156. }
          157. void usart_service(void)//串口服務(wù)程序,在main函數(shù)里
          158. {
          159. unsigned int i;
          160. if(uiSendCnt>=const_receive_time&&ucSendLock==1) //說明超過了一定的時(shí)間內(nèi),再也沒有新數(shù)據(jù)從串口來
          161. {
          162. ucSendLock=0; //處理一次就鎖起來,不用每次都進(jìn)來,除非有新接收的數(shù)據(jù)
          163. //下面的代碼進(jìn)入數(shù)據(jù)協(xié)議解析和數(shù)據(jù)處理的階段
          164. uiRcMoveIndex=0; //由于是判斷數(shù)據(jù)頭,所以下標(biāo)移動(dòng)變量從數(shù)組的0開始向最尾端移動(dòng)
          165. while(uiRcregTotal>=5&&uiRcMoveIndex<=(uiRcregTotal-5))
          166. {
          167. if(ucRcregBuf[uiRcMoveIndex+0]==0xeb&&ucRcregBuf[uiRcMoveIndex+1]==0x00&&ucRcregBuf[uiRcMoveIndex+2]==0x55)//數(shù)據(jù)頭eb 00 55的判斷
          168. {
          169. ucRcType=ucRcregBuf[uiRcMoveIndex+3]; //數(shù)據(jù)類型一個(gè)字節(jié)
          170. uiRcSize=ucRcregBuf[uiRcMoveIndex+4]; //數(shù)據(jù)長度兩個(gè)字節(jié)
          171. uiRcSize=uiRcSize<<8;
          172. uiRcSize=uiRcSize+ucRcregBuf[uiRcMoveIndex+5];
          173. ucRcCy=ucRcregBuf[uiRcMoveIndex+6+uiRcSize]; //記錄最后一個(gè)字節(jié)的校驗(yàn)
          174. ucRcregBuf[uiRcMoveIndex+6+uiRcSize]=0;//清零最后一個(gè)字節(jié)的累加和變量
          175. for(i=0;i<(3+1+2+uiRcSize);i++) //計(jì)算校驗(yàn)累加和
          176. {
          177. ucRcregBuf[uiRcMoveIndex+6+uiRcSize]=ucRcregBuf[uiRcMoveIndex+6+uiRcSize]+ucRcregBuf[uiRcMoveIndex+i];
          178. }
          179. if(ucRcCy==ucRcregBuf[uiRcMoveIndex+6+uiRcSize])//如果校驗(yàn)正確,則進(jìn)入以下數(shù)據(jù)處理
          180. {
          181. switch(ucRcType) //根據(jù)不同的數(shù)據(jù)類型來做不同的數(shù)據(jù)處理
          182. {
          183. case 0x01: //設(shè)置參數(shù)1
          184. ucStatus=1; //從設(shè)置參數(shù)1開始,表示當(dāng)前處于正在發(fā)送數(shù)據(jù)的狀態(tài)
          185. uiSetData1=ucRcregBuf[uiRcMoveIndex+6];//把兩個(gè)字節(jié)合并成一個(gè)int類型的數(shù)據(jù)
          186. uiSetData1=uiSetData1<<8;
          187. uiSetData1=uiSetData1+ucRcregBuf[uiRcMoveIndex+7];
          188. ucWd1Update=1; //窗口1更新顯示
          189. break;
          190. case 0x02: //設(shè)置參數(shù)2
          191. uiSetData2=ucRcregBuf[uiRcMoveIndex+6];//把兩個(gè)字節(jié)合并成一個(gè)int類型的數(shù)據(jù)
          192. uiSetData2=uiSetData2<<8;
          193. uiSetData2=uiSetData2+ucRcregBuf[uiRcMoveIndex+7];
          194. ucWd2Update=1; //窗口2更新顯示
          195. break;
          196. case 0x03: //設(shè)置參數(shù)3
          197. uiSetData3=ucRcregBuf[uiRcMoveIndex+6];//把兩個(gè)字節(jié)合并成一個(gè)int類型的數(shù)據(jù)
          198. uiSetData3=uiSetData3<<8;
          199. uiSetData3=uiSetData3+ucRcregBuf[uiRcMoveIndex+7];
          200. ucWd3Update=1; //窗口3更新顯示
          201. break;
          202. case 0x04: //設(shè)置參數(shù)4
          203. ucStatus=0; //從設(shè)置參數(shù)4結(jié)束發(fā)送數(shù)據(jù)的狀態(tài),表示發(fā)送數(shù)據(jù)的過程成功,切換回待機(jī)狀態(tài)
          204. uiSetData4=ucRcregBuf[uiRcMoveIndex+6];//把兩個(gè)字節(jié)合并成一個(gè)int類型的數(shù)據(jù)
          205. uiSetData4=uiSetData4<<8;
          206. uiSetData4=uiSetData4+ucRcregBuf[uiRcMoveIndex+7];
          207. ucWd4Update=1; //窗口4更新顯示
          208. break;
          209. }
          210. ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
          211. ucSendregBuf[1]=0x00;
          212. ucSendregBuf[2]=0x55;
          213. ucSendregBuf[3]=0xf5;//代表校驗(yàn)正確
          214. ucSendregBuf[4]=0x00;
          215. ucSendregBuf[5]=0x00;
          216. ucSendregBuf[6]=0x35;
          217. for(i=0;i<7;i++)//返回校驗(yàn)正確的應(yīng)答指令
          218. {
          219. eusart_send(ucSendregBuf[i]);//發(fā)送一串?dāng)?shù)據(jù)給上位機(jī)
          220. }
          221. }
          222. else
          223. {
          224. ucSendTimeOutLock=1; //原子鎖加鎖
          225. uiSendTimeOutCnt=0;//超時(shí)計(jì)時(shí)器計(jì)時(shí)清零
          226. ucSendTimeOutLock=0; //原子鎖解鎖
          227. ucSendregBuf[0]=0xeb; //把準(zhǔn)備發(fā)送的數(shù)據(jù)放入發(fā)送緩沖區(qū)
          228. ucSendregBuf[1]=0x00;
          229. ucSendregBuf[2]=0x55;
          230. ucSendregBuf[3]=0xfa; //代表校驗(yàn)錯(cuò)誤
          231. ucSendregBuf[4]=0x00;
          232. ucSendregBuf[5]=0x00;
          233. ucSendregBuf[6]=0x3a;
          234. for(i=0;i<7;i++)//返回校驗(yàn)錯(cuò)誤的應(yīng)答指令
          235. {
          236. eusart_send(ucSendregBuf[i]);//發(fā)送一串?dāng)?shù)據(jù)給上位機(jī)
          237. }
          238. }
          239. ucSendTimeOutLock=1; //原子鎖加鎖
          240. uiSendTimeOutCnt=0;//超時(shí)計(jì)時(shí)器計(jì)時(shí)清零
          241. ucSendTimeOutLock=0; //原子鎖解鎖
          242. break; //退出循環(huán)
          243. }
          244. uiRcMoveIndex++; //因?yàn)槭桥袛鄶?shù)據(jù)頭,游標(biāo)向著數(shù)組最尾端的方向移動(dòng)
          245. }
          246. uiRcregTotal=0;//清空緩沖的下標(biāo),方便下次重新從0下標(biāo)開始接受新數(shù)據(jù)
          247. }
          248. }
          249. void eusart_send(unsigned char ucSendData) //發(fā)送一個(gè)字節(jié),內(nèi)部自帶每個(gè)字節(jié)之間的delay延時(shí)
          250. {
          251. ES = 0; //關(guān)串口中斷
          252. TI = 0; //清零串口發(fā)送完成中斷請(qǐng)求標(biāo)志
          253. SBUF =ucSendData; //發(fā)送一個(gè)字節(jié)
          254. delay_short(400);//每個(gè)字節(jié)之間的延時(shí),這里非常關(guān)鍵,也是最容易出錯(cuò)的地方。延時(shí)的大小請(qǐng)根據(jù)實(shí)際項(xiàng)目來調(diào)整
          255. TI = 0; //清零串口發(fā)送完成中斷請(qǐng)求標(biāo)志
          256. ES = 1; //允許串口中斷
          257. }
          258. void display_service(void) //顯示的窗口菜單服務(wù)程序
          259. {
          260. switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級(jí)菜單的變量。代表顯示不同的窗口。
          261. {
          262. case 1: //顯示P--1窗口的數(shù)據(jù)
          263. if(ucWd1Update==1)//窗口1要全部更新顯示
          264. {
          265. ucWd1Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
          266. ucDigShow8=12;//第8位數(shù)碼管顯示P
          267. ucDigShow7=11;//第7位數(shù)碼管顯示-
          268. ucDigShow6=1; //第6位數(shù)碼管顯示1
          269. ucDigShow5=10;//第5位數(shù)碼管顯示無
          270. //先分解數(shù)據(jù)
          271. ucTemp4=uiSetData1/1000;
          272. ucTemp3=uiSetData1%1000/100;
          273. ucTemp2=uiSetData1%100/10;
          274. ucTemp1=uiSetData1%10;
          275. //再過渡需要顯示的數(shù)據(jù)到緩沖變量里,讓過渡的時(shí)間越短越好
          276. if(uiSetData1<1000)
          277. {
          278. ucDigShow4=10;//如果小于1000,千位顯示無
          279. }
          280. else
          281. {
          282. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
          283. }
          284. if(uiSetData1<100)
          285. {
          286. ucDigShow3=10;//如果小于100,百位顯示無
          287. }
          288. else
          289. {
          290. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
          291. }
          292. if(uiSetData1<10)
          293. {
          294. ucDigShow2=10;//如果小于10,十位顯示無
          295. }
          296. else
          297. {
          298. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
          299. }
          300. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
          301. }
          302. break;
          303. case 2://顯示P--2窗口的數(shù)據(jù)
          304. if(ucWd2Update==1)//窗口2要全部更新顯示
          305. {
          306. ucWd2Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
          307. ucDigShow8=12;//第8位數(shù)碼管顯示P
          308. ucDigShow7=11;//第7位數(shù)碼管顯示-
          309. ucDigShow6=2;//第6位數(shù)碼管顯示2
          310. ucDigShow5=10; //第5位數(shù)碼管顯示無
          311. ucTemp4=uiSetData2/1000; //分解數(shù)據(jù)
          312. ucTemp3=uiSetData2%1000/100;
          313. ucTemp2=uiSetData2%100/10;
          314. ucTemp1=uiSetData2%10;
          315. if(uiSetData2<1000)
          316. {
          317. ucDigShow4=10;//如果小于1000,千位顯示無
          318. }
          319. else
          320. {
          321. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
          322. }
          323. if(uiSetData2<100)
          324. {
          325. ucDigShow3=10;//如果小于100,百位顯示無
          326. }
          327. else
          328. {
          329. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
          330. }
          331. if(uiSetData2<10)
          332. {
          333. ucDigShow2=10;//如果小于10,十位顯示無
          334. }
          335. else
          336. {
          337. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
          338. }
          339. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
          340. }
          341. break;
          342. case 3://顯示P--3窗口的數(shù)據(jù)
          343. if(ucWd3Update==1)//窗口3要全部更新顯示
          344. {
          345. ucWd3Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
          346. ucDigShow8=12;//第8位數(shù)碼管顯示P
          347. ucDigShow7=11;//第7位數(shù)碼管顯示-
          348. ucDigShow6=3;//第6位數(shù)碼管顯示3
          349. ucDigShow5=10; //第5位數(shù)碼管顯示無
          350. ucTemp4=uiSetData3/1000; //分解數(shù)據(jù)
          351. ucTemp3=uiSetData3%1000/100;
          352. ucTemp2=uiSetData3%100/10;
          353. ucTemp1=uiSetData3%10;
          354. if(uiSetData3<1000)
          355. {
          356. ucDigShow4=10;//如果小于1000,千位顯示無
          357. }
          358. else
          359. {
          360. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
          361. }
          362. if(uiSetData3<100)
          363. {
          364. ucDigShow3=10;//如果小于100,百位顯示無
          365. }
          366. else
          367. {
          368. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
          369. }
          370. if(uiSetData3<10)
          371. {
          372. ucDigShow2=10;//如果小于10,十位顯示無
          373. }
          374. else
          375. {
          376. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
          377. }
          378. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
          379. }
          380. break;
          381. case 4://顯示P--4窗口的數(shù)據(jù)
          382. if(ucWd4Update==1)//窗口4要全部更新顯示
          383. {
          384. ucWd4Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
          385. ucDigShow8=12;//第8位數(shù)碼管顯示P
          386. ucDigShow7=11;//第7位數(shù)碼管顯示-
          387. ucDigShow6=4;//第6位數(shù)碼管顯示4
          388. ucDigShow5=10; //第5位數(shù)碼管顯示無
          389. ucTemp4=uiSetData4/1000; //分解數(shù)據(jù)
          390. ucTemp3=uiSetData4%1000/100;
          391. ucTemp2=uiSetData4%100/10;
          392. ucTemp1=uiSetData4%10;
          393. if(uiSetData4<1000)
          394. {
          395. ucDigShow4=10;//如果小于1000,千位顯示無
          396. }
          397. else
          398. {
          399. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
          400. }
          401. if(uiSetData4<100)
          402. {
          403. ucDigShow3=10;//如果小于100,百位顯示無
          404. }
          405. else
          406. {
          407. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
          408. }
          409. if(uiSetData4<10)
          410. {
          411. ucDigShow2=10;//如果小于10,十位顯示無
          412. }
          413. else
          414. {
          415. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
          416. }
          417. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
          418. }
          419. break;
          420. }
          421. }
          422. void key_scan(void)//按鍵掃描函數(shù) 放在定時(shí)中斷里
          423. {
          424. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
          425. {
          426. ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
          427. uiKeyTimeCnt1=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
          428. }
          429. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
          430. {
          431. uiKeyTimeCnt1++; //累加定時(shí)中斷次數(shù)
          432. if(uiKeyTimeCnt1>const_key_time1)
          433. {
          434. uiKeyTimeCnt1=0;
          435. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
          436. ucKeySec=1; //觸發(fā)1號(hào)鍵
          437. }
          438. }
          439. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
          440. {
          441. ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
          442. uiKeyTimeCnt2=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
          443. }
          444. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
          445. {
          446. uiKeyTimeCnt2++; //累加定時(shí)中斷次數(shù)
          447. if(uiKeyTimeCnt2>const_key_time2)
          448. {
          449. uiKeyTimeCnt2=0;
          450. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
          451. ucKeySec=2; //觸發(fā)2號(hào)鍵
          452. }
          453. }
          454. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
          455. {
          456. ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
          457. uiKeyTimeCnt3=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
          458. }
          459. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
          460. {
          461. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
          462. if(uiKeyTimeCnt3>const_key_time3)
          463. {
          464. uiKeyTimeCnt3=0;
          465. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
          466. ucKeySec=3; //觸發(fā)3號(hào)鍵
          467. }
          468. }
          469. if(key_sr4==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
          470. {
          471. ucKeyLock4=0; //按鍵自鎖標(biāo)志清零
          472. uiKeyTimeCnt4=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
          473. }
          474. else if(ucKeyLock4==0)//有按鍵按下,且是第一次被按下
          475. {
          476. uiKeyTimeCnt4++; //累加定時(shí)中斷次數(shù)
          477. if(uiKeyTimeCnt4>const_key_time4)
          478. {
          479. uiKeyTimeCnt4=0;
          480. ucKeyLock4=1;//自鎖按鍵置位,避免一直觸發(fā)
          481. ucKeySec=4; //觸發(fā)4號(hào)鍵
          482. }
          483. }
          484. }
          485. void key_service(void) //按鍵服務(wù)的應(yīng)用程序
          486. {
          487. switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
          488. {
          489. case 1:// 加按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
          490. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
          491. {
          492. case 1:
          493. uiSetData1++;
          494. if(uiSetData1>9999) //最大值是9999
          495. {
          496. uiSetData1=9999;
          497. }
          498. ucWd1Update=1;//窗口1更新顯示
          499. break;
          500. case 2:
          501. uiSetData2++;
          502. if(uiSetData2>9999) //最大值是9999
          503. {
          504. uiSetData2=9999;
          505. }
          506. ucWd2Update=1;//窗口2更新顯示
          507. break;
          508. case 3:
          509. uiSetData3++;
          510. if(uiSetData3>9999) //最大值是9999
          511. {
          512. uiSetData3=9999;
          513. }
          514. ucWd3Update=1;//窗口3更新顯示
          515. break;
          516. case 4:
          517. uiSetData4++;
          518. if(uiSetData4>9999) //最大值是9999
          519. {
          520. uiSetData4=9999;
          521. }
          522. ucWd4Update=1;//窗口4更新顯示
          523. break;
          524. }
          525. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          526. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          527. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          528. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
          529. break;
          530. case 2:// 減按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
          531. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
          532. {
          533. case 1:
          534. uiSetData1--;
          535. if(uiSetData1>9999)
          536. {
          537. uiSetData1=0;//最小值是0
          538. }
          539. ucWd1Update=1;//窗口1更新顯示
          540. break;
          541. case 2:
          542. uiSetData2--;
          543. if(uiSetData2>9999)
          544. {
          545. uiSetData2=0;//最小值是0
          546. }
          547. ucWd2Update=1;//窗口2更新顯示
          548. break;
          549. case 3:
          550. uiSetData3--;
          551. if(uiSetData3>9999)
          552. {
          553. uiSetData3=0;//最小值是0
          554. }
          555. ucWd3Update=1;//窗口3更新顯示
          556. break;
          557. case 4:
          558. uiSetData4--;
          559. if(uiSetData4>9999)
          560. {
          561. uiSetData4=0;//最小值是0
          562. }
          563. ucWd4Update=1;//窗口4更新顯示
          564. break;
          565. }
          566. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          567. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          568. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          569. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
          570. break;
          571. case 3:// 切換窗口按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
          572. ucWd++;//切換窗口
          573. if(ucWd>4)
          574. {
          575. ucWd=1;
          576. }
          577. switch(ucWd)//在不同的窗口下,在不同的窗口下,更新顯示不同的窗口
          578. {
          579. case 1:
          580. ucWd1Update=1;//窗口1更新顯示
          581. break;
          582. case 2:
          583. ucWd2Update=1;//窗口2更新顯示
          584. break;
          585. case 3:
          586. ucWd3Update=1;//窗口3更新顯示
          587. break;
          588. case 4:
          589. ucWd4Update=1;//窗口4更新顯示
          590. break;
          591. }
          592. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          593. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          594. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          595. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
          596. break;
          597. case 4:// 復(fù)位按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
          598. switch(ucStatus)//在不同的狀態(tài)下,進(jìn)行不同的操作
          599. {
          600. case 0://處于待機(jī)狀態(tài)
          601. break;
          602. case 1://處于正在通訊的過程
          603. break;
          604. case 2: //發(fā)送數(shù)據(jù)出錯(cuò),比如中間超時(shí)沒有接收到數(shù)據(jù)
          605. ucStatus=0; //切換回待機(jī)的狀態(tài)
          606. break;
          607. }
          608. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          609. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          610. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          611. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
          612. break;
          613. }
          614. }
          615. void display_drive(void)
          616. {
          617. //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
          618. switch(ucDisplayDriveStep)
          619. {
          620. case 1://顯示第1位
          621. ucDigShowTemp=dig_table[ucDigShow1];
          622. if(ucDigDot1==1)
          623. {
          624. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          625. }
          626. dig_hc595_drive(ucDigShowTemp,0xfe);
          627. break;
          628. case 2://顯示第2位
          629. ucDigShowTemp=dig_table[ucDigShow2];
          630. if(ucDigDot2==1)
          631. {
          632. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          633. }
          634. dig_hc595_drive(ucDigShowTemp,0xfd);
          635. break;
          636. case 3://顯示第3位
          637. ucDigShowTemp=dig_table[ucDigShow3];
          638. if(ucDigDot3==1)
          639. {
          640. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          641. }
          642. dig_hc595_drive(ucDigShowTemp,0xfb);
          643. break;
          644. case 4://顯示第4位
          645. ucDigShowTemp=dig_table[ucDigShow4];
          646. if(ucDigDot4==1)
          647. {
          648. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          649. }
          650. dig_hc595_drive(ucDigShowTemp,0xf7);
          651. break;
          652. case 5://顯示第5位
          653. ucDigShowTemp=dig_table[ucDigShow5];
          654. if(ucDigDot5==1)
          655. {
          656. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          657. }
          658. dig_hc595_drive(ucDigShowTemp,0xef);
          659. break;
          660. case 6://顯示第6位
          661. ucDigShowTemp=dig_table[ucDigShow6];
          662. if(ucDigDot6==1)
          663. {
          664. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          665. }
          666. dig_hc595_drive(ucDigShowTemp,0xdf);
          667. break;
          668. case 7://顯示第7位
          669. ucDigShowTemp=dig_table[ucDigShow7];
          670. if(ucDigDot7==1)
          671. {
          672. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          673. }
          674. dig_hc595_drive(ucDigShowTemp,0xbf);
          675. break;
          676. case 8://顯示第8位
          677. ucDigShowTemp=dig_table[ucDigShow8];
          678. if(ucDigDot8==1)
          679. {
          680. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
          681. }
          682. dig_hc595_drive(ucDigShowTemp,0x7f);
          683. break;
          684. }
          685. ucDisplayDriveStep++;
          686. if(ucDisplayDriveStep>8)//掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開始掃描
          687. {
          688. ucDisplayDriveStep=1;
          689. }
          690. }
          691. //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)
          692. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
          693. {
          694. unsigned char i;
          695. unsigned char ucTempData;
          696. dig_hc595_sh_dr=0;
          697. dig_hc595_st_dr=0;
          698. ucTempData=ucDigStatusTemp16_09;//先送高8位
          699. for(i=0;i<8;i++)
          700. {
          701. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
          702. else dig_hc595_ds_dr=0;
          703. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          704. delay_short(1);
          705. dig_hc595_sh_dr=1;
          706. delay_short(1);
          707. ucTempData=ucTempData<<1;
          708. }
          709. ucTempData=ucDigStatusTemp08_01;//再先送低8位
          710. for(i=0;i<8;i++)
          711. {
          712. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
          713. else dig_hc595_ds_dr=0;
          714. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          715. delay_short(1);
          716. dig_hc595_sh_dr=1;
          717. delay_short(1);
          718. ucTempData=ucTempData<<1;
          719. }
          720. dig_hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          721. delay_short(1);
          722. dig_hc595_st_dr=1;
          723. delay_short(1);
          724. dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
          725. dig_hc595_st_dr=0;
          726. dig_hc595_ds_dr=0;
          727. }
          728. //LED燈的74HC595驅(qū)動(dòng)函數(shù)
          729. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
          730. {
          731. unsigned char i;
          732. unsigned char ucTempData;
          733. hc595_sh_dr=0;
          734. hc595_st_dr=0;
          735. ucTempData=ucLedStatusTemp16_09;//先送高8位
          736. for(i=0;i<8;i++)
          737. {
          738. if(ucTempData>=0x80)hc595_ds_dr=1;
          739. else hc595_ds_dr=0;
          740. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          741. delay_short(1);
          742. hc595_sh_dr=1;
          743. delay_short(1);
          744. ucTempData=ucTempData<<1;
          745. }
          746. ucTempData=ucLedStatusTemp08_01;//再先送低8位
          747. for(i=0;i<8;i++)
          748. {
          749. if(ucTempData>=0x80)hc595_ds_dr=1;
          750. else hc595_ds_dr=0;
          751. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          752. delay_short(1);
          753. hc595_sh_dr=1;
          754. delay_short(1);
          755. ucTempData=ucTempData<<1;
          756. }
          757. hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          758. delay_short(1);
          759. hc595_st_dr=1;
          760. delay_short(1);
          761. hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
          762. hc595_st_dr=0;
          763. hc595_ds_dr=0;
          764. }
          765. void usart_receive(void) interrupt 4 //串口接收數(shù)據(jù)中斷
          766. {
          767. if(RI==1)
          768. {
          769. RI = 0;
          770. ++uiRcregTotal;
          771. if(uiRcregTotal>const_rc_size)//超過緩沖區(qū)
          772. {
          773. uiRcregTotal=const_rc_size;
          774. }
          775. ucRcregBuf[uiRcregTotal-1]=SBUF; //將串口接收到的數(shù)據(jù)緩存到接收緩沖區(qū)里
          776. if(ucSendCntLock==0)//原子鎖判斷
          777. {
          778. ucSendCntLock=1; //加鎖
          779. uiSendCnt=0;//及時(shí)喂狗,雖然在定時(shí)中斷那邊此變量會(huì)不斷累加,但是只要串口的數(shù)據(jù)還沒發(fā)送完畢,那么它永遠(yuǎn)也長不大,因?yàn)槊總€(gè)串口接收中斷它都被清零。
          780. ucSendCntLock=0; //解鎖
          781. }
          782. }
          783. else//我在其它單片機(jī)上都不用else這段代碼的,可能在51單片機(jī)上多增加" TI = 0;"穩(wěn)定性會(huì)更好吧。
          784. {
          785. TI = 0;//如果不是串口接收中斷,那么必然是串口發(fā)送中斷,及時(shí)清除發(fā)送中斷的標(biāo)志,否則一直發(fā)送中斷
          786. }
          787. }
          788. void T0_time(void) interrupt 1 //定時(shí)中斷
          789. {
          790. TF0=0;//清除中斷標(biāo)志
          791. TR0=0; //關(guān)中斷
          792. /* 注釋一:
          793. * 此處多增加一個(gè)原子鎖,作為中斷與主函數(shù)共享數(shù)據(jù)的保護(hù),實(shí)際上是借鑒了"紅金龍吸味"關(guān)于原子鎖的建議.
          794. */
          795. if(ucSendCntLock==0)//原子鎖判斷
          796. {
          797. ucSendCntLock=1; //加鎖
          798. if(uiSendCnt
          799. {
          800. uiSendCnt++; //表面上這個(gè)數(shù)據(jù)不斷累加,但是在串口中斷里,每接收一個(gè)字節(jié)它都會(huì)被清零,除非這個(gè)中間沒有串口數(shù)據(jù)過來
          801. ucSendLock=1; //開自鎖標(biāo)志
          802. }
          803. ucSendCntLock=0; //解鎖
          804. }
          805. if(ucVoiceLock==0) //原子鎖判斷
          806. {
          807. if(uiVoiceCnt!=0)
          808. {
          809. uiVoiceCnt--; //每次進(jìn)入定時(shí)中斷都自減1,直到等于零為止。才停止鳴叫
          810. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
          811. }
          812. else
          813. {
          814. ; //此處多加一個(gè)空指令,想維持跟if括號(hào)語句的數(shù)量對(duì)稱,都是兩條指令。不加也可以。
          815. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
          816. }
          817. }
          818. if(ucStatus!=0) //處于非待機(jī)的狀態(tài),Led閃爍
          819. {
          820. uiLedCnt++; //Led閃爍計(jì)時(shí)器不斷累加
          821. }
          822. if(ucStatus==1) //處于正在通訊的狀態(tài),
          823. {
          824. if(ucSendTimeOutLock==0)//原子鎖判斷
          825. {
          826. uiSendTimeOutCnt++; //超時(shí)計(jì)時(shí)器累加
          827. if(uiSendTimeOutCnt>const_send_time_out)//超時(shí)出錯(cuò)
          828. {
          829. uiSendTimeOutCnt=0;
          830. ucStatus=2;//切換到出錯(cuò)報(bào)警狀態(tài)
          831. }
          832. }
          833. }
          834. key_scan(); //按鍵掃描函數(shù)
          835. display_drive();//數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
          836. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
          837. TL0=0x0b;
          838. TR0=1;//開中斷
          839. }
          840. void delay_short(unsigned int uiDelayShort)
          841. {
          842. unsigned int i;
          843. for(i=0;i
          844. {
          845. ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語句
          846. }
          847. }
          848. void delay_long(unsigned int uiDelayLong)
          849. {
          850. unsigned int i;
          851. unsigned int j;
          852. for(i=0;i
          853. {
          854. for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
          855. {
          856. ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語句
          857. }
          858. }
          859. }
          860. void initial_myself(void)//第一區(qū) 初始化單片機(jī)
          861. {
          862. /* 注釋二:
          863. * 矩陣鍵盤也可以做獨(dú)立按鍵,前提是把某一根公共輸出線輸出低電平,
          864. * 模擬獨(dú)立按鍵的觸發(fā)地,本程序中,把key_gnd_dr輸出低電平。
          865. * 朱兆祺51學(xué)習(xí)板的S1就是本程序中用到的一個(gè)獨(dú)立按鍵。
          866. */
          867. key_gnd_dr=0; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
          868. led_dr=1;//點(diǎn)亮獨(dú)立LED燈
          869. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。
          870. hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈
          871. TMOD=0x01;//設(shè)置定時(shí)器0為工作方式1
          872. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
          873. TL0=0x0b;
          874. //配置串口
          875. SCON=0x50;
          876. TMOD=0X21;
          877. /* 注釋三:
          878. * 為了保證串口中斷接收的數(shù)據(jù)不丟失,必須設(shè)置IP = 0x10,相當(dāng)于把串口中斷設(shè)置為最高優(yōu)先級(jí),
          879. * 這個(gè)時(shí)候,串口中斷可以打斷任何其他的中斷服務(wù)函數(shù)實(shí)現(xiàn)嵌套,
          880. */
          881. IP =0x10;//把串口中斷設(shè)置為最高優(yōu)先級(jí),必須的。
          882. TH1=TL1=-(11059200L/12/32/9600);//串口波特率為9600。
          883. TR1=1;
          884. }
          885. void initial_peripheral(void) //第二區(qū) 初始化外圍
          886. {
          887. ucDigDot8=0; //小數(shù)點(diǎn)全部不顯示
          888. ucDigDot7=0;
          889. ucDigDot6=0;
          890. ucDigDot5=0;
          891. ucDigDot4=0;
          892. ucDigDot3=0;
          893. ucDigDot2=0;
          894. ucDigDot1=0;
          895. EA=1; //開總中斷
          896. ES=1; //允許串口中斷
          897. ET0=1; //允許定時(shí)中斷
          898. TR0=1; //啟動(dòng)定時(shí)中斷
          899. }


          總結(jié)陳詞:
          這節(jié)詳細(xì)講了從機(jī)收發(fā)端的程序框架,而主機(jī)端的程序則用電腦的串口助手來模擬。實(shí)際上,主機(jī)端的程序也有很多內(nèi)容,它包括依次發(fā)送每一串?dāng)?shù)據(jù),根據(jù)返回的應(yīng)答來決定是否需要重發(fā)數(shù)據(jù),重發(fā)三次如果沒反應(yīng)則進(jìn)行報(bào)錯(cuò),以及超時(shí)沒接收到數(shù)據(jù)等等內(nèi)容。主機(jī)收發(fā)端的程序框架是什么樣的?欲知詳情,請(qǐng)聽下回分解-----主機(jī)的串口收發(fā)綜合程序框架


          關(guān)鍵詞: 從機(jī)串口收程序框

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();