学习计划
- 每天更新STM32学习笔记
一、串口通信知识点
- 串口通信的数据按位顺序传输,其数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口,故串口通信至少需要两根线(GND和一根信号线)来实现单工通信。若要实现全双工通信,则要三根线(GND和两根信号线)。
- 串口通信的数据包由起始位、数据位(5~8位)、校验位(奇\偶\无校验位)以及停止位组成,通信双方的数据包格式要约定一致才能正常收发数据。
- 串口通信速率:波特率,单位Bits/s。
- UART只用于异步通信;USART用于同步/异步通信。若为同步通信,则要加一根时钟线。
嵌入式中的通讯协议——UART、I2C、SPI、DMA
二、硬件部分
1.所需硬件
STM32F407ZGT6相关开发板、USB转TTL、STLINK下载器
2.部分硬件连接
USB转TTL-----------STM32
RXD-------------------PA9
TXD-------------------PA10
STLINK--------------STM32
SWCLK--------------PA14
SWDIO--------------PA13
三、阻塞式
0、串口阻塞式发送和接收概念
串口阻塞发送:发送一段数据,在没有发送完所有数据之前,一直停留在此发送函数(可设定阻塞时间),这个过程中会阻塞别的程序运行;
1、STM32CUBEMX配置
在STM32CUBEMX中配置时钟树、选择系统调试方式后,STM32CUBEMX入门
配置串口参数:异步,115200,8,NONE,1。
2、编写阻塞式串口发送与接收代码
生成代码后,在main.c文件-while死循环前添加代码:
//阻塞式发送
HAL_UART_Transmit(&huart1, (uint8_t *)"HELLO", 5, 20);
//写在while死循环前只发送一次HELLO
在main.c文件-while死循环中添加代码:
//阻塞式接收
uint8_t rev[5];
HAL_UART_Receive(&huart1 ,rev, 3, 0xFFFF);//接收:串口1句柄、接收区首地址、接收的字节数、超时时间ms
HAL_UART_Transmit(&huart1, rev, 3, 0xFFFF);//接收到的数据,发送回去,验证是否发送成功
3、学习小技巧
编写阻塞式串口发送代码在学习的过程中可以通过左侧Functions栏,找到所需函数。
如需要串口发送函数:
4、程序编译与下载
编译成功后,连接好STLINK下载器,点击下载。
5、程序验证
连接USB转TTL模块,打开XCOM软件。
程序验证成功!
6、重定向printf和scanf
为了简写,需要重定向printf和scanf。但是printf()这个函数是格式化输出到屏幕的,scanf()函数又是格式化输入(从屏幕),并不能输出到串口助手中,所以需要进行重定向。
-
6.1、首先我们需要在keil集成开发环境中勾选STM32官方的微库(MicroLib是针对以C语言编写的基于ARM嵌入式应用程序的高度优化的库)。
-
6.2、引用标准库的头文件
#include <stdio.h>//引用标准库的头文件,重定义printf,scanf
- 6.3、添加重定向代码
//因为printf内部就是调用fputc进行单个字符输出,
//所以重定向printf就将单个字符以串口的形式发送出去。
int fputc(int c,FILE *f)//重定向printf
{
uint8_t ch[1]={c};
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
return c;
}
int fgetc(FILE *stream)//重定向scanf
{
uint8_t ch[1];
HAL_UART_Receive(&huart1, ch, 1, 0xFFFF);
return ch[0];
}
- 6.4、使用printf和scanf函数实现阻塞式串口发送与接收
printf("ABC%d",123);//写在while死循环前,只发送一次ABC123
int i=0;
scanf("%d",&i);//用scanf接收数据,scanf通过回车判断结束的,所以接收的字节数要+2 \r\n
printf("%d\r\n",i);//接收到的数据,用printf发送回去,验证是否发送成功
- 6.5、程序验证
三、中断式
0、串口中断式发送和接收概念
串口中断发送:送数据的过程在中断中进行,这个中断实际上是发送数据寄存器空的中断。
1、STM32CUBEMX配置更新
在阻塞式STM32CUBEMX配置上进行更新,再重新生成代码,自己写的阻塞式代码删除,学习中断式:
2、编写中断式串口发送与接收代码
//main函数中,在while循环前
//中断式发送
HAL_UART_Transmit_IT(&huart1, (uint8_t *)"HELLO", 5);//调用次函数,每发完一个字节就会进入一次中断, 在中断中,HAL库会自动触发下一个中断,直到发送完数据
//中断式接收
//uint8_t rev[5];//不能定义局部变量,要定义全局变量,因有可能在接收到数据时,改局部变量已经被销毁了。
HAL_UART_Receive_IT(&huart1 ,rev, 3);//当接收完数据时,会直接进入接收回调函数,要在接收回调函数中写发送代码,实现与阻塞式一样的效果
//接收回调函数,写在main.c文件中
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit_IT(&huart1, rev, 3);//接收到的数据,发送回去,验证是否发送成功
HAL_UART_Receive_IT(&huart1 ,rev, 3);//开启下一次接收中断
}
uint8_t rev[5];//全局变量
3、程序验证
四、DMA
0、DMA概念
DMA传输是将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。
1、STM32CUBEMX配置更新
在中断式STM32CUBEMX配置上进行更新:
USART1-DMA Setting-选择发送和接收,再重新生成代码:
2、编写DMA式不定长串口发送与接收代码
//在main.h中创建串口接收结构体
#define RX_BUF_MAX_LEN 512
typedef struct
{
uint8_t rx_buff[RX_BUF_MAX_LEN];//缓存区
uint16_t len; //接收长度
}USRAT_RX;
//在stm32xxxx_it.c中定义结构体变量
/* USER CODE BEGIN PV */
USRAT_RX usart1_rx;//首先定义一个结构体变量
/* USER CODE END PV */
//在stm32xxxx_it.c中找到串口1中断服务函数,编写不定长串口收发程序
void USART1_IRQHandler(void)//串口1中断服务函数,当串口1产生任何中断都会进入此函数
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE) != RESET)//如果空闲中断不为0 RESET,表示此时触发了空闲中断,收到一帧数据
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除空闲中断
HAL_UART_DMAStop(&huart1);//停止串口1的DMA传输
usart1_rx.len = RX_BUF_MAX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx); //计算接收到的数据长度:要接收到的字节数总数-剩余数=实际接收数
HAL_UART_Transmit_DMA(&huart1,usart1_rx.rx_buff,usart1_rx.len);
HAL_UART_Receive_DMA(&huart1,usart1_rx.rx_buff,RX_BUF_MAX_LEN);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
//在main.c中声明结构体变量
extern USRAT_RX usart1_rx;
//在main.c中添加string.h头文件,编写串口结构体初始化函数
#include <string.h>//使用memset函数,需引用此头文件
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void Clear_Usart(USRAT_RX *usart_rx)
//初始化(清空)串口结构体
{
memset((uint8_t*)usart_rx,0,sizeof(USRAT_RX));
}
/* USER CODE END 0 */
//在main.c中while循环前
/* USER CODE BEGIN 2 */
Clear_Usart(&usart1_rx); //初始化串口结构体
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能串口1的空闲中断,由于HAL库没有提供空闲函数的回调函数,所以要在串口中断服务函数中添加代码
HAL_UART_Receive_DMA(&huart1,usart1_rx.rx_buff,RX_BUF_MAX_LEN); //打开DMA传输模式
/* USER CODE END 2 */
3、程序验证
文章来源:https://www.toymoban.com/news/detail-759119.html
参考文章
嵌入式中的通讯协议——UART、I2C、SPI、DMA
STM32F4_HAL库_串口阻塞/中断/DMA三种方式发送数据的配置
【STM32】 DMA原理,步骤超细详解,一文看懂DMA
STM32串口DMA模式发送接收数据并控制LED灯
【STM32F4+CubeMX零基础快速入门】串口收发全攻略文章来源地址https://www.toymoban.com/news/detail-759119.html
到了这里,关于【STM32串口通信】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!