缺點:有些情況下會導致數據丟失(可能返回數據中0x0d、0a本身為有效數據)
適用:約定協議的數據幀(發送數據的設備必須以相應的約定字節作為一次數據結束)
void USART1_IRQHandler(void) //串口中斷服務程序(函數)
{
u8 Res; //定義Res,用于Res =USART_ReceiveData(USART1);中存儲串口1發送的數據(這里的數據按位發送)
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
{
Res =USART_ReceiveData(USART1); //讀取接收到的數據
if((USART_RX_STA&0x8000)==0)//接收未完成 1000 0000 0000 0000
//判斷USART_RX_STA的第一位是否為0,這時因為USART_RX_STA的初始值為0,所以我們進入if(USART_RX_STA&0x4000)。
{
if(USART_RX_STA&0x4000)//接收到了0x0d 0100 0000 0000 0000
//判斷USART_RX_STA的第二位是否為1,所以我們進入else //還沒收到0X0D。
{
if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;//再次判斷這次接收到的是不是0x0d,判斷了Res是否0x0d, 即Res是否為回車,這里如果串口有輸入數據的話明顯可以判斷的,所以我們進入下面的else.
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; // 0011 1111 1111 1111
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS
OSIntExit();
#endif
}
OSIntEnter()和OSIntExit()兩者必須成對出現。
進入中斷時調用OSIntEnter(),退出中斷時調用OSIntExit()。
OSIntEnter 是進?中斷服務函數,?來記錄中斷嵌套層數(OSIntNesting增加 1);
OSIntEnter()應該在中斷關閉后調用,所以函數里面沒有使用OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL(),如此在調用OSIntEnter()前需關閉中斷。
OSIntExit():所有中斷結束后進行任務調度,使系統更加實時。
OSIntExit 是退出中斷服務函數,該函數可能觸發?次任務切換(當 OSIntNesting==0&&調度器未上鎖&&就緒表最?優先級任務 != 被中斷的任務優先級時),否則繼續返回原來的任務執?代碼(如果 OSIntNesting 不為 0,則減 1)。
OS_Sched():uCOS進行任務調度,不在中斷調用。
OSIntNesting:統計中斷嵌套數,最多255。在OSIntExit()和OS_Sched()中都有判別。
OS_ENTER_CRITICAL():保存中斷狀態,關中斷。uCOS將無法再執行任務調度,硬件中斷也被屏蔽。
void OSIntEnter (void)
{
if (OSRunning == OS_TRUE) {
if (OSIntNesting < 255u) {
OSIntNesting++; /* Increment ISR nesting level */
}
}
}
這個函數的作用是對全局變量OSIntNesting增1,OSIntNesting為中斷嵌套深度。
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
if (OSRunning == OS_TRUE) {
OS_ENTER_CRITICAL();
if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping */
OSIntNesting--;
}
if (OSIntNesting == 0u) { /* Reschedule only if all ISRs complete ... */
if (OSLockNesting == 0u) { /* ... and not locked. */
OS_SchedNew();
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
#if OS_TASK_PROFILE_EN > 0u
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /* Keep track of the number of ctx switches */
OSIntCtxSw(); /* Perform interrupt level ctx switch */
}
}
}
OS_EXIT_CRITICAL();
}
}
函數的前面部分對OSIntNesting減1,剛好與OSIntEnter() 相對應;后面部分則進行任務調度。
總結:任何中斷服務函數,我們都應該加上 OSIntEnter 和 OSIntExit 函數,UCOSII 是?個可剝奪型的內核,中斷服務?程序運?之后,系統會根據情況進??次任務調度去運?優先級別最?的就緒任務,?并不?定接著運?被中斷的任務!
#if...#endif是C++中的條件編譯預處理命令 有兩種格式:
1:#ifdef 標示符
程序段1
#else
程序段2
#endif
表示:如果標示符已經被#define命令定義過,則編譯程序段1,否則編譯程序段2。期中else部分可以沒有。
2:#if 表達式
程序段1
#else
程序段2
#endif
表示:如果表達式為真,則編譯程序段1,否則編譯程序段2.
if((USART_RX_STA&0x8000)==0) //0x8000,即二進制1000 0000 0000 0000,與變量USART_RX_STA,按位與(&),并與0比較,作用是判斷USART_RX_STA數值第16位是否為0。
USART_RX_STA&0x8000有兩種可能:
第一種1××× ×××× ×××× ××××&1000 0000 0000 0000=1000 0000 0000 0000
第二種0××× ×××× ×××× ××××&1000 0000 0000 0000=0000 0000 0000 0000
由此可以判斷USART_RX_STA第16位是否為0
USART_RX_STA的作用,USART_RX_STA一共有16位,前兩位為標記位,后14位記錄了串口發送的數的位數。第一位標記位標記了Res是否為0x0a,第二位標記位標記了Res是否為0x0d。
知識點:0x0d是回車的ASCLL碼,0x0a是換行的ASCLL碼
USART_RX_BUF這個是用來保存接收到的數據的可以看到每次結束判斷會有
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA=0; //接收狀態標記
USART_RX_STA的作用就是在全部函數之間實現一個消息傳遞,自己設置,自己管理,自己識別。
bit15 bit14 bit13~0
接收完成標志0x0a 接收到0X0d標志 接收到的有效數據個數
USART_RX_STA|=0x4000;將第二位狀態標志位置為1;在倒數第1次循環中使用USART_RX_STA|=0x8000;將第一位狀態標志位也置為1,;而后串口數據接收結束,所有從串口接收的數據保存在USART_RX_BUF[ ]數組中,串口所發送的數據長度保存在USART_RX_STA的后14位中。
審核編輯:湯梓紅
-
STM32
+關注
關注
2270文章
10914瀏覽量
356724 -
串口
+關注
關注
14文章
1557瀏覽量
76719
發布評論請先 登錄
相關推薦
評論