這兩天一直想著如何去實現一個串口接收緩存。試著用stm32的DMA去實現,但總是不是很方便,自己寫了個循環存儲的程序,但是總有些問題。今天看到網上的一段代碼,感覺自己寫的程序就是渣渣,瘋狂用條件判斷,但沒有將這種想法提升到數學方法的層次,只局限于描述現象。特將FIFO的代碼復制過來,供學習用。
由一個串口接收數據引發的問題與字節緩沖流系統的設計???????????
?
在一個wifi數據收發項目調試時發現,數據在高速連續發送和接收時,經常出現數據出現了丟失和系統的死機。單片機在接收串口數據時,傳統采用中斷方法或者查詢指定標志位方法接收數據。查詢指定標志位:這種方式通常在main函數的大循環中不斷的檢測標志位或者等待該標志位來判斷是否有數據接收。通常有兩種方式:??
1:在大循環中if(標志位成立)表明有數據接收?然后進行數據的處理。??
?
優點:不會引起整個main函數?線程的阻塞?;在簡單的數據接收項目中可以使用?
缺點:單片機一般都為單線程,復雜的控制中采用操作系統,例如UC/OS;所以,將所以都函數放在main函數大循環中進行輪番處理。整個循環周期時間不確定,其他任務函數可能發生阻塞,不能夠保證數據到來時,正好在執行檢測指定標志位,從而出現了數據丟失。
2:在大循環中 while(標志位);通過while來等待數據的到來。
優點:數據不會出現丟失,穩定。
缺點:整個main函數主線程出現堵塞,其他函數無法執行,上述所示。
顯然:以上兩種發送在復雜的控制系統中是不能采用的 ,因此:在沒有多任務操作系統時,數據的接收采用中斷接收的法式是最佳的。使用中斷,可以不用查詢和等待的方式接收數據,解決了許多問題。,此時,單片機可以說是多線程執行程序。main函數是一個線程,中斷服務子程序是一個線程。中斷是前臺,main函數是后臺。由于是多線程(一般而言),不得不考慮數據的安全性。中斷可能隨時到來。Main函數會隨時被打斷,程序計數器寄存器PC指針指向中斷函數入口地址,指向中斷函數。Main函數在處理數據時被打斷,可能會引發數據的丟失。共同訪問全局變量時,使用互斥信號量等一些手段保障數據不被修改。設計可能被中斷打斷的函數時,要注意函數的重入問題,像static等關鍵字。
字節接收緩沖系統設計的核心思想:
1:前臺(即中斷)負責接收數據,并不進行處理,將數據放入消息隊列中。
2:后臺(main函數)負責從消息隊列中取出消息,并處理。
3:整個接收系統核心為 隊列,可以當做緩沖區;遵循先進先出原則 FIFO
采用隊列方式接收數據比較簡單,并且實現了緩沖,不會出現數據的丟失。
消息隊列核心算法實現:
1:消息隊列核心數據結構:
typedef struct Queue
{
unsigned char front; //隊列頭索引
unsigned char rear; //隊列尾索引
unsigned char *pArray;//簡易的隊列 指向數組
}QueueTypeDef;
2: 判斷隊列是否為滿偽算法
if( (rear + 1) % 數組的元素個數) == front)
3: 判斷隊列是否為空偽算法
if(rear == front)
4: 將數據加入隊列偽算法
if( 隊列不為滿 )
{
pArray[rear] = 數據;
rear = (rear + 1) % 數組的長度
}
5: 將數據從隊列中取出偽算法
if( 隊列不為空)
{
Val = pArray[front];
front = (front + 1 ) % 數組長度
}
以上是接收最簡單的一個字節的隊列;ASCII C 編譯通過 不依賴于單片機 ;將其加入中斷服務子程序中,把接收的數據加入隊列中;以stm32 單片機串口中斷為例:
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
en_queue(&Queue,(uint8_t)USART_ReceiveData(USART2)); //將數據加入消息隊列中
}
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET)
{
USART_ClearFlag(USART2,USART_FLAG_ORE);
USART_ReceiveData(USART2);
}
}
Main函數從消息隊列中取出數據
unsigned char val;
while(1)
{
if(out_queue(&Queue, &val)) //從隊列中取出數據
{
if(i == 16)
i=0;
LCD_print(1,i,val); //顯示取出的數據
i++;
}
….
……
//其他任務 …….
}
以上算法思路是以接收最簡單的一個字節為例:當然可以接收更復雜的數據,數據結構如下
typedef struct Message //消息數據結構
{
u8 clientID; //客戶端名
u8 messgeLength; //消息長度
u8 message_str[MessageSize]; //存放消息的數組
}MessageTypeDef;
typedef struct Queue //消息隊列 數據結構
{
u8 front; //隊列頭
u8 rear; //隊列尾 + 1
MessageTypeDef message[MessQueueSize]; //消息
BOOL (*postMessage)(MessageTypeDef dat ); //消息進列
BOOL (*getMessage)(MessageTypeDef * datAddr);//消息出列
}MessQueue;
MessageTypeDef;這個數據結構中 構造了接收數據的格式 并不是前面最簡單的一個字節,根據實際接收數據的需要來構造數據結構,當然在中斷函數中要進行數據的處理,也可以放在主函數中處理數據,中斷中依然是將字節放入消息隊列中。主函數處理完數據后在放入另一個消息隊列中,由其他函數處理數據,多級消息隊列。以下是帶特定格式的消息數據處理:
buff[buff_index] = USART_ReceiveData(USART2); //將接收的數據(1個字節)放入緩沖區
//
// if(buff[0] == 0x2B) //校驗數據頭
// {
// buff_index++;
// }
// else
// {
// buff_index = 0;
// }
//
// if(buff_index == 8) //獲取數據尾
// {
// length = (buff[7] - 0x30) + 1 + buff_index; // 計算數據尾索引
// }
//
// if(buff_index == length)
// {
// length = 200;
// buff_index = 0;
// receive = TRUE; //數據接收完成
// //DISABLE_WIFI_RX_IRQ(); //
// }
附: 字節緩沖流系統源碼:
文件 : queue.h
#ifndef QUEUE_H
#define QUEUE_H
#ifndef bool
#define bool unsigned char
#define true 1
#define false 0
#endif
#define QueueArraySize 32 //隊列長度 (字節)
typedef struct Queue
{
unsigned char front; //隊列頭
unsigned char rear; //隊列尾+1
unsigned char *pArray; //指向字節數組
}QueueTypeDef;
extern QueueTypeDef Queue;
extern unsigned char queueArray[QueueArraySize];
void queue_Init(QueueTypeDef *pQ, unsigned char *array); //初始化
bool full_queue(QueueTypeDef *pQ); //滿
bool emput_queue(QueueTypeDef *pQ); //空
bool en_queue(QueueTypeDef *pQ, unsigned char val); //入隊列
bool out_queue(QueueTypeDef *pQ, unsigned char *dat); //出隊列
#endif
文件:queue.c
#include “queue.h”
QueueTypeDef Queue;
unsigned char queueArray[QueueArraySize];
void queue_Init(QueueTypeDef *pQ, unsigned char *array)
{
Queue.front;
Queue.rear;
pQ->pArray = array;
pQ->front = 0;
pQ->rear = 0;
}
bool full_queue(QueueTypeDef *pQ)
{
if((pQ->rear + 1) % QueueArraySize == pQ->front)
return true;
else
return false;
}
bool emput_queue(QueueTypeDef *pQ)
{
if(pQ->front == pQ->rear)
return true;
else
return false;
}
bool en_queue(QueueTypeDef *pQ, unsigned char val)
{
if(full_queue(pQ))
{
return false;
}
else
{
*((pQ->pArray)+(pQ->rear)) = val;
//pQ->pArray[pQ->rear] = val;
pQ->rear = (pQ->rear + 1) % QueueArraySize;
return true;
}
}
bool out_queue(QueueTypeDef *pQ, unsigned char *dat)
{
if(emput_queue(pQ))
{
return false;
}
else
{
*dat = pQ->pArray[pQ->front];
pQ->front = (pQ->front + 1) % QueueArraySize;
return true;
}
}
附:復雜數據接收緩沖流實現
1:文件:queue.h
#ifndef QUEUE_H
#define QUEUE_H
#ifndef BOOL
#define BOOL unsigned char
#define TRUE 1
#define FALSE 0
#endif
#define MessageSize 10 //消息長度 (字節)
#define MessQueueSize 20 //隊列長度 sizeof( MessageTypeDef)
typedef unsigned char u8;
typedef unsigned int u16;
typedef struct Message //消息數據結構
{
u8 clientID; //客戶端名
u8 messgeLength; //消息長度
u8 message_str[MessageSize]; //存放消息的數組
}MessageTypeDef;
typedef struct Queue //消息隊列 數據結構
{
u8 front; //隊列頭
u8 rear; //隊列尾 + 1
MessageTypeDef message[MessQueueSize]; //消息
BOOL (*postMessage)(MessageTypeDef dat ); //消息進列
BOOL (*getMessage)(MessageTypeDef * datAddr);//消息出列
}MessQueue;
extern MessQueue mess_queue;
void MessageQueueInit(void); //初始化
BOOL full_queue(void) ;//判斷是否為滿
BOOL emput_queue(void);//判斷是否為空
BOOL en_queue(MessageTypeDef message) ;//入列
BOOL out_queue(MessageTypeDef *message); //出列
#endif
2:文件:queue.c
#include “queue1.h”
MessQueue mess_queue; //定義消息隊列
void MessageQueueInit(void) //初始化
{
mess_queue.front = 0;
mess_queue.rear = 0;
mess_queue.postMessage = en_queue;
mess_queue.getMessage = out_queue;
}
BOOL full_queue(void) //判斷隊列是否為滿
{
if( (mess_queue.rear + 1) % MessQueueSize == mess_queue.front ) // rear + 1 = front
{
return TRUE;
}
else
{
return FALSE;
}
}
BOOL emput_queue(void) //判斷隊列是否為空
{
if(mess_queue.front = mess_queue.rear) //front = rear
{
return TRUE;
}
else
{
return FALSE;
}
}
BOOL en_queue(MessageTypeDef message) //入列
{
if(full_queue()) //判斷隊列是否為滿
{
return FALSE;
}
else
{
u8 i = 0;
(&(mess_queue.message[mess_queue.rear]))->clientID = message.clientID;
(&(mess_queue.message[mess_queue.rear]))->messgeLength = message.messgeLength;
for(i=0; i<(message.messgeLength); i++)
{
(&(mess_queue.message[mess_queue.rear]))->message_str[i] = message.message_str[i];
}
mess_queue.rear = (mess_queue.rear + 1) % MessQueueSize;
return TRUE;
}
}
BOOL out_queue(MessageTypeDef *message) //出列
{
if(emput_queue()) //判斷是否為空
{
return FALSE;
}
else
{
u8 i;
message->clientID = (&(mess_queue.message[mess_queue.front]))->clientID;
message->messgeLength = (&(mess_queue.message[mess_queue.front]))->messgeLength;
for(i=0; i<(message->messgeLength); i++)
{
message->message_str[i] = (&(mess_queue.message[mess_queue.front]))->message_str[i];
}
mess_queue.front = (mess_queue.front + 1) % MessQueueSize;
return TRUE;
}
}
完! 以上為整個數據接收的核心算法 在ASCII C編譯器上編譯通過,不依賴于底層。移植時修改相應的數據類型。
上一篇:stm32驅動Lora串口模塊
下一篇:stm32l0 rtc休眠周期自動喚醒文檔整理
推薦閱讀
史海拾趣
隨著電動汽車行業的興起,汽車行業對零部件的標記和追蹤要求也日益嚴格。Datalogic憑借其強大的技術實力,成功開發出3W固態激光打標機Vlase UV 3,該產品能夠在橙色部件上實現高度可見、穩定和持久的對比度標記,解決了電動汽車生產中的一大難題。這一創新不僅展示了Datalogic的技術實力,也進一步鞏固了其在電子行業中的領先地位。
隨著市場的不斷擴張和競爭的加劇,Eurohm Resistors始終堅持品質至上的原則。公司建立了嚴格的質量控制體系,從原材料采購到生產流程,再到成品檢驗,每一個環節都嚴格把關。這種對品質的堅守不僅贏得了客戶的信任,也為公司贏得了良好的口碑。
DDD公司成立于1964年,當時正值電子行業的蓬勃發展期。創始人看到了延遲線技術在計算機和電信領域中的巨大潛力,決定投身其中。然而,初期的市場并不如預期般順利,公司面臨著資金短缺、技術難題和市場競爭等多重壓力。但DDD公司的創始人憑借對技術的熱情和堅定的信念,帶領團隊不斷研發新產品,優化生產工藝,逐漸在市場中樹立了自己的品牌形象。
隨著全球化進程的加速,高創也開始了其全球化布局的步伐。除了在以色列和中國設立研發中心外,高創還積極拓展國際市場,與全球多個國家和地區的客戶建立了長期合作關系。通過參加國際知名展會如漢諾威工業博覽會等,高創不僅展示了其最新技術和產品,還加強了與國際同行的交流與合作,進一步提升了其國際知名度和影響力。
Bias Power公司深知研發實力是企業發展的核心。因此,公司投入大量資源用于研發工作,建立了完善的研發團隊和實驗設施。通過不斷的技術創新和研發投入,Bias Power公司成功推出了一系列具有競爭力的新產品,鞏固了其在電子行業的領先地位。
同時,公司還注重知識產權的保護,積極申請專利,保護其核心技術不被侵犯。這些專利的申請和授權不僅提升了公司的技術實力,還為公司的發展提供了有力保障。
在網絡管理員努力理解 RF 頻譜中的干擾問題時,他們會聽到有關干擾對無線網絡的影響的傳言。 此白皮書幫助揭密網絡管理員在探索干擾問題時遇到的 10 大傳言。 作為一名網絡管理員,您關心 WLAN 的性能。您希望優化其性能以 ...… 查看全部問答∨ |
最近一直調試觸摸屏問題,有些ddsi函數也能執行, touch.dll也能被調用,但是就是點擊觸摸屏沒有反應,感覺中斷進不去呢,有懂觸摸屏 驅動的朋友嗎?感謝給與解答,多謝了!… 查看全部問答∨ |
近段時間確實有點賴: 看圖,說話! 詳細:http://hi.baidu.com/haorongwu/bl ... Stamp=1301570434921 (內有清晰視頻。。嘻嘻。。。賴人。。。 )… 查看全部問答∨ |
|
datasheet里面的Iam Active Mode Supply Current Into VCC Excluding External Current是不是沒有包括輸出?最差的情況下Iam也只有幾個mA,幾個管腳的拉電流加起來都不止了吧?… 查看全部問答∨ |