GD 32 流水灯

news2024/11/15 10:59:38

前言:


通过后面的学习掌握了一些逻辑架构的知识,通过复习的方式将学到的裸机任务架构的知识运用起来,同时巩固前面学到的知识,GPIO的配置等。


 开发板上LED引脚使用示意图

 注:此次LED灯的点亮凡是是高电平点亮,因为电流是从外部向内部进行流动,GND会引脚的店电平拉低,如果给低电平的话无法形成电势差,电流是无法流动的,给一个高电平,电流在电压的作用下点亮LED灯

第一种实现方式

这种方式类似于STM32的库函数编程,不使用结构体使用直接编写的方式进行配置,可以作为参考对比学习


1.0 初始化LED

void LED_Init(void)
{
	// 开启RCC时钟
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_GPIOE);
	rcu_periph_clock_enable(RCU_GPIOF);
    // 初始化gpio
	gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_8);
	gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_6);
	gpio_init(GPIOF,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_6);
	// 引脚默认电平为低电平
	gpio_bit_reset(GPIOA, GPIO_PIN_8);
	gpio_bit_reset(GPIOE, GPIO_PIN_6);
	gpio_bit_reset(GPIOF, GPIO_PIN_6);
}

 2.0 LED点亮熄灭

// 高电平的方式点亮
void LED1_On(void)
{
	gpio_bit_set(GPIOA, GPIO_PIN_8);
}

void LED2_On(void)
{
	gpio_bit_set(GPIOE, GPIO_PIN_6);
}

void LED3_On(void)
{
	gpio_bit_set(GPIOF, GPIO_PIN_6);
}

// 低电平的方式熄灭
void LED1_Off(void)
{
	gpio_bit_reset(GPIOA, GPIO_PIN_8);
}

void LED2_Off(void)
{
	gpio_bit_reset(GPIOE, GPIO_PIN_6);
}

void LED3_Off(void)
{
	gpio_bit_reset(GPIOF, GPIO_PIN_6);
}

3.0 LED 流水灯函数

// LED 灯流水效果函数
void LED_Run(void)
{
	LED1_On();
	DelayNms(1000);
	LED2_On();
	DelayNms(1000);
	LED3_On();
	DelayNms(1000);
	
	LED1_Off();
	LED2_Off();
	LED3_Off();
	DelayNms(1000);
}

4.0 LED灯初始化头文件

#ifndef  _LED_DRV_H_
#define  _LED_DRV_H_
#include <stdint.h>

void LED_Init(void);
void LED1_On(void);
void LED2_On(void);
void LED3_On(void);
void LED1_Off(void);
void LED2_Off(void);
void LED3_Off(void);
void LED_Run(void);

#endif

5.0 在主函数中调用

使用面向对象的编码方式,可以使程序看起来更为的简洁,方便程序的后续移植。

#include <stdint.h>
#include "gd32f30x.h"
#include "led_drv.h"
#include "delay.h"

int main(void)
{
	DelayInit();
	LED_Init();
	while(1)
	{
		LED_Run();
	}
}

** 方式 2 **

第二种实现方式

这种实现方式是配合结构体与for循环的方式进行实现,可以方便后续程序的编码与维护,让程序可移植性更强。


1.0 创建结构体

// 创建结构体
typedef struct
{
	// rcu时钟
	rcu_periph_enum rcu;
	// gpio口
	uint32_t gpio;
	// 对应引脚
	uint32_t pin;
	
}LED_GPIO_t;

 2.0 创建结构体数组

// 计算数组大小
#define  LED_NUM_MAX (sizeof(g_gpioList) / sizeof(g_gpioList[0]))

//创建结构体数组
static LED_GPIO_t g_gpioList[] = 
{
	{RCU_GPIOA, GPIOA, GPIO_PIN_8},
	{RCU_GPIOE, GPIOE, GPIO_PIN_6},
	{RCU_GPIOF, GPIOF, GPIO_PIN_6}
};

3.0 初始化GPIO

这里使用for循环遍历,然后将值一个个的赋值给结构体成员变量完成时钟的初始化

void LED_DrvInit(void)
{
	uint8_t i = 0;
	for(i = 0; i < LED_NUM_MAX; i++)
	{
		// 开启rcu时钟
		rcu_periph_clock_enable(g_gpioList[i].rcu);
		// 初始化gpio端口
		gpio_init
		(
			g_gpioList[i].gpio, 
			GPIO_MODE_OUT_PP,
			GPIO_OSPEED_2MHZ, 
			g_gpioList[i].pin
		);
		// 引脚默认值
		gpio_bit_reset(g_gpioList[i].gpio, g_gpioList[i].pin);
	}

}

4.0 点亮LED函数,带参数

// LED_ON 点亮
void LED_No(uint8_t ledNo)
{
	// 判断led编号的值是否大于最大数组长度
	if(ledNo > LED_NUM_MAX)
	{
		return; // 返回值无效
	}
	// 点亮
	gpio_bit_set(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}

5.0 熄灭LED灯函数,带参数

// LED_OFF熄灭
void LED_Off(uint8_t ledNo)
{
	if (ledNo >= LED_NUM_MAX)
	{
		return;
	}
	gpio_bit_reset(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}

6.0 流水灯程序代码实现

void LED_StructRun(void)
{
		LED_No(LED1);
		DelayNms(1000);
		LED_No(LED2);
		DelayNms(1000);
		LED_No(LED3);
		DelayNms(1000);
		LED_Off(LED1);
		LED_Off(LED2);
		LED_Off(LED3);
		DelayNms(1000);
}

8.0 #define 定义LED编号

#define  LED1  0
#define  LED2  1
#define  LED3  2

9.0 函数头文件代码

#ifndef  _LED_STRUCTDRV_H_
#define  _LED_STRUCTDRV_H_

#include "stdint.h"

void LED_DrvInit(void);
// LED_ON 点亮
void LED_No(uint8_t ledNo);
// LED_OFF熄灭
void LED_Off(uint8_t ledNo);
// 流水灯
void LED_StructRun(void);

#endif

10.0 主函数调用程序

#include <stdint.h>
#include "gd32f30x.h"
#include "led_drv.h"
#include "delay.h"
#include "led_struct_drv.h"


int main(void)
{
	DelayInit();
	//	LED_Init();
	LED_DrvInit();
	while(1)
	{
		//		LED_Run();
		LED_StructRun();
	}
}

11.0 完整代码展示

第一种方式完整C函数代码

#include "gd32f30x.h"                   // Device header
#include <stdint.h>
#include "led_drv.h"
#include "delay.h"

void LED_Init(void)
{
	// 开启RCC时钟
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_GPIOE);
	rcu_periph_clock_enable(RCU_GPIOF);
    // 初始化gpio
	gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_8);
	gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_6);
	gpio_init(GPIOF,GPIO_MODE_OUT_PP,GPIO_OSPEED_2MHZ,GPIO_PIN_6);
	// 引脚默认电平为低电平
	gpio_bit_reset(GPIOA, GPIO_PIN_8);
	gpio_bit_reset(GPIOE, GPIO_PIN_6);
	gpio_bit_reset(GPIOF, GPIO_PIN_6);
}

// 高电平的方式点亮
void LED1_On(void)
{
	gpio_bit_set(GPIOA, GPIO_PIN_8);
}

void LED2_On(void)
{
	gpio_bit_set(GPIOE, GPIO_PIN_6);
}

void LED3_On(void)
{
	gpio_bit_set(GPIOF, GPIO_PIN_6);
}

// 低电平的方式熄灭
void LED1_Off(void)
{
	gpio_bit_reset(GPIOA, GPIO_PIN_8);
}

void LED2_Off(void)
{
	gpio_bit_reset(GPIOE, GPIO_PIN_6);
}

void LED3_Off(void)
{
	gpio_bit_reset(GPIOF, GPIO_PIN_6);
}

// LED 灯流水效果函数
void LED_Run(void)
{
	LED1_On();
	DelayNms(1000);
	LED2_On();
	DelayNms(1000);
	LED3_On();
	DelayNms(1000);
	
	LED1_Off();
	LED2_Off();
	LED3_Off();
	DelayNms(1000);
}


第二种方式完整C函数代码

#include "gd32f30x.h"                   // Device header
#include "stdint.h"
#include "delay.h"

#define  LED1  0
#define  LED2  1
#define  LED3  2

// 创建结构体
typedef struct
{
	// rcu时钟
	rcu_periph_enum rcu;
	// gpio口
	uint32_t gpio;
	// 对应引脚
	uint32_t pin;
	
}LED_GPIO_t;

// 计算数组大小
#define  LED_NUM_MAX (sizeof(g_gpioList) / sizeof(g_gpioList[0]))

//创建结构体数组
static LED_GPIO_t g_gpioList[] = 
{
	{RCU_GPIOA, GPIOA, GPIO_PIN_8},
	{RCU_GPIOE, GPIOE, GPIO_PIN_6},
	{RCU_GPIOF, GPIOF, GPIO_PIN_6}
};

void LED_DrvInit(void)
{
	uint8_t i = 0;
	for(i = 0; i < LED_NUM_MAX; i++)
	{
		// 开启rcu时钟
		rcu_periph_clock_enable(g_gpioList[i].rcu);
		// 初始化gpio端口
		gpio_init
		(
			g_gpioList[i].gpio, 
			GPIO_MODE_OUT_PP,
			GPIO_OSPEED_2MHZ, 
			g_gpioList[i].pin
		);
		// 引脚默认值
		gpio_bit_reset(g_gpioList[i].gpio, g_gpioList[i].pin);
	}

}

// LED_ON 点亮
void LED_No(uint8_t ledNo)
{
	// 判断led编号的值是否大于最大数组长度
	if(ledNo > LED_NUM_MAX)
	{
		return; // 返回值无效
	}
	// 点亮
	gpio_bit_set(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}

// LED_OFF熄灭
void LED_Off(uint8_t ledNo)
{
	if (ledNo >= LED_NUM_MAX)
	{
		return;
	}
	gpio_bit_reset(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}

void LED_StructRun(void)
{
		LED_No(LED1);
		DelayNms(1000);
		LED_No(LED2);
		DelayNms(1000);
		LED_No(LED3);
		DelayNms(1000);
		LED_Off(LED1);
		LED_Off(LED2);
		LED_Off(LED3);
		DelayNms(1000);
}



12.0 回调函数基础知识补充

定义:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。如果代码立即被执行就称为同步回调,如果在之后晚点的某个时间再执行,则称之为异步回调

函数 F1 调用函数 F2 的时候,函数 F1 通过参数给 函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback),而先被当做指针传入、后面又被回调的函数 F3 就是回调函数。

以上定义参考自菜鸟教程

#define _CRT_SECURE_NO_WARNINGS
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>


int Sum(int x, int y) 
{
    return x + y;
}

// 创建一个函数,参数是函数指针
void Handle(int (*pSum)(int a, int b)) 
{
    int sum = (*pSum)(1, 2);
    printf("%d\n", sum);
}

int main() {
   
    Handle(Sum);
    return 0;

}

函数的执行结果是3

typedef 可以对函数进行重定义,注意这个时候的写法是表示的含义还是不同的比如以下的案例

typedef unsigned char uchar; 给变量进行从命名,如unsigned char 命名为uchar,

#define _CRT_SECURE_NO_WARNINGS
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

// 这个时候函数指针变量的名字是 PFUNC
typedef int (*PFUNC)(int a, int b);

int Sum(int x, int y) 
{
    return x + y;
}

// 创建一个函数,参数是函数指针
void Handle(PFUNC pSum)
{
    int sum = (*pSum)(1, 2);
    printf("%d\n", sum);
}

int main() {
   
    Handle(Sum);
    return 0;

}

以上程序的执行结果也是三


 ...


结尾


目的是通过本次代码的编写巩固之前的知识,同时使用想把裸机程序任务调度的方式,以及回调函数的知识运用在本次的代码当中,方便理解后续的代码知识,以上内容仅供学习参考,后续后继续更细裸机任务调度方案以及回调函数相关的运用。

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

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

相关文章

Java 集合中的 Vector 类和 Stack 类

一.介绍 Java 集合框架提供了一组强大的类和接口来处理和操作对象集合。其中&#xff0c;Vector 和 Stack 类提供了以顺序方式存储和管理元素的基本功能。这两个类都是传统集合的一部分&#xff0c;但由于它们的同步性质和特定用例&#xff0c;它们仍然具有相关性。Vector 类实…

【HarmonyOS】关于鸿蒙消息推送的心得体会(二)

【HarmonyOS】关于鸿蒙消息推送的心得体会&#xff08;二&#xff09; 前言 推送功能的开发与传统功能开发还是有很大区别。首先最大的区别点就在于需要多部门之间的协同&#xff0c;作为鸿蒙客户端开发&#xff0c;你需要和产品&#xff0c;运营&#xff0c;以及后台开发一起…

linux 部署flask项目

linux python环境安装: https://blog.csdn.net/weixin_41934979/article/details/140528410 1.创建虚拟环境 python3.12 -m venv .venv 2.激活环境 . .venv/bin/activate 3.安装依赖包(pip3.12 install -r requirements.txt) pip3.12 install -r requirements.txt 4.测试启…

Windows安装Visual Studio2022 + QT5.15开发环境

最近&#xff0c;把系统换成了Windows11&#xff0c;想重新安装QT5.12&#xff0c;结果发现下载不了离线安装包。 最后索性安装QT5.15了&#xff0c;特此记录下。 预祝大家&#xff1a;不论是何时安装&#xff0c;都可以安装到指定版本的QT。 一、VS2022安装 VS2022官网下…

推荐一款基于 SpringBoot2 的后台管理系统脚手架,非常轻量简单(附源码)

前言 在现代软件开发中&#xff0c;后台管理系统是企业数字化转型的关键组成部分。然而&#xff0c;现有软件常常存在一些痛点&#xff0c;如复杂的权限管理、缺乏灵活的工作流配置、监控和日志功能不完善等。此外&#xff0c;许多系统study 成本高&#xff0c;依赖关系复杂&a…

Pycharm软件Win 64位安装包+详细安装步骤 百度云

如大家所掌握的&#xff0c;Pycharm是一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门用于python语言开发的工具。作为一款功能强大的IDE&#xff0c;Pycharm提供了丰富的功能和工具&#xff0c;使得python开发变得更加高效和便捷。 Pycharm常用场景如下&#x…

Unity发布XR中用于worldbuilding的全新电子书

通过身临其境的虚拟领域开始旅程&#xff0c;在维度之间传送&#xff0c;或将数字奇迹与现实世界融合——虚拟现实(VR)和混合现实(MR)的千万种可能性将邀请创作者把他们的想象力带入生活。 Unity发布的最新版综合指南将帮助有抱负的创作者和经验丰富的开发者深入研究和理解构建…

LLM模型与实践之基于 MindSpore 实现 BERT 对话情绪识别

安装环境 # 该案例在 mindnlp 0.3.1 版本完成适配&#xff0c;如果发现案例跑不通&#xff0c;可以指定mindnlp版本&#xff0c;执行!pip install mindnlp0.3.1 !pip install mindnlp 模型简介 BERT是一种由Google于2018年发布的新型语言模型&#xff0c;它是基于Transforme…

云计算核心算法(二)

目录 二、DHT算法&#xff08;一&#xff09;DHT原理介绍&#xff08;二&#xff09;Chord中DHT的具体实现&#xff08;三&#xff09;Pastry中DHT的具体实现&#xff08;四&#xff09;CAN中DHT的具体实现&#xff08;五&#xff09;Tapestry中DHT的具体实现 三、Gossip协议&a…

数据结构之栈详解

1. 栈的概念以及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈…

HDU1032——The 3n + 1 problem,HDU1033——Edge,HDU1034——Candy Sharing Game

目录 HDU1032——The 3n 1 problem 题目描述 运行代码 代码思路 HDU1033——Edge 题目描述 运行代码 代码思路 HDU1034——Candy Sharing Game 题目描述 运行代码 代码思路 HDU1032——The 3n 1 problem 题目描述 Problem - 1032 运行代码 #include <iostr…

H3CNE(路由基础、直连路由与静态路由)

目录 6.1 直连路由 6.2 静态路由理解性实验 6.2.1 配置直连路由 6.2.2 配置静态路由 6.3 路由表的参数与比较 6.3.1 优先级的比较 6.3.2 开销的比较 6.4 路由器中的等价路由、浮动路由、默认路由 6.4.1 等价路由 6.4.2 浮动路由 6.4.3 默认路由(缺省路由) 6.1 直连路…

Golang | Leetcode Golang题解之第278题第一个错误的版本

题目&#xff1a; 题解&#xff1a; func firstBadVersion(n int) int {return sort.Search(n, func(version int) bool { return isBadVersion(version) }) }

宿舍生活新升级:智能指纹锁的便捷体验(嘉立创EDA设计)

宿舍生活新升级&#xff1a;智能指纹锁的便捷体验 引言 宿舍生活总是充满挑战和乐趣&#xff0c;但有时也会因为一些小事情而变得复杂。比如&#xff0c;忘记带钥匙或者需要频繁地给室友开门。随着科技的发展&#xff0c;智能设备逐渐走进我们的生活&#xff0c;为日常带来便…

iPhone能运行Windows了 iOS正在被逼加速开放

用iPhone来运行Windows 11&#xff1f;是的&#xff0c;两个八竿子打不着的设备和系统&#xff0c;居然还有融合的一天。虽然不管从哪个方向来看&#xff0c;这都是一个很奇葩的玩法&#xff0c;但是背后却代表着iOS生态的进一步松绑&#xff0c;iOSAndroid化似乎不再仅限于功能…

【iOS】进程与多线程

目录 前言进程和线程进程和线程的区别多线程的意义时间片概念 线程的生命周期线程池的运行策略自旋锁和互斥锁自旋锁互斥锁自旋锁和互斥锁区别原子属性 iOS多线程技术方案 前言 学习此文&#xff1a;iOS多线程 在平时的iOS开发中&#xff0c;多线程是我们常会遇到的&#xff0…

EasyMedia转码rtsp视频流flv格式,hls格式,H5页面播放flv流视频

EasyMedia转码rtsp视频流flv格式&#xff0c;hls格式 H5页面播放flv流视频 文章最后有源码地址 解决海康视频播放视频流&#xff0c;先转码后自定义页面播放flv视频流 先看效果&#xff0c;1&#xff0c;EasyMedia自带的页面&#xff0c;这个页面二次开发改动页面比较麻烦 …

WARNING: The Nouveau kernel driver is currently in use by your system. 处理方法

实践系统&#xff1a; 安装NVIDIA驱动时&#xff0c;提示&#xff1a; WARNING: The Nouveau kernel driver is currently in use by your system. This driver is incompatible with the NVIDIA driver&#xff0c;and must be disabled before proceeding.警告&#xff1…

【分布式锁】Redis实现分布式锁

在分布式系统中&#xff0c;当多个服务实例&#xff08;或节点&#xff09;需要访问或修改同一份共享资源时&#xff0c;就需要使用分布式锁来确保数据的一致性和防止并发问题。这种情况下&#xff0c;传统的Java并发控制机制如ReentrantLock或synchronized就无法满足需求&…

.NET开源、简单、实用的数据库文档生成工具

前言 今天大姚给大家分享一款.NET开源&#xff08;MIT License&#xff09;、免费、简单、实用的数据库文档&#xff08;字典&#xff09;生成工具&#xff0c;该工具支持CHM、Word、Excel、PDF、Html、XML、Markdown等多文档格式的导出&#xff1a;DBCHM。 支持的数据库 Sq…