串口通信
一、串口通信介绍
1.通信方式
并行和串行
并行通信:同一时刻传输多位数据。
串行通信:同一时刻只能传输一位数据。
同步和异步
同步通信:同步指的是通信双方按照事先约定好的顺序进行发和收,由时钟信号进行同步操作。
异步通信:没有时钟信号进行同步,一般由数据帧格式或者波特率做同步操作。
全双工,半双工,单工
单工:只有一根数据总线,并且只能单向通信。
半双工:只有一根数据总线,但是可以双向通信。
全双工:有两根数据总线,并且可以同时收和发。
2.串口通信的物理特性
串口通信全双工,传输速度慢,一般用于调试。
物理特性:一般芯片串口模块使用的是TTL电平进行数据发送和接收。而外部设备采用的是RS232,USB等电平。
因此串口想要通过usb和PC进行串口通信,则需要电平转换芯片将TTL电平转换为USB电平。
3.串口通信数据帧结构
起始位:1位低电平。
数据帧:可以配置7位或者8位,9位。
奇偶校验位:可以通过配置是否需要奇偶校验。如果不需要则数据帧全是有效数据,如果需要则数据帧最后一位是奇偶校验位。
停止位:可以通过配置0.5位-2位的高电平。
**偶校验:**校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为偶数。
例如:数据=00110101,有4个’1’,如果选择偶校验(在USART_CR1中的PS=0),校验位将
是’0’。
**奇校验:**此校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为奇数。
例如:数据=00110101,有4个’1’,如果选择奇校验(在USART_CR1中的PS=1),校验位将
是’1’。
4.串口通信的应用场景
调试;串口打印。
二、STM32串口通信模块
模块特性
工作方式
发送:只需要加数据写入TDR寄存器,然后等待硬件将TDR寄存器的值全部移动到移位寄存器,则可以传输下一个数据帧(将下一个数据写入TDR中)。
接收:可以轮询检测RXNE状态来判断是否有数据写入到RDR寄存器,RXNE置1则可以读数据。也可以通过RXNE置1产生的接收中断来读取RDR寄存器的值。
三、STM32串口通信实验
以UART1为例:
串口初始化配置
1.使能串口时钟(APB2)
2.使能GPIOA时钟(复用功能)
3.配置GPIOA10/9,输入和复用功能推挽输出模式
4.串口复位
5.停止串口复位
6.波特率设置
7.串口使能,接收使能,发送使能,设置停止位,奇偶校验
8.接收中断使能
void uart_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB2ENR|=1<<14; //使能串口时钟
GPIOA->CRH&=0XFFFFF00F;//IO状态设置
GPIOA->CRH|=0X000008B0;//IO状态设置
RCC->APB2RSTR|=1<<14; //复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位
//波特率设置
USART1->BRR=mantissa; // 波特率设置
USART1->CR1|=0X200C; //串口使能,字长为8,无奇偶校验,发送使能,接收使能
//没有配置CR2表示停止位设置为1位
//使能接收中断
USART1->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级
}
接收
使用图中三条信息则可完成接收程序:
轮询方式实现接收:
第一条:当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。
因此我们可以采取轮询的方式读取RXNE状态,来判断是否可以读取接收到的数据。
代码
第三条:对USART_DR的读操作可以将该位清零
备注:轮询方式,不要开启接收中断,接收中断执行完毕会导致RXNE被清0.
while(1)
{
if(USART1->SR&(1<<5)) //接收到数据
{
res=USART1->DR; //读取接收寄存器数据
if(res == 0x01)
{
LED0 = 0;
}else if(res == 0x02){
LED0 = 1;
}else{
//
}
}
}
中断方式实现接收
第二条:USART_CR1寄存器中的RXNEIE为1,则产生中断。
因此我们可以使能接收中断,在中断函数中读取接收寄存器数据。
void USART1_IRQHandler(void)
{
u8 res;
if(USART1->SR&(1<<5)) //接收到数据
{
res=USART1->DR;
if(res == 0x01)
{
LED0 = 0;
}else if(res == 0x02){
LED0 = 1;
}else{
}
}
}
发送
发送数据我们需要向USART_DR中写入数据,但是我们需要等待TDR寄存器中的数据被硬件转移到移位寄存器之后才能向USART_DR中写入下一个数据发送。因此我们可以用TXE的状态作为判断:
for(t=0;t<len;t++)
{
USART1->DR=USART_RX_BUF[t];
while((USART1->SR&0X40)==0);//等待发送结束
}