记录2——stm32f411CEU6的LED灯玩UART+DMA通信、外部中断EXIT、定时器中断(另含Proteus仿真)


前言

本文简单介绍一下UART+DMA通信、外部中断EXIT、定时器中断的实现方法,水平有限,仅供参考。

一、UART+DMA

DMA概述

即直接访问寄存器。用在外设和存储器之间以及存储器与存储器之间进行高速数据传输,传输过程由DMA控制器执行,无需CPU参与,节省CPU资源

DMA传输四要素:

  1. 传输源:数据传输来源
  2. 传输目标:数据传输目的
  3. 传输数量:传输数据的数量
  4. 触发信号:启动一次DMA数据传输的动作

任务

实现LED每隔1s亮一次,且每次每隔1s都发送"abc" 在串口调试助手上显示;当电脑发送两个字母或数字时,单片机再将接收的内容发送回给电脑。

配置工程

1.引脚配置PC13如上一次方法一样
2.配置USART2
在这里插入图片描述
添加串口接收和发送的DMA数据流:
在这里插入图片描述
在这里插入图片描述
优先级配置很重要!!!
在这里插入图片描述

代码实现

/* USER CODE BEGIN 0 */
uint8_t temp1[]="abc";
uint8_t temp2[2];
//声明发送与接收的变量
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_Delay (1);//可以不用延迟,只是想要试验优先级
	if(huart==&huart2) HAL_UART_Transmit_DMA(&huart2,temp2,sizeof(temp2));
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_Delay (1);//可以不用延迟,只是想要试验优先级
	if(huart==&huart2) HAL_GPIO_TogglePin (GPIOC ,GPIO_PIN_13); 
}
 /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_DMA(&huart2,temp2,sizeof(temp2));
//开启DMA接收,temp2为数组,所以不需要&,若只为变量则需要&.由于之前开启了circle循环模式,所以只需要开启一遍即可
  /* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
  while (1)
  {
		HAL_UART_Transmit_DMA(&huart2,temp1,sizeof(temp1));//发送
		HAL_Delay (1000);//延迟一秒
    /* USER CODE END WHILE */

(注意写在while(1)里头!!!)
执行完发送后便开启对应的发送回调函数void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)

(可以把单片机与调试器上对应的Tx、Rx用杜母线连接好,打开串口调试助手可以收发一些数据.注意:PA2连RX,PA3连TX。)

二、外部中断EXIT

通俗来说,中断就是当CPU在处理一件事是接到了另一件事发出的请求,CPU转去执行那一件事,完成之后又回来继续之前的事。

任务

实现按键控制LED亮灭,要求按键松开时触发中断

配置工程

配置PC13引脚与之前一样,按键控制的PA0为GPIO_EXTI0。选择的GPIO mode为上升沿进入外部中断,也就是松开按键时进入中断,不松KEY就不亮/灭;若选择为Falling edge trigger detection,则是一按键就亮/灭。
在这里插入图片描述

在这里插入图片描述
开启中断且设置优先级
在这里插入图片描述

代码实现

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
函数定义如下图:
在这里插入图片描述

拓展

让LED灯按下按键时亮,松开时灭(按下时亮需要配置控制按键的PA0为下降沿触发)

/* USER CODE BEGIN 2 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
	{
		if(GPIO_Pin==GPIO_PIN_0 )
		{
			HAL_Delay (10);
			if(HAL_GPIO_ReadPin (GPIOA ,GPIO_PIN_0)==GPIO_PIN_RESET)//按键按下
			{
				HAL_GPIO_WritePin (GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);//LED亮
			}
		}
		if(GPIO_Pin==GPIO_PIN_0 )//需要再进行一次判断实现消抖,效果更好
		{
			HAL_Delay (10);
			if(HAL_GPIO_ReadPin (GPIOA ,GPIO_PIN_0)==GPIO_PIN_SET)//按键松开
			{
				HAL_GPIO_WritePin (GPIOC,GPIO_PIN_13,GPIO_PIN_SET);LED灭
			}
		}
	}

/* USER CODE END 2 */

(效果好像还不是很理想,会有松开时仍然亮着的情况)
此时Rising/Falling edge 就很好地派上了用场,反正只要按键有电平变化就进入中断,翻转LED电平(不过用TogglePin这个函数还是有一定的失误率,不过后来发现WritePin会更好)

/* USER CODE BEGIN 2 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin ==GPIO_PIN_0 )
	{
		HAL_Delay(10);
		HAL_GPIO_TogglePin (GPIOC,GPIO_PIN_13);
	}	
}

/* USER CODE END 2 */

三.定时器中断

任务1

实现用定时器控制LED灯每隔1s亮一次。

简单介绍

计算公式如图:
在这里插入图片描述

配置工程

1.配置LED引脚(PC13),同之前配置一样
2.开启TIM2
在这里插入图片描述

3.配置时钟树
在这里插入图片描述
4.计算且使能TIM2中断
由开头的计算公式可知:若想让LED灯每隔一秒闪一次,即周期为1s。由时钟树可知TIM2对应的TIM_CLK为100MHz,即100*1000000Hz,则配置PSC为100-1,ARR为1000000-1,此时计算得到的周期为1s.
在这里插入图片描述
在这里插入图片描述
5.优先级配置
优先级数字越大,优先级越高
在这里插入图片描述

代码实现

1.开启定时器中断

/* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END 2 */

2.定时器中断回调函数

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);//翻转电平
}
/* USER CODE END 0 */

Proteus仿真

  • 由于proteus的stm32类型有限,此处以f103c6为例,模拟仿真,相关配置参照前面的方法利用CubeMX+Keil+Proteus即可。

  • PA8为开启定时器2的引脚,PB1可由PA15(连接按键BUTTON)的外部中断进行开关控制。

  • 实现效果:
    D1、D2开始均亮;
    按下按键,D1灭,再按,亮
    D2每隔1s闪烁一次。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Drawing Ting

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

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

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

打赏作者

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

抵扣说明:

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

余额充值