STM32的使用方法一

  • 注:我采用的是STM32F103RC芯片、相应的电路图和STM32CubeIDE软件
  • 这是在STM32CubeIDE软件定义芯片后,所给的必要的代码逻辑,加上了注释
cpp 复制代码
#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

  1. 在STM32中,GPIO(General Purpose Input/Output,通用输入/输出)是一个非常重要的外设,用于与外部设备进行交互。
  2. GPIO引脚可以通过软件配置为输入或输出,用于读取或控制外部设备的状态,如开关、LED、传感器等。
  3. GPIO模块将管脚分组为PA PB PC PD,每一组为16个。
  4. 使用
    • 由于我的电路图是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灯
cpp 复制代码
 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);
	  }
  1. 输出的推挽和开漏
    推挽 push pull 可以输出高低电平 有一定的驱动能力
    开漏 open drain 只能输出低,必须上拉电阻 没有驱动能力
  2. 代码
cpp 复制代码
#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 */

二、中断

  1. 中断(Interrupt)是一种非常重要的机制,用于处理外部或内部事件,而无需频繁地查询(轮询)硬件状态。
  2. 中断能够在事件发生时立即响应,并将处理器从主程序转移到中断服务程序(ISR),以处理特定的任务。
  3. 使用方法
    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)
  4. 代码示例
cpp 复制代码
//设置了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

三、时间获取和软件消抖

时间获取
  1. 在STM32中,通常使用 SysTick 定时器 来实现时间测量和滴答计数 (ticks)。
  2. HAL_GetTick() 是 HAL 库提供的函数,用于获取系统启动后经过的毫秒数。
  3. 每当系统启动时,计时器从 0 开始,每 1 毫秒 ticks 变量就会递增 1。
cpp 复制代码
uint32_t T1 = HAL_GetTick();  // 获取当前时间,单位是毫秒
do_something();               // 执行需要测量时间的操作
uint32_t T2 = HAL_GetTick();   // 获取结束时的时间

uint32_t elapsed_time = T2 - T1;  // 计算操作执行的时间差,单位为毫秒
软件消抖
  1. 用来处理按键等机械开关在按下或释放时产生的抖动信号。
  2. 机械开关的抖动会导致短时间内开关状态不稳定,造成误触发。
  3. 在嵌入式系统中,按键输入需要进行消抖处理,确保得到的按键状态是稳定的。
  4. 代码实现
cpp 复制代码
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行作为输入(中断模式),并设置为上拉电阻模式,等待按键按下时的中断信号。
    1. 中断触发后,进入中断处理函数
    2. 第一步:检测行
    • 重新配置行作为输入模式,列作为输出模式(列保持低电平);
    • 如果按键按下,某行的电平会被拉低,这样可以检测出是哪一行的按键被按下。
    1. 第二步:检测列
    • 重新配置列为输入模式,行作为输出模式(行输出低电平);
    • 此时检测列的电平,按键按下的列会被拉低,从而可以得知是哪一列的按键被按下。
    1. 行和列都确定
    • 知道按下的具体行和列,可以进行编码,根据行和列的组合确定按下的是哪一个键。
    1. 恢复中断模式
    • 按键检测完毕后,恢复最初的中断模式,即行作为输入(中断),列作为输出,继续等待下次按键按下的中断信号。

矩阵键盘的行和列

  • 使用方法
    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能够正常检测按键事件。
    • 这是任何硬件外设操作的第一步,在系统主循环开始之前,必须初始化所有 的硬件资源 ,以便后续的按键检测能够正常工作。
    1. 在void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)中处理即可
  • 代码示例
cpp 复制代码
#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
相关推荐
HQB20263 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science5 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn5 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天6 小时前
can总线
stm32
桀人6 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯7 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C7 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路7 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc8 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院8 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法