bufferedreader接收不到数据_FreeRTOS例程3-串口中断接收不定长的数据与二值信号量的使用
1 基礎(chǔ)知識(shí)點(diǎn)
1.1 串口中斷種類(lèi)
串口中斷屬于STM32本身的資源,不涉及到FreeRTOS,但可與FreeRTOS配合使用。
串口接收中斷
中斷標(biāo)志為:USART_IT_RXNE,即rx none empty,串口只要接收到數(shù)據(jù)就觸發(fā)中斷,如果是接收一個(gè)字符串,則每接收到一個(gè)字符就觸發(fā)一次中斷。
串口空閑中斷
中斷標(biāo)志為:USART_IT_IDLE,idle即空閑的意思,串口空閑時(shí)觸發(fā)的中斷,當(dāng)然也不是說(shuō)串口空閑時(shí)就一直觸發(fā)中斷,而實(shí)在每個(gè)連續(xù)的接收完成后,觸發(fā)中斷,如果是接收一個(gè)字符串,則接收完整個(gè)字符串后,觸發(fā)一次中斷。
所以,這兩個(gè)中斷可以配合使用,串口接收中斷實(shí)時(shí)接收數(shù)據(jù),接受完一串?dāng)?shù)據(jù)后,空閑中斷被觸發(fā),就可以對(duì)接收的一串?dāng)?shù)據(jù)分析處理了。這種方式不需要知道每次字符串的具體長(zhǎng)度,因而可以接收不定長(zhǎng)的串口數(shù)據(jù)。
1.2 信號(hào)量
FreeRTOS中的信號(hào)量是一種任務(wù)間通信的方式,信號(hào)量包括:二值信號(hào)量、互斥信號(hào)量、計(jì)數(shù)信號(hào)量,本次只使用二值信號(hào)量。
二值信號(hào)量
二值信號(hào)量只有兩種狀態(tài),可以先通俗的理解為它就是個(gè)標(biāo)志,0或1。信號(hào)量用于任務(wù)間的同步,FreeRTOS是多任務(wù)系統(tǒng),不同任務(wù)間可能需要某種同步關(guān)系,如串口中斷接收完數(shù)據(jù)后,數(shù)據(jù)分析處理任務(wù)才能拿到數(shù)據(jù)進(jìn)行分析,這就是一種同步。
信號(hào)量的基本操作有獲取信號(hào)量和釋放信號(hào)量,例如:數(shù)據(jù)分析處理任務(wù)需要處理串口數(shù)據(jù)時(shí),可先嘗試獲取信號(hào)量,若獲取不到,也就是信號(hào)量是0,則先進(jìn)入阻塞等待,等待超時(shí)可先跳出,之后繼續(xù)嘗試獲取信號(hào)量。串口空閑中斷接受完一串?dāng)?shù)據(jù)后,可執(zhí)行釋放信號(hào)量操作,這時(shí),數(shù)據(jù)分析處理任務(wù)就可以獲取到信號(hào)量,進(jìn)而可以處理串口數(shù)據(jù)了,實(shí)現(xiàn)了串口數(shù)據(jù)接收與數(shù)據(jù)處理的同步。
接下來(lái)的程序思路如下:
1.3 API函數(shù)
創(chuàng)建二值信號(hào)量xSemaphoreCreateBinary()
函數(shù)原型(tasks.c中):
SemaphoreHandle_t xSemaphoreCreateBinary( void )返回值:
- SemaphoreHandle_t:創(chuàng)建成功的二值信號(hào)量句柄,失敗返回NULL
釋放信號(hào)量xSemaphoreGive()
函數(shù)原型(tasks.c中):
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )參數(shù):
- xSemaphore:要釋放的信號(hào)量句柄
返回值:
- 釋放成功返回pdPASS,失敗返回errQUEUE_FULL
釋放信號(hào)量(中斷函數(shù)中)xSemaphoreGiveFromISR()
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,BaseType_t* pxHigherPriorityTaskWoken)參數(shù):
- xSemaphore:同上
- pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換
返回值:
- 同上
獲取信號(hào)量xSemaphoreTake()
函數(shù)原型(tasks.c中):
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xBlockTime)參數(shù):
- xSemaphore:要釋放的信號(hào)量句柄
- xBlockTime:阻塞時(shí)間
返回值:
- 獲取成功返回pdTRUE,失敗返回pdFALSE
獲取信號(hào)量(中斷函數(shù)中)xSemaphoreTakeFromISR()
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,BaseType_t* pxHigherPriorityTaskWoken)參數(shù):
- xSemaphore:同上
- pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換
返回值:
- 同上
2 編程要點(diǎn)
2.1 串口中斷與釋放信號(hào)量
串口配置時(shí)記得開(kāi)啟兩個(gè)中斷。
//======================================= //初始化IO 串口1 //bound:波特率 //======================================= void uart_init(u32 bound) {//GPIO端口設(shè)置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時(shí)鐘//串口1對(duì)應(yīng)引腳復(fù)用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9復(fù)用為USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10復(fù)用為USART1//USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9與GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10//USART1 初始化設(shè)置USART_InitStructure.USART_BaudRate = bound;//波特率設(shè)置USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長(zhǎng)為8位數(shù)據(jù)格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位USART_InitStructure.USART_Parity = USART_Parity_No;//無(wú)奇偶校驗(yàn)位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無(wú)硬件數(shù)據(jù)流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC);#if EN_USART1_RX USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開(kāi)啟相關(guān)中斷USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中斷通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=8;//搶占優(yōu)先級(jí)8NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子優(yōu)先級(jí)0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器#endif}中斷服務(wù)函數(shù)的串口空閑中斷,清除標(biāo)志位只能通過(guò)先讀SR寄存器,再讀DR寄存器清除!
中斷中使用信號(hào)量釋放要使用ISR結(jié)尾的函數(shù)xSemaphoreGiveFromISR,否則程序就卡住了。
//======================================= //串口1中斷服務(wù)程序 //======================================= void USART1_IRQHandler(void) {uint8_t data;//接收數(shù)據(jù)暫存變量BaseType_t xHigherPriorityTaskWoken;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷{data =USART_ReceiveData(USART1); Recv[rx_cnt++]=data;//接收的數(shù)據(jù)存入接收數(shù)組 USART_ClearITPendingBit(USART1,USART_IT_RXNE);} if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//空閑中斷{if(uartSemaphore!=NULL){//釋放二值信號(hào)量xSemaphoreGiveFromISR(uartSemaphore,&xHigherPriorityTaskWoken); //釋放二值信號(hào)量}portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的話進(jìn)行一次任務(wù)切換data = USART1->SR;//串口空閑中斷的中斷標(biāo)志只能通過(guò)先讀SR寄存器,再讀DR寄存器清除!data = USART1->DR;//USART_ClearITPendingBit(USART1,USART_IT_IDLE);//這種方式無(wú)效//rx_cnt=0;} }2.2 獲取信號(hào)量
編寫(xiě)一個(gè)任務(wù)來(lái)實(shí)現(xiàn)串口數(shù)據(jù)的獲取,該任務(wù)不斷嘗試獲取信號(hào)量,獲取成功后,對(duì)數(shù)據(jù)進(jìn)行處理。
獲取信號(hào)量xSemaphoreTake,阻塞(等待時(shí)間)10ms,獲取不到信號(hào)量則向下執(zhí)行,每個(gè)任務(wù)都是一個(gè)死循環(huán),馬上又會(huì)進(jìn)行信號(hào)量獲取。
//打印任務(wù)函數(shù) void print_task(void *pvParameters) {int count=0;BaseType_t err = pdFALSE;int size=50;uint8_t buf[64];//最多只取前64個(gè)數(shù)據(jù)//清空本地接收數(shù)組memset(buf,0,size);while(1){err=xSemaphoreTake(uartSemaphore,10); //獲取信號(hào)量if(err==pdTRUE) //獲取信號(hào)量成功{ //printf("%s",Data);if(rx_cnt < size)//收到的數(shù)據(jù)長(zhǎng)度在size范圍內(nèi){//void *memcpy(void *str1, const void *str2, size_t n) //從存儲(chǔ)區(qū) str2 復(fù)制 n 個(gè)字節(jié)到存儲(chǔ)區(qū) str1。memcpy(buf,Recv,rx_cnt);//有幾個(gè)復(fù)制幾個(gè)count=rx_cnt;//printf("%srn", buf);}else//收到的數(shù)據(jù)長(zhǎng)度太長(zhǎng)了{(lán)memcpy(buf,Recv,size);//只復(fù)制size個(gè)count=size;}rx_cnt=0;}if(count>0){count=0;printf("receive:%s",buf);//------------------------------------------------------------------------------//這里可以繼續(xù)對(duì)buf進(jìn)行分析和處理,比如根據(jù)buf的不同內(nèi)容執(zhí)行不同的小任務(wù)}} }2.3 一個(gè)小應(yīng)用
結(jié)合之前文章介紹的字符串操作的相關(guān)知識(shí):
碼農(nóng)愛(ài)學(xué)習(xí):C語(yǔ)言字符串相關(guān)函數(shù)使用示例 strtok_r strstr strtok atoi?zhuanlan.zhihu.com可以對(duì)“命令+參數(shù)”型的字符串?dāng)?shù)據(jù)進(jìn)行處理。
//先判斷指令名稱(chēng) char *cmd;//表示命令 char *paras;//表示命令后的參數(shù) cmd = strtok_r((char*)buf, " ", ¶s);char *ret; int i; for (i = 0; i < N;i++) {ret = strstr(cmd, struct_dostr1[i].name);if(ret!=NULL){ // printf("find cmd in funname[%d]rn", i);break;} } //printf("i:%drn",i); //printf("cmd:%s]rn", cmd); //printf("paras:%srn", paras); if(i==N) {printf("can't find cmd in funname[]rn"); } else { //是有效的指令,繼續(xù)判斷后續(xù)參數(shù)char* para[4]={0};//限定最多接收4個(gè)參數(shù)int j= 0;while((para[j]=strtok(paras," "))!= NULL)//改成這樣就可以了{(lán)j++;paras=NULL;if(j==4)break;}printf("paras nums:%drn",j);if(j>0)printf("para[0]:%srn", para[0]);if(j>1)printf("para[1]:%srn", para[1]);if(j>2)printf("para[2]:%srn", para[2]);if(j>3)printf("para[3]:%srn", para[3]);//執(zhí)行對(duì)應(yīng)的函數(shù)struct_dostr1[i].fun(para); }最后的函數(shù)執(zhí)行,是通過(guò)定義一個(gè)結(jié)構(gòu)體,將字符命令與函數(shù)指針對(duì)應(yīng)起來(lái):
#define N 2 typedef struct struct_dostr { char name[32]; int (*fun)(char *argv[]); }struct_dostr;struct_dostr struct_dostr1[N]={ {"hello",hello}, {"led", led}, };int hello(char* p[]) {printf("hello~~~~~~~~~~rn");return 0; }int led(char* p[]) {int p0,p1;p0=atoi(p[0]);p1=atoi(p[1]);printf("get led: %d, %drn",p0,p1);return 0; }3 實(shí)驗(yàn)結(jié)果
通過(guò)串口發(fā)送hello或led 80 5,可以看到想要的處理結(jié)果:
receive:hello hello~~~~~~~~~~ receive:led 80 5 get led: 80, 5完整工程代碼已保存至GitHub:
https://github.com/xxpcb/FreeRTOS-STM32F407-examples?github.com總結(jié)
以上是生活随笔為你收集整理的bufferedreader接收不到数据_FreeRTOS例程3-串口中断接收不定长的数据与二值信号量的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我国东风导弹摧毁预警机标靶
- 下一篇: 辽宁号航母出海一次,要花多少钱?