wordpress登入界面滎陽(yáng)seo
文章目錄
- 一、中斷+串口監(jiān)聽(tīng)方式
- 初始化
- 中斷處理
- 串口監(jiān)聽(tīng)
- 二、空閑中斷方式
- 三、空閑中斷+DMA方式
- 四、總結(jié)
本文將詳細(xì)介紹在STM32平臺(tái)上實(shí)現(xiàn)串口接收不定長(zhǎng)數(shù)據(jù)的幾種方法
一、中斷+串口監(jiān)聽(tīng)方式
這種方式也是我早期使用的方式,直接使用寄存器來(lái)操作,這種方式效率低,開(kāi)銷大,還要額外開(kāi)定時(shí)器監(jiān)聽(tīng)
初始化
temp=(float)(uart_config.pclk1000000)/(uart_config.bound16);//得到USARTDIV
mantissa=temp; //得到整數(shù)部分
fraction=(temp-mantissa)*16; //得到小數(shù)部分
mantissa<<=4;
mantissa+=fraction;
//初始化IO
Uart_MSP_Init(Uart_Type[uart_config.uart_num]);
//初始化clk
Uart_Clk_Init(Uart_Type[uart_config.uart_num]);
//波特率設(shè)置
Uart_Type[uart_config.uart_num]->BRR=mantissa; // 波特率設(shè)置
Uart_Type[uart_config.uart_num]->CR1|=0X200C; //1位停止,無(wú)校驗(yàn)位.
中斷處理
有數(shù)據(jù)就緩存到數(shù)組里
void USART3_IRQHandler(void)
{
uint8_t res;
if(USART3->SR&(1<<5)) //接收到數(shù)據(jù)
{
uart_lock[uart3] = 1;
res=USART3->DR;
if(Uart_RX_Data[uart3].RX_CNT<sizeof(Uart_RX_Data[uart3].RX_BUF))
{
Uart_RX_Data[uart3].RX_BUF[Uart_RX_Data[uart3].RX_CNT] = res;//緩存數(shù)據(jù)
Uart_RX_Data[uart3].RX_CNT++;//字節(jié)
}
}
}
串口監(jiān)聽(tīng)
主要作用是監(jiān)聽(tīng)中斷是否有數(shù)據(jù)更新,超過(guò)Nms認(rèn)為沒(méi)有數(shù)據(jù)更新,認(rèn)為這是一幀數(shù)據(jù),Uart3RxMonitor程序需要跑在1ms更新定時(shí)器中
static void Uart3RxMonitor(uint8_t ms) //串口接收監(jiān)控
{
if(uart_callback_handler[uart3] != NULL)
{
if(Uart_RX_Data[uart3].RX_CNT>0)//接收計(jì)數(shù)器大于零時(shí),監(jiān)控總線空閑時(shí)間
{
if(Uart_RX_Data[uart3].RX_BKP!=Uart_RX_Data[uart3].RX_CNT) //接收計(jì)數(shù)器改變,即剛接收到數(shù)據(jù)時(shí),清零空閑計(jì)時(shí)
{
//uart_lock[uart3] = 1;
Uart_RX_Data[uart3].RX_BKP=Uart_RX_Data[uart3].RX_CNT; //賦值操作,將實(shí)際長(zhǎng)度給USART1_RX_BKP
Uart_RX_Data[uart3].idletmr=0; //將監(jiān)控時(shí)間清零
}
else 接收計(jì)數(shù)器未改變,即總線空閑時(shí),累計(jì)空閑時(shí)間
{
//如果在一幀數(shù)據(jù)完成之前有超過(guò)2個(gè)字節(jié)時(shí)間的停頓,接收設(shè)備將刷新當(dāng)前的消息并假定下一個(gè)字節(jié)是一個(gè)新的數(shù)據(jù)幀的開(kāi)始
if(Uart_RX_Data[uart3].idletmr<2) //空閑時(shí)間小于1ms時(shí),持續(xù)累加
{
Uart_RX_Data[uart3].idletmr +=ms;
if(Uart_RX_Data[uart3].idletmr>=2) //空閑時(shí)間達(dá)到1ms時(shí),即判定為1幀接收完畢
{
len[uart3] = UartRead(uart3,buf[uart3],sizeof(buf[uart3]));
Uart_Buf_Def u_data;
u_data.data= buf[uart3];
u_data.len = len[uart3];
uart_callback_handleruart3;//得到一幀數(shù)據(jù)
uart_lock[uart3] = 0;
}
}
}
}
else
{
Uart_RX_Data[uart3].RX_BKP=0;
}
}
}
二、空閑中斷方式
// USART1 中斷服務(wù)程序 void USART1_IRQHandler(void) {
HAL_UART_IRQHandler(&huart1);
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
{
// 處理接收中斷
uint8_t res;
HAL_UART_Receive(&huart1, &res, 1, 1000);
// 將接收到的數(shù)據(jù)添加到緩沖區(qū),
Uart_RX_Data[uart1].RX_BUF[Uart_RX_Data[uart1].RX_CNT] = res;//緩存數(shù)據(jù)
Uart_RX_Data[uart1].RX_CNT++;//字節(jié)
}
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
{
// 處理空閑中斷
// 表示一幀數(shù)據(jù)接收完成,可以處理緩沖區(qū)中的數(shù)據(jù)
// 清除空閑中斷標(biāo)志位
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
// 處理接收到的數(shù)據(jù),例如發(fā)送出去或進(jìn)行其他處理
}
}
三、空閑中斷+DMA方式
目前主要使用的是這種方式,這種方式的好處是高效,不會(huì)頻繁進(jìn)入 RXNE中斷進(jìn)行緩存減小CPU開(kāi)銷,DMA回自動(dòng)把數(shù)據(jù)搬運(yùn)到你指定的緩存區(qū),整個(gè)數(shù)據(jù)幀傳送完畢后才會(huì)產(chǎn)生一個(gè)idle中斷
void USART1_IRQHandler(void)
{
uint32_t temp;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)) != RESET)//獲取IDLE標(biāo)志位,檢查idle標(biāo)志是否被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除標(biāo)志位
HAL_UART_DMAStop(&huart1); //
temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 獲取DMA中未傳輸?shù)臄?shù)據(jù)個(gè)數(shù)
temp = Usart1ReceiveLEN - temp; //總計(jì)數(shù)減去未傳輸?shù)臄?shù)據(jù)個(gè)數(shù),得到已經(jīng)接收的數(shù)據(jù)個(gè)數(shù)
uart_callback_handleruart1;//一幀數(shù)據(jù)獲取完成去做其他處理
HAL_UART_Receive_DMA(&huart1,Usart1_RX_Buffer,Usart1ReceiveLEN);//打開(kāi)DMA接收,數(shù)據(jù)存入rx_buffer數(shù)組中。(數(shù)組重新復(fù)位)
}
四、總結(jié)
在STM32平臺(tái)上實(shí)現(xiàn)串口接收不定長(zhǎng)數(shù)據(jù),可以通過(guò)不使用DMA的方式和使用DMA的方式來(lái)實(shí)現(xiàn)。不使用DMA的方式依賴于中斷和緩沖區(qū)處理,適用于數(shù)據(jù)量不大或?qū)崟r(shí)性要求不高的場(chǎng)景。而使用DMA的方式可以顯著提高數(shù)據(jù)傳輸?shù)男?#xff0c;減少CPU的干預(yù),適用于大數(shù)據(jù)量傳輸或需要高效率數(shù)據(jù)處理的場(chǎng)景。 在實(shí)際應(yīng)用中,可以根據(jù)具體的需求和場(chǎng)景選擇合適的實(shí)現(xiàn)方式。無(wú)論采用哪種方式,都需要對(duì)串口通信的原理和STM32的HAL庫(kù)有深入的理解,才能編寫出高效、穩(wěn)定的代碼。