STM32零基础入门(四)USART 串口

本文详细介绍了STM32中USART通信的基本原理,包括协议、波特率、数据信号构成,以及标准库和HAL库的使用方法,重点讲解了阻塞式、中断式和DMA模式的串口操作,以及CUbeMx配置和代码示例。
摘要由CSDN通过智能技术生成

前言

      最近因为一些私人事情断更了一段时间,跟大家说声抱歉,现在我回来更新了,感谢大家的支持,有不会的欢迎评论区留言。

    对于标准库的同学,基础阶段的USART基本只用到发送(USART_SendData)和接收(USART_ReceiveData)两个基础函数,想要学会自己写代码,就在我讲的这篇文章之后自己再仔细阅读uasrt.h文件,学习使用里面的各种函数,根据函数定义的参数去配置使用,才能精准深刻的掌握串口功能。这里推荐大家去看B站江协科技讲解的STM32入门教程,非常通透详细,简直是我偶像。

对于HAL库的同学,原理部分和标准库是一样的,我也推荐大家去看B站江协科技讲解的STM32入门教程里面的原理,真的很棒,一下就懂了,我的写作能力还有待提升。我上传了之前给社团新人做培训演示的实验代码,但是把各种通讯方式写一起了,但是我有标注释学会了很好改。

一 原理

1.1 具象化理解

        生活中,我们想给一个人传递消息,首先,必须用相同的语言,我们没有办法让只会中文的人和只会英文的人不借助任何翻译软件去进行沟通;其次,两个人的语速要适中,一个刚刚学会英语的人A,和英语母语者B沟通,如果A不放慢语速,B也是听不懂的。

所以,沟通需要两个因素:相同的协议、相同的传输速率。

1.2 回归板子

        单片机和另一个物体通信,也是同理。在这里,我们需要相同的协议和相同的波特率。

1.2.1 协议:通信的规则

名称

工作方式

时钟

通信对象

USART

全双工

异步

1V1

I2C

半双工

同步

多对多

SPI

全双工

同步

多对多

CAN

半双工

异步

多对多

USB

半双工

异步

1V1

PS:  单  工:发送端接收端固定,信道单向。

半双工:发送端接收端可以互换,信道双向,但是同一时刻信息只能在一个方向传输。

全双工:发送端接收端可以互换,信道双向,但是同一时刻信息可以双向传输。

1.2.2 波特率 

串口通信的速率,即每秒传输二进制的位数。

1.3 看懂原理图

我们要设置串口通信的引脚,需要看自己板子的引脚图,找到对应的功能设置引脚,如下图所示,找到标有USARTx的引脚进行配置即可(串口引脚x=1、2要成套,例如PA9和PA10)

1.4 硬件连接

USART是STM32中一个真实存在的硬件外设(刚从软件转过嵌入式的同学注意转换观念,他不是一个虚构的指令),它可以根据数据寄存器的一个字节数据生成顺序的数据帧,这些数据被A外设的TX引脚传给B的RX,这样B就可以处理通信传输过来的数据了。同理,

A是从RX引脚接收传输过来的数据的。

硬件连接示意图如下图所示:

1.5 数据信号

数据信号可以理解为从A地寄到B地的一个快递包裹,它整体由起始位、数据位、校验位、停止位组成,这个数据信号一共有8位或9位,下面是一个具象的数据位的示意图

起始位:第一个低电平开始,告诉接收端开始接收

数据位:传递消息的部分,是数据信号承载信息的部分

校验位:检查数据是否正确。发送方根据配置按照校验规律进行发送,接收端发现不符合校验规律则说明传输错错误。

奇校验:数据位和校验位中逻辑为1的个数为奇数。

偶校验:数据位和校验位中逻辑为1的个数为偶数。

停止位:表示数据帧的停止,表现为高电平。

1.6 通信方式

阻塞式:我们要传输的数据都传输/接收完成之后,这个函数才会执行结束。

中断式:避免阻塞式缺点,减少CPU浪费,节省时间。每发完一个字节就进入一次中断,HAL库自动触发下一次字节的传送,直到发完所有目标数据进入回调函数,节省时间,释放出while循环。

DMA:单片机数据传输助手,(内存与内存之间,内存与外设之间)CPU只需要告诉DMA搬运哪些数据而不需要去控制每个字节的传输,这样可以降低CPU的负载。DMA可以自动把数据依次通过串口发出,也可以把串口收到的数据自动保存在内存中,CPU只需要为DMA设定内存空间而不需要去处理。

注:电脑和单片机通信要加USB-TTL模块。因为电脑是USB接口,电平逻辑遵循USB原则,单片机串行通信的电平逻辑遵循TTL原则,USB-TTL模块就是将电平转换为双方都能识别的逻辑进行通信。

二. 上手

2.1 标准库

2.1.1 配置

  1. 在所有的标准库的目的功能配置之前要把所有用到的时钟配好:(本次实验串口和GPIO)
  2. 初始化:GPIO  TX复用输出RX输入(例Pin=PA9,Mode=复用输出;Pin=PA9,Mode=输入)

                       USART 直接配置所有结构体。

     3.只发送:直接开启USART

        需要接受:配置中断(ITConfig、NVIC)之后开启中断

2.2 CUbeMx

2.2.1 配置

中断/DMA配置

注意:一定注意勾选上!

2.2.2 代码

HAL库中printf /scanf的使用
int fputc(int c,FILE *stream)   //重定向c库函数getchar,printfDEBUG_USARTx
{
  uint8_t ch[1]={c};//定义一个数组保存字符  
  HAL_UART_Transmit(&huart1,ch,1,0xFFFFF);//调用函数串口发送
  return c;
}
int fgetc(FILE *stream)     //重定向c库函数getchar,scanf到DEBUG_USARTx
{
  uint8_t ch[1];
  HAL_UART_Receive(&huart1, ch, 1, 0xFFFF);
  return ch[0];
}
阻塞式

HAL_UART_Transmit();串口发送数据,使用超时管理机制

HAL_UART_Receive();串口接收数据,使用超时管理机制

中断式

HAL_UART_Transmit_IT();串口中断模式发送  

HAL_UART_Receive_IT();串口中断模式接收

          串口中断接收,以中断方式接收指定长度数据。大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)

串口中断处理函数: HAL_UART_IRQHandler(UART_HandleTypeDef *huart);

          功能:对接收到的数据进行判断和处理 判断是发送中断还是接收中断,然后进行数据的发送和接收,在中断服务函数中使用 如果接收数据,则会进行接收中断处理函数 如果发送数据,则会进行发送中断处理函数

 串口接收中断回调函数: HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  

         功能:HAL库的中断进行完之后,并不会直接退出,而是会进入中断回调函数中,用户可以在其中设置代码, 串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改

举例:   HAL_UART_RxCpltCallback(&huart1)                

        {  

                           //用户设定的代码            

             }

DMA

代码:  中断换成DMA ,效果相似 

HAL_UART_Transmit_DMA();串口DMA模式发送

HAL_UART_Transmit_DMA();串口DMA模式接收

区别:中断每个字节都要进行一次中断

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#include <string.h>
#include <stdio.h>
 
#define RXBUFFERSIZE 256     //最大接收字节数
char RxBuffer[RXBUFFERSIZE];  //接收数据
uint8_t aRxBuffer;			//接收中断缓冲 
uint8_t Uart1_Rx_Cnt = 0;		//接收缓冲计数

/* USER CODE END PTD */
/* USER CODE BEGIN PV */
uint8_t buffer[5];       

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE BEGIN 0 */
/*int fputc(int c,FILE *stream)   //重定向c库函数getchar,scanf到DEBUG_USARTx
{
	uint8_t ch[1]={c};//定义一个数组保存字符  
	HAL_UART_Transmit(&huart1,ch,1,0xFFFFF);//调用函数串口发送
	return c;
}
int fgetc(FILE *stream)     //重定向c库函数getchar,scanf到DEBUG_USARTx
{
  uint8_t ch[1];
  HAL_UART_Receive(&huart1, ch, 1, 0xFFFF);
  return ch[0];
}*/

//void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
//{
//	
//	HAL_UART_Transmit_DMA(&huart1,buffer,3);
//	HAL_UART_Receive_DMA(&huart1,buffer,3);
//}
/* USER CODE END 0 */
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);        //中断接收
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		//HAL_UART_Transmit(&huart1,(uint8_t*)"Hello",5,0xFFFF);                   //阻塞式串口发送函数
		
		/*uint8_t buf[5];//找到一块区域存放接收到的数据
		HAL_UART_Receive(&huart1,buf,3,0xFFFF);//接收三个字节到数组buf里面          //阻塞式串口接收函数
		HAL_UART_Transmit(&huart1,buf,3,0xFFFF);*///发送验证接收到的数据是否正确
		
		/*printf("Hello %d\r\n",123);
		HAL_Delay(1000);                    //阻塞式串口函数printf
		int val=0;
		scanf ("%d",&val);
    printf(" %d\r\n",val);		*/        //阻塞式串口函数scanf 
		
		
		
		
		
  }
  /* USER CODE END 3 */
}

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值