- 注:我采用的是STM32F103RC芯片、相应的电路图和STM32CubeIDE软件
- 这是在STM32CubeIDE软件定义芯片后,所给的必要的代码逻辑,加上了注释
#include "main.h"
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 声明系统时钟配置函数
##关键词解释
句柄 :对硬件资源或系统资源的抽象,通常用于标识和管理这些资源。通常是一个包含配置参数、状态信息和相关寄存器地址的结构体。定义句柄后,可以通过该句柄对相应的硬件外设进行配置、操作和管理。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
// 初始化HAL库,配置系统时钟和外设
HAL_Init();
HAL 库提供了一套统一的 API 来抽象硬件外设(如GPIO、ADC、UART、I2C、SPI等)的操作。
// 配置系统时钟
SystemClock_Config();
MX_ 前缀通常表示由 STM32CubeMX 工具生成的初始化代码,而不是开发者手动编写的函数。
// 在这里可以初始化其他外设
// 无限循环,主程序运行的核心循环
while (1)
{
// 这里可以放置主循环代码
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // RCC振荡器初始化结构体
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // RCC时钟初始化结构体
// 配置HSI(内部高速时钟)作为时钟源
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON; // 打开HSI
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; // 设置HSI校准值
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // 不使用PLL(相位锁定环)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler(); // 如果配置失败,调用错误处理函数
}
// 配置AHB、APB1、APB2总线时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // 使用HSI作为系统时钟源
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟不分频
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1时钟不分频
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2时钟不分频
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler(); // 如果配置失败,调用错误处理函数
}
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
__disable_irq(); // 禁用所有中断
while (1)
{
// 错误处理:进入死循环
}
}
#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)
{
// 用户可以在这里添加自己的实现来报告文件名和行号
}
#endif /* USE_FULL_ASSERT */
一、GPIO
- 在STM32中,GPIO(General Purpose Input/Output,通用输入/输出)是一个非常重要的外设,用于与外部设备进行交互。
- GPIO引脚可以通过软件配置为输入或输出,用于读取或控制外部设备的状态,如开关、LED、传感器等。
- GPIO模块将管脚分组为PA PB PC PD,每一组为16个。
- 使用
- 由于我的电路图是PC6,PC7,PC8为LED灯连接。故配置它们为GPIO_Output,因此在代码中多了static void MX_GPIO_Init(void);
函数,进行串口的配置,故也要在main函数中GPIO初始化。MX_GPIO_Init();
- 又因为PC2控制着LED的亮灭,故将PC2设置为GPIO_Intput,并将其上拉。
- 为什么上拉:芯片的管脚浮在空中,电平是不确定的.为了使之稳定,我们可以需要对其进行 上拉和下拉。
-HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);
用于将6,7,8管脚设置为输出状态。GPIO_PIN_RESET
可以将指定的 GPIO 引脚输出设为逻辑低电平(0V),通常表示逻辑0。
-HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
对输入输出取反操作,即设置一定的延时可以一闪一闪的。
- 利用PC2开关LED灯
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2) == GPIO_PIN_RESET) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_RESET);
}
- 输出的推挽和开漏
推挽 push pull 可以输出高低电平 有一定的驱动能力
开漏 open drain 只能输出低,必须上拉电阻 没有驱动能力
- 代码
#include "main.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2) == GPIO_PIN_RESET) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_RESET);
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
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();
}
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();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
二、中断
- 中断(Interrupt)是一种非常重要的机制,用于处理外部或内部事件,而无需频繁地查询(轮询)硬件状态。
- 中断能够在事件发生时立即响应,并将处理器从主程序转移到中断服务程序(ISR),以处理特定的任务。
- 使用方法
1). 设置管脚为GPIO_EXTI
2). 在NVIC Interrupt Table表中允许对应的中断管脚使能
3). 设置对应的管脚为边缘触发,并为GPIO上拉。(根据情况即可)
4). 触发中断后执行中断函数void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
注: 外部中断有很多,都是使用相同的函数,可以通过GPIO_Pin来区分到底是哪一个中断。例如if(GPIO_Pin== GPIO_PIN_2) - 代码示例
//设置了PC2和PB9两个中断。
#include "main.h" // 包含主头文件,定义了使用的库函数和STM32相关功能
// 中断处理函数,当外部中断发生时调用
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_2) // 检查是否由PC2引脚引发中断
{
static int keycnt = 0; // 计数变量,保存按键次数
keycnt++; // 每次中断计数加1
if(keycnt % 2) { // 如果按键次数是奇数,打开LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET); // 将PC6引脚设为高电平(LED亮)
}
else { // 如果按键次数是偶数,关闭LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); // 将PC6引脚设为低电平(LED灭)
}
}
else if(GPIO_Pin == GPIO_PIN_9) // 检查是否由PB9引脚引发中断
{
static int keycnt1 = 0; // 另一个计数变量,用于PB9引脚
keycnt1++; // 每次中断计数加1
if(keycnt1 % 2) { // 如果按键次数是奇数,打开另一个LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET); // 将PC7引脚设为高电平(LED亮)
}
else { // 如果按键次数是偶数,关闭LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET); // 将PC7引脚设为低电平(LED灭)
}
}
}
int main(void)
{
HAL_Init(); // 初始化HAL库,配置STM32硬件抽象层
SystemClock_Config(); // 配置系统时钟
MX_GPIO_Init(); // 初始化GPIO(通用输入输出引脚)
while (1) // 无限循环,程序在此循环中持续运行
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // 定义RCC时钟配置结构体
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 定义时钟初始化结构体
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; // 选择HSI(高精度内部振荡器)作为时钟源
RCC_OscInitStruct.HSIState = RCC_HSI_ON; // 启用HSI
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; // 使用默认的HSI校准值
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // 不启用PLL(相位锁定环)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) // 如果时钟配置失败
{
Error_Handler(); // 调用错误处理函数
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; // 配置AHB、APB1、APB2总线时钟
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // 使用HSI作为系统时钟
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB总线时钟不分频
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1总线时钟不分频
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2总线时钟不分频
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) // 如果时钟配置失败
{
Error_Handler(); // 调用错误处理函数
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // 定义GPIO初始化结构体
__HAL_RCC_GPIOC_CLK_ENABLE(); // 启用GPIOC引脚的时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 启用GPIOB引脚的时钟
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8, GPIO_PIN_RESET); // 将PC6、PC7和PC8引脚设为低电平(关闭)
GPIO_InitStruct.Pin = GPIO_PIN_2; // 配置PC2引脚
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 设为下降沿触发中断模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 开启上拉电阻
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC2引脚
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8; // 配置PC6、PC7、PC8为输出模式
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设为推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无需上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 设为低速输出
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC6、PC7、PC8引脚
GPIO_InitStruct.Pin = GPIO_PIN_9; // 配置PB9引脚
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 设为下降沿触发中断模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 开启上拉电阻
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化PB9引脚
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); // 设置EXTI2中断优先级为0
HAL_NVIC_EnableIRQ(EXTI2_IRQn); // 使能EXTI2中断
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); // 设置EXTI9-5中断优先级为0
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); // 使能EXTI9-5中断
}
void Error_Handler(void)
{
__disable_irq(); // 禁用所有中断
while (1) // 进入死循环,等待人为重启
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
// 调试信息,显示在哪个文件和第几行发生了错误
}
#endif
三、时间获取和软件消抖
时间获取
- 在STM32中,通常使用 SysTick 定时器 来实现时间测量和滴答计数 (ticks)。
- HAL_GetTick() 是 HAL 库提供的函数,用于获取系统启动后经过的毫秒数。
- 每当系统启动时,计时器从 0 开始,每 1 毫秒 ticks 变量就会递增 1。
uint32_t T1 = HAL_GetTick(); // 获取当前时间,单位是毫秒
do_something(); // 执行需要测量时间的操作
uint32_t T2 = HAL_GetTick(); // 获取结束时的时间
uint32_t elapsed_time = T2 - T1; // 计算操作执行的时间差,单位为毫秒
软件消抖
- 用来处理按键等机械开关在按下或释放时产生的抖动信号。
- 机械开关的抖动会导致短时间内开关状态不稳定,造成误触发。
- 在嵌入式系统中,按键输入需要进行消抖处理,确保得到的按键状态是稳定的。
- 代码实现
void intr_fun(uint32_t debounce_time)//消抖函数。debounce_time 为使用的消抖时间
{
static uint32_t pre_ticks = 0;
if(HAL_GetTick() - pre_ticks < debounce_time)
{
return;
}
pre_ticks = HAL_GetTick();
// 执行中断处理代码
}
四、矩阵键盘
- 原理图
- 矩阵键盘的优点是能够使用较少的引脚来检测多个按键,这对于微控制器(如STM32)尤其有用。
- 矩阵键盘处理逻辑(行和列的模式切换速度非常快,用户感知不到)
1. 进入中断模式
- 矩阵键盘的行和列分别连接到单片机的GPIO引脚。
- 4列作为输出,输出低电平;
- 4行作为输入(中断模式),并设置为上拉电阻模式,等待按键按下时的中断信号。
2. 中断触发后,进入中断处理函数
3. 第一步:检测行
- 重新配置行作为输入模式,列作为输出模式(列保持低电平);
- 如果按键按下,某行的电平会被拉低,这样可以检测出是哪一行的按键被按下。
4. 第二步:检测列
- 重新配置列为输入模式,行作为输出模式(行输出低电平);
- 此时检测列的电平,按键按下的列会被拉低,从而可以得知是哪一列的按键被按下。
5. 行和列都确定
- 知道按下的具体行和列,可以进行编码,根据行和列的组合确定按下的是哪一个键。
6. 恢复中断模式
- 按键检测完毕后,恢复最初的中断模式,即行作为输入(中断),列作为输出,继续等待下次按键按下的中断信号。
矩阵键盘的行和列
- 使用方法
1. 将PA1~PA3的管脚作为输出设置为GPIO_Output
2. 将PA4~PA7的管脚作为中断模式,设置为GPIO_EXTI,等待按键按下
3. 在NVIC Interrupt Table中允许PA4~PA7启用中断。
4. 导入特定的文件矩阵键盘文件。c文件在Src中,h文件在Inc中。
5. 导入矩阵键盘的头文件,并在main函数中初始化keyboard_init();
6. 对五的注解:
- 调用 keyboard_init() 是为了完成矩阵键盘的GPIO引脚和中断的初始配置,确保STM32能够正常检测按键事件。
- 这是任何硬件外设操作的第一步,在系统主循环开始之前,必须初始化所有的硬件资源,以便后续的按键检测能够正常工作。
7. 在void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
中处理即可 - 代码示例
#include "main.h"
#include "keyboard.h"
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
static uint32_t pre_ticks = 0;
if (HAL_GetTick() - pre_ticks < 200) // 防抖处理
{
return;
}
pre_ticks = HAL_GetTick();
char keynum = keyboard_getKeyNum(GPIO_Pin);
switch (keynum) {
case '1':
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
break;
case '2':
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
break;
case '3':
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
break;
default:
// 关闭所有 LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
break;
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
keyboard_init();
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
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();
}
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();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif