资讯详情

【STM32】标准库与HAL库对照学习教程八--串口通信详解

【STM32】标准库与HAL对比学习教程8-串口通信

  • 一、前言
  • 二、准备工作
  • 三、通信的基本概念
    • 1、通信方式
    • 2.串行通信和并行通信
      • (1)串行通信
      • (2)并行通信
    • 3、异步通信与同步通信
      • (1)异步通信
      • (2)同步通信
    • 4.单工、半双工和全双工通信
      • (1)单工通信
      • (2)半双工通信
      • (3)全双工通信
    • 5、通信速率
  • 四、STM32F1的USART介绍
    • 1.串口通信简介
    • 2、USART简介
    • 3、USART结构框图
    • 4、USART关键控制位置的寄存器
      • (1)TXE
      • (2)TC
      • (3)RXNE
    • 5、STM32与PC主机通信方式
  • 五、USB转串口模块
  • 六、标准库使用串口中断通信
    • 一、配置步骤
    • 二、配置工程
    • 三、相关程序
    • 四、实验效果
  • 七、HAL库使用串口中断通信
    • 一、cubemx配置工程
    • 二、常用函数讲解
    • 三、主函数程序
    • 四、实验效果
  • 八、关于printf重定向
  • 九、RS232补充说明(选择)
    • 1、接口标准
    • 2.规定逻辑电平

一、前言

本文详细介绍了单片机串口通信,作为串口通信STM32单片机的重要功能在程序调试中起着重要作用。本文从解释通信的基本原理开始,让您一步一步地理解和使用它STM实验过程包括标准库和32串口通信HAL库,例程是串口中断通信实验,您也可以点击目录跳转到您想内容。

二、准备工作

  • 开发板(我用的是普中STM32F103ZE开发板)

三、通信的基本概念

1、通信方式

通信可分为多种方式:

  • 按照可分为
  • 按照通信的,可分为
  • 按照又可分为

让我们简要介绍一下这些通信方式。

2.串行通信和并行通信

(1)串行通信

是指,将,每个数据占据固定的时间长度。 在这里插入图片描述

  • 优点:传输线路少,长途传输成本低。
  • 缺点:数据传输控制比并行通信复杂,速度相对较慢。

(2)并行通信

通常是,通常是8位、16位、32位等数据一起传输。

  • 优点:控制简单,传输速度快。
  • 缺点:长途传输成本高,接收方同时接收困难,抗干扰能力差 。

3.异步通信和同步通信

(1)异步通信

异步通信是指通信的发送和接收设备控制数据的发送和接收过程。 异步通信是以传输,字符之间的间隙(时间间隔)是任意的。

优点:不要求双方收发时钟严格一致,容易实现。 缺点:每个字符应在起止位置附加2~3位,每帧之间有间隔,因此传输效率不高 。

(2)同步通信

建立同步通信。有外同步和自同步两种实现方法。 优点:由于传输,传输效率高。 缺点:同步实现困难,成本高。

4.单工、半双工和全双工通信

(1)单工通信

是指数据传输,只要发送一个设备,接收一个设备。

(2)半双工通信

是指数据传输。也就是说,发送时不能接收,接收时不能发送。

(3)全双工通信

指数据可以。也就是说,发送时可以接收,接收时可以发送。

5、通信速率

衡量通信性能的一个非常重要的参数就是通信速率,通常以(Bitrate)来表示。 ,单位是:位/秒(bps)。 例如:每秒钟传送200个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×200个/秒 = 2000 bps

四、STM32F1的USART介绍

1、串口通信简介

,是指之间,通过等,按,属于。 串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。

2、USART简介

,它能够灵活地与外部设备进行全双工数据交换。,它是在USART基础上裁剪掉了同步通信功能。芯片含有3个USART,2个UART外设。

3、USART结构框图

图片在STM32F1xx中文参考手册 通用同步异步收发器章节

结构图重点在框住的部分,通过寄存器知道串口收发情况。

4、USART寄存器重点控制位

(1)TXE

,为时,移位寄存器,为时,

(2)TC

,为时,中的数据,为时,

(3)RXNE

时,该位为,其他时候为

5、STM32与PC主机通信的方法

串口数据收发线要,并且。 如下图:

五、USB转串口模块

单片机与电脑进行通信需要用到,因为电脑上没有RXD、TXD引脚,并且电脑还要安装。 市场常见的: 接上电脑,TX接单片机的RX,RX接单片机的TX,电源与地接到单片机上就可以串口通信了。 电脑上的CH340驱动我放在网盘上了,有需要自己去下载。 https://pan.baidu.com/s/1bO7mpkwjkB19HXvmD0083Q 密码:kpa6

六、标准库使用串口中断通信

一、配置步骤

(1) (2) (3) (4) (5) (6) (7)

二、配置工程



用来存放与串口相关的文件。


。 ① ②


,并添加。 ① ②


。 ① ②


三、相关程序


#include "LED.h"
#include "Delay.h"
#include "System.h"
#include "usart.h"


/************************************************* *函数名: main *函数功能: 主函数 *输入: 无 *返回值: 无 **************************************************/
int main()
{ 
        
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //抢占式优先级与响应式优先级的分组
	LED_Init();
	USART1_Init(9600);
	while(1)
	{ 
        
		  
	}
}

#ifndef USART_H_
#define USART_H_

#include "stm32f10x.h"

/************串口引脚************/
#define USART1_GPIO_Port GPIOA
#define USART1_RX_Pin GPIO_Pin_10
#define USART1_TX_Pin GPIO_Pin_9

/************串口函数************/
void USART1_Init(u32 bound);          //串口初始化
void USART_SendBit(USART_TypeDef* USARTx,u16 Data);   //发送单个数据
uint16_t USART_ReceiveBit(USART_TypeDef* USARTx);     //接收单个数据
void USART_SendString(USART_TypeDef* USARTx,char *string); //发送字符串


#endif

#include "usart.h"


/************************************************* *函数名: USART1_Init *函数功能: 串口1的初始化 *输入: bound:波特率 *返回值: 无 **************************************************/
void USART1_Init(u32 bound)
{ 
        
	GPIO_InitTypeDef GPIO_InitStruct;
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); //时钟使能
	
	GPIO_InitStruct.GPIO_Pin = USART1_TX_Pin;      //发送引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //发送速度
	GPIO_Init(USART1_GPIO_Port, &GPIO_InitStruct); //引脚初始化
	
	GPIO_InitStruct.GPIO_Pin = USART1_RX_Pin;      //接收引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Init(USART1_GPIO_Port, &GPIO_InitStruct); //引脚初始化
	
	USART_InitStruct.USART_BaudRate = bound; //波特率
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
	USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收发模式
	USART_InitStruct.USART_Parity = USART_Parity_No; //没有校验位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;  //一位停止位
	USART_InitStruct.USART_WordLength = USART_WordLength_8b; //8位一个字节
	USART_Init(USART1, &USART_InitStruct); //初始化串口
	
	USART_Cmd(USART1, ENABLE);  //串口使能
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //接收中断使能
	
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;  //要打开的中断通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; //抢占式优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;   //相应式优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;  //NVIC通道使能
	NVIC_Init(&NVIC_InitStruct);
	
	USART_ClearFlag(USART1, USART_FLAG_TC); //TC位初始值位1,要先清0
}


//直接使用串口发送接收函数会出现内容覆盖的问题,所以需要我们重写函数
/************************************************* *函数名: USART_SendBit *函数功能: 串口发送函数 *输入: Data:发送的数据 *返回值: 无 **************************************************/
void USART_SendBit(USART_TypeDef* USARTx,u16 Data)   
{ 
        
	USART_SendData(USARTx, Data);
	
	//while(!USART_GetFlagStatus(USARTx, USART_FLAG_TXE)); //要等待数据全部转到移位寄存器
	//USART_ClearFlag(USARTx, USART_FLAG_TXE); //清空标志位
	
	while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC));//要等待数据全部发出
	USART_ClearFlag(USARTx, USART_FLAG_TC); //清空标志位
}

/************************************************* *函数名: USART_ReceiveBit *函数功能: 串口接收函数 *输入: USARTx:串口 *返回值: 接收到的数据 **************************************************/
uint16_t USART_ReceiveBit(USART_TypeDef* USARTx)
{ 
        
	while(!USART_GetFlagStatus(USARTx, USART_FLAG_RXNE)); //等待接收的数据全部接收
	USART_ClearFlag(USARTx, USART_FLAG_RXNE);
	return USART_ReceiveData(USARTx);
}

/************************************************* *函数名: USART_SendString *函数功能: 串口发送字符串函数 *输入: USARTx:串口,string:字符型指针 *返回值: 无 **************************************************/
void USART_SendString(USART_TypeDef* USARTx,char *string)
{ 
        
	while(*string)
	{ 
        
		USART_SendBit(USARTx,*string++);
	}
}

/************************************************* *函数名: USART1_IRQHandler *函数功能: 串口中断函数-将从电脑发送的数据发回给电脑 *输入: 无 *返回值: 无 **************************************************/
void USART1_IRQHandler()
{ 
        
	u16 r;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)  //判断中断标志
	{ 
        
		r = USART_ReceiveData(USART1);
		USART_SendBit(USART1,r);
	}
}

四、实验效果

七、HAL库使用串口中断通信

一、cubemx配置工程


打开,新建工程,选择自己的芯片。


,选择




① ②


二、常用函数讲解


  • ;串口发送数据,使用超时管理机制
  • ;串口接收数据,使用超时管理机制
  • ;串口中断模式发送(只触发一次中断)
  • ;串口中断模式接收(只触发一次中断)
  • ;串口DMA模式发送
  • ;串口DMA模式接收
  • ;判断接收与发送是否结束

相关参数:

  • UART_HandleTypeDef *huart
  • *
  • ,接收完成标志
  • ,发送完成标志

  • ;//接收中断回调函数
  • ; //发送中断回调函数
  • void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数
  • void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数

串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改。


三、主函数程序


#include "string.h"
uint8_t Rx_String[100];    //接收字符串数组
uint8_t Rx_Flag=0;         //接收字符串计数
uint8_t Rx_buff;           //接收缓存

HAL_UART_Receive_IT(&huart1, (uint8_t *)&Rx_buff, 1);   //开启接收中断

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{ 
        
	if(huart == &huart1)
	{ 
        
		Rx_String[Rx_Flag++] = Rx_buff;  //接收字符
		if(Rx_String[Rx_Flag-1] == 0x0A) //判断是否接收结束
		{ 
        
			HAL_UART_Transmit(&huart1, (uint8_t *)&Rx_String, Rx_Flag,0xFFFF); //字符串发送
			while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //判断发送是否完毕
			memset(Rx_String,0x00,sizeof(Rx_buff)); //清空接收字符串
			Rx_Flag = 0; //清空计数器
		}
		HAL_UART_Receive_IT(&huart1, (uint8_t *)&Rx_buff, 1);   //再开启接收中断
	}
}

四、实验效果

八、关于printf重定向

C语言中默认输出设备是显示器,如果要实现在 串口或者LCD上显示,必须。比如。 这一过程就叫


将这段程序加入主函数中

int fputc(int ch,FILE *p)  //函数默认的,在使用printf函数时自动调用
{ 
        
	USART_SendData(USART1,(u8)ch);	
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return ch;
}

int fgetc(FILE *p)
{ 
        
  uint8_t ch = 0;
  USART_SendData(USART1, ch);
  return ch;
}

并添加头文件,就可以使用C语言中的将字符串通过串口打印在电脑上了。


将这段程序加入主函数中

/** * 函数功能: 重定向c库函数printf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
int fputc(int ch, FILE *f)
{ 
        
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/** * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
int fgetc(FILE *f)
{ 
        
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

并添加头文件,就可以使用C语言中的将字符串通过串口打印在电脑上了。


九、RS232补充说明(选看)

1、接口标准

串口通信的接口标准有很多,有RS-232C、RS-232、RS-422A、RS-485等。常用的就是RS-232和RS-485。RS-232其实是RS-232C的改进,原理是一样的。这里我们就以RS-232C接口进行讲解。 RS-232C是EIA(美国电子工业协会)1969年修订RS-232C标准。RS-232C定义了数据终端设备(DTE)与数据通信设备(DCE)之间的物理接口标准。 RS-232C接口规定使用25针连接器,简称DB25,连接器的尺寸及每个插针的排列位置都有明确的定义 。

2、逻辑电平规定

RS-232C对逻辑电平也做了规定,如下:

  • 在TXD和RXD数据线上,逻辑1为(-3)V到(-15)V的电压,逻辑0为3V到15V的电压。
  • 在RTS、CTS、DSR、DTR和DCD等控制线上,信号有效(ON状态)为3V到15V的电压,信号无效(OFF状态)为(-3)V到(-15V)的电压。

由此可见,RS-232C是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(TTL)以高低电平表示逻辑状态的规定正好相反

到这里就结束啦!

标签: 针推挽式连接器晶体管输出型cts7

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台