熟女俱乐部五十路二区av,又爽又黄禁片视频1000免费,国产卡一卡二卡三无线乱码新区,中文无码一区二区不卡αv,中文在线中文a

新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 第43節(jié):通過串口用計數延時方式發(fā)送一串數據

第43節(jié):通過串口用計數延時方式發(fā)送一串數據

作者: 時間:2016-11-22 來源:網絡 收藏
開場白:
上一節(jié)講了通過串口用delay延時方式發(fā)送一串數據,這種方式要求發(fā)送一串數據的時候一氣呵成,期間不能執(zhí)行其它任務,由于delay(400)這個時間還不算很長,所以可以應用在很多簡單任務的系統(tǒng)中。但是在某些任務量很多的系統(tǒng)中,實時運行的主任務不允許被長時間和經常性地中斷,這個時候就需要用計數延時來替代delay延時。本節(jié)要教會大家兩個知識點:
第一個:用計數延時方式發(fā)送一串數據的程序框架。
第二個:環(huán)形消息隊列的程序框架。

具體內容,請看源代碼講解。

(1)硬件平臺:
基于朱兆祺51單片機學習板。

(2)實現功能:
波特率是:9600.
用朱兆祺51單片機學習板中的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)源代碼講解如下:
  1. #include "REG52.H"
  2. #define const_send_time100//累計主循環(huán)次數的計數延時 請根據項目實際情況來調整此數據大小
  3. #define const_send_size10//串口發(fā)送數據的緩沖區(qū)數組大小
  4. #define const_Message_size10//環(huán)形消息隊列的緩沖區(qū)數組大小
  5. #define const_key_time120 //按鍵去抖動延時的時間
  6. #define const_key_time220 //按鍵去抖動延時的時間
  7. #define const_key_time320 //按鍵去抖動延時的時間
  8. #define const_key_time420 //按鍵去抖動延時的時間
  9. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時間
  10. void initial_myself(void);
  11. void initial_peripheral(void);
  12. //void delay_short(unsigned int uiDelayshort);
  13. void delay_long(unsigned int uiDelaylong);
  14. void eusart_send(unsigned char ucSendData);//發(fā)送一個字節(jié),內部沒有每個字節(jié)之間的延時
  15. void send_service(void);//利用累計主循環(huán)次數的計數延時方式來發(fā)送一串數據
  16. void T0_time(void);//定時中斷函數
  17. void usart_receive(void); //串口接收中斷函數
  18. void key_service(void); //按鍵服務的應用程序
  19. void key_scan(void); //按鍵掃描函數 放在定時中斷里
  20. void insert_message(unsigned char ucMessageTemp);//插入新的消息到環(huán)形消息隊列里
  21. unsigned char get_message(void);//從環(huán)形消息隊列里提取消息
  22. sbit led_dr=P3^5;//Led的驅動IO口
  23. sbit beep_dr=P2^7; //蜂鳴器的驅動IO口
  24. sbit key_sr1=P0^0; //對應朱兆祺學習板的S1鍵
  25. sbit key_sr2=P0^1; //對應朱兆祺學習板的S5鍵
  26. sbit key_sr3=P0^2; //對應朱兆祺學習板的S9鍵
  27. sbit key_sr4=P0^3; //對應朱兆祺學習板的S13鍵
  28. sbit key_gnd_dr=P0^4; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
  29. unsigned char ucSendregBuf[const_send_size]; //串口發(fā)送數據的緩沖區(qū)數組
  30. unsigned char ucMessageBuf[const_Message_size]; //環(huán)形消息隊列的緩沖區(qū)數據
  31. unsigned intuiMessageCurrent=0;//環(huán)形消息隊列的取數據當前位置
  32. unsigned intuiMessageInsert=0;//環(huán)形消息隊列的插入新消息時候的位置
  33. unsigned intuiMessageCnt=0;//統(tǒng)計環(huán)形消息隊列的消息數量等于0時表示消息隊列里沒有消息
  34. unsigned char ucMessage=0; //當前獲取到的消息
  35. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時間計數器
  36. unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
  37. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
  38. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動延時計數器
  39. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標志
  40. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動延時計數器
  41. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標志
  42. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動延時計數器
  43. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標志
  44. unsigned intuiKeyTimeCnt4=0; //按鍵去抖動延時計數器
  45. unsigned char ucKeyLock4=0; //按鍵觸發(fā)后自鎖的變量標志
  46. unsigned char ucSendStep=0;//發(fā)送一串數據的運行步驟
  47. unsigned intuiSendTimeCnt=0; //累計主循環(huán)次數的計數延時器
  48. unsigned int uiSendCnt=0; //發(fā)送數據時的中間變量
  49. void main()
  50. {
  51. initial_myself();
  52. delay_long(100);
  53. initial_peripheral();
  54. while(1)
  55. {
  56. key_service(); //按鍵服務的應用程序
  57. send_service();//利用累計主循環(huán)次數的計數延時方式來發(fā)送一串數據
  58. }
  59. }
  60. /* 注釋一:
  61. * 通過判斷數組下標是否超范圍的條件,把一個數組的首尾連接起來,就像一個環(huán)形,
  62. * 因此命名為環(huán)形消息隊列。環(huán)形消息隊列有插入消息,獲取消息兩個核心函數,以及一個
  63. * 統(tǒng)計消息總數的uiMessageCnt核心變量,通過此變量,我們可以知道消息隊列里面是否有消息需要處理.
  64. * 我在做項目中很少用消息隊列的,印象中我只在兩個項目中用過消息隊列這種方法。大部分的單片機
  65. * 項目其實直接用一兩個中間變量就可以起到傳遞消息的作用,就能滿足系統(tǒng)的要求。以下是各變量的含義:
  66. * #define const_Message_size10//環(huán)形消息隊列的緩沖區(qū)數組大小
  67. * unsigned char ucMessageBuf[const_Message_size]; //環(huán)形消息隊列的緩沖區(qū)數據
  68. * unsigned intuiMessageCurrent=0;//環(huán)形消息隊列的取數據當前位置
  69. * unsigned intuiMessageInsert=0;//環(huán)形消息隊列的插入新消息時候的位置
  70. * unsigned intuiMessageCnt=0;//統(tǒng)計環(huán)形消息隊列的消息數量等于0時表示消息隊列里沒有消息
  71. */
  72. void insert_message(unsigned char ucMessageTemp)//插入新的消息到環(huán)形消息隊列里
  73. {
  74. if(uiMessageCnt
  75. {
  76. ucMessageBuf[uiMessageInsert]=ucMessageTemp;
  77. uiMessageInsert++;//插入新消息時候的位置
  78. if(uiMessageInsert>=const_Message_size) //到了緩沖區(qū)末尾,則從緩沖區(qū)的開頭重新開始。數組的首尾連接,看起來就像環(huán)形
  79. {
  80. uiMessageInsert=0;
  81. }
  82. uiMessageCnt++; //消息數量累加等于0時表示消息隊列里沒有消息
  83. }
  84. }
  85. unsigned char get_message(void)//從環(huán)形消息隊列里提取消息
  86. {
  87. unsigned char ucMessageTemp=0;//返回的消息中間變量,默認為0
  88. if(uiMessageCnt>0)//只有消息數量大于0時才可以提取消息
  89. {
  90. ucMessageTemp=ucMessageBuf[uiMessageCurrent];
  91. uiMessageCurrent++;//環(huán)形消息隊列的取數據當前位置
  92. if(uiMessageCurrent>=const_Message_size) //到了緩沖區(qū)末尾,則從緩沖區(qū)的開頭重新開始。數組的首尾連接,看起來就像環(huán)形
  93. {
  94. uiMessageCurrent=0;
  95. }
  96. uiMessageCnt--; //每提取一次,消息數量就減一等于0時表示消息隊列里沒有消息
  97. }
  98. return ucMessageTemp;
  99. }
  100. void send_service(void)//利用累計主循環(huán)次數的計數延時方式來發(fā)送一串數據
  101. {
  102. switch(ucSendStep)//發(fā)送一串數據的運行步驟
  103. {
  104. case 0: //從環(huán)形消息隊列里提取消息
  105. if(uiMessageCnt>0)//說明有消息需要處理
  106. {
  107. ucMessage=get_message();
  108. switch(ucMessage) //消息處理
  109. {
  110. case 1:
  111. ucSendregBuf[0]=0xeb; //把準備發(fā)送的數據放入發(fā)送緩沖區(qū)
  112. ucSendregBuf[1]=0x00;
  113. ucSendregBuf[2]=0x55;
  114. ucSendregBuf[3]=0x01; //01代表1號鍵
  115. ucSendregBuf[4]=0x00;
  116. ucSendregBuf[5]=0x00;
  117. ucSendregBuf[6]=0x00;
  118. ucSendregBuf[7]=0x00;
  119. ucSendregBuf[8]=0x41;
  120. uiSendCnt=0; //發(fā)送數據的中間變量清零
  121. uiSendTimeCnt=0; //累計主循環(huán)次數的計數延時器清零
  122. ucSendStep=1; //切換到下一步發(fā)送一串數據
  123. break;
  124. case 2:
  125. ucSendregBuf[0]=0xeb; //把準備發(fā)送的數據放入發(fā)送緩沖區(qū)
  126. ucSendregBuf[1]=0x00;
  127. ucSendregBuf[2]=0x55;
  128. ucSendregBuf[3]=0x02; //02代表2號鍵
  129. ucSendregBuf[4]=0x00;
  130. ucSendregBuf[5]=0x00;
  131. ucSendregBuf[6]=0x00;
  132. ucSendregBuf[7]=0x00;
  133. ucSendregBuf[8]=0x42;
  134. uiSendCnt=0; //發(fā)送數據的中間變量清零
  135. uiSendTimeCnt=0; //累計主循環(huán)次數的計數延時器清零
  136. ucSendStep=1; //切換到下一步發(fā)送一串數據
  137. break;
  138. case 3:
  139. ucSendregBuf[0]=0xeb; //把準備發(fā)送的數據放入發(fā)送緩沖區(qū)
  140. ucSendregBuf[1]=0x00;
  141. ucSendregBuf[2]=0x55;
  142. ucSendregBuf[3]=0x03; //03代表3號鍵
  143. ucSendregBuf[4]=0x00;
  144. ucSendregBuf[5]=0x00;
  145. ucSendregBuf[6]=0x00;
  146. ucSendregBuf[7]=0x00;
  147. ucSendregBuf[8]=0x43;
  148. uiSendCnt=0; //發(fā)送數據的中間變量清零
  149. uiSendTimeCnt=0; //累計主循環(huán)次數的計數延時器清零
  150. ucSendStep=1; //切換到下一步發(fā)送一串數據
  151. break;
  152. case 4:
  153. ucSendregBuf[0]=0xeb; //把準備發(fā)送的數據放入發(fā)送緩沖區(qū)
  154. ucSendregBuf[1]=0x00;
  155. ucSendregBuf[2]=0x55;
  156. ucSendregBuf[3]=0x04; //04代表4號鍵
  157. ucSendregBuf[4]=0x00;
  158. ucSendregBuf[5]=0x00;
  159. ucSendregBuf[6]=0x00;
  160. ucSendregBuf[7]=0x00;
  161. ucSendregBuf[8]=0x44;
  162. uiSendCnt=0; //發(fā)送數據的中間變量清零
  163. uiSendTimeCnt=0; //累計主循環(huán)次數的計數延時器清零
  164. ucSendStep=1; //切換到下一步發(fā)送一串數據
  165. break;
  166. default://如果沒有符合要求的消息,則不處理
  167. ucSendStep=0; //維持現狀,不切換
  168. break;
  169. }
  170. }
  171. break;
  172. case 1://利用累加主循環(huán)次數的計數延時方式來發(fā)送一串數據
  173. /* 注釋二:
  174. * 這里的計數延時為什么不用累計定時中斷次數的延時,而用累計主循環(huán)次數的計數延時?
  175. * 因為本程序定時器中斷一次需要500個指令時間,時間分辨率太低,不方便微調時間。因此我
  176. * 就用累計主循環(huán)次數的計數延時方式,在做項目的時候,各位讀者應該根據系統(tǒng)的實際情況
  177. * 來調整const_send_time的大小。
  178. */
  179. uiSendTimeCnt++;//累計主循環(huán)次數的計數延時,為每個字節(jié)之間增加延時,
  180. if(uiSendTimeCnt>const_send_time)//請根據實際系統(tǒng)的情況,調整const_send_time的大小
  181. {
  182. uiSendTimeCnt=0;
  183. eusart_send(ucSendregBuf[uiSendCnt]);//發(fā)送一串數據給上位機
  184. uiSendCnt++;
  185. if(uiSendCnt>=9) //說明數據已經發(fā)送完畢
  186. {
  187. uiSendCnt=0;
  188. ucSendStep=0; //返回到上一步,處理其它未處理的消息
  189. }
  190. }
  191. break;
  192. }
  193. }
  194. void eusart_send(unsigned char ucSendData)
  195. {
  196. ES = 0; //關串口中斷
  197. TI = 0; //清零串口發(fā)送完成中斷請求標志
  198. SBUF =ucSendData; //發(fā)送一個字節(jié)
  199. /* 注釋三:
  200. * 根據我個人的經驗,在發(fā)送一串數據中,每個字節(jié)之間必須添加一個延時,用來等待串口發(fā)送完成。
  201. * 當然,也有一些朋友可能不增加延時,直接靠單片機自帶的發(fā)送完成標志位來判斷,但是我以前
  202. * 在做項目中,感覺單單靠發(fā)送完成標志位來判斷還是容易出錯(當然也有可能是我自身程序的問題),
  203. * 所以后來在大部分的項目中我就干脆靠延時來等待它發(fā)送完成。我在51,PIC單片機中都是這么做的。
  204. * 但是,憑我的經驗,在stm32單片機中,可以不增加延時,直接靠單片機自帶的標志位來判斷就很可靠。
  205. */
  206. //delay_short(400);//因為外部在每個發(fā)送字節(jié)之間用了累計主循環(huán)次數的計數延時,因此不要此行的delay延時
  207. TI = 0; //清零串口發(fā)送完成中斷請求標志
  208. ES = 1; //允許串口中斷
  209. }
  210. void key_scan(void)//按鍵掃描函數 放在定時中斷里
  211. {
  212. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
  213. {
  214. ucKeyLock1=0; //按鍵自鎖標志清零
  215. uiKeyTimeCnt1=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
  216. }
  217. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
  218. {
  219. uiKeyTimeCnt1++; //累加定時中斷次數
  220. if(uiKeyTimeCnt1>const_key_time1)
  221. {
  222. uiKeyTimeCnt1=0;
  223. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
  224. ucKeySec=1; //觸發(fā)1號鍵
  225. }
  226. }
  227. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
  228. {
  229. ucKeyLock2=0; //按鍵自鎖標志清零
  230. uiKeyTimeCnt2=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
  231. }
  232. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
  233. {
  234. uiKeyTimeCnt2++; //累加定時中斷次數
  235. if(uiKeyTimeCnt2>const_key_time2)
  236. {
  237. uiKeyTimeCnt2=0;
  238. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
  239. ucKeySec=2; //觸發(fā)2號鍵
  240. }
  241. }
  242. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
  243. {
  244. ucKeyLock3=0; //按鍵自鎖標志清零
  245. uiKeyTimeCnt3=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
  246. }
  247. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
  248. {
  249. uiKeyTimeCnt3++; //累加定時中斷次數
  250. if(uiKeyTimeCnt3>const_key_time3)
  251. {
  252. uiKeyTimeCnt3=0;
  253. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
  254. ucKeySec=3; //觸發(fā)3號鍵
  255. }
  256. }
  257. if(key_sr4==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
  258. {
  259. ucKeyLock4=0; //按鍵自鎖標志清零
  260. uiKeyTimeCnt4=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
  261. }
  262. else if(ucKeyLock4==0)//有按鍵按下,且是第一次被按下
  263. {
  264. uiKeyTimeCnt4++; //累加定時中斷次數
  265. if(uiKeyTimeCnt4>const_key_time4)
  266. {
  267. uiKeyTimeCnt4=0;
  268. ucKeyLock4=1;//自鎖按鍵置位,避免一直觸發(fā)
  269. ucKeySec=4; //觸發(fā)4號鍵
  270. }
  271. }
  272. }
  273. void key_service(void) //第三區(qū) 按鍵服務的應用程序
  274. {
  275. switch(ucKeySec) //按鍵服務狀態(tài)切換
  276. {
  277. case 1:// 1號鍵 對應朱兆祺學習板的S1鍵
  278. insert_message(0x01);//把新消息插入到環(huán)形消息隊列里等待處理
  279. ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數的共享數據
  280. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
  281. ucVoiceLock=0; //原子鎖解鎖
  282. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
  283. break;
  284. case 2:// 2號鍵 對應朱兆祺學習板的S5鍵
  285. insert_message(0x02);//把新消息插入到環(huán)形消息隊列里等待處理
  286. ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數的共享數據
  287. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
  288. ucVoiceLock=0; //原子鎖解鎖
  289. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
  290. break;
  291. case 3:// 3號鍵 對應朱兆祺學習板的S9鍵
  292. insert_message(0x03);//把新消息插入到環(huán)形消息隊列里等待處理
  293. ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數的共享數據
  294. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
  295. ucVoiceLock=0; //原子鎖解鎖
  296. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
  297. break;
  298. case 4:// 4號鍵 對應朱兆祺學習板的S13鍵
  299. insert_message(0x04);//把新消息插入到環(huán)形消息隊列里等待處理
  300. ucVoiceLock=1;//原子鎖加鎖,保護中斷與主函數的共享數據
  301. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
  302. ucVoiceLock=0; //原子鎖解鎖
  303. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
  304. break;
  305. }
  306. }
  307. void T0_time(void) interrupt 1 //定時中斷
  308. {
  309. TF0=0;//清除中斷標志
  310. TR0=0; //關中斷
  311. /* 注釋四:
  312. * 此處多增加一個原子鎖,作為中斷與主函數共享數據的保護,實際上是借鑒了"紅金龍吸味"關于原子鎖的建議.
  313. */
  314. if(ucVoiceLock==0) //原子鎖判斷
  315. {
  316. if(uiVoiceCnt!=0)
  317. {
  318. uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
  319. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
  320. }
  321. else
  322. {
  323. ; //此處多加一個空指令,想維持跟if括號語句的數量對稱,都是兩條指令。不加也可以。
  324. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
  325. }
  326. }
  327. key_scan();//按鍵掃描函數
  328. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
  329. TL0=0x0b;
  330. TR0=1;//開中斷
  331. }
  332. void usart_receive(void) interrupt 4 //串口中斷
  333. {
  334. if(RI==1)
  335. {
  336. RI = 0; //接收中斷,及時把接收中斷標志位清零
  337. }
  338. else
  339. {
  340. TI = 0; //發(fā)送中斷,及時把發(fā)送中斷標志位清零
  341. }
  342. }
  343. //void delay_short(unsigned int uiDelayShort)
  344. //{
  345. // unsigned int i;
  346. // for(i=0;i
  347. // {
  348. // ; //一個分號相當于執(zhí)行一條空語句
  349. // }
  350. //}
  351. void delay_long(unsigned int uiDelayLong)
  352. {
  353. unsigned int i;
  354. unsigned int j;
  355. for(i=0;i
  356. {
  357. for(j=0;j<500;j++)//內嵌循環(huán)的空指令數量
  358. {
  359. ; //一個分號相當于執(zhí)行一條空語句
  360. }
  361. }
  362. }
  363. void initial_myself(void)//第一區(qū) 初始化單片機
  364. {
  365. /* 注釋五:
  366. * 矩陣鍵盤也可以做獨立按鍵,前提是把某一根公共輸出線輸出低電平,
  367. * 模擬獨立按鍵的觸發(fā)地,本程序中,把key_gnd_dr輸出低電平。
  368. * 朱兆祺51學習板的S1和S5兩個按鍵就是本程序中用到的兩個獨立按鍵。
  369. */
  370. key_gnd_dr=0; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
  371. led_dr=0; //關Led燈
  372. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
  373. //配置定時器
  374. TMOD=0x01;//設置定時器0為工作方式1
  375. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
  376. TL0=0x0b;
  377. //配置串口
  378. SCON=0x50;
  379. TMOD=0X21;
  380. TH1=TL1=-(11059200L/12/32/9600);//串口波特率9600。
  381. TR1=1;
  382. }
  383. void initial_peripheral(void) //第二區(qū) 初始化外圍
  384. {
  385. EA=1; //開總中斷
  386. ES=1; //允許串口中斷
  387. ET0=1; //允許定時中斷
  388. TR0=1; //啟動定時中斷
  389. }

總結陳詞:
前面幾個章節(jié)中,每個章節(jié)要么獨立地講解串口收數據,要么獨立地講解發(fā)數據,實際上在大部分的項目中,串口都需要“一收一應答”的握手協(xié)議,上位機作為主機,單片機作為從機,主機先發(fā)一串數據,從機收到數據后進行校驗判斷,如果校驗正確則返回正確應答指令,如果校驗錯誤則返回錯誤應答指令,主機收到應答指令后,如果發(fā)現是正確應答指令則繼續(xù)發(fā)送其它的新數據,如果發(fā)現是錯誤應答指令,或者超時沒有接收到任何應答指令,則繼續(xù)重發(fā),如果連續(xù)重發(fā)三次都是錯誤應答或者無應答,主機就進行報錯處理。讀者只要把我的串口收發(fā)程序結合起來,就很容易實現這樣的功能,我就不再詳細講解了。從下一節(jié)開始我講解單片機掉電后數據保存的內容,欲知詳情,請聽下回分解-----利用AT24C02進行掉電后的數據保存。


評論


技術專區(qū)

關閉