【速成】蓝桥杯嵌入式省一教程:(一)点亮LED

本文介绍了单片机开发中的基本操作,包括GPIO概念、如何通过STM32G431RBT6控制LED亮灭,以及使用Cube配置GPIO输出模式和实现LED操作的代码示例。作者还展示了如何将LED操作封装成库,便于在嵌入式项目中复用。
摘要由CSDN通过智能技术生成

如同所有编程入门的第一个教程——打印"Hello world"一样,点亮LED可以算得上是嵌入式开发中的"Hello world",所有的单片机开发入门都从这里开始。

在点亮LED前,我们需要先了解一个重要概念——GPIO(General Purpose Input Output),即通用输入输出端口。一个单片机上通常有许许多多的端口,这些端口通常都可用作GPIO输入或输出。当其被作为GPIO输出时,我们可以通过编程,使该端口输出高电平或低电平,从而实现点灯操作;当其被作为GPIO输入时,可以将该端口外接某电路的某一接口(如按键),从而编程读取该端口的电平状态,为我们的其他功能服务。在对GPIO有一个初步了解之后,我们就可以通过电路原理图来看看如何点亮LED。(下图在选手资源数据包——CT117E-M4产品手册中)

可以看到,STM32G431RBT6是通过控制PC8~PC15以及PD2的电平状态来控制LED的亮灭的。以LD1为例,PD2端口为使能位(LE——LED ENABLE),PD2置高时,才能对LED进行操作;而当PC8置低时,二极管导通,LD1被点亮,当PC8置高时,二极管截止,LD1熄灭因此,我们要将这些端口设置为GPIO输出模式。

在Cube中,我们进行如下配置,从而设置需要用到的端口为GPIO输出模式:

点亮LD1的代码实现如下:

/* 点亮LD1一秒后熄灭 */
void LD1_TEST(void)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);    //PD2置高,使能LED
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);  //PC8置低,点亮LD1
    HAL_Delay(1000);                                       //延时1s
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);    //PC8置高,熄灭LD1
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);  //PD2置低,关闭LED操作
}

这是最基础的LED操作。学会点亮LD1之后,就可以随心所欲地对LED进行操作,实现各种功能啦!

#define DELAY_TIME 100 //延时100ms

/* LD1~LD8轮流亮灭,实现跑马灯 */
void LED_TEST(void)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_8);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_11);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_12);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_15);                //翻转电平
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_Delay(DELAY_TIME);
}

其实不止点亮LED,单片机端口的GPIO输出功能还能应用于各种各样的场景。当某一电路的某一接口需要外部输入高低电平来控制某一功能时,就可以使用到这一功能。HAL库中与GPIO输出有关的函数如下:

/**
  * @brief  Set or clear the selected data port bit.
  *
  * @note   This function uses GPIOx_BSRR and GPIOx_BRR registers to allow atomic read/modify
  *         accesses. In this way, there is no risk of an IRQ occurring between
  *         the read and the modify access.
  *
  * @param  GPIOx where x can be (A..G) to select the GPIO peripheral for STM32G4xx family
  * @param  GPIO_Pin specifies the port bit to be written.
  *         This parameter can be any combination of GPIO_PIN_x where x can be (0..15).
  * @param  PinState specifies the value to be written to the selected bit.
  *         This parameter can be one of the GPIO_PinState enum values:
  *            @arg GPIO_PIN_RESET: to clear the port pin
  *            @arg GPIO_PIN_SET: to set the port pin
  * @retval None
  */
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

/**
  * @brief  Toggle the specified GPIO pin.
  * @param  GPIOx where x can be (A..G) to select the GPIO peripheral for STM32G4xx family
  * @param  GPIO_Pin specifies the pin to be toggled.
  *         This parameter can be any combination of GPIO_PIN_x where x can be (0..15).
  * @retval None
  */
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

另外,LED操作中还使用到了一个非常常用的函数——延时函数,它是以ms为单位进行延时的。

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay);

为方便,我们可以将LED操作写成一个库,这样在需要的时候直接调用库即可。这种模块化思想在复杂的嵌入式系统中是极为关键的。

/* led.c */

#include "led.h"

/* 点亮LED */
void LED_On(uint16_t LED_Pin)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC, LED_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

/* 熄灭LED */
void LED_Off(uint16_t LED_Pin)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC, LED_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

/* 翻转LED */
void LED_Toggle(uint16_t LED_Pin)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_TogglePin(GPIOC, LED_Pin);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
/* led.h */

#ifndef __LED_H
#define __LED_H

#include "main.h"

#define LD1     GPIO_PIN_8
#define LD2     GPIO_PIN_9
#define LD3     GPIO_PIN_10
#define LD4     GPIO_PIN_11
#define LD5     GPIO_PIN_12
#define LD6     GPIO_PIN_13
#define LD7     GPIO_PIN_14
#define LD8     GPIO_PIN_15
#define LD_None 0x0000
#define LD_All  0xFF00

void LED_On(uint16_t LED_Pin);
void LED_Off(uint16_t LED_Pin);
void LED_Toggle(uint16_t LED_Pin);

#endif /* __LED_H */

下面我们以第十四届省赛题为例,总结本文所讲内容:

/* Cube自动生成的头文件引用 */
#include "led.h"

int main(void)
{
    /* Cube自动生成的初始化 */
    LED_Off(LD_All);

    while(1)
    {
        if (数据界面)
        {
            LED_On(LD1);
        }
        else
        {
            LED_Off(LD1);
        }

        if (模式切换)
        {
            LED_Toggle(LD2);
            HAL_Delay(100);
        }

        if (锁定状态)
        {
            LED_On(LD3);
        }
        else
        {
            LED_Off(LD3);
        }
    }
}
  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值