在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

FreeRTOS串口中斷接收不定長的數(shù)據(jù)與二值信號量的使用

碼農(nóng)愛學(xué)習(xí) ? 來源:碼農(nóng)愛學(xué)習(xí) ? 作者:碼農(nóng)愛學(xué)習(xí) ? 2022-09-26 09:02 ? 次閱讀

基礎(chǔ)知識點

串口中斷種類

串口中斷屬于STM32本身的資源,不涉及到FreeRTOS,但可與FreeRTOS配合使用。

串口接收中斷

中斷標(biāo)志為:USART_IT_RXNE,即rx none empty,串口只要接收到數(shù)據(jù)就觸發(fā)中斷,如果是接收一個字符串,則每接收到一個字符就觸發(fā)一次中斷。

串口空閑中斷

中斷標(biāo)志為:USART_IT_IDLE,idle即空閑的意思,串口空閑時觸發(fā)的中斷,當(dāng)然也不是說串口空閑時就一直觸發(fā)中斷,而實在每個連續(xù)的接收完成后,觸發(fā)中斷,如果是接收一個字符串,則接收完整個字符串后,觸發(fā)一次中斷。

所以,這兩個中斷可以配合使用,串口接收中斷實時接收數(shù)據(jù),接受完一串?dāng)?shù)據(jù)后,空閑中斷被觸發(fā),就可以對接收的一串?dāng)?shù)據(jù)分析處理了。這種方式不需要知道每次字符串的具體長度,因而可以接收不定長的串口數(shù)據(jù)。

信號

FreeRTOS中的信號量是一種任務(wù)間通信的方式,信號量包括:二值信號量、互斥信號量、計數(shù)信號量,本次只使用二值信號量。

二值信號量

二值信號量只有兩種狀態(tài),可以先通俗的理解為它就是個標(biāo)志,0或1。信號量用于任務(wù)間的同步,F(xiàn)reeRTOS是多任務(wù)系統(tǒng),不同任務(wù)間可能需要某種同步關(guān)系,如串口中斷接收完數(shù)據(jù)后,數(shù)據(jù)分析處理任務(wù)才能拿到數(shù)據(jù)進(jìn)行分析,這就是一種同步。

信號量的基本操作有獲取信號量釋放信號量,例如:數(shù)據(jù)分析處理任務(wù)需要處理串口數(shù)據(jù)時,可先嘗試獲取信號量,若獲取不到,也就是信號量是0,則先進(jìn)入阻塞等待,等待超時可先跳出,之后繼續(xù)嘗試獲取信號量。串口空閑中斷接受完一串?dāng)?shù)據(jù)后,可執(zhí)行釋放信號量操作,這時,數(shù)據(jù)分析處理任務(wù)就可以獲取到信號量,進(jìn)而可以處理串口數(shù)據(jù)了,實現(xiàn)了串口數(shù)據(jù)接收與數(shù)據(jù)處理的同步。

接下來的程序思路如下:

pYYBAGMwYwaAMgtaAAD5P19tOnw458.png

API函數(shù)

創(chuàng)建二值信號量xSemaphoreCreateBinary()

函數(shù)原型(tasks.c中):

SemaphoreHandle_t xSemaphoreCreateBinary( void )

返回值:

SemaphoreHandle_t:創(chuàng)建成功的二值信號量句柄,失敗返回NULL

釋放信號量xSemaphoreGive()

函數(shù)原型(tasks.c中):

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )

參數(shù)

xSemaphore:要釋放的信號量句柄

返回值:

釋放成功返回pdPASS,失敗返回errQUEUE_FULL

釋放信號量(中斷函數(shù)中)xSemaphoreGiveFromISR()

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                                  BaseType_t* pxHigherPriorityTaskWoken)

參數(shù):

xSemaphore:同上

pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換

返回值:

同上

獲取信號量xSemaphoreTake()

函數(shù)原型(tasks.c中):

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
                           TickType_t xBlockTime)

參數(shù):

xSemaphore:要釋放的信號量句柄

xBlockTime:阻塞時間

返回值:

獲取成功返回pdTRUE,失敗返回pdFALSE

獲取信號量(中斷函數(shù)中)xSemaphoreTakeFromISR()

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
                                  BaseType_t* pxHigherPriorityTaskWoken)

參數(shù):

xSemaphore:同上

pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換

返回值:

同上

編程要點

串口中斷與釋放信號量

串口配置時記得開啟兩個中斷。

//=======================================
//初始化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時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時鐘

	//串口1對應(yīng)引腳復(fù)用映射
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9復(fù)用為USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10復(fù)用為USART1

	//USART1端口配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9與GPIOA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
	GPIO_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;//字長為8位數(shù)據(jù)格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據(jù)流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收發(fā)模式
	USART_Init(USART1, &USART_InitStructure); //初始化串口1

	USART_Cmd(USART1, ENABLE);  //使能串口1 

	USART_ClearFlag(USART1, USART_FLAG_TC);
	
#if EN_USART1_RX	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟相關(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)先級8
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子優(yōu)先級0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根據(jù)指定的參數(shù)初始化VIC寄存器

#endif
	
}

中斷服務(wù)函數(shù)的串口空閑中斷,清除標(biāo)志位只能通過先讀SR寄存器,再讀DR寄存器清除!

中斷中使用信號量釋放要使用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)
		{
			//釋放二值信號量
			xSemaphoreGiveFromISR(uartSemaphore,&xHigherPriorityTaskWoken);	//釋放二值信號量
		}
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的話進(jìn)行一次任務(wù)切換
		
		data = USART1->SR;//串口空閑中斷的中斷標(biāo)志只能通過先讀SR寄存器,再讀DR寄存器清除!
		data = USART1->DR;
		//USART_ClearITPendingBit(USART1,USART_IT_IDLE);//這種方式無效
	
		//rx_cnt=0;
	}
} 

獲取信號量

編寫一個任務(wù)來實現(xiàn)串口數(shù)據(jù)的獲取,該任務(wù)不斷嘗試獲取信號量,獲取成功后,對數(shù)據(jù)進(jìn)行處理。

獲取信號量xSemaphoreTake,阻塞(等待時間)10ms,獲取不到信號量則向下執(zhí)行,每個任務(wù)都是一個死循環(huán),馬上又會進(jìn)行信號量獲取。

//打印任務(wù)函數(shù)
void print_task(void *pvParameters)
{
	int count=0;
	BaseType_t err = pdFALSE;
	
	int size=50;
	uint8_t buf[64];//最多只取前64個數(shù)據(jù)

	//清空本地接收數(shù)組
	memset(buf,0,size);
	
	while(1)
	{
		err=xSemaphoreTake(uartSemaphore,10);	//獲取信號量
		if(err==pdTRUE)							//獲取信號量成功
		{  
			//printf("%s",Data);
			if(rx_cnt < size)//收到的數(shù)據(jù)長度在size范圍內(nèi)
			{
				//void *memcpy(void *str1, const void *str2, size_t n)  
				//從存儲區(qū) str2 復(fù)制 n 個字節(jié)到存儲區(qū) str1。
				memcpy(buf,Recv,rx_cnt);//有幾個復(fù)制幾個
				count=rx_cnt;
				//printf("%srn", buf);
			}
			else//收到的數(shù)據(jù)長度太長了
			{
				memcpy(buf,Recv,size);//只復(fù)制size個
				count=size;
			}
			rx_cnt=0;
		}
		
		if(count>0)
		{
			count=0;
			printf("receive:%s",buf);
			
			//------------------------------------------------------------------------------
			//這里可以繼續(xù)對buf進(jìn)行分析和處理,比如根據(jù)buf的不同內(nèi)容執(zhí)行不同的小任務(wù)

		}
	}
}

一個小應(yīng)用

結(jié)合之前文章介紹的字符串操作的相關(guān)知識:,可以對“命令+參數(shù)”型的字符串?dāng)?shù)據(jù)進(jìn)行處理。

//先判斷指令名稱
char *cmd;//表示命令
char *paras;//表示命令后的參數(shù)
cmd = strtok_r((char*)buf, " ", ?s);//這里有點小問題,不帶參數(shù)的命令,后面需要一個空格

char *ret;
int i;
for (i = 0; i < N;i++)
{
    ret = strstr(struct_dostr1[i].name, cmd);
    if(ret!=NULL)
    {
//        printf("find cmd in funname[%d]rn", i);
        break;
    }
}
if(i==N)
{
    printf("can't find cmd in funname[]rn");
}
else
{				
    //是有效的指令,繼續(xù)判斷后續(xù)參數(shù)
    char* para[4]={0};//限定最多接收4個參數(shù)
    para[0] = strtok(paras, " ");
    int j= 1;
    while(paras != NULL)//這里有點小問題,不可以提前結(jié)束
    {
        para[j++] = strtok(NULL, " ");
        if(j==4)
            break;
    }

    //執(zhí)行對應(yīng)的函數(shù)
    struct_dostr1[i].fun(para);
}

最后的函數(shù)執(zhí)行,是通過定義一個結(jié)構(gòu)體,將字符命令與函數(shù)指針對應(yīng)起來:

#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;
}

實驗結(jié)果

通過串口發(fā)送helloled 80 5,可以看到想要的處理結(jié)果:

receive:hello  

hello~~~~~~~~~~

receive:led 80 5

get led: 80, 5

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1554

    瀏覽量

    76512
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    484

    瀏覽量

    62172
收藏 人收藏

    評論

    相關(guān)推薦

    FreeRTOS串口DMA收發(fā)不定長數(shù)據(jù)

    FreeRTOS例程,介紹串口DMA收發(fā)不定長數(shù)據(jù)
    的頭像 發(fā)表于 09-26 09:08 ?4647次閱讀
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>串口</b>DMA收發(fā)<b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    FreeRTOS信號量使用教程

    信號量是操作系統(tǒng)中重要的一部分,信號量一般用來進(jìn)行資源管理和任務(wù)同步, FreeRTOS信號量又分為
    的頭像 發(fā)表于 12-19 09:22 ?3221次閱讀
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>使用教程

    CW32L083串口中斷+定時器實現(xiàn)不定長數(shù)據(jù)接收

    CW32L083 用串口中斷加定時器中斷實現(xiàn)串口不定長數(shù)據(jù)接收,特別適用于AT指令的
    的頭像 發(fā)表于 07-12 09:00 ?2018次閱讀
    CW32L083<b class='flag-5'>串口中斷</b>+定時器實現(xiàn)<b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>接收</b>

    如何利用串口空閑中斷接收不定長數(shù)據(jù)

    在上一篇文章STM32單片機(jī)串口空閑中斷接收不定長數(shù)據(jù)中介紹了利用串口空閑
    發(fā)表于 02-22 07:34

    Freertos串口中斷中釋放信號量,線程捕捉不到是為什么?

    Freertos串口中斷中釋放信號量,線程捕捉不到
    發(fā)表于 10-15 10:40

    stm32 串口接收不定長度數(shù)據(jù)及黏包處理 + 串口DMA接收

    ,那么stm32串口是如何實現(xiàn)接收不定長度數(shù)據(jù)的呢? 串口接收數(shù)據(jù)一般會采用
    發(fā)表于 12-23 19:09 ?27次下載
    stm32 <b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定長度數(shù)據(jù)</b>及黏包處理 + <b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>

    STM32 DMA串口接收不定長數(shù)據(jù)

    STM32 DMA串口接收不定長數(shù)據(jù)
    發(fā)表于 12-24 18:50 ?40次下載
    STM32  DMA<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    STM32之串口DMA接收不定長數(shù)據(jù)

    使用stm32或者其他單片機(jī)的時候,會經(jīng)常使用到串口通訊,那么如何有效地接收數(shù)據(jù)呢?假如這段數(shù)據(jù)不定長的有如何高效
    發(fā)表于 12-24 19:03 ?30次下載
    STM32之<b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    STM32WB55XX freertos 信號量+dma+idle 不定長串口接收 + dma傳輸完成中斷

    2、開啟全局中斷低功耗串口1 : 添加 DMA時鐘源選擇1.2 freertos 配置添加串口任務(wù)創(chuàng)建信號量
    發(fā)表于 12-24 19:13 ?5次下載
    STM32WB55XX  <b class='flag-5'>freertos</b> <b class='flag-5'>二</b><b class='flag-5'>值</b><b class='flag-5'>信號量</b>+dma+idle <b class='flag-5'>不定長串口</b><b class='flag-5'>接收</b> + dma傳輸完成<b class='flag-5'>中斷</b>

    STM32單片機(jī)串口空閑中斷+DMA接收不定長數(shù)據(jù)

    在上一篇文章STM32單片機(jī)串口空閑中斷接收不定長數(shù)據(jù)中介紹了利用串口空閑
    發(fā)表于 12-27 19:24 ?18次下載
    STM32單片機(jī)<b class='flag-5'>串口</b>空閑<b class='flag-5'>中斷</b>+DMA<b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    單片機(jī)接收不定長數(shù)據(jù),最優(yōu)解是DMA+串口空閑中斷

    如果單片機(jī)不支持串口空閑中斷和DMA,可以參考之前寫的,串口只用接收中斷,完成不定長的分包。這里
    發(fā)表于 12-28 19:26 ?25次下載
    單片機(jī)<b class='flag-5'>接收</b><b class='flag-5'>不定長</b>的<b class='flag-5'>數(shù)據(jù)</b>,最優(yōu)解是DMA+<b class='flag-5'>串口</b>空閑<b class='flag-5'>中斷</b>

    使用UART IDLE中斷接收不定長數(shù)據(jù)

    在本文中,將介紹使用該中斷來進(jìn)行不定長串口數(shù)據(jù)接收的辦法。通過該中斷,可以省卻用于檢測數(shù)據(jù)傳輸是
    發(fā)表于 02-08 15:29 ?6次下載
    使用UART IDLE<b class='flag-5'>中斷</b><b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    FreeRTOS信號量

    FreeRTOS中的信號量是一種任務(wù)間通信的方式,信號量包括:信號量、互斥
    的頭像 發(fā)表于 02-10 15:07 ?1505次閱讀

    STM32CubeMX之串口接收不定長數(shù)據(jù)

    基本串口通信通常只能接收定長數(shù)據(jù),無法穩(wěn)定接收不定長數(shù)據(jù)
    的頭像 發(fā)表于 05-11 09:59 ?3395次閱讀
    STM32CubeMX之<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>

    使用UART IDLE中斷接收不定長數(shù)據(jù)

    使用UART IDLE中斷接收不定長數(shù)據(jù)
    的頭像 發(fā)表于 09-18 15:41 ?1129次閱讀
    使用UART IDLE<b class='flag-5'>中斷</b><b class='flag-5'>接收</b><b class='flag-5'>不定長</b><b class='flag-5'>數(shù)據(jù)</b>
    主站蜘蛛池模板: 97精品伊人久久久大香线焦| 亚洲免费在线观看视频| 狂捣猛撞侍卫攻双性王爷受| 色丁香六月| 最近最新中文字幕6页| 手机看片www xiao2b cm| 五月天精品在线| 国产美女免费观看| haodiaose在线精品免费观看| 一级特黄特黄xxx视频| 国产三级a三级三级野外| 国产亚洲片| 性xxxxfreexxxxx国产| 都市激情综合网| 欧美一区二区三区激情啪啪| 天堂中文字幕在线| 亚洲午夜小视频| 亚洲系列中文字幕一区二区| 欧洲精品码一区二区三区免费看 | 日本一区二区免费在线观看| 日韩毛片一级| 天堂在线最新版在线www| 老师受年下高h男| 狠狠色狠狠色综合日日不卡| 国产狂喷冒白浆免费视频| 网址色| 亚洲国产tv| 男男宿舍高h炒肉bl| 久久久综合色| 性夜影院爽黄a爽免费看网站| 色综合激情| 色偷偷尼玛图亚洲综合| 一色屋免费视频| 5月色婷婷| 久久国产精品免费观看| 国产色婷婷精品综合在线手机播放| 1024久久| 你懂的在线看| 国产精品莉莉欧美自在线线| 色婷婷成人| 九九视频只有精品|