一、硬件连接
连接图
其中,USB转串口硬件的TXD和RXD分别接入stm32的PA10和PA9接口
二、CubeMX配置项目
1.选择芯片
2.设置RCC
3.设置SYS
4.设置USART
5.设置NVIC
6.创建项目
三、使用keil实现STM32给上位机连续发送数据
1.main.c中定义全局变量
char message[]="hello Windows! \r\n";//输出信息
2.main函数中的while循环里添加传输代码
//发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF);
//延时
HAL_Delay(1000);
还需加入头文件#include <string.h>
3.阻塞模式发送函数说明
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
该函数的作用是将数据通过UART发送到外部设备或其他设备。
参数说明:
huart: UART句柄,表示要使用的UART外设。
pData: 要发送的数据的指针,即数据的起始地址。
Size: 要发送的数据的大小,以字节为单位。用sizeof()函数获取发送缓冲区的长度
Timeout: 发送的超时时间,单位为毫秒。如果在指定的时间内发送完成,则函数返回HAL_OK;否则,返回 HAL_TIMEOUT。如果设置为HAL_MAX_DELAY,处理器就会一直等到数据发送完成再执行下一条语句。
4.烧录代码并观察结果
烧录代码
效果
视频
延时
波形图
按下图进行配置
发送了160bit
这里与我们设置的波特率115200误差相差1500hz
while循环中删去延时语句,实验结果
视频
无延时
四、扩展功能
1.功能描述
当上位机给stm32发送一个字符“#”后,stm32暂停发送“hello windows!”;发送一个字符“*”后,stm32继续发送;
2.在main.c文件中定义全局变量
char c;//指令 0:停止 1:开始
char message[]="hello Windows\r\n";//输出信息
char tips[]="CommandError\r\n";//出错
char tips1[]="开始.....\r\n";//开始发送
char tips2[]="停止......\r\n";//停止发送
int flag=0;//标志 0:停止发送 1.开始发送
3.while循环中的代码
if(flag==1){
//发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF);
//延时
HAL_Delay(1000);
}
4.设置接受中断
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
参数说明:
第一个参数是要使用的串口句柄地址
第二个参数是发送缓冲区的首地址,用于存放要发送的数据
第三个参数是发送缓冲区长度
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
添加在main函数中
5.main函数下面写中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令为#时,发送提示并改变flag
if(c=='#'){
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF);
}
//当输入的指令为*时,发送提示并改变flag
else if(c=='*'){
flag=1;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF);
}
//当输入不存在指令时,发送提示并改变flag
else {
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips, strlen(tips),0xFFFF);
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
}
6.烧录及效果
烧录
当发送“*”时,stm32发送“hello Windows!”
当发送“#”时,stm32停止发送
6.效果视频
五、串口中断方式
1.中断模式发送接收函数
发送函数
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
这个函数的目的是启动UART传输并以非阻塞的方式发送一定数量的数据。
参数说明:中断方式的收发函数只有三个参数
第一个参数是要使用的串口句柄地址
第二个参数是发送缓冲区的首地址,用于存放要发送的数据
第三个参数是发送缓冲区长度
接收函数
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
参数说明与发送函数类似,只是把第二个和第三个参数变为了接收缓冲区。
中断模式的前三个参数和阻塞方式完全一致,只是没有了超时时间管理,因为中断(IT)方式配置完成寄存器之后不需要再占用CPU,会在接收/发送数据完成后触发中断,因此不需要超时时间管理机制。
2.创建项目
与上面创建项目步骤相同
3.代码
声明全局变量
int flag=0;//标志位
char c; //输入字符
char message[]="hello Windows!\r\n"; //信息
char tip[]="开始\r\n"; //发送开始
char tip1[]="停止\r\n"; //发送停止
main函数下加入中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令#为时,发送提示并改变flag
if(c=='#'){
flag=0;
HAL_UART_Transmit_IT(&huart1,(uint8_t *)&tip1,5);
}
//当输入的指令为*时,发送提示并改变flag
else if(c=='*'){
flag=1;
HAL_UART_Transmit_IT(&huart1,(uint8_t *)&tip,5);
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
}
main函数
int main(void)
{
/* 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_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if(flag==1)
{
HAL_UART_Transmit_IT(&huart1,(uint8_t *)message,16);
HAL_Delay(1000);
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
4.烧录及运行结果视频
串口中断
六、DMA模式实现
1.什么是DMA
DMA(Direct Memory Access,直接内存访问)是一种计算机系统中用于数据传输的机制。它允许数据在外设和内存之间直接传输,而不需要CPU的介入,从而减轻了CPU的负担,提高了数据传输的效率。
举个例子:
想象一下我们搬家的场景:你要把家里的一些东西从旧房子搬到新房子。在传统的情况下,你要亲自搬每一箱东西,把它们从旧房子搬到新房子。这就相当于CPU传统地处理数据传输的方式。
现在,有一支搬家队,他们专门负责搬家。你只需要告诉他们从哪里搬,搬到哪里,然后他们就会自己完成这项任务。而你可以利用这段时间去做其他事情,不需要亲自动手。这就类似于DMA的工作原理。
在计算机中,CPU通常会处理数据的传输工作,就像你亲自搬家一样。但有了DMA,就有了一支专门负责数据传输的队伍。CPU只需要告诉DMA从哪里搬,搬到哪里,然后就可以去处理其他任务了。DMA负责在外设和内存之间直接传输数据,而不需要CPU一直参与。
简而言之,DMA就像是一支搬家队伍,负责在不需要CPU亲自操劳的情况下完成数据传输任务,从而提高了系统的效率。
2.DMA模式发送接收函数
发送函数
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
接收函数
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
发送和接受函数的参数类型与中断模式的参数一模一样!
3.创建项目
与上文步骤一致,只有USART1这一步不同,查看下方图片
4.代码
定义message变量为“赵小雷”
main函数的while循环里写message下的一句代码
char message [] = "赵小雷\r\n";
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&message, sizeof(message));
5.视频
即stm32用115200bps的速率不断向上位机发送赵小雷
DMA
七、总结
本次实验主要使用了以下三种方式进行USART串口收发数据
1.阻塞模式收发数据
HAL_UART_Transmit():串口发送数据
HAL_UART_Receive(): 串口接收数据
2.中断模式收发数据
HAL_UART_Transmit_IT():串口中断模式发送
HAL_UART_Receive_IT(): 串口中断模式接收
3.DMA模式发送数据
HAL_UART_Transmit_DMA():串口DMA模式发送
八、心得体会
通过本次实验,我对STM32的USART串口通信有了更深入的理解和实践。实验涵盖了三种主要的串口数据传输方式:阻塞模式、非阻塞中断模式、以及DMA模式。每种方式在不同场景下具有不同的应用和优势。
-
阻塞模式: 阻塞模式下,数据传输过程会等待完成,CPU在发送或接收数据时会一直等待,直到任务完成后再进行下一步操作。这种方式简单易用,但由于其阻塞特性,会使得系统在等待期间无法执行其他任务,因此适用于对实时性要求不高的简单应用。
-
中断模式: 中断模式下,数据传输由中断触发,传输任务不会阻塞CPU的其他操作。通过设置中断回调函数,可以在数据传输完成后进行后续操作。中断模式适合处理需要实时响应的任务,但要注意中断优先级的管理,避免系统进入死锁状态。
-
DMA模式: DMA模式可以实现高效的数据传输,尤其在需要传输大量数据时,它通过直接内存访问来减轻CPU负担,大大提高了数据传输的效率。通过DMA,STM32能够在后台传输数据,而不需要CPU干预,这对于实时性要求高的应用非常有用。
心得体会:
学习过程:通过实验,我不仅了解了不同模式下的串口通信方式,还掌握了如何使用HAL库提供的相关API来实现不同模式的串口通信。每种模式的特点和使用场景都有所不同,理解其工作原理对项目开发至关重要。
实际应用:通过实验中的扩展功能,当STM32收到上位机的指令时,能够暂停或继续发送数据,这为我将来在实际项目中处理数据流控制和通信协议提供了很好的参考。对于上位机与STM32的通信,能够灵活使用不同的模式,根据实时要求选择合适的通信方式。
挑战与收获:在实验过程中,我遇到了串口中断和DMA的配置难题,特别是在中断优先级和DMA缓冲区管理方面。通过查阅资料和调试,我逐渐克服了这些困难,并成功实现了STM32与上位机的稳定通信。这些经验不仅加深了我对STM32硬件和通信原理的理解,还让我在编程和调试能力上得到了提升。
总之,本次实验让我对STM32串口通信有了全面的认识,并为我今后进行嵌入式开发奠定了坚实的基础。