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

news2024/11/24 4:25:14

如同所有编程入门的第一个教程——打印"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  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);

/**
  * @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);

另外,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 */

/* 点亮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 LED1     GPIO_PIN_8
#define LED2     GPIO_PIN_9
#define LED3     GPIO_PIN_10
#define LED4     GPIO_PIN_11
#define LED5     GPIO_PIN_12
#define LED6     GPIO_PIN_13
#define LED7     GPIO_PIN_14
#define LED8     GPIO_PIN_15
#define LED_None 0x0000
#define LED_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 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/882400.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】queue容器

1.queue容器基本概念 2.queue常用接口 #include <iostream> using namespace std;//队列queue #include<queue>//创建Person类 class Person { public:Person(string name, int age){this->m_Name name;this->m_Age age;}string m_Name; //姓名int m_Age; …

【hive】hive中row_number() rank() dense_rank()的用法

hive中row_number() rank() dense_rank()的用法 一、函数说明 主要是配合over()窗口函数来使用的&#xff0c;通过over(partition by order by )来反映统计值的记录。 rank() over()是跳跃排序&#xff0c;有两个第二名时接下来就是第四名(同样是在各个分组内)dense_rank() …

04-分支语句和逻辑运算符

分支语句和逻辑运算符 6.1、if语句 if 结构 例子 统计输入的字符数、空格数 // if.cpp -- using the if statement #include <iostream> int main() {using std::cin; // using declarationsusing std::cout;char ch;int spaces 0;int total 0;cin.get(ch);wh…

mysql数据库设置创建时间和更新时间自动更新

1、创建时间&#xff1a;CURRENT_TIMESTAMP 2、修改时间&#xff1a;ON UPDATE CURRENT_TIMESTAMP DROP TABLE IF EXISTS mall_pay_info; CREATE TABLE mall_pay_info (id int(11) NOT NULL AUTO_INCREMENT,user_id int(11) DEFAULT NULL COMMENT 用户id,order_no bigint(20)…

IS3DH加速度计使用SPI和IIC方式读取数据LIS3DH中英文文档和测试代码

最近博主在研究一款低功耗加速度计LIS3DH&#xff0c;该加速度计有两种通信模式&#xff0c;IIC和SPI方式。IIC通信方式搞了一下 就好了&#xff0c;但是SPI方式针扎了两天才做出来&#xff0c;现在和大家分享一下心得。 开发环境&#xff1a;MDK keil5 使用芯片&#xff1a…

Centos7 配置Docker镜像加速器

daemon.json 文档说明&#xff1a; docker安装后默认没有daemon.json这个配置文件&#xff0c;需要进行手动创建&#xff0c;docker不管是在哪个平台以何种方式启动, 默认都会来这里读取配置,使用户可以统一管理不同系统下的 docker daemon 配置。 如果在daemon.json文件中进行…

Syncfusion Essential Studio JavaScrip Crack

Syncfusion Essential Studio JavaScrip Crack 数据透视表 添加了在将数据透视表导出到PDF文档时自定义列宽的支持。 签名 添加了对在特定位置绘制文本的支持。 Syncfusion Essential Studio for JavaScript在一个包中包含80多个高性能、轻量级、模块化和响应式UI组件。包括Jav…

Memory Allocators 101 - Write a simple memory allocator

Memory Allocators 101 - Write a simple memory allocator - Arjun Sreedharan BlogAboutContactPosts GoogleLinkedInGithubFacebookTwitterUMass Amherst 1:11 AM 9th 八月 20160 notes Memory Allocators 101 - Write a simple memory allocator Code related to this…

数据结构——B-树、B+树、B*树

一、B-树 1. B-树概念 B树是一种适合外查找的、平衡的多叉树。一棵m阶&#xff08;m>2&#xff09;的B树&#xff0c;是一棵平衡的M路平衡搜索树&#xff0c;它可以是空树或满足以下性质&#xff1a; &#xff08;1&#xff09;根节点至少有两个孩子。 &#xff08;2&#…

Integer中缓存池讲解

文章目录 一、简介二、实现原理三、修改缓存范围 一、简介 Integer缓存池是一种优化技术&#xff0c;用于提高整数对象的重用和性能。在Java中&#xff0c;对于整数值在 -128 到 127 之间的整数对象&#xff0c;会被放入缓存池中&#xff0c;以便重复使用。这是因为在这个范围…

UDP 的报文结构以及注意事项

UDP协议 1.UDP协议端格式 1.图中的16位UDP长度,表示整个数据报(UDP首部UDP数据)的最大长度 2.若校验和出错,会直接丢弃 2.UDP的报文结构 UDP报文主体分为两个部分:UDP报头(占8个字节)UDP载荷/UDP数据 1.源端口号 16位,2个字节 2.目的端口号 16位,2个字节 3.包长度 指示了…

laravel框架中批量更新数据

在php框架中 tp中就有批量更新封装好的 SaveAll 在laravel中有批量插入没有批量更新操作;因此我们可以自己去封装一个 然后批量进行更新操作 封装参考代码: /*** 批量更新** param $tableName 表名称* param string $pk 更新的字段* param array $multipleData 要更新的数据*…

免费SAFe敏捷工具,SAFe框架执行

Leangoo领歌覆盖了敏捷项目研发全流程&#xff0c;包括小型团队敏捷开发&#xff0c;Scrum of Scrums大规模敏捷。 Leangoo领歌是ScrumCN&#xff08;scrum.cn&#xff09;旗下的一款永久免费的敏捷研发管理工具。 Leangoo领歌覆盖了敏捷研发全流程&#xff0c;包括小型团队敏…

七、Linux操作系统下,whichfind如何使用?

1、which命令 &#xff08;1&#xff09;语法&#xff1a;which 参数 &#xff08;2&#xff09;参数&#xff1a;要查找的命令 &#xff08;3&#xff09;示例&#xff1a; 2、find命令 &#xff08;1&#xff09;find 起始路径 -name “被查找的文件名” 注意&#xff1…

多环境_部署项目

多环境&#xff1a; 指同一套项目代码在不同的阶段需要根据实际情况来调整配置并且部署到不同的机器上。 为什么需要&#xff1f; 1. 每个环境互不影响 2. 区分不同的阶段&#xff1a;开发 / 测试 / 生产 3. 对项目进行优化&#xff1a; 1. 本地日志级别 2. 精简依赖&a…

虫情测报灯——监测预警分析

KH-CQPest虫情测报灯是专为田间虫害统计、农林虫情测报而研制的设备&#xff0c;利用光、电、数控等技术实现自动诱虫、杀虫、虫体分散、拍照、运输、收集、排水等系统作业等功能&#xff0c;当有害虫出现时&#xff0c;会受到诱集光源的影响&#xff0c;自动飞扑撞向撞击屏&am…

网络基础——网络协议是什么?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、理解网络协议 1、网络协议是什么&#xff1f; 2、网络协议的三要素 二、常见的网络协议 1、TCP/IP协议 2、HTTP协议 3、FTP协…

AD8302 - 信号幅度相位检测

AD8302 - 信号幅度相位检测 AD8302模块AD8302简介芯片特点模块引脚AD8302工作原理内部框图工作原理 实验接线鉴相鉴幅 实验总结 AD8302模块 AD8302简介 AD8302是ADI公司推出的一个款用于测量RF/IF信号幅度和相位的单片集成电路&#xff0c;它能同时测量从低频到 2.7GHz 频率范…

uniapp的uview-plus组件库的导入

uniapp的vue3中使用uview-plus组件库。在插件市场中找到该组件并点击如下所示绿色按钮&#xff0c;弹出弹窗选择要导入的项目后&#xff0c;就会在uni_modules文件中生成如下文件内容 关于插件的下载区别&#xff0c;可参考&#xff1a;https://uniapp.dcloud.net.cn/compone…

互联网发展历程:跨越远方,路由器的启示

互联网的蓬勃发展&#xff0c;一直在追求更广阔的连接&#xff0c;更遥远的距离。然而&#xff0c;在早期的网络中&#xff0c;人们面临着连接距离有限的问题。一项重要的技术应运而生&#xff0c;那就是“路由器”。 连接受限的问题&#xff1a;距离有限 早期的网络受限于直接…