LED接口实现
两个分类,interface实现通用接口,实现完毕后一般不准更改,interface_app里面添加具体硬件driver函数
led_interface.c
/*
* @brief: 集成驱动LED, 如74HC595 驱动8路
* @author:xuyan
* @date:2024.08.20
* @note: 这个文件请勿更改
*/
#include "led_interface.h"
/*
* @brief: 设置LED开关状态,这个状态是逻辑值,非真实值
* @para:led:该LED指针
* @para:status:需要设置的状态
* @return:无
*/
void Led_Interface_Write_Pin_cb(void* p, uint32_t status)
{
led_interface_t* this = (led_interface_t*)p;
if(this == NULL)
return;
if(this->info.status == status)
return;
this->info.status = status;
uint32_t level = 0;
for(uint8_t i = 0; i < this->info.led_num; i++)
{
//触发值为高,设置值为高
if( (this->info.valid_level & (1 << i)) == LED_LEVEL_HIGH && (this->info.status & (1 << i)) == LED_ON )
{
level |= (1 << i);
}
//触发值为低,设置值为低
if( (this->info.valid_level & (1 << i)) == LED_LEVEL_LOW && (this->info.status & (1 << i)) == LED_OFF )
{
level |= (1 << i);
}
}
this->set_pin_level(level);
}
/*
* @brief: 设置单个LED开关状态,这个状态是逻辑值,非真实值
* @para:index: 该LED索引,从0开始
* @para:status:需要设置的状态
* @return:无
*/
void Led_Interface_Write_Single_Pin_cb(void* p, uint8_t index, led_status_t status)
{
led_interface_t* this = (led_interface_t*)p;
if(this == NULL)
return;
if(index >= this->info.led_num)
return;
uint32_t state = this->info.status;
if(status == LED_ON)
state |= (1 << index);
else
state &= ~(1 << index);
this->write_pin(this, state);
}
/*
* @brief: 获取LED地址
* @para:无
* @return:LED指针
*/
void Led_Interface_Init(led_interface_t* p,
uint8_t led_num,
Led_Interface_Hardware_Init_callback Hardware_Init_cb,
Led_Interface_Set_Pin_Level_callback Set_Pin_Level_cb)
{
if(p == NULL)
return;
p->info.led_num = led_num;
//设置回调函数
p->hardware_init = Hardware_Init_cb;
p->set_pin_level = Set_Pin_Level_cb;
p->write_pin = Led_Interface_Write_Pin_cb;
p->write_single_pin = Led_Interface_Write_Single_Pin_cb;
//硬件初始化
p->hardware_init();
//关闭所有LED
uint32_t level = 0;
for(uint8_t i=0; i < p->info.led_num; i++)
{
if(( p->info.valid_level & (1<<i) ) == LED_LEVEL_LOW)
{
level |= 1 <<i;
}
}
p->set_pin_level(level);
}
led_interface.h
/* * @brief: 集成驱动LED,如74HC595输出,可串联多个,74HC165输入,也可串联多个 * @author:xuyan * @date:2024.08.20 * @note: 这个文件请勿更改 */ #include <stdint.h> #include <stdio.h> #ifndef LED_H_ #define LED_H_ typedef enum{ LED_LEVEL_LOW=0, LED_LEVEL_HIGH, }led_level_t; //LED真实电平 typedef enum{ LED_OFF=0, LED_ON, }led_status_t; //LED开关状态,逻辑值 typedef struct{ uint8_t first_inited; uint8_t led_num; //总共的LED灯数量 uint32_t status;//led灯电平状态 uint32_t valid_level; //是 高电平或者低电平触发 打开, //注意,这里代表真实的电平状态 }led_info_t; /* * @brief: 硬件初始化 * @para:led:该LED指针 * @return:无 */ typedef void (*Led_Interface_Hardware_Init_callback)(); /* * @brief: 设置LED真实电平,可以是单个PIN to PIN 或者 集成输入芯片 74HC595 * @para:led:该LED指针 * @return:无 */ typedef void (*Led_Interface_Set_Pin_Level_callback)(uint32_t level); /* * @brief: 设置LED开关状态,这个状态是逻辑值,非真实值 * @para:led:该LED指针 * @para:status:需要设置的状态 * @return:无 */ typedef void (*Led_Interface_Write_Pin_callback)(void* p, uint32_t status); /* * @brief: 设置单个LED开关状态,这个状态是逻辑值,非真实值 * @para:index: 该LED索引,从0开始 * @para:status:需要设置的状态 * @return:无 */ typedef void (*Led_Interface_Write_Single_Pin_callback)(void* p, uint8_t index, led_status_t status); typedef struct { led_info_t info; Led_Interface_Hardware_Init_callback hardware_init; Led_Interface_Set_Pin_Level_callback set_pin_level; Led_Interface_Write_Pin_callback write_pin; Led_Interface_Write_Single_Pin_callback write_single_pin; }led_interface_t; /* * @brief: 获取LED地址 * @para:无 * @return:LED指针 */ void Led_Interface_Init(led_interface_t* p, uint8_t led_num, Led_Interface_Hardware_Init_callback Hardware_Init_cb, Led_Interface_Set_Pin_Level_callback Set_Pin_Level_cb); #endif
led_interface_app.c
/* * @brief: 集成驱动LED示例 * @author:xuyan * @date:2024.08.20 * @note: 这里需要完成两件事: * @note: 1: 完成集成驱动硬件初始化 * @note: 2: 数据写入集成驱动 */ #include "led_interface.h" #include "drv_74hc595.h" #define LED_NUM (32) #define BAR_LED_NUM (2) typedef struct{ uint32_t gpio; uint32_t pin; }led_port_pin_info_t; led_port_pin_info_t bar_led_port_pin_info[BAR_LED_NUM]={ {GPIOD,GPIO_PIN_12}, {GPIOD,GPIO_PIN_13}, }; static led_interface_t led_interface; static led_interface_t bar_led_interface; //iolink error LED /* @brief: 硬件初始化 * @para:led:该LED指针 * @return:无 */ void Led_Interface_App_Hardware_Init_cb() { //User1: 输出时钟、端口初始化 drv_74hc595_init(); } /* * @brief: Bar LED硬件初始化 * @para:led:该LED指针 * @return:无 */ void Bar_Led_Interface_App_Hardware_Init_cb() { //User1: 输出时钟、端口初始化 rcu_periph_clock_enable(RCU_GPIOD); for(uint8_t i = 0; i < BAR_LED_NUM; i++) { gpio_init(bar_led_port_pin_info[i].gpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, bar_led_port_pin_info[i].pin); } } /* * @brief: 设置LED真实电平,可以是 集成输入芯片 74HC595 * @para:led:该LED指针 * @return:无 */ void Led_Interface_App_Set_Pin_Level_cb(uint32_t level) { //点位重新与原理图映射一下 //端口映射 static uint8_t led_pin_map[32]={7,6,5,4,1,0,3,2, 15,14,13,12,9,8,11,10, 23,22,21,20,17,16,19,18, 31,30,29,28,25,24,27,26}; uint32_t level_tmp = 0; for(uint8_t i = 0; i < LED_NUM; i++) { if((level >> i) & 0x01) level_tmp |= (1 << led_pin_map[i]); else level_tmp &= ~(1 << led_pin_map[i]); } //User2: 写入事件 drv_74hc595_write_data(level_tmp); } /* * @brief: 设置Bar LED真实电平 * @para:led: * @return:无 */ void Bar_Led_Interface_App_Set_Pin_Level_cb(uint32_t level) { //User2: 写入事件 for(uint8_t i = 0; i < BAR_LED_NUM; i++) { if((level>>i)&0x01) gpio_bit_write(bar_led_port_pin_info[i].gpio, bar_led_port_pin_info[i].pin, SET); else gpio_bit_write(bar_led_port_pin_info[i].gpio, bar_led_port_pin_info[i].pin, RESET); } } /* * @brief: 用户初始化LED * @para:无 * @return: */ void Led_Interface_App_Init() { //低电平有效 led_interface.info.valid_level = 0x00000000; //16个输入输出指示灯 Led_Interface_Init(&led_interface, LED_NUM, Led_Interface_App_Hardware_Init_cb, Led_Interface_App_Set_Pin_Level_cb); //低电平有效 bar_led_interface.info.valid_level = 0x00000000; //两个指示灯 Led_Interface_Init(&bar_led_interface, BAR_LED_NUM, Bar_Led_Interface_App_Hardware_Init_cb, Bar_Led_Interface_App_Set_Pin_Level_cb); } /* * @brief: 获取LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Led_interface_App_Singleton() { return &led_interface; } /* * @brief: 获取Bar LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Bar_Led_interface_App_Singleton() { return &bar_led_interface; }
led_interface_app.h
/* * @brief: 集成驱动LED, 如输出74HC595 * @author:xuyan * @date:2024.08.20 * @note: 这里需要完成两件事: * @note: 1: 完成集成驱动硬件初始化 * @note: 2: 数据写入集成驱动 */ #ifndef LED_INTERFACE_APP_H #define LED_INTERFACE_APP_H #include "led_interface.h" /* * @brief: 用户初始化LED * @para:无 * @return:LED状态 */ void Led_Interface_App_Init(void); /* * @brief: 获取LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Led_interface_App_Singleton(void); /* * @brief: 获取Bar LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Bar_Led_interface_App_Singleton(void); /* * @brief: 获取Power yellow LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Power_Led_Yellow_interface_App_Singleton(void); /* * @brief: 获取Power green LED interface实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_interface_t* Power_Led_Green_interface_App_Singleton(void); #endif
通过上面方式,如果你作为一个架构师,即使缺少interface_app.c和.h,那么也可以用interface.c和.h通用接口实现led的控制,具体的硬件实现可以让写app的开发人员根据芯片驱动接口去填写回调函数,
我们需要做的就是搭建高楼的框架,至于每层的房间怎么填砖不需要管,不影响大楼的落成。
上面只是控制灯的开关,是高电平或者低电平开关,实际上,灯的控制方式非常多,如开关,闪烁,呼吸等
下面的控制依赖上面的接口,而且上面的接口无需更改,真正做到了一次开发,多次使用。
led_control.c
/* * @brief: LED模式控制,目前支持开闭,闪烁 * @author:xuyan * @date:2024.08.20 * @note: 这个文件请勿更改 */ #include "led_control.h" /* * @brief: 统一闪烁时间,为了每个灯闪烁的步调一致 * @para:无 * @return:无 */ static uint16_t Unify_Flash_Time(void* p) { led_control_t* this = (led_control_t*)p; if (this == NULL) return 0; uint16_t flash_time = 0; for(uint8_t i = 0; i < this->interface->info.led_num; i++) { if( this->control_info[i].flashing_time ) { flash_time = this->control_info[i].flashing_time; break; } } return flash_time; } /* * @brief: LED模式设置 * @para: index:灯的索引,从0开始 * @para: mode:灯的模式 * @para: status:灯的状态,这个值仅在LED_MODE_IO模式下有效 * @return:无 */ void Led_Control_cb(void* p, uint8_t index, led_mode_t mode, led_status_t status ) { led_control_t* this = (led_control_t*)p; if (this == NULL) return; if(this->interface == NULL) return; if (mode > LED_MODE_BREATH) return; if(mode == LED_MODE_IO) { this->control_info[index].state = status; this->control_info[index].flashing_time = 0; } else { if(this->control_info[index].mode != mode) { this->control_info[index].flashing_time = Unify_Flash_Time(this); } } this->control_info[index].mode = mode; } /* * @brief: LED模式循环,请将这个函数放在固定1ms执行的函数中 * @para:无 * @return:无 */ void Led_Control_Loop_cb(void* p) { led_control_t* this = (led_control_t*)p; if (this == NULL || this->interface == NULL) return; for(uint8_t i = 0; i < this->interface->info.led_num; i++) { if(this->control_info[i].mode == LED_MODE_IO) { this->interface->write_single_pin(this->interface, i, this->control_info[i].state); } else if(this->control_info[i].mode == LED_MODE_FLASH_1_2) { this->control_info[i].flashing_time++; if(this->control_info[i].flashing_time < 500) { this->interface->write_single_pin(this->interface, i, LED_ON); } else if(this->control_info[i].flashing_time < 1000) { this->interface->write_single_pin(this->interface, i, LED_OFF); } else { this->control_info[i].flashing_time = 0; } } else if(this->control_info[i].mode == LED_MODE_FLASH_1_4) { this->control_info[i].flashing_time++; if(this->control_info[i].flashing_time < 750) { this->interface->write_single_pin(this->interface, i, LED_ON); } else if(this->control_info[i].flashing_time < 1000) { this->interface->write_single_pin(this->interface, i, LED_OFF); } else { this->control_info[i].flashing_time = 0; } } else if(this->control_info[i].mode == LED_MODE_FLASH_1_8) { this->control_info[i].flashing_time++; if(this->control_info[i].flashing_time < 875) { this->interface->write_single_pin(this->interface, i, LED_ON); } else if(this->control_info[i].flashing_time < 1000) { this->interface->write_single_pin(this->interface, i, LED_OFF); } else { this->control_info[i].flashing_time = 0; } } else if(this->control_info[i].mode == LED_MODE_BREATH) { //TODO } } } /* * @brief: LED模式初始化 * @para:无 * @return:无 */ void Led_Control_Init(led_control_t* p_instance, led_interface_t* p_interface) { if (p_instance == NULL || p_interface ==NULL) return; p_instance->interface = p_interface; p_instance->control = Led_Control_cb; p_instance->loop = Led_Control_Loop_cb; }
led_control.h
/* * @brief: LED模式控制 * @author:xuyan * @date:2024.08.20 * @note: 这个文件请勿更改 */ #include <stdint.h> #include <stdio.h> #include "led_interface.h" #ifndef LED_CONTROL_H_ #define LED_CONTROL_H_ typedef enum{ LED_MODE_IO = 0, //简单亮灭控制 LED_MODE_FLASH_1_2, //闪烁,默认周期1s,灭1/2时间 LED_MODE_FLASH_1_4, //闪烁,默认周期1s,灭1/4时间 LED_MODE_FLASH_1_8, //闪烁,默认周期1s,灭1/8时间 LED_MODE_BREATH, //呼吸,默认周期2s }led_mode_t; //LED运行模式 typedef struct{ led_mode_t mode; //模式 led_status_t state; uint16_t flashing_time;//给闪烁用 uint16_t breath_pwm;//给呼吸灯用 }led_control_info_t; //LED运行模式控制时间 typedef void (*Led_Control_callback)(void* p, uint8_t index, led_mode_t mode, led_status_t statu); typedef void (*Led_Control_Loop_callback)(void* p); typedef struct { led_control_info_t control_info[32]; //最大支持32个灯 led_interface_t* interface; Led_Control_callback control; Led_Control_Loop_callback loop; }led_control_t; void Led_Control_Init(led_control_t* p_instance, led_interface_t* p_interface); #endif
led_control_app.c
/* * @brief: 集成驱动LED示例, * @author:xuyan * @date:2024.08.20 * @note: */ #include "led_interface.h" #include "led_interface_app.h" #include "led_control_app.h" static led_control_t led_control; static led_control_t bar_led_control; /* * @brief: 用户初始化LED * @para:无 * @return: */ void Led_Control_App_Init() { Led_Interface_App_Init(); Led_Control_Init(&led_control, Led_interface_App_Singleton()); Led_Control_Init(&bar_led_control, Bar_Led_interface_App_Singleton()); } /* * @brief: 获取LED Singleton实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_control_t* Led_Control_Singleton() { return &led_control; } /* * @brief: 获取BAR LED Singleton实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_control_t* Bar_Led_Control_Singleton() { return &bar_led_control; }
led_control_app.h
/* * @brief: 集成驱动LED示例 * @author:xuyan * @date:2024.08.20 */ #ifndef LED_CONTROL_APP_H #define LED_CONTROL_APP_H #include "led_control.h" typedef enum{ IOLINK_LED = 0, ERROR_LED , }led_name_t; /* * @brief: 用户初始化LED control * @para:无 * @return: */ void Led_Control_App_Init(void); /* * @brief: 获取LED Control实体, * @para:无 * @return:实体指针 */ led_control_t* Led_Control_Singleton(void); /* * @brief: 获取BAR LED Singleton实体,注意:LED初始化后,方可使用 * @para:无 * @return:实体指针 */ led_control_t* Bar_Led_Control_Singleton(void); #endif
下面给出一个示例
#include "led_control_app.h" int main() {
//初始化 Init_Control_Led();
Led_Control_Singleton()->control( 2, LED_MODE_IO, LED_ON);
while(1); return 0; } //这里是定时器终端,因为闪烁和呼吸依赖时基,必须放在定时器里面执行循环 tim_isr() { //LED灯循环 Led_Control_Singleton()->loop(); }