網(wǎng)站內(nèi)容建設(shè)ppt目前最新的營(yíng)銷方式有哪些
①M(fèi)CU為STM32L431,使用串口2。
②Liteos采用接管中斷的方式。
STM32CubeMX配置生成串口代碼:
串口DMA接收和發(fā)送配置區(qū)別是接收采用循環(huán)模式,發(fā)送為正常模式。
將生成的代碼移植到liteos工程中,由于使用的接管中斷的方式,所以使能中斷的時(shí)候需要先注冊(cè)中斷。
HAL_NVIC_SetPriority(USART2_IRQn, 1, 0);HAL_NVIC_EnableIRQ(USART2_IRQn);HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 1, 0);HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 2, 0);HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);改為:uvIntSave = LOS_IntLock();LOS_HwiCreate(USART2_IRQn,1,(HWI_MODE_T)0,(HWI_PROC_FUNC)USART2_IRQHandler,(HWI_ARG_T)0);LOS_HwiCreate(DMA1_Channel6_IRQn,1,(HWI_MODE_T)0,(HWI_PROC_FUNC)DMA1_Channel6_IRQHandler,(HWI_ARG_T)0);LOS_HwiCreate(DMA1_Channel7_IRQn,2,(HWI_MODE_T)0,(HWI_PROC_FUNC)DMA1_Channel7_IRQHandler,(HWI_ARG_T)0); LOS_IntRestore(uvIntSave);
創(chuàng)建一個(gè)事件標(biāo)志組,并用其中的一位來表示串口接收到數(shù)據(jù)。
#define ZigbeeUartIdle (0x01<<0)#define ZigbeeUartRecv (0x01<<1)UINT32 uwRet = LOS_OK;uwRet = LOS_EventInit(&SysEventGroup);if(uwRet != LOS_OK){PRINT_ERR("Event Error Code:0x%X\n",uwRet);return uwRet;}
串口初始化函數(shù)中使能串口接收:
__HAL_UART_CLEAR_IDLEFLAG(&huart2); HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*)Usart2RxBuf, USART2_RX_BUFFER_LEN);
不要使用HAL_UART_Receive_DMA函數(shù),直接使用HAL_UARTEx_ReceiveToIdle_DMA函數(shù),該函數(shù)會(huì)以DMA方式接收一定數(shù)量的數(shù)據(jù),直到收到預(yù)期數(shù)量的數(shù)據(jù)或者發(fā)生IDLE事件時(shí)會(huì)產(chǎn)生中斷,這樣的話在中斷服務(wù)函數(shù)中可以直接調(diào)用回調(diào)函數(shù),去處理DMA接收的數(shù)據(jù)。
串口的中斷服務(wù)函數(shù):
void ClearError(UART_HandleTypeDef *huart)
{uint32_t isrflags = READ_REG(huart->Instance->ISR);uint32_t errorflags;/* If no error occurs */errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));if (errorflags != 0U) {__HAL_UART_CLEAR_FLAG(&huart2, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_PEF | UART_CLEAR_FEF);}
}void USART2_IRQHandler(void)
{ClearError(&huart2);HAL_UART_IRQHandler(&huart2);
}
在中斷服務(wù)函數(shù)中調(diào)用ClearError是為了防止因?yàn)樯弦珏e(cuò)誤或者幀錯(cuò)誤導(dǎo)致一直進(jìn)入中斷服務(wù)函數(shù)中,所以在處理中斷事件時(shí)先把錯(cuò)誤清除。
如果在初始化串口的時(shí)候注冊(cè)了DMA通道的中斷的話,當(dāng)使用DMA發(fā)送數(shù)據(jù)時(shí)半發(fā)送或者發(fā)送完成時(shí),都會(huì)進(jìn)入DMA通道中斷,同樣的在接收數(shù)據(jù)的時(shí)候當(dāng)收到定義的緩沖區(qū)一半或者接收滿時(shí)也會(huì)進(jìn)入DMA通道中斷。
void DMA1_Channel6_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma_usart2_rx);
}void DMA1_Channel7_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma_usart2_tx);
}
使用DMA發(fā)送數(shù)據(jù)完成會(huì)調(diào)用HAL_UART_TxCpltCallback回調(diào)函數(shù),可以在這里表示串口空閑。
/*** @brief Tx Transfer completed callback* @param UartHandle: UART handle. * @note This example shows a simple way to report end of DMA Tx transfer, and * you can add your own implementation. * @retval None*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{/* Set transmission flag: transfer complete*/LOS_EventWrite(&SysEventGroup,ZigbeeUartIdle);
}
當(dāng)發(fā)生空閑中斷的時(shí)候會(huì)調(diào)用HAL_UARTEx_RxEventCallback函數(shù)來處理,函數(shù)參數(shù)Size表示接收到的字節(jié)數(shù),如果使用的循環(huán)模式,那么傳進(jìn)來的Size會(huì)自動(dòng)循環(huán)。比如定義的接收緩沖區(qū)共有56個(gè)字節(jié),第一次產(chǎn)生空閑中斷時(shí)接收20字節(jié),Size大小為20,第二次產(chǎn)生空閑中斷時(shí)接收20字節(jié),Size大小為40,第三次產(chǎn)生空閑中斷時(shí)接收20字節(jié),Size大小為4。
Usart2RxLen為一個(gè)全局變量,用來表示任務(wù)在每次處理數(shù)據(jù)時(shí)需要處理的數(shù)據(jù)長(zhǎng)度,比如第一次收到20字節(jié),任務(wù)立刻處理,那么會(huì)在任務(wù)中把Usart2RxLen清零;如果第一次收到20字節(jié),任務(wù)沒有處理,第二次又收到20字節(jié),Usart2RxLen會(huì)累加,那么這個(gè)時(shí)候任務(wù)需要從接收緩存區(qū)中讀取的數(shù)據(jù)長(zhǎng)度就是40。RecvOnce是一個(gè)靜態(tài)的全局變量,用來記錄上次執(zhí)行HAL_UARTEx_RxEventCallback函數(shù)時(shí)傳入的Size值,以此來區(qū)分本次空閑中斷產(chǎn)生時(shí),接收的數(shù)據(jù)有沒有從頭開始,從而正確的計(jì)算出本次接收到數(shù)據(jù)的長(zhǎng)度。
volatile uint16_t Usart2RxLen = 0;
static uint16_t RecvOnce = 0;
/*** @brief Reception Event Callback (Rx event notification called after use of advanced reception service).* @param huart UART handle* @param Size Number of data available in application reception buffer (indicates a position in* reception buffer until which, data are available)* @retval None*/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart->Instance == USART2){LOS_EventWrite(&SysEventGroup,ZigbeeUartRecv);//通知任務(wù)接收到數(shù)據(jù)if(Size > RecvOnce){PRINT_INFO("size = %d\r\n",Size-RecvOnce);Usart2RxLen = (Usart2RxLen + Size - RecvOnce) % USART2_RX_BUFFER_LEN; }else{PRINT_INFO("size = %d\r\n",(USART2_RX_BUFFER_LEN - RecvOnce + Size));Usart2RxLen = (Usart2RxLen+(USART2_RX_BUFFER_LEN - RecvOnce + Size)) % USART2_RX_BUFFER_LEN; } RecvOnce = Size;}
}
任務(wù)中讀取數(shù)據(jù):
void Process_Task(void)
{UINT32 uwRet = LOS_OK; UINT16 msglen = 0;UINT8 msg[USART2_RX_BUFFER_LEN];while(1){uwRet = LOS_EventRead(&SysEventGroup,ZigbeeUartRecv,LOS_WAITMODE_AND | LOS_WAITMODE_CLR,0);if(uwRet & ZigbeeUartRecv){msglen = Usart2RxLen;Usart2RxLen = 0;//待處理數(shù)據(jù)長(zhǎng)度清零memset(msg,0x00,USART2_RX_BUFFER_LEN);if((msglen + DealAddr) <= USART2_RX_BUFFER_LEN){memcpy(msg,&Usart2RxBuf[DealAddr],msglen);}else{memcpy(msg,&Usart2RxBuf[DealAddr],(USART2_RX_BUFFER_LEN - DealAddr));memcpy(&msg[USART2_RX_BUFFER_LEN - DealAddr],Usart2RxBuf,(msglen+DealAddr-USART2_RX_BUFFER_LEN));}DealAddr = (DealAddr+msglen) % USART2_RX_BUFFER_LEN;HAL_UART_Transmit_DMA(&huart2,msg,msglen);}LOS_TaskDelay(LOS_MS2Tick(50));//50ms輪詢一次}
}
任務(wù)處理串口數(shù)據(jù)的周期是50ms,使用LOS_EventRead讀取事件標(biāo)志的時(shí)候超時(shí)時(shí)間設(shè)置為0,作用相當(dāng)于輪詢狀態(tài)后直接返回,處理數(shù)據(jù)的時(shí)候使用DealAddr變量來記錄上次處理之后的位置,通過(msglen + DealAddr)的值和接收緩沖區(qū)的長(zhǎng)度比較,來確定讀取數(shù)據(jù)的方式,并使用HAL_UART_Transmit_DMA函數(shù)來完成數(shù)據(jù)回環(huán)測(cè)試。
接收緩沖區(qū)的長(zhǎng)度是56,可以看到在第三次和第六次接收的時(shí)候,一幀數(shù)據(jù)調(diào)用了兩次HAL_UARTEx_RxEventCallback函數(shù),這是因?yàn)镈MA通道產(chǎn)生了半接收(28)和接收完成中斷(56),但是對(duì)一幀數(shù)據(jù)的接收沒有影響。
如果不想有這種情況,可以不使能串口RX綁定的DMA通道中斷。
模擬串口收到一幀數(shù)據(jù),但是任務(wù)沒有處理數(shù)據(jù),又來一幀時(shí)一起處理。