重庆交通大学信息科学与工程学院
《嵌入式系统基础 A》课程
实验报告
班 级: 物联网工程 2101
**姓名-学号 : 江欣朋-632007060322 **
实验项目名称: 基于中断/DMA 的串口通信
**实验项目性质: 设计性 **
**实验所属课程: 《嵌入式系统基础 A》 **
**实验室(中心): 南岸校区语音大楼 **
**指 导 教 师 : 娄路 **
完成时间: 2023 年 10 月 28 日
一、实验内容和任务
1.了解串口协议和 RS-232 标准,以及 RS232 电平与 TTL 电平的区别;了解"USB/TTL 转 232"模块(以 CH340 芯片模块为例)的工作原理。 使用 HAL 库(或标准库)方式,设置 USART1 波特率为 115200,1 位停止位,无校验位,分别采用中断方式、DMA 方式完成下列任务:
STM32 系统给上位机(win10)连续发送“hello windows!”;当上位机给 stm32 发送字符“stop”后,stm32 暂停发送“hello windows!”;发送一个字符“start”后,stm32 继续发送;
参考网址:STM32 串口通信 USART 学习笔记
基于 MDK 创建 STM32 汇编程序:串口输出 Hello worldSTM32最小核心板F103串口通信USART_f103 usart-CSDN博客
HAL 库中断方式进行串口通信
HAL库中断方式进行串口通信-CSDN博客
基于 HAL 库实现 DMA 串口通信
基于HAL库实现DMA串口通信_hal_dma_start_it-CSDN博客
在没有示波器条件下,可以使用 Keil 的软件仿真逻辑分析仪功能观察串口输出波形,并分析时序状态正确与否,计算波特率实际为多少。
参考:stm32外部中断模式控制灯亮灭_stm32编程后怎么停下来-CSDN博客HAL库中断方式进行串口通信-CSDN博客https://www.cnblogs.com/breezy-ye/articles/12157442.html
【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)_stm32h7 串口dma 发送 第一次成功-CSDN博客
二、实验要求
1. 分组要求:每个学生独立完成,即 1 人 1 组。
2. 程序及报告文档要求:具有较好的可读性,如叙述准确、标注明确、截图清晰等。
3.把项目完整打包为 zip 文件,与实验报告(Markdown 源码及 PDF 文件)、作业博客地址一起提交到学习通。
三. 实验过程介绍 (此处可以填博客内容)
1. 用 stm32F103 核心板的 GPIOA 端一管脚接一个 LED,GPIOB 端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED 亮灯;接低电平时,LED 灭灯。
一丶通过 STMCube 配置项目 RCC 配置:
SYS 配置:
SYS 配置:
CLOCK:
配置 GPIO:
这里要注意: 把 A4 配置为高电平 把 B9 中断配置为上升沿和下降沿都触发 然后创建项目就 OK
二、通过 KEil 配置代码 在 main.c 中加入:
注意不是加入到 int main 函数当中; 然后编译生成 hex 文件 然后烧录
实例: 插入 B9 灯灭
2. 采用串口中断方式重做上周的串口通信作业,分别实现:1)当 stm32 接收到字符“s”时,停止持续发送“hello windows!”; 当接收到字符“t”时,持续发送“hello windows!”(提示:采用一个全局标量做信号灯);2)当 stm32 接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”
1) (1)STM32CubeMX 配置 USART1 设置:
RCC 设置:
sys 配置:
USART1 选上这个
(2)编写代码 在 main.c 里声名全局变量
main.c 全部函数
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include <string.h>
void SystemClock_Config(void);
char c;//指令 0:停止 1:开始
char message[]="hello Windows\n";//输出信息
char tips[]="CommandError\n";//提示1
char tips1[]="Start.....\n";//提示2
char tips2[]="Stop......\n";//提示3
int flag=0;//标志 0:停止发送 1.开始发送
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
//设置接受中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
//当flag为1时,每秒发送一次信息
//当flag为0时,停止
while (1)
{
if(flag==1){
//发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF);
//延时
HAL_Delay(1000);
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令为0时,发送提示并改变flag
if(c=='t'){
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF);
}
//当输入的指令为1时,发送提示并改变flag
else if(c=='s'){
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);
}
/* USER CODE END 4 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
重写中断函数
实例:
- 在 main.c 和 usart.c 中添加头文件#include "stdio.h"之后,在 usart.c 文件中,添加如下代码,进行重定义
在 main.c 中设置两个字符型数组,用来存放需要判别的字符串(记得添加头文件#include "string.h")。同时设置 FLAG 标志变量,来判断电脑向 stm32 发送了哪一个字符串。
uint8_t aRxBuffer;
uint8_t Uart1_RxBuff[256];
uint8_t str1[20]="go stm32!";
uint8_t str2[20]="stop stm32!";
uint8_t Uart1_Rx_Cnt=0;
uint8_t cAlmStr[]="数据溢出(256)\r\n";
在 main.c 主函数 while(1)中添加一下内容(根据你要发送的字符串来修改)
修改回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
if (strcmp(Uart1_RxBuff, str1) == 0) flag = 0;
if (strcmp(Uart1_RxBuff, str2) == 0) flag = 1;
//if(Uart1_RxBuff[0]=='g') flag = 1;
//if(Uart1_RxBuff[0]=='s') flag = 0;
if(Uart1_Rx_Cnt >= 255) //溢出判断
{
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);
}
else
{
Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer; //接收数据转存
if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
{
HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff)); //清空数组
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1); //再开启接收中断
}
实例演示:
3. STM32 采用串口 DMA 方式,用 115200bps 或更高速率向上位机连续发送数据。
一、工程设置: 1.sys 设置
2.RCC 设置
设置串口
DMA 设置
点击 DMA Setting 的 Add 添加通道,传输速率设置为中速 Medium
在 main.c 文件添加代码
在 while 函数中加入
实例演示:
总结:此次实验我们学习了如何使用串口 DMA 方式向上位机连续发送数据,如何使用串口中断。这次实验让我收获不少,做实验也越来越有心得,更加熟练,希望以后实验也能做好。