ARM32开发--GPIO--LED驱动开发

news2024/11/15 18:50:42

知不足而奋进 望远山而前行


目录

文章目录

前言

目标

内容

需求介绍

现实问题

需求分析

测试案例构建

BSP驱动构建

接口定义

业务实现

总结


前言

前言:
在这个快节奏的开发环境中,面对紧迫的项目截止日期和有限的资源,我们作为软件工程师需要具备快速解决问题的能力。本项目要求我们设计一个基于STM32的BSP驱动,以实现一个智能充电状态显示系统,该系统通过四个LED灯来展示充电状态和电量百分比。尽管在产品最终的电路板还未完成的情况下,我们只有开发板可以使用,但我们仍然面临着快速完成这个任务的压力。

在这个过程中,我们将采用模块化的方法来编写代码,以确保其可读性和可维护性。我们将定义一系列接口,以便其他开发者在将来可以轻松地与我们的驱动代码集成。我们还将在设计中考虑时间管理和延时问题,以确保LED灯的闪烁效果能够准确地反映充电状态。


目标

  1. 能够理解bsp开发
  2. 能够基于需求进行bsp驱动封装

内容

需求介绍

开发版中有4个灯,现在需要用4个灯显示充电情况:

  1. 开始充电时,需要呈现出流水灯闪烁
  2. 4盏灯表示当前的电量
  3. 充电流水灯起始位置是当前电量,全部点亮后,再次从当前电量位置进入流水灯效果
  4. 结束充电时,关闭充电显示,当前电量进行闪烁3次,然后熄灭。

现实问题

  1. 产品最终电路板还没画好,目前只有产品所使用的芯片对应的开发板。
  2. ADC功能是别人开发,还没完成。
  3. 老板要求,如果开发板好了,要尽快完成工作。

需求分析

要啥没啥,还得尽快完成。盘点手头有的东西,开发板。构建测试案例逻辑,方便后续移植。

测试案例设计:

  1. 准备工作,4个灯,3个按钮
  2. 按钮1按下时,模拟开始充电
  3. 按钮2按下时,模拟停止充电
  4. 按钮3按下时,模拟电量增加。

如果测试方案通过,基本上功能完成,那么后续其他人工作完成后,只需要对接以下逻辑:

  1. 灯对应的引脚和最终设计的电路板引脚进行校准
  2. 开始充电
  3. 电量变化时,更新电量
  4. 结束充电

编码实现分析:

  1. 需要把4个灯作为一个业务逻辑整体,完成一套关于电池电量显示的驱动
  2. 需要抽象出业务逻辑,转换为函数实现

测试案例构建

  • PC0作为:开始按钮
  • PC1作为:停止按钮
  • PC2作为:电量更新按钮

按钮逻辑构建

static void GPIO_config(){	
	// PD0	开始充电
	// PD1 	结束充电
	// PD5	电量变化
	// rcu时钟
	rcu_periph_clock_enable(RCU_GPIOD);
	// 配置GPIO模式
	gpio_mode_set(GPIOD,GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5);	
}

int main(void) {

	// 系统滴答定时器初始化
	systick_config();
	// GPIO初始化
	GPIO_config();

	// LED初始化
	Battery_led_init();

	FlagStatus pre_state0 = SET;// 默认高电平抬起
	FlagStatus pre_state1 = SET;// 默认高电平抬起
	FlagStatus pre_state2 = SET;// 默认高电平抬起
	uint32_t cnt = 0;
	uint8_t power = 1;
	while(1) {
		// PC0
		FlagStatus state0 = gpio_input_bit_get(GPIOC, GPIO_PIN_0);
		if (state0 != pre_state0){
			if(state0 == RESET){   // 当前低电平, 上一次为高电平,按下
				Battery_led_start(power);
			}
			pre_state0 = state0;	
		}
		// PC1
		FlagStatus state1 = gpio_input_bit_get(GPIOC, GPIO_PIN_1);
		if (state1 != pre_state1){
			if(state1 == RESET){   // 当前低电平, 上一次为高电平,按下
				Battery_led_stop();
			}
			pre_state1 = state1;	
		}
		// PC2
		FlagStatus state2 = gpio_input_bit_get(GPIOC, GPIO_PIN_2);
		if (state2 != pre_state2){
			if(state2 == RESET){   // 当前低电平, 上一次为高电平,按下
				//				Battery_led_turn_off(LED1);
				Battery_led_update(++power);
			}
			pre_state2 = state2;	
		}

		// 间隔50个10ms = 500ms执行一次led的状态更新
		if(++cnt % 50 == 0){
			Battery_led_loop();
		}

		delay_1ms(10);
	}

}
BSP驱动构建
接口定义
  1. 驱动初始化,属于标配
  2. 业务相关的操作行为抽象化
  3. 时序问题
void Battery_led_int();

具体的业务抽象行为

void Battery_led_start(uint8_t power);
void Battery_led_stop();
void Battery_led_update(uint8_t power);

在涉及到需要控制时间的问题时,我们通常有以下做法:

  1. 自己主动调用 delay来进行延时
  2. 使用统一的延时,到达自己的时间点就去执行

自己调用delay 不利于后续的移植。

采用统一时钟,方便移植,也方便时间片统一调度管理

业务实现
  1. 采用bsp独立驱动进行开发
  2. 状态管理,通过status记录当前状态。
  3. 电量记录,记录当前电量。
  4. 充电闪烁计数,记录当前的闪烁的值。
#ifndef __BSP_BATTERY_LED_H__
#define __BSP_BATTERY_LED_H__

#include "gd32f4xx.h"

#define LED1	1
#define LED2	2
#define LED3	3
#define LED4	4

void Battery_led_init();

void Battery_led_turn_on(uint8_t led_index);

void Battery_led_turn_off(uint8_t led_index);

void Battery_led_turn(uint8_t led_index, uint8_t value);

void Battery_led_start(uint8_t power);

void Battery_led_loop();

void Battery_led_update(uint8_t power);

void Battery_led_stop();

#endif
#include "bsp_battery_led.h"
#include "systick.h"

// 声明gpio初始化所需参数的结构体
typedef struct {
  rcu_periph_enum rcu;
  uint32_t port;
  uint32_t pin;
} Led_GPIO_t;

// 声明所有gpio对应参数的数组
Led_GPIO_t g_gpio_list[] = {
  {RCU_GPIOC, GPIOC, GPIO_PIN_6},        // LED_SW
  {RCU_GPIOD, GPIOD, GPIO_PIN_8},        // LED1
  {RCU_GPIOD, GPIOD, GPIO_PIN_9},        // LED2
  {RCU_GPIOD, GPIOD, GPIO_PIN_10},       // LED3
  {RCU_GPIOD, GPIOD, GPIO_PIN_11},       // LED4
};

// 用于计算数组长度的宏
#define MAX_LED_COUNT	(sizeof(g_gpio_list) / sizeof(Led_GPIO_t))

/**********************************************************
 * @brief LED GPIO初始化
 **********************************************************/
static void GPIO_config(rcu_periph_enum rcu, uint32_t port, uint32_t pin) {
  // 初始化为推挽输出模式
  rcu_periph_clock_enable(rcu);
  gpio_mode_set(port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, pin);
  gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, pin);
}

void Battery_led_init() {

  uint8_t count = MAX_LED_COUNT;
  for(uint8_t i = 0; i < count; i++) {
    Led_GPIO_t gpio = g_gpio_list[i];
    // 初始化
    GPIO_config(gpio.rcu,gpio.port, gpio.pin);
    // 默认全部拉高(关闭)
    gpio_bit_write(gpio.port, gpio.pin, SET);
  }

  // 总开关拉低(打开)
  gpio_bit_write(g_gpio_list[0].port, g_gpio_list[0].pin, RESET);
}

// 开灯
void Battery_led_turn_on(uint8_t led_index) {
  Led_GPIO_t gpio = g_gpio_list[led_index];
  gpio_bit_write(gpio.port, gpio.pin, RESET);
}

// 关灯
void Battery_led_turn_off(uint8_t led_index) {
  Led_GPIO_t gpio = g_gpio_list[led_index];
  gpio_bit_write(gpio.port, gpio.pin, SET);
}

/**********************************************************
 * @brief 设置灯亮灭
 * @param led_index LED索引
 * @param value 0亮,其他灭
 * @return
 **********************************************************/
void Battery_led_turn(uint8_t led_index, uint8_t value) {
  Led_GPIO_t gpio = g_gpio_list[led_index];
  gpio_bit_write(gpio.port, gpio.pin, value ? RESET : SET);
}

int state = 0; // 0:停止, 1:充电中
uint8_t current_power = 0;
uint8_t show_power = 0;
/**********************************************************
 * @brief 开始充电流水灯
 * @param 当前电量[0,1,2,3,4]
 **********************************************************/
void Battery_led_start(uint8_t power) {

  current_power = power;
  show_power = current_power;

  state = 1;
}

void Battery_led_loop() {

  if(state == 0) {
    Battery_led_turn_off(LED1);
    Battery_led_turn_off(LED2);
    Battery_led_turn_off(LED3);
    Battery_led_turn_off(LED4);
  } else if(state == 1) {
    Battery_led_turn(LED1, show_power >= 1);
    Battery_led_turn(LED2, show_power >= 2);
    Battery_led_turn(LED3, show_power >= 3);
    Battery_led_turn(LED4, show_power >= 4);
    if(++show_power > 4) show_power = current_power;
  }
}

void Battery_led_update(uint8_t power) {
  current_power = power;
}

void Battery_led_stop() {
  // 当前电量闪三次
  for( uint8_t i = 0; i < 3; i++) {
    // 关闭所有灯
    Battery_led_turn_off(LED1);
    Battery_led_turn_off(LED2);
    Battery_led_turn_off(LED3);
    Battery_led_turn_off(LED4);
    delay_1ms(200);
    // 根据当前电量闪灯
    Battery_led_turn(LED1, current_power >= 1);
    Battery_led_turn(LED2, current_power >= 2);
    Battery_led_turn(LED3, current_power >= 3);
    Battery_led_turn(LED4, current_power >= 4);
    delay_1ms(200);
  }

  state = 0;
}

总结

在本文中,我们详细介绍了如何在资源有限的情况下设计一个BSP驱动来控制四个LED灯,以展示充电状态和电量百分比。我们首先定义了接口和驱动初始化函数,然后实现了业务逻辑,包括开始充电、更新电量、停止充电和LED灯闪烁。我们还设计了测试案例来验证我们的驱动功能是否按照预期工作。

通过采用模块化设计,我们能够确保代码的可复用性和可移植性。尽管在产品最终电路板还未完成的情况下,我们只有开发板可以使用,但我们通过创新的方法和细致的规划,成功地解决了这一挑战。我们相信,通过遵循这些最佳实践,我们能够在未来的项目中更加高效地工作,并为我们的团队和公司创造更大的价值。

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

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

相关文章

BC9 printf的返回值

BC9 printf的返回值 这里我们先要了解库函数printf printf的返回值&#xff0c;是写入的字符总数 我们第一遍写代码时候可能写成这样: #include<stdio.h> int main() {int retprintf("Hello world!");printf("%d", ret);return 0; }我们发现这样是通…

MPU6050篇——姿态解算,卡尔曼滤波

一、DMP文件的修改&#xff1a; 首先我们打开inv_mpu.c文件夹&#xff0c;如下图所示便是第一个要修改的地方&#xff1a; 我们将其修改为&#xff1a;define定义可以改为自己使用的型号的单片机。 修改后在上面定义这个宏&#xff0c;并加上一个MPU6050的宏&#xff0c;用于源…

算法005:有效三角形的个数

. - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/valid-triangle-number/ 要组成三角形的三条边&#xff0c;需要保证&am…

【MATLAB源码-第224期】基于matlab的快跳频系统仿真采用4FSK,模拟了单音干扰,宽带干扰以及部分频带干扰,输出误码率曲线以及各节点图像。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 跳频通信系统概述 跳频通信系统是一种通过快速切换载波频率来进行信息传输的无线通信技术。它在军事和商业通信中广泛应用&#xff0c;具有较强的抗干扰和抗截获能力。系统设计主要包括信号调制、跳频序列生成、信道模拟以及…

BC6 小飞机

BC6 小飞机 废话不多说先上题目&#xff1a; 代码如下&#xff1a; #include<stdio.h> int main() {printf(" ## \n############\n############\n # # \n # # \n");return 0; }这是用一个printf打印我们还可以用多个printf发打印代码如下…

俄罗斯服务器租用攻略:选择优质服务器,开启海外市场新征程

随着国际贸易的不断发展&#xff0c;俄罗斯作为一个重要的贸易伙伴备受关注。许多企业和公司为了开拓海外市场&#xff0c;选择将业务拓展到俄罗斯&#xff0c;而在这个过程中&#xff0c;租用一台优质的服务器成为了必须面对的问题。俄罗斯作为一个经济发展迅速的国家&#xf…

JavaEE初阶---多线程编程(一.线程与进程)

目录 &#x1f923;一.线程与进程的概念与联系&#xff1a; 进程的基本概念&#xff1a; 线程的基本概念&#xff1a; 进程和线程的区别与联系&#xff1a; &#x1f643;代码执行实列&#xff1a; 1.通过继承Thread父类来实现多线程 2.通过实现Runnable接口来实现多线程…

JavaEE:http请求 | 过滤器 | 同步与异步请求 | 跨域问题 | axios框架 有这一篇就够!

&#x1f4c3;HTTP请求 ▐ http超文本传输协议&#xff1a; ⦁ http超文本传输协议属于应用层协议&#xff0c;传输内容必须是超文本内容 (网页内容) ⦁ 例如在网页上点击超链接&#xff0c;提交表单&#xff0c;都可以向后端发送一个http请求 ⦁ 一次http请求中包含请求行、…

《深入浅出C语言:从基础到指针的全面指南》

1. 简介 C语言是一种通用的编程语言&#xff0c;广泛应用于系统编程、嵌入式系统和高性能应用程序。它由Dennis Ritchie在1972年开发&#xff0c;并且至今仍然非常流行。C语言以其高效、灵活和强大的功能著称&#xff0c;是许多现代编程语言的基础。 2. 基本语法 2.1 Hello, …

Ezsql(buuctf加固题)

开启环境 SSH连接 第一个为页面地址WEB服务 or 11# 利用万能密码登录 密码可以随便输入或者不输入 这里就可以判断这个题目是让我们加固这个登录页面 防止sql注入 查看index.php 添加以下代码 $username addslashes($username); $password addslashes($password);…

SEO之关键词分布

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议 2、新手上云 经过核心关键词确定与关键词扩展&#xff0c;应该已经得到一个至少包含几百个相关关键词的大列表。这些关键…

02.体验CSS以及Bootstrap框架

目录 CSS固定格式 1&#xff09;style标签 2&#xff09;div标签 3&#xff09;span标签 CSS属性 一、文字属性 1.规范文字样式的属性 2.规定文字粗细的属性 3.规定文字大小的属性 4.规范文字字体的属性 二、文本属性 1.文本装饰属性 2.文本水平对齐属性 3.文本缩进…

数据库中锁的机制和MVCC协议以及隔离级别

文章目录 数据库中的锁锁与索引的关系释放锁的时机乐观锁与悲观锁行锁与表锁共享锁与排它锁意向锁记录锁、间隙锁和临键锁记录锁间隙锁临键锁 锁优化方案 MVCC协议MySQL的隔离级别脏读和幻读快照读和当前读 版本链Read ViewRead View 与已提交读Read View 与可重复读m_up_limit…

【C语言题解】1、写一个宏来计算结构体中某成员相对于首地址的偏移量;2、写一个宏来交换一个整数二进制的奇偶位

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f308;感谢大家的阅读、点赞、收藏和关注 &#x1f495;希望大家喜欢我本次的讲解&#x1f495; 目录&#x1f451; 1、写一个宏&#xff0c;计算结构体中某变量相对于首地址的偏…

STM32_HAL库_外部中断

一、设置分组 stm32f1xx_hal_cortex.c 查看分组 五个形参&#xff0c;分组0~4 stm32f1xx_hal.c 设置了分组为2&#xff0c; 此工程就不需要再设置了 再回到stm32f1xx_hal_cortex.c 查看NVIC_SetPriorityGrouping的定义&#xff0c;若无法跳转&#xff0c;先编译一下&…

【数据结构】穿梭在二叉树的时间隧道:顺序存储的实现

专栏引入 哈喽大家好&#xff0c;我是野生的编程萌新&#xff0c;首先感谢大家的观看。数据结构的学习者大多有这样的想法&#xff1a;数据结构很重要&#xff0c;一定要学好&#xff0c;但数据结构比较抽象&#xff0c;有些算法理解起来很困难&#xff0c;学的很累。我想让大家…

Apple开发者应用商店(AppStore)描述文件及ADHOC描述文件生成

创建AD HOC描述文件 1.选中Profiles,然后点击加号创建 2.创建已注册设备可安装描述文件 3.选择要注册的id 4.选择证书 5.选择设备 6.输入文件名,点击生成 7.生成成功,点击下载

重新ysyx

一、克隆仓库 1.创建ssh key ssh-keygen -t rsa cd ~/.ssh ls 查看里面是否有id_rsa id_rsa.pub ssh-keygen -t rsa -C "xiantong15834753336outlook.com" cat id_rsa.pub***********查看里面的内容&#xff0c;复制到下图中绿色的按钮 git init ssh -T g…

Alsa UCM

Alsa Use Case Manager&#xff08;用例管理器&#xff09;描述如何为某些用例&#xff08;如 “播放音频”、“通话”&#xff09;设置 mixer 混频器。它还描述如何修改 mixer 混频器状态以将音频路由到某些输出和输入&#xff0c;以及如何控制这些设备。 这基本上涵盖了 Pul…

胶南代理记账,为您提供专业、便捷的会计服务

欢迎来到胶南代理记账服务站&#xff0c;这里我们专注于为企业提供专业的会计服务&#xff0c;无论您是初创企业还是已经在业界有一定规模的企业&#xff0c;我们都将以最专业的态度和最高效的服务为您量身定制合适的记账方案。 我们的目标不仅是帮助您完成财务报告的制作&…