一.串口简介
串口通信是非常常见的一种串行通信方式,在无人机上我们可以通过电脑的串口调试工具与飞机上的单片机进行通讯以及传送数据。
其传送数据有通用的协议,由发送方的TXD发送到接收方的RXD,其协议层也规定了数据包的格式,如图所示,包括起始位、数据主体、校验位以及停止位。
这也就要求接收方与发送方对应的数据格式包括奇偶校验位等一定要约定一致,才可以成功通信。如果我们的通信方式为异步通信,由于没有时钟信号,我们还要提前约定好一个统一的波特率,其实不用知道波特率是如何计算出的,因为stm32官方的固件库中有相应函数会帮我们计算,我们只需记住常用的波特率即可:4800、9600、115200。
二.USART功能框图
串口的功能框图无疑是最核心的部分,掌握框图,对有一个清晰的编程思路也有很大的帮助。下面介绍一下USART功能框图。
这个框图取自官方中文手册,主要有四部分构成:
1.引脚端:其实在这里我接触到的只有发送引脚和接收引脚,即TX和RX。我们在接收发送数据时好像一般都是用软件处理,用不到硬件流控制,暂时是这样。这里还涉及到一个问题,对于stm32来说,有十几组GPIO,上百个引脚,我们怎么知道哪个是接收,哪个是发送。其实在英文数据手册中就可以查到每个引脚的复用功能。在用到相应的引脚,对其初始化即可。
2.数据寄存器:这也是数据发送接收的核心部分,我们应该熟悉相应寄存器。在框图中我们可以看到,这部分有两条通道,一条是发送数据,一条是接收数据,下面进行介绍。
首先是数据发送,首先是cpu将数据发送到发送数据寄存器中,一般为八位数据字长,即uint8_t,由于是串行通信所以数据是一位一位发送的。接下来,发送数据寄存器会将这个数据发送到发送移位寄存器,当发送完时,在状态寄存器USART_SR中的TXE位会置1,当我们使能USART_CR1中的TXEIE位,则发送数据寄存器为空时会产生中断,我们可以通过编写中断服务函数来告诉单片机中断时干点啥。然后发送移位寄存器会将数据传到发送引脚,将数据传给串口外设。同样,当发送移位寄存器为空时,也可以产生相应中断,其寄存器对应的位叫TC位,当然还是要先使能USART_CR1中的TCIE位。
3.控制器:其实在第二部分我们已经介绍了,其对应的寄存器就是USART_CRx,值得注意的是发送器有两个中断,一个是发送数据寄存器为空,一个是发送移位寄存器为空,但接收器只有一个中断,就是接收为空。
4.波特率生成器:这一部分上面也说了,个人觉得不必过分学习,在框图中也可以推得计算公式:
三.飞控中的串口通信
个人认为其中最重要的就是中断服务函数的编写,以代码摘自烈火开源飞控,对其做了详细的注释。
void USART1_IRQHandler(void)
{
if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)//检查是否溢出错误,若溢出则产生中断
{
USART_ReceiveData(USART1);//若有溢出,返回串口最近接收到的数据
}
if(USART1->SR & USART_SR_TC)//检查发送移位寄存器是否发送完成,若完成则产生中断
{
USART1->DR = TxBuff[TxCount++];// 左操作数为发送数据,将下一个串口发送缓冲区数据发送到发送数据寄存器
if(TxCount == Count)//若缓冲区数据都发送完成了
{
USART1->CR1 &= ~USART_CR1_TXEIE;//禁止TXE中断,即cpu不再向发送数据寄存器发数据
}
}
if(USART1->SR & USART_SR_RXNE)//检查是否接收到数据,若接收非空则产生中断
{
volatile int8_t com_data ;
com_data = USART1->DR;//右操作数为接收数据,将接收到的数据送入cpu
}
}
其中需要说明的是,在编写中,我们如何能区分此时的数据寄存器是作接收还是发送呢?我的小技巧是如果当寄存器为左操作数就是发送数据,如果为右操作数那么就是接收数据。