不忍一时之苦,何谈百世之功
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式
的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。
STM32 的串口资源相当丰富的,功能也相当强劲。比如STM32F103ZET6 最多可提供 5 路串
口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持LIN(局部互连网),智能卡
协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理
器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。
接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚:接收数据
输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,
并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送
和接收。
串口外设主要由三个部分组成,分别是波特率的控制部分、收发控制部分及数据存储转移部分。
1、波特率控制
波特率,即每秒传输的二进制位数,用 b/s (bps)表示,通过对时钟的控制可以改变波特率。
在配置波特率时,我们向波特比率寄存器 USART_BRR 写入参数,修改了串口时钟的分频值
USARTDIV。USART_BRR 寄存器包括两部分,分别是 DIV_Mantissa(USARTDIV 的整数部分)和
DIVFraction(USARTDIV的小数)部分,最终,计算公式为:
USARTDIV=DIV_Mantissa+(DIVFraction/16)。
2、分数波特率的产生
接收器和发送器的波特率在USARTDIV的整数和小数寄存器中的值应设置成相同。
Tx / Rx 波特率 =fCK/(16*USARTDIV)
这里的fCK是给外设的时钟(PCLK1用于USART2、3、4、5,PCLK2用于USART1) USARTDIV是
一个无符号的定点数。这12位的值设置在USART_BRR寄存器。
注: 在写入USART_BRR之后,波特率计数器会被波特率寄存器的新值替换。因此,不要在通信
进行中改变波特率寄存器的数值。
USARTDIV 是对串口外设的时钟源进行分频的,对于 USART1,由于它是挂载在 APB2 总线上
的,所以它的时钟源为 fPCLK2;而 USART2、3 挂载在APB1 上,时钟源则为 fPCLK1,串口的
时钟源经过 USARTDIV 分频后分别输出作为发送器时钟及接收器时钟,控制发送和接收的时序。
3、收发控制
围绕着发送器和接收器控制部分,有好多个寄存器:CR1、CR2、CR3、SR,即 USART 的
三个控制寄存器(Control Register)及一个状态寄存器(Status Register)。通过向寄存器
写入各种控制参数,来控制发送和接收,如奇偶校验位,停止位等,还包括对 USART 中断的
控制;串口的状态在任何时候都可以从状态寄存器中查询得到。具体的控制和状态检查,我们
都是使用库函数来实现的,在此就不具体分析这些寄存器位了。
4、数据存储转移部分
收发控制器根据我们的寄存器配置,对数据存储转移部分的移位寄存器进行控制。
当我们需要发送数据时,内核或 DMA 外设(一种数据传输方式,在下一章介绍)把数据从内存
(变量)写入到发送数据寄存器 TDR 后,发送控制器将适时地自动把数据从 TDR 加载到发送移位寄
存器,然后通过串口线 Tx,把数据一位一位地发送出去,在数据从 TDR 转移到移位寄存器时,会
产生发送寄存器TDR 已空事件 TXE,当数据从移位寄存器全部发送出去时,会产生数据发送完成事
件 TC,这些事件可以在状态寄存器中查询到。
而接收数据则是一个逆过程,数据从串口线 Rx 一位一位地输入到接收移位寄存器,然后自动
地转移到接收数据寄存器 RDR,最后用内核指令或 DMA读取到内存(变量)中。
选中:CMSIS>CORE;Device>Startup;>StdPeriphDrivers>Flash;>Framework;>GPIO;
>RCC;>USART等.
1)串口时钟使能,GPIO时钟使能;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
2)串口复位;
当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让
其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是
在函数 USART_DeInit()中完成:
void USART_DeInit(USART_TypeDef* USARTx);//串口复位
比如要复位串口 1,方法为:
USART_DeInit(USART1); //复位串口 1
3) GPIO端口模式设置;
//PA9
//声明结构体
GPIO_InitTypeDef GPIO_InitStructure;
//设置选择引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
//设置引脚最大输出频率
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//设置引脚输出模式——复用推挽输出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
//根据设置的InitStructure初始化GPIO口
GPIO_Init(GPIOA,&GPIO_InitStructure);
//PA10
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
//设置引脚输出模式——浮空输入
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
//根据设置的InitStructure初始化GPIO口
GPIO_Init(GPIOA,&GPIO_InitStructure);
4)串口参数初始化;
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = Baudrate; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
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(USART1,&USART_InitStructure); //初始化串口1
5)开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init (&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启串口接受完成中断
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启串口空闲中断
6)使能串口;
USART_Cmd(USART1,ENABLE); //使能串口1
7)编写中断处理函数;
void USART1_IRQHandler(void)
{
if((USART_GetITStatus(USART1,USART_IT_RXNE))!=RESET) //判断是否有中断
{
aRxbuffer[counter++] = USART_ReceiveData(USART1); //接收字符存入数组
USART_ClearFlag(USART1,USART_IT_RXNE); //清除中断标志位
}
else if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET)
{
USART1->SR;
USART1->DR;
counter = 0;
if(memcmp((uint8_t*)aRxbuffer,(uint8_t *)aRxbuffCompare,BUFFERSIZE)==0)
{
Usart_SendString(USART1,(char *)aTxbuffer);
}
else
{
Usart_SendString(USART1,"Error");//(char *)aRxbuffer
}
}
USART_ClearFlag(USART1,USART_IT_RXNE); //清除中断标志位
}
字符串清空方法
https://blog.csdn.net/caoshunxin01/article/details/79355064
STM32库函数USART配置
https://blog.csdn.net/cow825/article/details/51232154
https://blog.csdn.net/u012075442/article/details/50865644
https://blog.csdn.net/Ele_Dd/article/details/78162109
https://blog.csdn.net/dragon12345666/article/details/24883111
https://blog.csdn.net/T_zty_Y/article/details/79974470
https://www.cnblogs.com/microxiami/p/3752715.html
https://www.cnblogs.com/pertor/p/9488446.html
https://blog.csdn.net/u013002186/article/details/81429456
USART讲解:
https://blog.csdn.net/dragon12345666/article/details/24484185
https://blog.csdn.net/zxh1592000/article/details/78656609