1. STM32F105RCT6 单片机上跑FreeRTOS 操作系统,使用USART2 进行通信,TX 发送数据每个字节之间间隔1ms
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. 屏蔽中断后效果明显改善了
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. 加临界区保护后串口发送间隔变小了
9. 因为我这个项目同时用到了好几个串口,可能是串口之间相互干扰了吧,串口中断干扰,后期需要优化一下
10. 还有一种办法,串口发送数据的时候用DMA 搬运数据, USART2_TX 开启DMA
STM32F105RCT6 :
USART2_Rx – DMA1_Channel6
USART2_Tx – DMA1_Channel7
11. 初始化配置DMA
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 里面发送给从机
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