当前位置: 首页 > news >正文

嵌入式软件--stm32 DAY 4 中断系统

1.课后练习

学了这么长时间,现在让我们第一次做练习。

1.1往返流水灯

1.1.1 LED1-LED2-LED3-LED2-LED1```循环

(1)工程准备

复制上一个寄存器实现的工程文档,删减修改我们正要实现的工程。为了区别练习和学习工程,我们统一加上ex前缀作为练习工程。

(2)代码编写

在VSCODE中打开。

方法一:main.c

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"int main(void)
{//1.初始化LED_Init();//4.在循环中依次点亮,延迟一段时间关闭uint16_t leds[]={LED_1,LED_2,LED_3};uint8_t n=3;while(1){//第一轮循环中LED123分别亮灭uint8_t i;for(i=0;i<n;i++){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}//方法一,在一次循环中,让led_2多经历一次亮灭LED_On(LED_2);delay_ms(500);LED_Off(LED_2);}}

方法二:正向遍历,反向取数组元素

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"int main(void)
{//1.初始化LED_Init();//4.在循环中依次点亮,延迟一段时间关闭uint16_t leds[]={LED_1,LED_2,LED_3};uint8_t n=3;while(1){//第一轮循环中LED123分别亮灭uint8_t i;for(i=0;i<n;i++){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}//方法一,在一次循环中,让led_2多经历一次亮灭// LED_On(LED_2);// delay_ms(500);// LED_Off(LED_2);//方法二,方向遍历for(i=1;i<n-1;i++){LED_On(leds[n-i-1]);delay_ms(500);LED_Off(leds[n-i-1]);}}}

 方法三:方向遍历

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"int main(void)
{//1.初始化LED_Init();//4.在循环中依次点亮,延迟一段时间关闭uint16_t leds[]={LED_1,LED_2,LED_3};while(1){//第一轮循环中LED123分别亮灭uint8_t i;uint8_t n=3;for(i=0;i<n;i++){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}//方法一,在一次循环中,让led_2多经历一次亮灭// LED_On(LED_2);// delay_ms(500);// LED_Off(LED_2);//方法二// for(i=1;i<n-1;i++)// {// 	LED_On(leds[n-i-1]);// 	delay_ms(500);// 	LED_Off(leds[n-i-1]);// }//方法三,通用方法,反向遍历for (i = n-2; i >0; i--){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}}}

这三种方法其实本质上都是多了一个LED_2的一亮一灭。

1.1.2 LED1-LED2-LED3-LED3-LED2-LED1-LED1-...

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"int main(void)
{//1.初始化LED_Init();//4.在循环中依次点亮,延迟一段时间关闭uint16_t leds[]={LED_1,LED_2,LED_3};while(1){//第一轮循环中LED123分别亮灭uint8_t i;uint8_t n=3;for(i=0;i<n;i++){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}delay_ms(500);//方法一,在一次循环中,让led_2多经历一次亮灭// LED_On(LED_2);// delay_ms(500);// LED_Off(LED_2);//方法二// for(i=1;i<n-1;i++)// {// 	LED_On(leds[n-i-1]);// 	delay_ms(500);// 	LED_Off(leds[n-i-1]);// }//方法三,通用方法,反向遍历// for (i = n-2; i >0; i--)// {// 	LED_On(leds[i]);// 	delay_ms(500);// 	LED_Off(leds[i]);// }//第二层反向循环,321亮灭uint8_t k=3;for (int8_t i = k-1; i >=0;i--){LED_On(leds[i]);delay_ms(500);LED_Off(leds[i]);}delay_ms(500);}}

1.2 依次开关灯

用HAL库,就用CUBEmx创建。

添加了led.c led.h之后简单debug,就打开VScode,开始简单编程。

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 */
//依次打开LED1 LED2 LED3HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);HAL_Delay(500);HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);HAL_Delay(500);HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET);HAL_Delay(2000);//依次关闭LED3 LED2 LED1HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);HAL_Delay(500);HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);HAL_Delay(500);HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @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_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;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_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

如果把led相关函数单独写一处。

led.c

#include "led.h"//开关LED灯,参数就定为led,要开哪个灯就传哪个灯
void LED_On(uint16_t led)
{
HAL_GPIO_WritePin(GPIOA,led,GPIO_PIN_RESET);
}
void LED_Off(uint16_t led)
{HAL_GPIO_WritePin(GPIOA,led,GPIO_PIN_SET);}//反转LED灯状态
void LED_Toggle(uint16_t led)
{HAL_GPIO_TogglePin(GPIOA,led);
}//控制所有灯的开关
void LED_OnAll(uint16_t leds[],uint8_t size)//全开
{for (uint8_t i = 0; i < size; i++){LED_On(leds[i]);}}
void LED_OffAll(uint16_t leds[],uint8_t size)//全关
{for (uint8_t i = 0; i < size; i++){LED_Off(leds[i]);}}

led.h

#ifndef __LED_H__
#define __LED_H__
#include "gpio.h"//开关LED灯,参数就定为led,要开哪个灯就传哪个灯
void LED_On(uint16_t led);
void LED_Off(uint16_t led);//反转LED灯状态
void LED_Toggle(uint16_t led);//控制所有灯的开关
void LED_OnAll(uint16_t leds[],uint8_t size); //全开
void LED_OffAll(uint16_t leds[],uint8_t size);//全关
#endif  

2.问题解答

增加了.c文件一定要加入工程。

组的名字叫什么都可以,为了分类明确,所以按照实际去写。

关于引用#include 如果是< >的话,是从c标准库里引用的。“ ”是用户自定义的包含路径去找。

3.中断的概念

 

优先级高的中断任务打断优先级低的中断任务。

4.为什么需要中断

5. STM32的中断

5.1中断系统体系结构

数值越小,优先级越高。

我们要从手册学会看中断向量表

可以看出复位优先级是最高的,不管当前在运行什么,都会被复位打断。 

5.2 NVIC

5.2.1 NVIC介绍

 NVIC 和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地处理中断。嵌套向量中断控制器管理着包括内核异常,外部中断等所有中断。由NVIC决定哪个中断的处理程序交给CPU来执行。

5.2.2 中断优先级

NVIC为了管理中断方便,通过软件给每个中断设置优先级。NVIC用4个位来控制优先级,值小的优先级高。优先级两种:抢占优先级和响应优先级。

 先划分组优先级,再从组中分子优先级。

6.外部中断控制器

7.软件实现

7.1需求

利用外部中断检测按键KEY3,当按键按下,翻转LED1显示。

7.2 硬件电路设计

LED1 PA0    LED2 PA1  LED3 PA8

KEY3   PF10  输入

对应我们硬件最上边的按键。当KEY3被按下去的时候,PF10是高电平。平时应该输入一个低电平,下拉电阻。

按下KEY1,就会输入低电平,要上拉一个电阻才能保持。

按键有一个消抖的过程,我们一般用延时一段时间,检测稳定的电平。一般10~15ms.

KEY3--PF10--EXTI 10 

配EXTI10这四位。

7.3 软件设计

(1)寄存器实现

清除中断标志位

EXTI->PR |=EXTI_PR_PR10;

复制前边03的副本,将里面无关的文件删除。

在Hardware文件夹下创建KEY文件夹,KEY文件夹下创建key.c和key.h文件。

用keil打开项目文件。

如此配置完成。

之后通过vscode打开。

代码实现KEY3控制黄灯的亮灭。

key.h

key.c

main.c

key.c

#include "key.h"
#include "delay.h"
#include "led.h"
void KEY_Init(void)
{//1.开启时钟RCC->APB2ENR|=RCC_APB2ENR_IOPFEN; RCC->APB2ENR|=RCC_APB2ENR_AFIOEN;//2.PF10 工作模式:下拉输入,CNF=10,MODE=00GPIOF->CRH&=~GPIO_CRH_MODE10;GPIOF->CRH|=GPIO_CRH_CNF10_1;GPIOF->CRH&=~GPIO_CRH_CNF10_0;GPIOF->ODR&=~GPIO_ODR_ODR10;//3.AFIO引脚复用配置 EXTI10 - PF10AFIO->EXTICR[2]|=AFIO_EXTICR3_EXTI10_PF;//4.EXTI配置//4.1配置上升沿触发EXTI->RTSR|=EXTI_RTSR_TR10;//4.2打开屏蔽位EXTI->IMR|=EXTI_IMR_MR10;//5.NVIC配置//5.1设置优先级组方案NVIC_SetPriorityGrouping(3);//全部4位都是抢占优先级NVIC_SetPriority(EXTI15_10_IRQn,2);NVIC_EnableIRQ(EXTI15_10_IRQn);}
//中断处理程序
void EXTI15_10_IRQHandler(void)
{//1.清除挂起位(PR置1)EXTI->PR|=EXTI_PR_PR10;//2.防抖延时Delay_ms(15);//3.确认当前PF10依然输入高电平,就翻转LED1if ((GPIOF->IDR&GPIO_IDR_IDR10)!=0){LED_Toggle(LED_1);}
}

key.h

#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
//定义LED灯
#define LED_1 GPIO_ODR_ODR0
#define LED_2 GPIO_ODR_ODR1
#define LED_3 GPIO_ODR_ODR8
//初始化
void LED_Init(void);
//开关LED灯
void LED_On(uint16_t led);
void LED_Off(uint16_t led);//翻转LED灯状态
void LED_Toggle(uint16_t led);
//控制所有LED灯的开关
void LED_OnAll(uint16_t leds[],uint8_t size);
void LED_OffAll(uint16_t leds[],uint8_t size);
#endif

main.c

#include <stdint.h>
#include "delay.h"
#include "led.h"
int main(void){//1.时钟配置,开启GPIOA时钟// *(uint32_t *)(0x40021000+0x18)=4;// //2.配置PA0 PA1为输出// *(uint32_t *)(0x40010800+0x00)=0x33;// //配置PA8为输出,根据数据手册8在高寄存器,偏移地址0x04// *(uint32_t *)(0x40010800+0x04)=0x03;// //PAO,PA1,PA8输出为低电平// *(uint32_t *)(0x40010800+0x0C)=0xfefc;//初始化
LED_Init();
KEY_Init();while(1){}}

(2)HAL库实现

<1>打开STM32 CubeMX,新建项目

<2>

在HAL库中。KEY和led的初始化在gpio中已经配置完成,无需额外配置。

相应的中断服务函数也有。 

在VSCODE中点开一看,再次回调实现其他函数

 

因此可以在it.c文件中复制引用函数,重新定义,判断到底是哪个中断。

主函数初始化后便无需再配,直接烧写。 

8.资料下载

stm32开发官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘

相关文章:

  • 从零开始了解数据采集(二十一)——电子制造行业趋势分析案例
  • 消防应急物资智能调用立库:豪越科技助力消防“速战速决”
  • 央视两次采访报道爱藏评级,聚焦生肖钞市场升温,评级币成交易安全“定心丸”
  • uniapp: 低功耗蓝牙(BLE)的使用
  • 《代码整洁之道》第8章 边界 - 笔记
  • JVM——垃圾收集策略
  • 【首款Armv9开源芯片“星睿“O6测评】SVE2指令集介绍与测试
  • Spring AI Alibaba - MCP连接 MySQL
  • [三分钟]web自动化测试(二):selenium自动化测试常用函数(上)
  • HarmonyOS Next~鸿蒙系统流畅性技术解析:预加载与原生架构的协同进化
  • vite.config.ts 的详细配置项说明、完整代码示例及表格总结
  • Nacos简介—4.Nacos架构和原理三
  • 英语中时间的表达
  • 数据一致性问题剖析与实践(四)——竞态条件竞争导致的一致性问题
  • C++入门小馆: STL 之queue和stack
  • JavaScript输出数据的方法
  • 解决qnn htp 后端不支持boolean 数据类型的方法。
  • 如何创建并使用极狐GitLab 部署令牌?
  • shell命令二
  • 迈锐思C1pro插件安装包【附百度网盘链接】
  • 上海明天起进入“升温通道”,五一假期冲刺33℃
  • 党旗下的青春|83岁仍在“下生活”,他说生活是创作的源泉
  • 影子调查丨起底“三无”拖拉机产销链:出口掩内销,监管如虚设
  • 新任浙江省委常委、组织部长杨荫凯到嘉兴南湖瞻仰红船
  • 俄联邦安全局:俄军高级官员汽车爆炸案嫌疑人已被捕
  • 学大教育:去年净利润1.797亿元,学习中心增加约60所