在使用单片机做项目开发的时候,串口是最常用的外设之一,比如打印调试信息,接主从串口设备等。这里主要对串口通信时中断方式收发数据的超时时间的设置和485发送数据时控制IO口的处理做一些记录。
1.串口中断接收超时设置
在项目中,如果使用中断方式数据,那么需要设置一个超时时间,超过设置的时间没有收到数据则认为当前数据包接收完成,为一个完整的数据包并开始后续的数据处理;那么这个超时时间的设置需要根据实际的应用情况合理的设置。首先,如果只做简单的超时或者MCU缓存足够大,则可以选择内核心跳或者心跳定时器来做超时,各个波特率做一个统一的超时时间,比如20毫秒;但是,如果时序相对严格或者缓存不够大,那么在硬件资源允许的情况下最好单独开一个定时器来做串口超时定时器,比如本菜鸟常用结构如下:
switch(boundrate)
{
...... //其它波特率
case RATE_9600:
//波特率设置
//超时时间设置
break;
...... //其它配置
default:
break;
}
在我使用的部分单片机中,GD32的某个系列的单片机串口自带了超时功能,开启并设置合适的时间,不得不说还是方便了不少。超时时间根据实际应用和实际使用的波特率来确定,比如实效高的应用则需要尽可能的短一点,减少通信延迟,2倍单字节时间即可;如果是标准ModBus协议则至少需要3.5背单字节时间;但是如果是带有操作系统的中断超时分包则要尽可能的长,因为时间太短可能会因为系统调度的原因导致一个数据包被拆分成好几个。
2.中断方式通过485发送数据
如果是查询方式或者DMA方式不考虑,此处主要是中断方式发送数据,发送之前首先将485芯片控制脚拉高,为发送状态,然后开始发送数据,一般开启的中断方式为发送为空中断,但是发送为空中断只是判断数据寄存器中是否为空,并不表示移位寄存器中的数据已经发出,所以在一个数据包的最后一个字节需要修改发送空中断为发送完成中断,确保最后一个字节发送完成后再拉低485控制脚,转为接收状态。如果使用STM32单片机的话,官方文档有详细说明,ST官方的中断处理源代码如下:
void USART1_IRQHandler(void)
{
/* If the buffer is fully transmitted */
if(TxCount == TxLength)
{
/* Set DE pin to low level (TC interrupt is occured )*/
GPIOC->BRR = GPIO_Pin_6;
/* Disable the USART1 Transmit Complete interrupt */
USART_ITConfig(USART1, USART_IT_TC, DISABLE);
USART_ClearFlag(USART1, USART_FLAG_TC);
}
else if ((TxCount == (TxLength-1)) && (TxLength /= 1))
{
/* Enable TC interrupt at the last byte to transmit */
USART1->DR = TxBuffer[TxCount++];
/* Enable USART TC interrupt */
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
/* Disable USART TXE interrupt */
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
else if(TxCount != 0) /* if it's not the first byte */
{
/* USART1 Tx empty interrupt has occured */
if(USART1->SR & 0x80)
{
/* Continue the buffer transmission via USART */
USART1->DR = TxBuffer[TxCount++];
}
}
else /* The first byte to be transmitted */
{
/* USART1 Tx empty interrupt has occured */
if(USART1->SR & 0x80)
{
/* Set DE pin to high level */
GPIOC->BSRR = GPIO_Pin_6;
/* Transmit the first byte */
USART1->DR = TxBuffer[TxCount++];
}
if (TxLength == 1 )
{
/* Enable TC interrupt at the last byte to transmit (single byte) */
/* Enable USART TC interrupt */
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
/* Disable USART TXE interrupt */
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
}
485为差分信号,属于半双工通信,如果发送时处理不当会出现丢数据;另外,如果通信比较密集,最好能做一下485防冲突,避免数据冲突出现错误。