第8周实验 基于中断/DMA方式的串口通信
一、DMA串口通信与中断
DMA (Direct Memory Access) 是一种数据传输方式,用于实现高速的设备之间的数据传输,而不需要 CPU 的干预。在传统的串口通信中,数据的传输需要 CPU 介入,通过轮询或中断的方式进行数据的收发。而使用 DMA 串口通信,可以通过 DMA 控制器直接进行数据的传输,减轻了 CPU 的负担,提高了数据传输的效率。
DMA 串口通信的流程如下:
- 配置串口通信参数:包括波特率、数据位数、停止位等参数;
- 配置 DMA 控制器:设置 DMA 通道和传输方向(接收或发送);
- 配置 DMA 缓冲区:设置用于数据传输的缓冲区地址和大小;
- 启动 DMA 传输:通过编程方式启动 DMA 传输;
- 在传输完成后,DMA 控制器会触发中断通知 CPU。
中断是一种机制,用于处理异步事件或外部设备的请求。在串口通信中,中断可以用于通知 CPU 数据的传输完成或数据的接收。当 DMA 传输完成时,DMA 控制器会发出中断信号,中断控制器会将中断请求传递给 CPU,CPU 接收到中断请求后会执行相应的中断处理程序。
中断处理程序的流程如下:
- CPU 接收到中断请求后,保存当前的执行现场(包括程序计数器、寄存器等);
- 执行中断处理程序,处理与中断相关的操作,如数据的接收或发送、状态的更新等;
- 中断处理程序执行完毕后,恢复之前保存的执行现场,继续执行被中断的程序。
通过使用 DMA 串口通信和中断,可以实现高效的数据传输和并行处理,提高系统的性能和效率。
二、实验过程
1.设置项目
打开STM32CubeMX,创建一个新项目,选择芯片,进入设置
设置RCC
设置SYS
设置USART
设置NVIC
创建项目
2.keil设置
项目创建完毕,打开项目,点击uzer里面的main.c,修改main.c里面的内容
main.c函数代码如下:
#include “main.h”
#include “usart.h”
#include “gpio.h”
#include <string.h>
void SystemClock_Config(void);
char start[6] = “start”;
char message[]=“hello Windows\r\n”;//输出信息
char tips[]=“CommandError\r\n”;//提示1
char tips1[]=“Start…\r\n”;//提示2
char tips2[]=“Stop…\r\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 *)&start, 1);
//当flag为1时,每秒发送一次信息
//当flag为0时,停止
while (1)
{
if(flag==1){
//发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF);
//延时
HAL_Delay(1000);
}
}
}
int stringcompare(char str1[6],char str2[6])
{
for(uint8_t i = 0 ; i < 6 ; i++)
{
if (str1[i] != str2[i])
return 0;
}
return 1;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(stringcompare(start,"stop!"))//输入为stop时,标志位置0
{
flag=0;
}
else if(stringcompare(start,"start"))//输入为 start时,标志位置1
{
flag=1;
}
//重新设置中断
HAL_UART_Receive_IT(&huart1,(uint8_t*)start,5);
}
/* 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 */
}
执行结果:
三、实验分析与总结
rn state /
__disable_irq();
while (1)
{
}
/ USER CODE END Error_Handler_Debug */
}
执行结果:
[外链图片转存中…(img-SrbgBOZM-1698929792811)]
三、实验分析与总结
本次实验在上一次实验的基础上,新增加了中断功能,扩展的地方主要就是我们需要发送信息,芯片接收到信息之后反馈信息。难度的话变化不算太大,有上一次的基础这次做来也会容易一些。HAL库的方式确实让整个过程都变得轻松不少。本次实验用字符串来控制接收发送,这也需要注意不能弄错。