<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                【132.1 字節間隔時間、雙緩存切換、指針切換關聯。】 在一些通訊模塊的項目中,常常涉及數據的轉發,透傳,提取關鍵字的處理,單片機接收到的數據不許隨意丟失,必須全部暫存,然后提取關鍵字,再把整包數據“原封不動”或者“略作修改”轉發給“下家”。這類項目的特點是,通訊協議不是固定唯一的,因此,前面章節那種接頭暗號(數據頭)的程序框架不適合這里,本節跟大家分享另外一種程序框架。 第一個要突破的技術難點是,既然通訊協議不是固定唯一的,那么,如何識別一串數據已經接收完畢?答案是靠接收每個字節之間的間隔時間來識別。當一串數據正在接收時,每個字節之間的間隔時間是“短暫的相對均勻的”。當一串數據已經接收完畢時,每個字節之間的間隔時間是“突然變長的”。代碼的具體實現,是靠一個軟件定時器,模擬單片機“看門狗”的“喂狗”原理。 第二個要突破的技術難點是,既然通訊協議不是固定唯一的,數據內容帶有隨機性,甚至字節之間的間隔時間的長短也帶有隨機性和不確定性,那么,如何預防正在處理數據時突然“接收中斷”又接收到的新數據覆蓋了尚未來得及處理的舊數據,或者,如何預防正在處理舊數據時,丟失了“突然又新過來的本應該接收的新數據”?答案是用雙緩存輪流切換的機制。雙緩存,一個用在處理剛剛接收到的舊數據,另一個用在時刻準備著接收新數據,輪流切換,兩不誤。 第三個要突破的技術難點是,既然是用雙緩存輪流切換的機制,那么,在主程序里如何統一便捷地處理兩個緩存的數組?這里的“統一”是關鍵,要把兩個數組“統一”成(看成是)一個數組,方法是,只需用“指針切換關聯”的技術就可以了。 【132.2 程序例程。】 **![](https://img.kancloud.cn/89/70/8970513a066fe0726b2997dcb0329ce0_194x190.png)** 上圖132.2.1 有源蜂鳴器電路 ![](https://img.kancloud.cn/57/01/57010762abae4157797b57319514eff1_468x181.png) 上圖132.2.2 232串口電路 程序功能如下:單片機接收任意長度(最大一次不超過30字節)的一串數據。如果發現連續有三個字節是0x02 0x03 0x04,蜂鳴器則“短叫”100ms提示;如果發現連續有四個字節是0x06 0x07 0x08 0x09,蜂鳴器則“長叫”2000ms提示。 比如測試“短叫”100ms,發送十六進制的數據串:05 02 00 00 02 03 04 09 比如測試“長叫”2000ms,發送十六進制的數據串:02 02 06 07 08 09 01 08 03 00 05 代碼如下: \#include "REG52.H" \#define DOG\_TIME\_OUT 20 //理論上,9600波特率的字節間隔時間大概0.8ms左右,因此取20ms足夠 \#define RECE\_BUFFER\_SIZE 30 //接收緩存的數組大小 void usart(void); //串口接收的中斷函數 void T0\_time(); //定時器的中斷函數 void UsartTask(void); //串口接收的任務函數,放在主函數內 void SystemInitial(void) ; void Delay(unsigned long u32DelayTime) ; void PeripheralInitial(void) ; void BeepOpen(void); void BeepClose(void); void VoiceScan(void); sbit P3\_4=P3^4; unsigned char Gu8CurrentReceBuffer\_Sec=0; //當前接收緩存的選擇標志。0代表緩存A,1代表緩存B unsigned char Gu8ReceBuffer\_A\[RECE\_BUFFER\_SIZE\]; //雙緩存其中之一的緩存A unsigned long Gu32ReceCnt\_A=0; //緩存A的數組下標與計數器,必須初始化為0,做好接收準備 unsigned char Gu8ReceBuffer\_B\[RECE\_BUFFER\_SIZE\]; //雙緩存其中之一的緩存B unsigned long Gu32ReceCnt\_B=0; //緩存B的數組下標與計數器,必須初始化為0,做好接收準備 unsigned char Gu8ReceFeedDog=1; //“喂狗”的操作變量。 unsigned char Gu8FinishFlag=0; //接收完成標志。0代表還沒有完成,1代表已經完成了一次接收 volatile unsigned char vGu8ReceTimeOutFlag=0;//通信過程中字節之間的超時定時器的開關 volatile unsigned int vGu16ReceTimeOutCnt=0; //通信過程中字節之間的超時定時器,“喂狗”的對象 volatile unsigned char vGu8BeepTimerFlag=0; volatile unsigned int vGu16BeepTimerCnt=0; void main() { SystemInitial(); Delay(10000); PeripheralInitial(); while(1) { UsartTask(); //串口接收的任務函數 } } void usart(void) interrupt 4 { if(1==RI) { RI = 0; Gu8FinishFlag=0; //此處也清零,意味深長,當主函數正在處理數據時,可以兼容多次接收完成 Gu8ReceFeedDog=1; //看門狗的“喂狗”操作,給軟件定時器繼續“輸血” if(0==Gu8CurrentReceBuffer\_Sec) //0代表選擇緩存A { if(Gu32ReceCnt\_A<RECE\_BUFFER\_SIZE) { Gu8ReceBuffer\_A\[Gu32ReceCnt\_A\]=SBUF; Gu32ReceCnt\_A++; //記錄當前緩存A的接收字節數 } } else //1代表選擇緩存B { if(Gu32ReceCnt\_B<RECE\_BUFFER\_SIZE) { Gu8ReceBuffer\_B\[Gu32ReceCnt\_B\]=SBUF; Gu32ReceCnt\_B++; //記錄當前緩存B的接收字節數 } } } else //發送數據引起的中斷 { TI = 0; //及時清除發送中斷的標志,避免一直無緣無故的進入中斷。 //以下可以添加一個全局變量的標志位的相關代碼,通知主函數已經發送完一個字節的數據了。 } } void UsartTask(void) //串口接收的任務函數,放在主函數內 { static unsigned char \*pSu8ReceBuffer; //“指針切換關聯”中的指針,切換內存 static unsigned char Su8Lock=0; //用來避免一直更新的臨時變量 static unsigned long i; //用在數據處理中的循環變量 static unsigned long Su32ReceSize=0; //接收到的數據大小的臨時變量 if(1==Gu8ReceFeedDog) //每被“喂一次狗”,就及時更新一次“超時檢測的定時器”的初值 { Gu8ReceFeedDog=0; Su8Lock=0; //解鎖。用來避免一直更新的臨時變量 //以下三行代碼是看門狗中的“喂狗”操作。繼續給軟件定時器“輸血” vGu8ReceTimeOutFlag=0; vGu16ReceTimeOutCnt=DOG\_TIME\_OUT;//正在通信時,兩個字節間隔的最大時間,本節選用20ms vGu8ReceTimeOutFlag=1; } else if(0==Su8Lock&&0==vGu16ReceTimeOutCnt) //超時,代表一串數據已經接收完成 { Su8Lock=1; //避免一直進來更新 Gu8FinishFlag=1; //兩個字節之間的時間超時,因此代表了一串數據已經接收完成 } if(1==Gu8FinishFlag) //1代表已經接收完畢一串新的數據,需要馬上去處理 { if(0==Gu8CurrentReceBuffer\_Sec) { Gu8CurrentReceBuffer\_Sec=1; //以最快的速度先切換接收內存,避免丟失新發過來的數據 //Gu32ReceCnt\_B=0;//這里不能清零緩存B的計數器,意味深長,避免此處臨界點發生中斷 Gu8FinishFlag=0; //盡可能以最快的速度清零本次完成的標志,為下一次新數據做準備 pSu8ReceBuffer=(unsigned char \*)&Gu8ReceBuffer\_A\[0\]; //關聯剛剛接收的數據緩存 Su32ReceSize=Gu32ReceCnt\_A; //記錄當前緩存的有效字節數 Gu32ReceCnt\_A=0; //及時把當前緩存計數清零,為一次切換接收緩存做準備。意味深長。 } else { Gu8CurrentReceBuffer\_Sec=0; //以最快的速度先切換接收內存,避免丟失新發過來的數據 //Gu32ReceCnt\_A=0;//這里不能清零緩存A的計數器,意味深長,避免此處臨界點發生中斷 Gu8FinishFlag=0; //盡可能以最快的速度清零本次完成的標志,為下一次新數據做準備 pSu8ReceBuffer=(unsigned char \*)&Gu8ReceBuffer\_B\[0\]; //關聯剛剛接收的數據緩存 Su32ReceSize=Gu32ReceCnt\_B; //記錄當前緩存的有效字節數 Gu32ReceCnt\_B=0; //及時把當前緩存計數清零,為一次切換接收緩存做準備。意味深長。 } //Gu8FinishFlag=0; //之所以不選擇在這里清零,是因為在上面清零更及時快速。意味深長。 //開始處理剛剛接收到的一串新數據,直接“統一”處理pSu8ReceBuffer指針為代表的數據即可 for(i=0;i<Su32ReceSize;i++) { if(0x02==pSu8ReceBuffer\[i\]&& 0x03==pSu8ReceBuffer\[i+1\]&& 0x04==pSu8ReceBuffer\[i+2\]) //連續三個數是0x02 0x03 0x04 { vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=100; //讓蜂鳴器“短叫”100ms vGu8BeepTimerFlag=1; return; //直接退出當前函數 } if(0x06==pSu8ReceBuffer\[i\]&& 0x07==pSu8ReceBuffer\[i+1\]&& 0x08==pSu8ReceBuffer\[i+2\]&& 0x09==pSu8ReceBuffer\[i+3\]) //連續四個數是0x06 0x07 0x08 0x09 { vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=2000; //讓蜂鳴器“長叫”2000ms vGu8BeepTimerFlag=1; return; //直接退出當前函數 } } } } void T0\_time() interrupt 1 { VoiceScan(); if(1==vGu8ReceTimeOutFlag&&vGu16ReceTimeOutCnt>0) //通信過程中字節之間的超時定時器 { vGu16ReceTimeOutCnt--; } TH0=0xfc; TL0=0x66; } void SystemInitial(void) { unsigned char u8\_TMOD\_Temp=0; //以下是定時器0的中斷的配置 TMOD=0x01; TH0=0xfc; TL0=0x66; EA=1; ET0=1; TR0=1; //以下是串口接收中斷的配置 //串口的波特率與內置的定時器1直接相關,因此配置此定時器1就等效于配置波特率。 u8\_TMOD\_Temp=0x20; //即將把定時器1設置為:工作方式2,初值自動重裝的8位定時器。 TMOD=TMOD&0x0f; //此寄存器低4位是跟定時器0相關,高4位是跟定時器1相關。先清零定時器1。 TMOD=TMOD|u8\_TMOD\_Temp; //把高4位的定時器1填入0x2,低4位的定時器0保持不變。 TH1=256-(11059200L/12/32/9600); //波特率為9600。11059200代表晶振11.0592MHz, TL1=256-(11059200L/12/32/9600); //L代表long的長類型數據。根據芯片手冊提供的計算公式。 TR1=1; //開啟定時器1 SM0=0; SM1=1; //SM0與SM1的設置:選擇10位異步通信,波特率根據定時器1可變 REN=1; //允許串口接收數據 //為了保證串口中斷接收的數據不丟失,必須設置IP = 0x10,相當于把串口中斷設置為最高優先級, //這個時候,串口中斷可以打斷任何其他的中斷服務函數實現嵌套, IP =0x10; //把串口中斷設置為最高優先級,必須的。 ES=1; //允許串口中斷 EA=1; //允許總中斷 } void Delay(unsigned long u32DelayTime) { for(;u32DelayTime>0;u32DelayTime--); } void PeripheralInitial(void) { } void BeepOpen(void) { P3\_4=0; } void BeepClose(void) { P3\_4=1; } void VoiceScan(void) { static unsigned char Su8Lock=0; if(1==vGu8BeepTimerFlag&&vGu16BeepTimerCnt>0) { if(0==Su8Lock) { Su8Lock=1; BeepOpen(); } else { vGu16BeepTimerCnt--; if(0==vGu16BeepTimerCnt) { Su8Lock=0; BeepClose(); } } } }
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看