STM32CubeMx实现串口通信
使用CubeMx来实现USART的阻塞式接受和发送,中断式接受和发送,中断+DMA接受和发送。
一、环境
硬件:STM32F103C8T6核心板
软件:STM32CubeMx
软件:Keil5 MDK
二、使用STM32CubeMx
1、选择芯片型号
我使用的是STM32F103C8T6的芯片,大家可以选择自己需要的芯片类型。
2、配置SYS
点击System Core下拉栏的SYS,选择Debug调试,我选择的是serial wire。
3、配置RCC
配置RCC时钟,点击HSE,选择Crystal/Ceramic Resonator。
进行系统的具体时钟配置,点击Clock Configuration选择栏,将时钟配置如图显示。
4、启动USART1
点击Connectivity,选择USART1,配置成Asynchronous。
5、项目名称和配置
点击Project Name,选择project,填写项目的名称。
在Code Generator 点击生成独立的C、H文件,然后点击生成文件。
打开生成的工程,编译一下,查看是否有错。
三、USART
1、阻塞式发送
使用HAL_UART_Transmit()函数发送
点击main.c文件,在主函数里面,添加两行代码:
HAL_UART_Transmit(&huart1,(uint8_t*)"Hello World",11,0xFFFF);
HAL_Delay(500);
代码编译成功之后,点击烧入单片机,(我使用的是最新的KEI软件,有个BUG就是,烧入代码之后需要按下复位键,代码才会执行,可以在魔术棒那里,点击Debug,点击Pack,取消ENABLE)。
打开串口调试助手,连接串口,查看信息
可以看到串口助手,每500ms打印一次Hello World。
2、Printf 串口打印
通过对printf重定向,使用printf 可以用来串口打印数据。
在主函数里面,添加头文件 stdio.h,在对printf 进行重定向,在后面增加函数:
int fputc(int c,FILE *f)
{
uint8_t ch[1]={c};
HAL_UART_Transmit(&huart1,ch,1,0xFFFF);
return c;
}
在while函数 注释之前写的,添加:
printf("Hello World\r\n");
HAL_Delay(500);
使用MicroLIB,需要勾选。
添加函数后,点开魔术棒,勾选Use MicroLIB,然后编译代码,零个错误,下载成功之后。就打开串口查看结果。
倘如出现以下问题
出现这个问题就打开以下文件
将60行和289行注释一下,编译以下,在取消注释,编译一下,就解决问题了,这个应该是MDK的BUG吧
串口调试结果。
3、阻塞式接收
使用HAL_UART_Receive()函数接收。
在主函数定义一个接收缓存的Buf,在while调用HAL_UART_Receive函数,接收串口发来的数据,为了验证是否接收,我们在后面调用HAL_UART_Transmit函数,将接收的数据打印在串口里面。
HAL_UART_Receive(&huart1,Buf,5,0xFFFF);
HAL_UART_Transmit(&huart1,Buf,5,0xFFFF);
HAL_Delay(500);
在串口助手,发送区输入 Hello,点击发送,可以看到接收区会显示Hello,证明接收成功,多点击几次发送Hello,查看接收数据有误丢失。
4、中断式发送和接收
阻塞的发送,太浪费CPU了,中断式发送使用HAL_UART_Transmit_IT()函数。
在上述CubeMX配置基础上,继续配置NVIC中断
点击NVIC,我们点击USART1,将中断打开,然后生成代码。
打开STM32F1xx.it.c文件,找到USART1_IRQHandler(void),在里面添加代码:
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE)!=RESET)
{
uint8_t ch;
ch=READ_REG(huart1.Instance->DR);
WRITE_REG(huart1.Instance->DR,ch);
}
在串口初始化里面添加启动中断代码:
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
编译成功后,点击烧入,就可以打开串口调试助手了。
在发送区里面我相继发送了Hello 、Hello World、Hello World Hello World Hello World、在接受区可以查看结果,采用的不定长发送,无论发送多少数据,都可以接收。
5、中断+DMA发送和接收
首先打开CubeMx,在USART1添加DMA
点击USART1,打开DMA设置,点击add,添加USAER1_RX,USART1_TX.再点击生成代码。
在main.定义一个接受100的数组,大家需要发送更大的数量,可以自行更改,在main.h声明外部可调用。
在usart.c文件里面的USART1初始化中,我们需要先打开接受DMA,在启动空闲中断,添加代码:
HAL_UART_Receive_DMA(&huart1,DMA_Buf,100);
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
在STMF1xx.it.c文件中,找到USART1串口中断,添加代码:(感谢提醒,上图漏了一行HAL_UART_DMAStop(&huart1),下面代码已纠正)。
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);//先关闭接收
uint8_t len=100-__HAL_DMA_GET_COUNTER(huart1.hdmarx);//计算实际接收到的数据的长度
HAL_UART_Transmit_DMA(&huart1,DMA_Buf,len);//发送回去
HAL_UART_Receive_DMA(&huart1,DMA_Buf,100);//重新启动接收
}
进入中断后,先清除标志位,在计算DMA的数量,将接受的通过HAL_UART_Transmit_DMA函数发送,在启动一次DMA接受,点击编译,编译成功后,打开串口助手。
在发送区,我们输入自己发送的值,可以查看接受区是否有数据,我定义的是100的数组,最多传送的数据为一百。
本次讲解了USART的三种使用方法,分别是阻塞式发送和接受,中断式发送和接受,中断+DMA式发送和接受。