STM32串口通信基本原理

Posted 想成为大师啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32串口通信基本原理相关的知识,希望对你有一定的参考价值。

参考正点原子视频

通信方式

并行通信

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

串行通信

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

串行通信

按照数据传送方向,分为

  • 单工:数据传输只支持数据在一个方向上传输
  • 半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信
  • 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力

串口通信三种传送方式

在这里插入图片描述

串行通信的通信方式

  • 同步通信:带时钟同步信号传输。 -SPI,IIC通信接口
  • 异步通信:不带时钟同步信号。 -UART(通用异步收发器),单总线

在同步通信中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。例如,通讯中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样。

在异步通信中不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些用于同步的信号位,或者将主题数据进行打包,以数据帧的格式传输数据。通讯中还需要双方规约好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。

在同步通讯中,数据信号所传输的内容绝大部分是有效数据,而异步通讯中会则会包含数据帧的各种标识符,所以同步通讯效率高,但是同步通讯双方的时钟允许误差小,稍稍时钟出错就可能导致数据错乱,异步通讯双方的时钟允许误差较大。

常见的串行通信接口

在这里插入图片描述

STM32的串口通信接口

  • UART:通用异步收发器
  • USART:通用同步异步收发器

UART异步通信方式引脚连接方式

  • RXD:数据输入引脚。数据接收
  • TXD:数据发送引脚。数据发送

在这里插入图片描述
在这里插入图片描述

UART异步通信方式特点

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

串口通信过程

在这里插入图片描述

STM32串口异步通信需要定义的参数

  1. 起始位
  2. 数据位(8位或者9位)
  3. 奇偶校验位(第9位)
  4. 停止位(4,15,2位)
  5. 波特率设置

在这里插入图片描述

USART框图

在这里插入图片描述

常用的串口相关寄存器

  • USART_SR状态寄存器
  • USART_DR数据寄存器
  • USART_BRR波特率寄存器

波特率计算方法

在这里插入图片描述

串口操作相关库函数

void USART_Init();//串口初始化:波特率,数据字长,奇偶检验位,硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断

void USART_SendData();//发送数据到串口,DR
uint16_ USART_ReceiveData();//接受数据,从DR读取接受到的数据

FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearTPendingBit();//清除中断状态标志位

USART_InitTypeDef

typedef struct
{
  //设置波特率
  uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
                                           The baud rate is computed using the following formula:
                                            - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
                                            - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
  //设置字长度
  uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.
                                           This parameter can be a value of @ref USART_Word_Length */
  //设置停止位
  uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.
                                           This parameter can be a value of @ref USART_Stop_Bits */
  //设置奇偶校验
  uint16_t USART_Parity;              /*!< Specifies the parity mode.
                                           This parameter can be a value of @ref USART_Parity
                                           @note When parity is enabled, the computed parity is inserted
                                                 at the MSB position of the transmitted data (9th bit when
                                                 the word length is set to 9 data bits; 8th bit when the
                                                 word length is set to 8 data bits). */
  //设置通信模式
  uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
                                           This parameter can be a value of @ref USART_Mode */
  //设置硬件流
  uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
                                           or disabled.
                                           This parameter can be a value of @ref USART_Hardware_Flow_Control */
} USART_InitTypeDef;

串口配置的一般步骤

STM32串口配置的一般步骤(库函数)

  1. 串口时钟使能:RCC_APBxPeriphClockCmd();
    GPIO时钟使能:RCC_AHBxPeriphClockCmd();
  2. 引脚复用映射:GPIO_PinAFConfig();
  3. GPIO端口模式配置:GPIO_Init(); 模式配置为GPIO_Mode_AF_PP
  4. 串口参数初始化:USART_Init();
  5. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
    NVIC_Init();
    USART_ITConfig();
  6. 使能串口:USART_Cmd();
  7. 编写中断处理函数:USARTx_IRQHandler();
  8. 串口数据收发:
    void USART_SendData();//发送数据到串口,DR
    uint16_t USART_ReceiveData();//接收数据,从DR读取接收的数据
  9. 串口传输状态获取:
    FlagStatus USART_GetFlagStatus();
    void USART_ClearITPendingBit();

例子配置

void uart_init(u32 bound){
  GPIO_InitTypeDef GPIO_InitStructure;//GPIO端口设置
	USART_InitTypeDef USART_InitStructure;//USART端口设置
	NVIC_InitTypeDef NVIC_InitStructure;//NVIC中断设置
	 
	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;//速度50MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//根据指定参数初始化GPIOA
   
  //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);	//根据指定的参数初始化NVIC
  
   //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);//开启串口接受中断(USART1_IRQHandler)
  USART_Cmd(USART1, ENABLE);//使能串口1

}

void USART1_IRQHandler(void)//串口1中断服务程序
	{
	u8 Res;//8位无标志字符
#if SYSTEM_SUPPORT_OS  //如果SYSTEM_SUPPORT_OS为真,则需要支持OS
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接受中断(接收到的数据必须是0x0d 0x0a结尾)		
	{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了
				}
			else //还没收到0x0d
				{	
				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;//接收数据错误,重新开始接收  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS
	OSIntExit();  											 
#endif
}

以上是关于STM32串口通信基本原理的主要内容,如果未能解决你的问题,请参考以下文章

STM32驱动开发--串口原理与开发实践

基于是stm32的串口通信

基于STM32F103入门4——串口通信

基于STM32F103入门4——串口通信

基于STM32F103入门4——串口通信

嵌入式09STM32串口通信协议