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