中断LED与中断方式进行串口通信

一、原理

1、中断介绍

中断通常被定义为一个事件,该事件能够改变处理器执行指令的顺序。这样的事件与 CPU 芯片内外部硬件电路产生的电信号相对应。

中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被中断处继续执行或调度新的进程执行的过程。

2、中断作用

速度匹配:可以解决快速的CPU与慢速的外部设备之间传送数据的矛盾。 分时操作:CPU可以分时为多个外部设备服务,提高计算机的利用率。
实时响应:CPU能够及时处理应用系统的随机事件,增强系统的实时性。 可靠性高:CPU可以处理设备故障及掉电等突发事件,提高可靠性。

3、中断优先级

多个中断同时出现时,处理器先响应高优先级的中断 低优先级中断的ISR执行时,可以被高优先级中断再次打断 ISR比App
Code拥有更高的执行优先级

二、中断LED实现

以中断方式模拟开关实现LED灯的亮灭

1、设计思路

以PA1模拟开关

PA1接高电平开关按下LED灯亮
PA1接低电平开关断开ED灯灭

2、创建新项目

(1)进入CubeMX界面,在New Project 中选择ACCESS TO MCU SELECTOR 进行创建项目,会弹出一个小的弹窗选择 NO即进入参数设置界面
在这里插入图片描述
在这里插入图片描述

(2)参数配置
外设设置
设置指示灯LED引脚PB5,设置引脚模式为输出模式GPIO_Output
设置按键引脚PA1,设置引脚为外部中断功能,PA1与外部中断线EXIT1连接GPIO_EXIT1

在这里插入图片描述
对于LED对应的PB5管脚,默认设置即可,名字设为LED
在这里插入图片描述

在这里插入图片描述
对于开关对应管脚PA1,设置其触发方式为上升沿触发
External Interrupt Mode with Rising edge trigger detection上升沿
使能对应的外部中断线,点击Enabled
在这里插入图片描述
User Label处设置名字为 A1_EXTI

在这里插入图片描述

在这里插入图片描述
配置中断优先级
(大多数情况下不必设置中断优先级,直接使用中断编号设置的默认中断优先级)
在这里插入图片描述
时钟设置
这里设置了36M
在这里插入图片描述

生成工程文件

3、代码编写

当捕获到上升沿,触发中断,就会进入到这个函数里面

然后就会执行HAL_GPIO_EXTI_Callback(GPIO_Pin)函数,此函数为回调函数我们
打开可以发现前面有个weak。
前面的 __weak 表示此函数为虚函数,需要用户重写的。
在这里插入图片描述
那么我们在main.c文件中找个地方重新写一下。
位置在main函数下方。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if( GPIO_Pin == A1_EXTI_Pin)//判断外部中断源
	{
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);//翻转LED状态
	}
}


在这里插入图片描述
编译无错

4、电路连接

TXDA10
RXDA9
GRDGRD
3V33V3
PB5LED灯短脚
3v3LED长脚
PA13V3 LED灯亮
PA1GED LED灯灭

5、实现结果展示

在这里插入图片描述

三、中断串口通信

1、字符实现串口通信

当stm32接收到字符“s”时,停止持续发送“hello windows!”; 当接收到字符“t”时,持续发送“hello windows!”

(1)设计思路

采用一个全局标量做信号灯,本次实验选用flag作为全局变量

flag=0停止发送
flag=1恢复发送
指令s恢复发送
指令t停止发送

(2)创建新项目

1.进入CubeMX界面,在New Project 中选择ACCESS TO MCU SELECTOR 进行创建项目,会弹出一个小的弹窗选择 NO即进入参数设置界面
在这里插入图片描述
在这里插入图片描述

2.设置RCC

在这里插入图片描述
3.设置SYS

在这里插入图片描述
4.设置USART
在这里插入图片描述
5.设置NVIC
在这里插入图片描述
6.创建项目
在这里插入图片描述

在这里插入图片描述

项目创建后选择Open Project 进入keil 配置代码
在这里插入图片描述

(3)代码编写

1.在main函数前定义全局变量

char c;//指令 s:停止  t:开始
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.开始发送

在这里插入图片描述
2.main函数中设置接收中断
函数说明:

函数原型

 HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

功能

功能:串口中断接收,以中断方式接收指定长度数据。 大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。
接收到数据时,会触发串口中断。 再然后,串口中断函数处理,直到接收到指定长度数据
而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)

参数

UART_HandleTypeDef *huart      UATR的别名    
 huart1  *pData      			接收到的数据存放地址
 Size                      		接收的字节数


HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);

3.main函数中的while循环里面添加传输代码

if(flag==1){
			//发送信息
			HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF); 
			
			//延时
			HAL_Delay(1000);
		}

4.在main函数下面重写中断处理函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	
	//当输入的指令为0时,发送提示并改变flag
	if(c=='s'){
		flag=0;
		HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF); 
	}
	
	//当输入的指令为1时,发送提示并改变flag
	else if(c=='t'){
		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.main函数中全部代码


#include "main.h"
#include "usart.h"
#include "gpio.h"
#include <string.h>

void SystemClock_Config(void);

char c;//指令 s:停止  t:开始
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=='s'){
		flag=0;
		HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF); 
	}
	
	//当输入的指令为1时,发送提示并改变flag
	else if(c=='t'){
		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 */
}

6.编译烧录
在这里插入图片描述

(4)结果展示

当发送t后不断输出“hello Windows
在这里插入图片描述
当发送s停止发送
在这里插入图片描述

2、字符串实现串口通信

当stm32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”(提示:要将接收到的连续字符保存到一个字符数组里,进行判别匹配。写一个接收字符串的函数

(1)设计思路

设计接收字符串的函数,将接收到的连续字符保存到一个字符数组里,进行判别匹配

(2)创建项目

(1)进入CubeMX界面,在New Project 中选择ACCESS TO MCU SELECTOR 进行创建项目,会弹出一个小的弹窗选择 NO即进入参数设置界面
在这里插入图片描述
设置高速外部时钟HSE,选择外部时钟源
在这里插入图片描述

设置串口
1)点击USART1
2)设置MODE为异步通信
3)基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1,接收和发送都使能
4)GPIO引脚设置 USART1_RX/USART_TX(这里一般自动设置好了)
在这里插入图片描述

5) NVIC Settings 一栏使能接收中断

在这里插入图片描述

时钟设置
在这里插入图片描述

之后导出Keil文件并打开。

(3)代码编写

printf函数设置
在main.c和usart.c中添加头文件#include “stdio.h”
之后,在usart.c文件中,添加如下代码,进行重定义

/* USER CODE BEGIN 1 */

//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)	
#if 1
//#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	
	 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0x0001);  
	return ch;
}
#endif 

/* USER CODE END 1 */

在这里插入图片描述

在main.c主函数中,添加发送数据
在这里插入图片描述

    /* USER CODE END WHILE */
	  	printf("Hello windows!\r\n");
		HAL_Delay(500);
    /* USER CODE BEGIN 3 */

在这里插入图片描述

在main.c中添加如下定义,用来接收串口数据

uint8_t aRxBuffer;			//接收中断缓冲
uint8_t Uart1_RxBuff[256];		//接收缓冲
uint8_t Uart1_Rx_Cnt = 0;		//接收缓冲计数
uint8_t	cAlmStr[] = "数据溢出(大于256)\r\n";

在这里插入图片描述

添加开启接收中断的语句

/* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */

在这里插入图片描述

在main.c下部添加中断回调函数

/* USER CODE BEGIN 4 */
/**
  * @brief  Rx Transfer completed callbacks.
  * @param  huart pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
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(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);   //再开启接收中断
}
/* USER CODE END 4 */

在这里插入图片描述

编译无错烧录
烧录时boot0接1
在这里插入图片描述

(4)结果展示

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

四、串口DMA

1、DMA原理

DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。

我们知道CPU有转移数据、计算、控制程序转移等很多功能,系统运作的核心就是CPU,

CPU无时不刻的在处理着大量的事务,但有些事情却没有那么重要,比方说数据的复制和存储数据,如果我们把这部分的CPU资源拿出来,让CPU去处理其他的复杂计算事务,是不是能够更好的利用CPU的资源呢?

因此:转移数据(尤其是转移大量数据)是可以不需要CPU参与。比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,直接让数据由A拷贝到B
不经过CPU的处理

2、创建项目

在这里插入图片描述
在这里插入图片描述
设置RCC
设置高速外部时钟HSE 选择外部时钟源
,在这里插入图片描述
设置串口USART1
点击USATR1,设置MODE为异步通信(Asynchronous),基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1 接收和发送都使能GPIO引脚自动设置 USART1_RX/USART_TX
在这里插入图片描述
NVIC Settings 一栏使能接收中断
在这里插入图片描述
DMA设置
点击DMASettings 点击 Add 添加通道,选择USART_RX USART_TX 传输速率设置为中速,DMA传输模式为正常模式,DMA内存地址自增,每次增加一个Byte(字节)
在这里插入图片描述
1DMA基础设置
右侧点击System Core 点击DMA
在这里插入图片描述
时钟设置
在这里插入图片描述
项目文件设置
点击Project Manager
在这里插入图片描述
创建工程文件
在这里插入图片描述

创建工程
GENERATE CODE 点击Open Project
进入keil进行代码编写
配置下载工具
新建的工程所有配置都是默认的 我们需要自行选择下载模式,勾选上下载后复位运行
在这里插入图片描述

3、代码编写

uint8_t Senbuff[] = "Hello world!";  //定义数据发送数组

在这里插入图片描述

  HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Senbuff, sizeof(Senbuff));
  HAL_Delay(1000);

在这里插入图片描述

4、结果展示

编译无错后,烧录
在这里插入图片描述
在这里插入图片描述

总结

本次实验难点主要在于字符串实现中断通信,在while语句中添加字符匹配判别来实现中断。对于中断有了进一步了解与加深。

参考

https://blog.csdn.net/qq_46467126/article/details/121055475?spm=1001.2014.3001.5506
https://blog.csdn.net/qq_47281915/article/details/121053903
https://blog.csdn.net/as480133937/article/details/104827639/
https://blog.csdn.net/qq_46467126/article/details/121076618
DMA

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妤哕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值