因为要使用可替代芯片,之前用DMA配置的串口在某些国产pin to pin的MCU上无法使用,所以得改回中断方式进行收发,就最近修改的心得与各位分享一下。
标志位USART_IT_RXNE触发,一次获取一字节数据,中断里需要使用数组将接收数据存起来,因为是一个字节一个字节存,这就有可能导致存较长数据的时候数据分段了,协议无法校验。
然后我上网搜到了USART_IT_IDLE空闲中断,它一次存一帧数据,就很少会出现丢失数据的情况了。其实,在今天之前,我一直以为串口的IDLE空闲中断是必须配置DMA才能使用,大意了。
1. 串口3初始化配置
在这里插入代码片
void USART3_Config(uint32_t baudRate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baudRate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE ,ENABLE);
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); //空闲中断
}
2. 中断处理函数
这里我使用了空闲中断接收+中断发送
我想发送函数放在中断里完成速度会更快点吧
u16 com3_rx_len=0;//接收长度
u8 com3_recv_end_flag=0;//接收完成标志
u8 com3_rx_buffer[100]={0};//接收缓存数组
void USART3_IRQHandler(void) //串口3中断服务程序
{
u8 i;
if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET) //接收中断触发
{
com3_rx_buffer[com3_rx_len++]=USART_ReceiveData(USART3); //清除中断标志位(接收函数有清标志位的作用)
}
else if(USART_GetITStatus(USART3,USART_IT_IDLE) != RESET)//接收到一帧数据 空闲中断触发
{
USART3->SR;//先读SR
USART3->DR;//再读DR
com3_recv_end_flag=1;//接收完成标志位
}
if(USART_GetITStatus(USART3, USART_IT_TXE) != RESET)//主循环开启发送中断
{
uart3_SendBuff(send_buf,send_buf_len); //串口3数据处理完,返回上位机
USART_ITConfig(USART3, USART_IT_TXE, DISABLE); //关闭发送中断
for(i=0;i<send_buf_len;i++) send_buf[i]=0; //清除发送缓存
}
}
3. 发送函数
void uart3_SendBuff(uint8_t * buf, u16 len)
{
while(len--)
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET); //等待发送结束
USART_SendData(USART3, *buf++);
}
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);
}