1. 0 软件架构设置
2.0 API 接口以及数据结构定义
3.0 程序代码实现
程序项目的结构如下所示:
第一步:编写LED驱动,初始化驱动程序
创建结构体:第一个参数表示GPIO使能,第二个参数表示单片机的IO口,第三个参数表示需要草操作的单片机引脚,typedef在C语言中可以用于结构体的从命名,结构体的名称是LED_GPIO_T.
创建一个结构体数组,用于存放结构体变量的参数
宏定义数组大小:使用动态的方式进行计算SIZEOF可以计算数组的长度
初始化GPIO驱动,调用结构体变量进行赋值
LED灯开启和熄灭代码
LED.C程序代码
#include "gd32f30x.h" // Device header
#include "Delay.h"
#include <stdint.h>
// 初始化结构体结构体数据类型
typedef struct Led_gpio_t{
rcu_periph_enum rcu;
uint32_t gpio;
uint32_t pin;
}LED_GPIO_T;
// 定义一个静态全局变量保存GPIO口的资源信息
static LED_GPIO_T Gpio_List[] = {
{RCU_GPIOA,GPIOA,GPIO_PIN_8},
{RCU_GPIOE,GPIOE,GPIO_PIN_6},
{RCU_GPIOF,GPIOF,GPIO_PIN_6}
};
// 宏定义确定数组的大小
#define LED_NUM_MAX (sizeof(Gpio_List) / sizeof(Gpio_List[0]))
void LED_Init_Drive(void){
for(uint8_t i = 0; i < LED_NUM_MAX; i++){
// 开启GPIO时钟
rcu_periph_clock_enable(Gpio_List[i].rcu);
// 初始化GPIO
gpio_init(
Gpio_List[i].gpio,
GPIO_MODE_OUT_PP,
GPIO_OSPEED_10MHZ,
Gpio_List[i].pin);
// GPIO 初始化调用的方式
gpio_bit_reset(Gpio_List[i].gpio,Gpio_List[i].pin);
}
}
void Turn_LedOn(uint8_t LedNo){
if(LedNo >= LED_NUM_MAX){
return;
}else{
gpio_bit_set(Gpio_List[LedNo].gpio,Gpio_List[LedNo].pin);
}
}
void Turn_OffLed(uint8_t LedOff){
if(LedOff >= LED_NUM_MAX){
return;
}else{
gpio_bit_reset(Gpio_List[LedOff].gpio,Gpio_List[LedOff].pin);
}
}
// 初始化LED灯
void LED_Init(void){
// 使能RCU时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 配置引脚输出频率
gpio_init( GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_8);
// 初始化GPIOE的引脚
rcu_periph_clock_enable(RCU_GPIOE);
// 配置引脚输出频率
gpio_init( GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_6);
// 初始化GPIOE的引脚
rcu_periph_clock_enable(RCU_GPIOF);
// 配置引脚输出频率
gpio_init( GPIOF, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_6);
}
// 实现循环流水灯的功能
void LED_Cycle(void){
DelayInit();
while(1){
gpio_bit_set(GPIOA, GPIO_PIN_8);
DelayNms(1000);
gpio_bit_reset(GPIOA, GPIO_PIN_8);
DelayNms(1000);
gpio_bit_set(GPIOE, GPIO_PIN_6);
DelayNms(1000);
gpio_bit_reset(GPIOE, GPIO_PIN_6);
DelayNms(1000);
gpio_bit_set(GPIOF, GPIO_PIN_6);
DelayNms(1000);
gpio_bit_reset(GPIOF, GPIO_PIN_6);
DelayNms(1000);
}
}
LED.H 程序代码
#ifndef _LED_H_
#define _LED_H_
#include <stdint.h>
//宏定义LED灯的引脚
#define LED1 0
#define LED2 1
#define LED3 2
void LED_Init(void);
void LED_Cycle(void);
void LED_Init_Drive(void);
void Turn_LedOn(uint8_t LedNo);
void Turn_OffLed(uint8_t LedOff);
#endif
硬件延时代码参考(GD32)
DELAY.C
#include <stdint.h>
#include "gd32f30x.h"
/**
***********************************************************
* @brief DWT初始化配置
* @param
* @return
***********************************************************
*/
void DelayInit(void)
{
/* 关闭 TRC */
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
/* 打开 TRC */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* 关闭计数功能 */
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
/* 打开计数功能 */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
/* 计数清零 */
DWT->CYCCNT = 0;
}
/**
***********************************************************
* @brief 微秒级延时函数
* @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us
* @return
***********************************************************
*/
void DelayNus(uint32_t nUs)
{
uint32_t tickStart = DWT->CYCCNT;
/* 转换为nUs对应的时钟跳动次数rcu_clock_freq_get获取系统的时钟频率*/
nUs *= (rcu_clock_freq_get(CK_AHB) / 1000000);
/* 延时等待 */
while ((DWT->CYCCNT - tickStart) < nUs);
}
/**
***********************************************************
* @brief 毫秒级延时函数
* @param nMs,延时时间n毫秒
* @return
***********************************************************
*/
void DelayNms(uint32_t nMs)
{
for (uint32_t i = 0; i < nMs; i++)
{
DelayNus(1000);
}
}
DELAY.H
#ifndef _DELAY_H_
#define _DELAY_H_
#include <stdint.h>
void DelayInit(void);
void DelayNus(uint32_t nUs);
void DelayNms(uint32_t nMs);
#endif
main 函数代码实现
#include <stdio.h>
#include "gd32f30x.h"
#include "Delay.h"
#include "LED.h"
/*
硬件延时的方法:比较准确
*/
int main(void)
{
// 初始化LED
DelayInit();
// 初始化LED
LED_Init_Drive();
while(1){
Turn_LedOn(LED1);
DelayNms(1000);
Turn_LedOn(LED2);
DelayNms(1000);
Turn_LedOn(LED3);
DelayNms(1000);
Turn_OffLed(LED1);
Turn_OffLed(LED2);
Turn_OffLed(LED3);
DelayNms(1000);
}
}
以上是LED实现流水灯代码案例
4.0 STM32 单片机类比学习
.....