欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32学习——USART

程序员文章站 2024-02-22 12:16:35
...

1. 概述

1.1 处理器与外部设备通信方式

1.1.1并行通信

  • 传输原理:数据各个位同时传输。
  • 优点:速度快
  • 缺点:占用引脚资源多

1.1.2 串行通信(本文重点讲解此通信方式

  • 传输原理:数据按位顺序传输
  • 优点:占用引脚资源少
  • 缺点:速度相对较慢

1.2 串行通信的数据传输方向

1.2.1 单工

数据传输只支持数据在一个方向上的传输

1.2.2 半双工

允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,他实际上是一种切换方向的单工通信

1.2.3 全双工

允许数据同时在两个方向上传输,因此,全双工通信时两个单工通信方式的结合,他要求发送设备和接收设备都有独立的接收和发送能力
STM32学习——USART

1.3 串行通信的通信方式

1.3.1 同步通信

  • 带时钟同步信号传输(SPI,IIC通信接口)

1.3.2 异步通信

  • 不带时钟同步信号(UART:通用异步收发器,单总线)
    STM32学习——USART
    在STM32中有UART和USART两种收发器,其中UART为通用异步收发器,USART为通用同步异步收发器(即可用与同步或者异步收发)

1.4 UART异步通信

1.4.1 引脚连接方法

STM32学习——USARTSTM32学习——USART
STM32学习——USART

1.4.2 特点

  • 全双工异步通信。
  • 分数波特率发生器系统,提供精确的波特率。
    -发送和接受共用的可编程波特率,最高可达4.5Mbits/s
  • 可编程的数据字长度(8位或者9位);
  • 可配置的停止位(支持1或者2位停止位);
  • 可配置的使用DMA多缓冲器通信。
  • 单独的发送器和接收器使能位。
  • 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志
  • 多个带标志的中断源。触发中断。
  • 其他:校验控制,四个错误检测标志。

1.4.3 通信过程

STM32学习——USART
STM32学习——USART

2.思路

异步通信在通信时需要先约定好波特率,才能够确保发送和接收数据的完整。
在程序中需要将串口初始化并且使能串口,若需要接收到数据后产生中断则需要加上中断使能函数。
参考正点原子的教程,其还增加了一个校验的功能(其实正常的通信都应该要加上起始位和结束位,确保数据的正确性),定义了一个函数:
bit13~0:接收到的有效数据个数,bit14:接收到0X0D标志,bit15:接收0X0A完成标志。
STM32学习——USART

3.寄存器说明

3.1 状态寄存器(USART_SR)

STM32学习——USARTRXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。

TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写USART_DR。 2)直接向该位写 0。

3.2 数据寄存器(USART_DR)

STM32学习——USART
DR(8:0):包含了发送或接收的数据。

3.2 波特比率寄存器(USART_BRR)

STM32学习——USART
STM32学习——USART
STM32学习——USART

4.库函数说明

项目 功能
void USART_Init() 串口初始化:波特率,数据字长奇偶校验,硬件流控以及收发使能
void USART_Cmd() 使能串口
void USART_ITConfig() 使能相关中断
void USART_SendData() 发送数据到串口,DR
uint16_t USART_ReceiveData() 接受数据,从DR读取接受到的数据
FlagStatus USART_GetFlagStatus() 获取状态标志位
void USART_ClearFlag() 清除状态标志位
ITStatus USART_GetITStatus() 获取中断状态标志位
void USART_ClearITPendingBit() 清除中断状态标志位

5. 串口配置代码

  • 串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
  • 串口复位:USART_DeInit(); 这一步不是必须的
  • GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
  • 串口参数初始化:USART_Init();
  • 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
    NVIC_Init();
    USART_ITConfig();
  • 使能串口:USART_Cmd();
  • 编写中断处理函数:USARTx_IRQHandler();
  • 串口数据收发:
    void USART_SendData();//发送数据到串口,DR
    uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
  • 串口传输状态获取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
void My_USART1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStrue;
	USART_InitTypeDef USART_InitStrue;
	NVIC_InitTypeDef NVIC_InitStrue;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStrue);
	
	GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStrue);
	
	USART_InitStrue.USART_BaudRate=115200;
	USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
	USART_InitStrue.USART_Parity=USART_Parity_No;
	USART_InitStrue.USART_StopBits=USART_StopBits_1;
	USART_InitStrue.USART_WordLength=USART_WordLength_8b;
	
	USART_Init(USART1,&USART_InitStrue);
	
	USART_Cmd(USART1,ENABLE);
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStrue);
	
	
}

void USART1_IRQHandler(void)
{
	u8 res;
	 if(USART_GetITStatus(USART1,USART_IT_RXNE))
 {
     res= USART_ReceiveData(USART1); 
     USART_SendData(USART1,res);   
  }
}

加上“USART_RX_STA”校验

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
   {
   	Res =USART_ReceiveData(USART1);
   	
   	if((USART_RX_STA&0x8000)==0)
   		{
   		if(USART_RX_STA&0x4000)
   			{
   			if(Res!=0x0a)USART_RX_STA=0;
   			else USART_RX_STA|=0x8000;	
   			}
   		else
   			{	
   			if(Res==0x0d)USART_RX_STA|=0x4000;
   			else
   				{
   				USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
   				USART_RX_STA++;
   				if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;  
   				}		 
   			}
   		}   		 
    } 

参考:

1.正点原子库函数版本实现

相关标签: 异步通信