定时器中断(另含Proteus仿真)"/>
记录2——stm32f411CEU6的LED灯玩UART+DMA通信、外部中断EXIT、定时器中断(另含Proteus仿真)
文章目录
- 前言
- 一、UART+DMA
- DMA概述
- DMA传输四要素:
- 任务
- 配置工程
- 代码实现
- 二、外部中断EXIT
- 任务
- 配置工程
- 代码实现
- 拓展
- 三.定时器中断
- 任务1
- 简单介绍
- 配置工程
- 代码实现
- 1.开启定时器中断
- 2.定时器中断回调函数
- Proteus仿真
前言
本文简单介绍一下UART+DMA通信、外部中断EXIT、定时器中断的实现方法,水平有限,仅供参考。
一、UART+DMA
DMA概述
即直接访问寄存器。用在外设和存储器之间以及存储器与存储器之间进行高速数据传输,传输过程由DMA控制器执行,无需CPU参与,节省CPU资源。
DMA传输四要素:
- 传输源:数据传输来源
- 传输目标:数据传输目的
- 传输数量:传输数据的数量
- 触发信号:启动一次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——stm32f411CEU6的LED灯玩UART+DMA通信、外部中断EXIT、定时器中断(另含Proteus仿真)
发布评论