B站账号:小光学嵌入式
- ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大二学生。
- ⏩最近开始系统性补习STM32基础知识,规划有:串口通信,Github,Ucos等等。
- ⏩今天总结一下串口通信之stm32-USART。
USART
一.原理讲解
请跳转->串口通信————UART、I2C、SPI详解(总结篇
二.USART和UART的区别
UART:universal asynchronous receiver and transmitter通用异步收/发器
USART:universal synchronous asynchronous receiver and transmitter通用同步/异步收/发器
大家能看出来USART和UART相比较,可以实现同步,就是说USART相对UART的区别之一就是能提供主动时钟。
三.具体固件库实现
1.USART初始化
根据USART的外设配置,我们可以得知,全双工模式,发送端设置为复用推挽输出,接收端设置为浮空输入或上拉输入。
初始化步骤:
- 使能USART使用引脚时钟
使能串口使用所在引脚 - GPIO初始化
初始化串口所在IO - 接收中断初始化
设置中断优先级和通道 - 初始化USART
初始化USART,波特率、数据格式、奇偶校验位、收发模式等等。 - 开启中断
USART_ITConfig();//开启串口接受中断 - 使能串口
USART_Cmd();
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
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_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
2.串口收发数据
串口发送一般不会用到中断发送,接收会用到中断接收,因为串口通信在没有用到主动时钟的时候,他是异步通信的。
我们先认识一下固件库中的这几个函数:
void USART_SendData();//发送数据到串口,DR
uint_16_t USART_ReceiveData();//接收数据,从DR读取接收到的数据
FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位
我们通过上面这些函数就可以完成一次成功的数据发送与接收。
下面是一个例子,完成了两个STM32之间的传输数据:
1.主机发送
发送时我们封装一个函数:
步骤:
- USART_ClearFlag()清除标志位
- USART_SendData()每次发送一个字符
- USART_GetFlagStatus()等待发送完成
- USART_ClearFlag()清楚标志位,然后继续发送知道截至标志
//串口发送字符串
void USART_SendString(USART_TypeDef* USARTx, char *DataString)
{
int i = 0;
USART_ClearFlag(USARTx,USART_FLAG_TC); //发送字符前清空标志位(否则缺失字符串的第一个字符)
while(DataString[i] != '\0') //字符串结束符
{
USART_SendData(USARTx,DataString[i]); //每次发送字符串的一个字符
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == 0); //等待数据发送成功
USART_ClearFlag(USARTx,USART_FLAG_TC); //发送字符后清空标志位
i++;
}
}
2.从机接收数据
在接收的时候,我们使用中断接收,所以我们就要编写中断服务函数:void USARTx_IRQHandler(void)
这个名字一定不能变。
接收数据步骤:
-
USART_GetITStatus()
判断是否有数据 -
USART_ReceiveData()
读取寄存器中的数据,存放到我们定义的USART_ReceiveString
中 -
if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' )
回车换行作为结束标志位,当接收完成后根据接收到的数据USART_ReceiveString
直接执行相应的操作。
char USART_ReceiveString[20]; //接收PC端发送过来的字符
int Receive_Flag = 0; //接收消息标志位
int Receive_sum = 0; //数组下标
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE) == 1) //USART_FLAG_RXNE判断数据,== 1则有数据
{
if(Receive_sum > 49) //数组能存放50个字节的数据
{
USART_ReceiveString[49] = '\0'; //数据字节超过50位时,将最后一位设置为\0
Receive_Flag = 1; //接收标志位置1,停止接收数据
Receive_sum = 0; //数组下标置0
}
if(Receive_Flag == 0) //接收标志位等于0,开始接收数据
{
USART_ReceiveString[Receive_sum] = USART_ReceiveData(USART1); //通过USART1串口接收字符
Receive_sum++; //数组下标++
}
if(Receive_sum >= 2) //数组下标大于2
{
if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' )
{
USART_ReceiveString[Receive_sum-1] = '\0';
USART_ReceiveString[Receive_sum-2] = '\0';
Receive_Flag = 1; //接收标志位置1,停止接收数据
Receive_sum = 0; //数组下标置0
if(strcmp(USART_ReceiveString,"hello") == 0)
{
LED0 = !LED0;
}
if(strcmp(USART_ReceiveString,"world") == 0)
{
LED1 = !LED1;
}
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //接收后先清空标志位
}
}
我们可以通过调整Receive_Flag
的值来让它开始或者停止接收。
我用这个做了实验,完成了简单的两个板子之间的通信。
总结
今天复习了串口通信中的USART,把之前串口接收中断没有搞懂的搞懂了,之后还有SPI和I2C通信。都会用代码实现并且实验它。
继续加油!!!