STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析

1. STM32F105RCT6 单片机上跑FreeRTOS 操作系统,使用USART2 进行通信,TX 发送数据每个字节之间间隔1ms

STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第1张图片

2. 串口发送函数

void UsartSend(USART_TypeDef *USARTx, BYTE *pucSendData, WORD wDataLen)
{
    WORD wLoop = 0;
    
    for (wLoop = 0; wLoop < wDataLen; wLoop++)
    {
        USARTx->DR = pucSendData[wLoop];
        while (FALSE == (USARTx->SR & 0x40));
    }
}

3. 在发送数组未发送完之前把所有中断屏蔽掉,发送完之后再重新开中断

void UsartSend(USART_TypeDef *USARTx, BYTE *pucSendData, WORD wDataLen)
{
    WORD wLoop = 0;

    __disable_irq();  // disable system interrupt
    for (wLoop = 0; wLoop < wDataLen; wLoop++)
    {
        USARTx->DR = pucSendData[wLoop];
        while (FALSE == (USARTx->SR & 0x40));
    }
    __enable_irq(); // enable system interrupt
}

4. 屏蔽中断后效果明显改善了

STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第2张图片

5. 之前还试过加临界区,但是我串口2 这里一加临界区保护就会导致安卓屏无法开机

6. 串口1 (USART1)也有一样的问题,加临界区保护之后就好了,但是串口2 不能加临界区保护,具体原因就不分析了,没时间

7. 串口1 (USART1)加临界区保护

static void Usart1Send(USART_TypeDef *USARTx, BYTE *pucSendData, WORD wDataLen)
{
    WORD wLoop = 0;

    taskENTER_CRITICAL(); // add critical zone protection
    for (wLoop = 0; wLoop < wDataLen; wLoop++)
    {
        USARTx->DR = pucSendData[wLoop];
        while (FALSE == (USARTx->SR & 0x40));
    }
    taskEXIT_CRITICAL(); // exit critical zone
}

8. 加临界区保护后串口发送间隔变小了

STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第3张图片

9. 因为我这个项目同时用到了好几个串口,可能是串口之间相互干扰了吧,串口中断干扰,后期需要优化一下

10. 还有一种办法,串口发送数据的时候用DMA 搬运数据, USART2_TX 开启DMA

STM32F105RCT6 :
USART2_Rx – DMA1_Channel6
USART2_Tx – DMA1_Channel7
STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第4张图片

11. 初始化配置DMA

STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第5张图片

12. 初始化配置DMA, 发送DMA

// usart2_tx - dma1_ch7
void USART2_Tx_DMA1_Ch7_Init(uint8_t sendBuff[], uint8_t sendBuffLen)
{
    if (NULL == sendBuff)
    {
        return;
    }
    assert_param(sendBuffLen);

    DMA_InitTypeDef DMA_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel7); // usart2_tx - dma1_ch7

    g_usartxDMAxSendDataByteCounter = sendBuffLen;

    DMA_InitStruct.DMA_BufferSize = sendBuffLen;
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)sendBuff;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&(USART2->DR));
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;

    DMA_Init(DMA1_Channel7, &DMA_InitStruct); // usart2_tx - dma1_ch7

    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
}

13. 将要发送的数组拷贝到全局数组 g_usart2Dma1Channel7TxBuff 里面发送给从机

STM32F105RCT6 上跑 FreeRTOS 操作系统,串口发送数据分析_第6张图片

void UsartSend(USART_TypeDef *USARTx, BYTE *pucSendData, WORD wDataLen)
{
    memcpy(g_usart2Dma1Channel7TxBuff, pucSendData, wDataLen);
    Usart2Dma1Channel7_TxEnable();
    for (;;)
    {
         if (DMA_GetFlagStatus(DMA1_FLAG_TC7) != RESET)
         {
            DMA_ClearFlag(DMA1_FLAG_TC7);
            break;
         }
    }
}

14. 还可以调整FreeRTOS 的系统时钟节拍

我是在STM32F105RCT6 芯片上跑的freeRTOS 实时操作系统

#define configTICK_RATE_HZ    (1000) // system ticks freq, T = 1 / F = 1 / configTICK_RATE_HZ s = 1ms

你可能感兴趣的:(stm32,嵌入式硬件,单片机,FreeRTOS)