目录
[(2)STM32CubeMX 软件配置](#(2)STM32CubeMX 软件配置)
[🟢️main 函数](#🟢️main 函数)
[(2)STM32CubeMX 软件配置](#(2)STM32CubeMX 软件配置)
[🟢️main 函数](#🟢️main 函数)
一、GPIO输出------LED
(1)资源介绍
🔅原理图
在新版蓝桥杯物联网竞赛实训平台中,每个节点都有3个板载 LED ,D1 、D2 、D3;
🟢️LED原理图如图1所示:
图1 LED电路原理图
通过电路图连接可知,引脚资源配置情况为:
LED | MCU |
---|---|
D1 | PB2 |
D2 | PB5 |
D3 | PB12 |
[表1 引脚资源配置情况] |
🔅驱动原理
D1 、D2 、D3 是发光二极管,其左侧连接芯片引脚,右侧连接 VDD,即节点电源。
- 当引脚输出低电平时,LD 两侧压差大于二极管导通电压而导通,LD 点亮;
- 当引脚输出高电平时,LD 两侧压差小于二极管导通电压而截止,LD 熄灭;
(2)STM32CubeMX 软件配置
1️⃣打开软件,在搜索栏中搜索 STM32WLE5CCU6 系列 → 在右侧下方选择 UFQFPN48 封装 → 点击 "Start Project";
图2 STM32CubeMX芯片选择
2️⃣点击 "System Core" 栏 → 点击 "RCC" → 将 "HSE" 和 "LSE" 配置为**"Crystal/Ceramic Resonator"**(水晶/陶瓷晶振);
如图4所示,新版平台的MCU 连接了两个外部晶振,分别是32.768kHz 的低速晶振和32MHz的高速晶振,能够提供更稳定的时钟;
这里的低速晶振修复了旧平台RTC 时钟不准的bug;
图3 外部时钟源配置
图4 外部晶振
3️⃣点击 "Trace and Debug" → 点击 "DEBUG" → 将**"JTAG and Trace"** 栏配置为 "Serial Wire" ,从而配置 Debug 串行线,有助于 Keil 编译器的 Debug调试与信号的追踪检测;
图5 Debug线配置
4️⃣点击 "Clock Configuration" 栏 → 在 "HCLK1(MHz)" 框中填写最大时钟 48 (MHz) → 回车即可自动配置时钟树;
图6 时钟树配置
5️⃣回到 "Pinout & Configuration" 栏 → 点击 "System Core" 栏 → 点击 "NVIC" 栏 → 将**"Time base: System tick timer"** 的 "Preemption priority" 更改为0;
⚠️这里是将时基时钟中断的抢占优先级 更改为0,即最高优先级,以此保证时基时钟的准确性;
图7 时基时钟中断抢占优先级更改
6️⃣点击引脚 PB2、PB5、PB12 → 选择 GPIO_Output模式(此处默认为推挽输出);
图8 LED引脚配置
7️⃣点击 "Project Manager" 栏 → ⚠️注意 "Toolchain / IDE" 应当修改为 "MDK-ARM" → **"Code Generator"**栏中配置如图10所示 → 生成代码,打开文件即可;
图9 工具链切换
图10 Code Generator配置
(3)代码编写
🟢️main 函数
cpp
/**
* @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 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 引脚电平翻转
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
// 延迟500ms
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(4)实验现象
D1、D2、D3 间隔0.5s闪烁;
二、LED接口函数封装
🟡️LED接口函数
cpp
/* LED接口函数 */
void LED_Disp(uint8_t led_state)
{
/* LD1 */
if((led_state & 1) == 1)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET); // 低电平点亮
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); // 高电平熄灭
/* LD2 */
if((led_state & 2) == 2)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
/* LD3 */
if((led_state & 4) == 4)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
}
🔴LED接口函数调用实例
cpp
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t led_state = 0; // led状态变量定义
/* 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 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
led_state ^= 1; // D1状态取反
led_state &= ~2; // D2点亮
LED_Disp(led_state);
HAL_Delay(500);
led_state |= 2; // D2熄灭
LED_Disp(led_state);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
三、GPIO输入------KEY
(1)资源介绍
🔅原理图
在新版蓝桥杯物联网竞赛实训平台中,每个节点都有2个板载 KEY ,SW1 、SW2;
🟢️KEY原理图如图11所示:
图11 KEY电路原理图
通过电路图连接可知,引脚资源配置情况为:
KEY | MCU |
---|---|
SW1 | PA8 |
SW2 | PB8 |
[表2 引脚资源配置情况] |
🔅驱动原理
SW 上方连接着 10K 电阻(上拉电阻)、节点电源 VDD、引脚,下方接地。
- 当按键按下时,引脚与 GND 连接导通,读取到低电平;
- 当按键抬起时,引脚与 VDD 连接,读取到高电平;
(2)STM32CubeMX 软件配置
1️⃣返回软件,点击引脚 PA8、PB8 → 选择 GPIO_Input模式(此处默认不配置上拉电阻和下拉电阻,由于按键电路已经带有上拉电阻,故不修改相关配置);
图12 按键引脚配置
2️⃣生成代码;
(3)代码编写
🟢️main 函数
cpp
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t led_state = 0xff; // led状态变量,初始全灭
/* 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 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// SW1按键状态检测
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0)
{
HAL_Delay(10); // 延迟消抖
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) // 再次检测,确认是否是按下
{
led_state &= ~1; // D1亮
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0); // 抬手检测
}
}
// SW2按键状态检测
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == 0)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == 0)
{
led_state |= 1; // D1灭
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == 0);
}
}
// LED显示
LED_Disp(led_state);
HAL_Delay(10); // 延迟10ms
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(4)实验现象
按下按键SW1 ,D1亮;
按下按键SW2 ,D1灭;
四、KEY接口函数封装
🟡️KEY接口函数
cpp
uint8_t Key_Read(void)
{
uint8_t key_value = 0; // 中间变量,存储按键状态
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) // 引脚状态读取
key_value |= 1; // 读取到按键SW1按下
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == 0)
key_value |= 2; // 读取到按键SW2按下
else
key_value = 0; // 均未读到
return key_value;
}
🔴KEY接口函数调用实例
cpp
uint8_t cnt_10ms; // 10ms计时变量,放在滴答计时器中自增
uint8_t led_state = 0xff; // led状态变量,初始全灭
/* 按键任务处理函数 */
void Task_Key(void)
{
uint8_t key_temp, key_down;
static uint8_t key_old = 0;
/* 每10ms进入一次 */
if(cnt_10ms < 10) return;
cnt_10ms = 0;
/* 边沿检测 */
key_temp = Key_Read(); // 键值读取
key_down = key_temp & (key_temp ^ key_old); // 下降沿判断
key_old = key_temp; // 键值存储
/* 下降沿逻辑 */
if(key_down)
{
switch(key_down)
{
// SW1 按下
case 1:
led_state &= ~1; // D1亮
break;
// SW2 按下
case 2:
led_state |= 1; // D1灭
break;
// SW1和SW2同时按下
case 3:
led_state ^= 2; // D2状态取反
break;
default: break;
}
}
}
五、GPIO常用函数讲解
🔅GPIO写函数
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
- **作用:**设置或清除选定的数据端口位;
- **参数1:**GPIO端口
- **参数2:**GPIO引脚
- **参数3:**指定要写入所选位的值:GPIO_PIN_RESET(清除)、GPIO_PIN_SET(置位)
- **返回值:**无
在LED接口封装函数中,使用了该函数。可以理解为对端口引脚写入电平1或者电平0;
🔅GPIO读函数
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
- 作用:读取指定引脚的电平;
- 参数1:GPIO端口
- 参数2:GPIO引脚
- 返回值:引脚电平值
在KEY接口封装函数中,使用了该函数。用于读取引脚的输入电平;
⚠️该函数不仅仅用于读取输入引脚,还可以用于读取输出引脚,从而判断是否输出正确的电平值❗️
🔅GPIO翻转函数
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
- **作用:**翻转指定引脚的电平;
- **参数1:**GPIO端口
- **参数2:**GPIO引脚
- **返回值:**无
在做LED闪烁功能时,可以直接调用该函数;