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(); }

 

posted @ 2024-09-02 10:10  njit-sam  阅读(8)  评论(0编辑  收藏  举报