網(wǎng)站建設(shè)木馬科技成都優(yōu)化網(wǎng)站建設(shè)
鶴壁市浩天電氣有限公司
2026/01/24 11:11:04
網(wǎng)站建設(shè)木馬科技,成都優(yōu)化網(wǎng)站建設(shè),杭州百度seo代理,海爾網(wǎng)站建設(shè)投入使用stm32f103vct6,串口通信時遇到一個小問題 記錄一下:設(shè)置dma傳輸?shù)拈L度是 maxLen,在接收時判斷了剩余dma緩存長度,當(dāng)接收的長度等于maxlen時就出現(xiàn)了問題,返回的是maxLen長度.當(dāng)接收長度小于maxLen時 返回的長度是剩余長度./*** brief Returns the number of remaining dat…使用stm32f103vct6,串口通信時遇到一個小問題 記錄一下:設(shè)置dma傳輸?shù)拈L度是 maxLen,在接收時判斷了剩余dma緩存長度,當(dāng)接收的長度等于maxlen時就出現(xiàn)了問題,返回的是maxLen長度.當(dāng)接收長度小于maxLen時 返回的長度是剩余長度./** * brief Returns the number of remaining data units in the current * DMAy Channelx transfer. * param DMAy_Channelx: where y can be 1 or 2 to select the DMA and * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. * retval The number of remaining data units in the current DMAy Channelx * transfer. */ uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx) { /* Check the parameters */ assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); /* Return the number of remaining data units for DMAy Channelx */ return ((uint16_t)(DMAy_Channelx-CNDTR)); }這段描述也是返回剩余字節(jié)數(shù).實際仿真maxLen等于接收長度時會出現(xiàn) 剩余長度等于maxLen的現(xiàn)象.使用中增大 dma緩存 大于接收的字節(jié)數(shù)返回都是正常的.代碼例程如下:/* 初始化部分 */ void USART2_Init(uint32_t baudrate) { GPIO_InitTypeDef ioCfg; USART_InitTypeDef uartCfg; DMA_InitTypeDef dmaCfg; NVIC_InitTypeDef nvicCfg; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); ioCfg.GPIO_Pin GPIO_Pin_5; // TX ioCfg.GPIO_Mode GPIO_Mode_AF_PP; ioCfg.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOD, ioCfg); ioCfg.GPIO_Pin GPIO_Pin_6; // RX ioCfg.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, ioCfg); // 1. 開啟時鐘 uartCfg.USART_BaudRate baudrate; uartCfg.USART_WordLength USART_WordLength_8b; uartCfg.USART_StopBits USART_StopBits_1; uartCfg.USART_Parity USART_Parity_No; uartCfg.USART_HardwareFlowControl USART_HardwareFlowControl_None; uartCfg.USART_Mode USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART2, uartCfg); // DMA接收配置循環(huán)模式 DMA_DeInit(DMA1_Channel6); dmaCfg.DMA_PeripheralBaseAddr (uint32_t)USART2-DR; dmaCfg.DMA_MemoryBaseAddr (uint32_t)dmaU2RxBuffer[currentU2RxBuf]; dmaCfg.DMA_DIR DMA_DIR_PeripheralSRC; dmaCfg.DMA_BufferSize UART2_RX_BUFFER_SIZE; dmaCfg.DMA_PeripheralInc DMA_PeripheralInc_Disable; dmaCfg.DMA_MemoryInc DMA_MemoryInc_Enable; dmaCfg.DMA_PeripheralDataSize DMA_PeripheralDataSize_Byte; dmaCfg.DMA_MemoryDataSize DMA_MemoryDataSize_Byte; dmaCfg.DMA_Mode DMA_Mode_Circular; dmaCfg.DMA_Priority DMA_Priority_High; dmaCfg.DMA_M2M DMA_M2M_Disable; DMA_Init(DMA1_Channel6, dmaCfg); // DMA發(fā)送配置 DMA_DeInit(DMA1_Channel7); dmaCfg.DMA_PeripheralBaseAddr (uint32_t)USART2-DR; dmaCfg.DMA_MemoryBaseAddr (uint32_t)dmaU2TxBuffer; // 需要添加dmaU2TxBuffer定義 dmaCfg.DMA_DIR DMA_DIR_PeripheralDST; dmaCfg.DMA_BufferSize UART2_TX_BUFFER_SIZE; dmaCfg.DMA_PeripheralInc DMA_PeripheralInc_Disable; dmaCfg.DMA_MemoryInc DMA_MemoryInc_Enable; dmaCfg.DMA_PeripheralDataSize DMA_PeripheralDataSize_Byte; dmaCfg.DMA_MemoryDataSize DMA_MemoryDataSize_Byte; dmaCfg.DMA_Mode DMA_Mode_Normal; dmaCfg.DMA_Priority DMA_Priority_Medium; dmaCfg.DMA_M2M DMA_M2M_Disable; DMA_Init(DMA1_Channel7, dmaCfg); nvicCfg.NVIC_IRQChannel DMA1_Channel7_IRQn; nvicCfg.NVIC_IRQChannelPreemptionPriority 5; nvicCfg.NVIC_IRQChannelSubPriority 1; nvicCfg.NVIC_IRQChannelCmd ENABLE; NVIC_Init(nvicCfg); DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE); // 使能DMA和空閑中斷 USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE); // NVIC配置 nvicCfg.NVIC_IRQChannel USART2_IRQn; nvicCfg.NVIC_IRQChannelPreemptionPriority 5; nvicCfg.NVIC_IRQChannelSubPriority 0; nvicCfg.NVIC_IRQChannelCmd ENABLE; NVIC_Init(nvicCfg); USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); DMA_Cmd(DMA1_Channel6, ENABLE); USART_Cmd(USART2, ENABLE); }中斷部分:/* dma串口中斷 */ void USART2_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken pdFALSE; fData_t mData; if (USART_GetITStatus(USART2, USART_IT_IDLE) ! RESET) { uint16_t recvLen; DMA_Cmd(DMA1_Channel6, DISABLE); USART_ClearITPendingBit(USART2, USART_IT_IDLE); USART_ReceiveData(USART2); // 清除空閑中斷標(biāo)志 recvLen UART2_RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel6); // 如果接收到了數(shù)據(jù)就發(fā)送到隊列處理 if (recvLen rfFrameMaxLen) { // 發(fā)送到FreeRTOS隊列 memcpy(mData.fData, dmaU2RxBuffer[currentU2RxBuf], recvLen); memset(dmaU2RxBuffer[currentU2RxBuf],0, recvLen); mData.fLen recvLen; xQueueSendFromISR(uart2_rx_queue, mData, xHigherPriorityTaskWoken); // 切換緩沖區(qū) currentU2RxBuf ^ 1; DMA1_Channel6-CMAR (uint32_t)dmaU2RxBuffer[currentU2RxBuf]; // 檢查是否需要立即調(diào)度更高優(yōu)先級的任務(wù) if (xHigherPriorityTaskWoken ! pdFALSE) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } DMA_Cmd(DMA1_Channel6, ENABLE); } } void DMA1_Channel7_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_TC7)) { DMA_ClearITPendingBit(DMA1_IT_TC7); USART_DMACmd(USART2, USART_DMAReq_Tx, DISABLE); } }/* 任務(wù)部分 *//* 隊列初始化 */ static void initQueueAndTimer(void) { // 創(chuàng)建發(fā)送隊列 uart2_tx_queue xQueueCreate(U2_QUEUE_LENGTH, sizeof(fData_t)); if (uart2_tx_queue NULL) { // dPrintf(Transmit queue creation failed
); return; } // 創(chuàng)建接收隊列 uart2_rx_queue xQueueCreate(U2_QUEUE_LENGTH, sizeof(fData_t)); if (uart2_rx_queue NULL) { // dPrintf(Receive queue creation failed
); return; } } /* 串口實際初始化調(diào)用位置 */ void uart2Init(void) { USART2_Init(9600); initQueueAndTimer(); } // 2. 修改接收任務(wù)函數(shù) void uart2_rx_task(void *pvParameters) { fData_t mData; #ifdef debug volatile UBaseType_t uxHighWaterMark; #endif while (1) { #ifdef debug uxHighWaterMark uxTaskGetStackHighWaterMark(NULL); #endif if (xQueueReceive(uart2_rx_queue, mData, portMAX_DELAY) pdTRUE) { // 處理接收到的數(shù)據(jù) if (parse_packet(mData.fData, mData.fLen) ! 0) { // 錯誤處理 } } vTaskDelay(2); } } // 優(yōu)化發(fā)送任務(wù)處理函數(shù) void uart2_tx_task(void *pvParameters) { fData_t mData; #ifdef debug volatile UBaseType_t uxHighWaterMark; #endif while (1) { #ifdef debug uxHighWaterMark uxTaskGetStackHighWaterMark(NULL); #endif if (xQueueReceive(uart2_tx_queue, mData, portMAX_DELAY) pdTRUE) { // 使用優(yōu)化的發(fā)送函數(shù) TickType_t xStartTime xTaskGetTickCount(); while (DMA_GetCurrDataCounter(DMA1_Channel7) ! 0) { if ((xTaskGetTickCount() - xStartTime) pdMS_TO_TICKS(100)) { break; // 超時100ms后強制退出 } vTaskDelay(1); } // 配置DMA發(fā)送 DMA_Cmd(DMA1_Channel7, DISABLE); // 復(fù)制數(shù)據(jù)到DMA發(fā)送緩沖區(qū) memcpy(dmaU2TxBuffer, mData.fData, mData.fLen); // 配置DMA發(fā)送緩沖區(qū)和長度 DMA1_Channel7-CMAR (uint32_t)dmaU2TxBuffer; DMA1_Channel7-CNDTR mData.fLen; DMA_Cmd(DMA1_Channel7, ENABLE); USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); } vTaskDelay(5); } } void sendData2U2(u8 *data, u16 sLen) { fData_t txData {0}; do { /* */ if (data NULL || sLen 0 || sLen UART2_TX_BUFFER_SIZE) { break; } /* 將數(shù)據(jù)發(fā)送到串口隊列 */ txData.fLen sLen; memcpy(txData.fData, data, sLen); if (xQueueSend(uart2_tx_queue, txData, 0) ! pdPASS) { } } while (0); }解析部分就不貼出了;貼一下幀頭部分:// 定義緩沖區(qū)大小 QueueHandle_t uart2_rx_queue; // 接收隊列句柄 QueueHandle_t uart2_tx_queue; // 發(fā)送隊列句柄 #define U2_QUEUE_LENGTH 5 // 接收隊列長度 #define U2_RX_ITEM_SIZE sizeof(fData_t) // 接收隊列項大小 #define rfFrameMaxLen 7 uint8_t dmaU2RxBuffer[2][UART2_RX_BUFFER_SIZE] {0}; uint8_t dmaU2TxBuffer[UART2_TX_BUFFER_SIZE] {0}; volatile uint8_t currentU2RxBuf 0;