🎬 秋野醬:《個人主頁》
🔥 個人專欄:《Java專欄》《Python專欄》
??心若有所向往,何懼道阻且長
文章目錄
- 需求介紹
- 現實問題
- 需求分析
- 測試案例構建
- BSP驅動構建
- 業務實現
需求介紹
開發版中有4個燈,現在需要用4個燈顯示充電情況:
- 開始充電時,需要呈現出流水燈閃爍
- 4盞燈表示當前的電量
- 充電流水燈起始位置是當前電量,全部點亮后,再次從當前電量位置進入流水燈效果
- 結束充電時,關閉充電顯示,當前電量進行閃爍3次,然后熄滅。
現實問題
- 產品最終電路板還沒畫好,目前只有產品所使用的芯片對應的開發板。
- ADC功能是別人開發,還沒完成。
- 老板要求,如果開發板好了,要盡快完成工作。
需求分析
要啥沒啥,還得盡快完成。盤點手頭有的東西,開發板。構建測試案例邏輯,方便后續移植。
測試案例設計:
- 準備工作,4個燈,3個按鈕
- 按鈕1按下時,模擬開始充電
- 按鈕2按下時,模擬停止充電
- 按鈕3按下時,模擬電量增加。
如果測試方案通過,基本上功能完成,那么后續其他人工作完成后,只需要對接以下邏輯: - 燈對應的引腳和最終設計的電路板引腳進行校準
- 開始充電
- 電量變化時,更新電量
- 結束充電
編碼實現分析:
- 需要把4個燈作為一個業務邏輯整體,完成一套關于電池電量顯示的驅動
- 需要抽象出業務邏輯,轉換為函數實現
測試案例構建
● 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) {// PC0FlagStatus state0 = gpio_input_bit_get(GPIOC, GPIO_PIN_0);if (state0 != pre_state0){if(state0 == RESET){ // 當前低電平, 上一次為高電平,按下Battery_led_start(power);}pre_state0 = state0; }// PC1FlagStatus state1 = gpio_input_bit_get(GPIOC, GPIO_PIN_1);if (state1 != pre_state1){if(state1 == RESET){ // 當前低電平, 上一次為高電平,按下Battery_led_stop();}pre_state1 = state1; }// PC2FlagStatus 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驅動構建
接口定義
- 驅動初始化,屬于標配
- 業務相關的操作行為抽象化
- 時序問題
void Battery_led_int();
具體的業務抽象行為
void Battery_led_start(uint8_t power);
void Battery_led_stop();
void Battery_led_update(uint8_t power);
在涉及到需要控制時間的問題時,我們通常有以下做法:
- 自己主動調用 delay來進行延時
- 使用統一的延時,到達自己的時間點就去執行
自己調用delay 不利于后續的移植。
采用統一時鐘,方便移植,也方便時間片統一調度管理
業務實現
- 采用bsp獨立驅動進行開發
- 狀態管理,通過status記錄當前狀態。
- 電量記錄,記錄當前電量。
- 充電閃爍計數,記錄當前的閃爍的值。
#ifndef __BSP_BATTERY_LED_H__
#define __BSP_BATTERY_LED_H__#include "gd32f4xx.h"#define LED1 1
#define LED2 2
#define LED3 3
#define LED4 4void 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;
}