文章目录[隐藏]
前言
本文简单介绍一下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,即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 */
版权声明:本文为CSDN博主「weixin_65489379」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_65489379/article/details/122783396
暂无评论