GD 32 流水灯

前言:


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


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

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

第一种实现方式

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


1.0 初始化LED

cpp 复制代码
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点亮熄灭

cpp 复制代码
// 高电平的方式点亮
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 流水灯函数

cpp 复制代码
// 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灯初始化头文件

cpp 复制代码
#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 在主函数中调用

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

cpp 复制代码
#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 创建结构体

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

2.0 创建结构体数组

cpp 复制代码
// 计算数组大小
#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循环遍历,然后将值一个个的赋值给结构体成员变量完成时钟的初始化

cpp 复制代码
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函数,带参数

cpp 复制代码
// 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灯函数,带参数

cpp 复制代码
// 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 流水灯程序代码实现

cpp 复制代码
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编号

cpp 复制代码
#define  LED1  0
#define  LED2  1
#define  LED3  2

9.0 函数头文件代码

cpp 复制代码
#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 主函数调用程序

cpp 复制代码
#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函数代码

cpp 复制代码
#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函数代码

cpp 复制代码
#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 就是回调函数。

以上定义参考自菜鸟教程

cpp 复制代码
#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,

cpp 复制代码
#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;

}

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


...


结尾


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

相关推荐
智商偏低6 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen7 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森9 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白9 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D10 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术13 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt13 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘13 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang14 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n16 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件