分享,自己用的led闪烁程序。
使用方式:主要有三个函数:
vLedInit,用来初始化灯的模式,亮度调节,呼吸灯,闪烁,显示1字节数据,四种模式。支持pwm输出控制led,或者用io模拟pwm实现呼吸灯效果。
ucLedTriggerMode,比如当前处于呼吸灯模式,由于响应一些按键,需要灯做出响应,可以用这个实现,用来触发或者永久修改灯的模式
lLedRun,周期运行,暂时只支持1毫秒一次运行。
举例1,IO模式:
LedCtrl_T tLed ;
main()
{
vLedInit(&tLed,0,1,BREATHING,2);//输出0对应最大灯亮度,输出1代表熄灭灯,呼吸灯模式,2秒周期。
while(1)
{
LED_GPIO = lLedRun(&tLed);
vTaskDelay(1);//1ms
}
}
举例2,PWM模式:
LedCtrl_T tLed ;
main()
{
vLedInit(&tLed,255,0,BREATHING,2);//输出255代表最大亮度,0代表熄灭灯,呼吸灯模式,2秒周期。
while(1)
{
set_pwm_val(lLedRun(&tLed));
vTaskDelay(1);//1ms
}
}
/******************************************************************
* 文件名: led_ctrl.c
* 内容简述:
* 控制led灯的亮灭,可实现4种状态,亮度调整,闪烁,呼吸灯,字节显示
* 文件历史:
* 版本号 日期 作者 说明
******************************************************************/
#include "led_ctrl.h"
#define MIN_BRIGHTNESS_HZ 40 //亮度控制频率,测试电路板上led灯在40hz看起来不闪烁
#define MAX_TWINKLING_HZ 50 //闪烁频率,赫兹
#define MIN_TWINKLING_HZ 1 //闪烁频率,赫兹
#define MAX_BREATHING_S 10 //呼吸灯时间,秒
#define MIN_BREATHING_S 1 //呼吸灯时间,秒
#define START_BIT_DELAY_MS 1000 //启动位延时时间,毫秒
#define ONE_BIT_DELAY_MS 1000 //1位显示时间
#define STOP_BIT_DELAY_MS 1000 //停止位延时时间,毫秒
#define BIT_1_TWINKLING_HZ 20 //1的显示频率
#define BIT_0_TWINKLING_HZ 5 //0的显示频率
static int32_t lLedBrightnessCtrl(LedCtrl_T *tpLed);
static int32_t lLedTwinklingCtrl(LedCtrl_T *tpLed);
static int32_t lLedBreathingCtrl(LedCtrl_T *tpLed);
static int32_t lLedDisplayByteCtrl(LedCtrl_T *tpLed);
/******************************************************************
* 函数名: ledInit()
* 功 能: 初始化配置
* 输 入:
* tpLed:led指针
* lOnVal:设置点亮电平值,如果是pwm,这两个值的为pwm定时器重装数
* lOffVal:设置熄灭电平值,如果是pwm,这两个值的为pwm定时器重装数
* eMode:
BRIGHTNESS亮度
TWINKLING 闪烁
BREATHING 呼吸灯
DISPLAYBYTE 字节显示
* ucValue:
BRIGHTNESS亮度范围:0-100,代表0%-100%
TWINKLING 闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
BREATHING 呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
DISPLAYBYTE 字节显示范围:0x00~0xFF,起始位1秒常亮,低位在前显示,1快闪,0慢闪,停止位2秒常灭
* 输 出: 无
*/
void vLedInit(LedCtrl_T *tpLed,int32_t lOnVal,int32_t lOffVal,LED_MODE_E eMode,uint8_t ucValue)
{
tpLed->tConfig.lOnVal = lOnVal;
tpLed->tConfig.lOffVal = lOffVal;
tpLed->eMode = eMode;
tpLed->ucValue = ucValue;
tpLed->tPriData.lTimeCount_ms = 0;
tpLed->tPriData.lCurDispBitNum = 0;
tpLed->tPriData.lTimeTrgger_ms = -1;
tpLed->tPriData.eModeExp = tpLed->eMode;
tpLed->tPriData.ucValueExp = tpLed->ucValue;
tpLed->tPriData.eModeBackup = tpLed->eMode;
tpLed->tPriData.ucValueBackup = tpLed->ucValue;
}
/******************************************************************
* 函数名: vLedTriggerMode()
* 功 能: 触发led模式,永久修改模式,或者触发一定时间再恢复之前模式
* 输 入:
* tpLed:led指针
* eMode:
BRIGHTNESS亮度
TWINKLING 闪烁
BREATHING 呼吸灯
DISPLAYBYTE 字节显示
* ucValue:
BRIGHTNESS亮度范围:0-100,代表0%-100%
TWINKLING 闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
BREATHING 呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
DISPLAYBYTE 字节显示范围:0x00~0xFF,起始位1秒常亮,低位在前显示,1快闪,0慢闪,停止位2秒常灭
* lTime:触发新的模式持续时间,单位,毫秒。注意,如果为0,则永久修改模式
* 输 出: 成功设置,返回0,失败,返回1
*/
uint8_t ucLedTriggerMode(LedCtrl_T *tpLed,LED_MODE_E eMode,uint8_t ucValue,int32_t lTime_ms)
{
if(tpLed->tPriData.lTimeTrgger_ms == -1)
{
tpLed->tPriData.eModeExp = eMode;
tpLed->tPriData.ucValueExp = ucValue;
if(lTime_ms == 0)
{
tpLed->tPriData.eModeBackup = tpLed->eMode;
tpLed->tPriData.ucValueBackup = tpLed->ucValue;
}
else
{
tpLed->tPriData.eModeBackup = tpLed->tPriData.eModeExp;
tpLed->tPriData.ucValueBackup = tpLed->tPriData.ucValueExp;
}
tpLed->tPriData.lTimeTrgger_ms = lTime_ms;
return 0;
}
else
{
return 1;
}
}
/******************************************************************
* 函数名: lLedSoftPWMGenerator()
* 功 能: 模拟PWM发生器
* 输 入:
* lTimeCount_ms:定时器时间,可以大于lPeriodSet_ms,会自动计算余数用于调整占空比,毫秒
* lPeriodSet_ms:周期时间,毫秒
* lDutyRatio_PCT:百分比,0-100
* 输 出: 当前输出电平,1高,0低
*/
static int32_t lLedSoftPWMGenerator(int32_t lTimeCount_ms,int32_t lPeriodSet_ms,uint8_t ucDutyRatioSet_PCT)
{
int32_t lHighLevelTime_ms = lPeriodSet_ms * ucDutyRatioSet_PCT / 100;
if((lTimeCount_ms % lPeriodSet_ms) < lHighLevelTime_ms)
{
return 1;
}
else
{
return 0;
}
}
/******************************************************************
* 函数名: lLedBrightnessCtrl()
* 功 能: 亮度控制
* 输 入:
* tpLed:led指针
* 输 出: IO控制量
*/
static int32_t lLedBrightnessCtrl(LedCtrl_T *tpLed)
{
int32_t lReturnVal = 0;
int32_t lTempCheck = tpLed->tConfig.lOnVal - tpLed->tConfig.lOffVal;
if(lTempCheck >= -1 && lTempCheck <= 1)//io模式
{
int32_t lPeriod_ms = (int32_t)(1000 / MIN_BRIGHTNESS_HZ);
int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,tpLed->ucValue);
lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
tpLed->tPriData.lTimeCount_ms++;
if(tpLed->tPriData.lTimeCount_ms > lPeriod_ms)
{
tpLed->tPriData.lTimeCount_ms = 0;
}
}
else//pwm模式
{
if(lTempCheck > 1)
{
lReturnVal = tpLed->ucValue / 100 * lTempCheck + tpLed->tConfig.lOffVal;
}
else if(lTempCheck < -1)
{
lReturnVal = tpLed->ucValue / 100 * -lTempCheck - tpLed->tConfig.lOffVal;
}
}
return lReturnVal;
}
/******************************************************************
* 函数名: lLedTwinklingCtrl()
* 功 能: 闪烁控制
* 输 入:
* tpLed:led指针
* 输 出: IO控制量
*/
static int32_t lLedTwinklingCtrl(LedCtrl_T *tpLed)
{
int32_t lTemp_Hz = 0;
int32_t lReturnVal = 0;
int32_t lPeriod_ms = 0;
int32_t lPWMLevel = 0;
lTemp_Hz = tpLed->ucValue < MIN_TWINKLING_HZ ? MIN_TWINKLING_HZ : tpLed->ucValue;
lTemp_Hz = tpLed->ucValue > MAX_TWINKLING_HZ ? MAX_TWINKLING_HZ : tpLed->ucValue;
lPeriod_ms = 1000 / lTemp_Hz;
lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,50);
lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
tpLed->tPriData.lTimeCount_ms++;
if(tpLed->tPriData.lTimeCount_ms > lPeriod_ms)
{
tpLed->tPriData.lTimeCount_ms = 0;
}
return lReturnVal;
}
/******************************************************************
* 函数名: lLedBreathingCtrl()
* 功 能: 呼吸灯控制
* 输 入:
* tpLed:led指针
* 输 出: IO控制量
*/
static int32_t lLedBreathingCtrl(LedCtrl_T *tpLed)
{
int32_t lPeriod_ms = 0;
int32_t lRiseUpTime_ms = 0;
int32_t lReturnVal = 0;
float fBrightnessPCT = 0.0f;
lPeriod_ms = tpLed->ucValue < MIN_BREATHING_S ? MIN_BREATHING_S * 1000 : tpLed->ucValue * 1000 ;
lPeriod_ms = tpLed->ucValue > MAX_BREATHING_S ? MAX_BREATHING_S * 1000 : tpLed->ucValue * 1000 ;
lRiseUpTime_ms = lPeriod_ms / 2;
//亮度切换
if(tpLed->tPriData.lTimeCount_ms <= lRiseUpTime_ms)//由暗变亮
{
fBrightnessPCT = (float)(tpLed->tPriData.lTimeCount_ms) / (float)lRiseUpTime_ms;
}
else if(tpLed->tPriData.lTimeCount_ms > lRiseUpTime_ms && tpLed->tPriData.lTimeCount_ms <= lPeriod_ms)//由亮变暗
{
fBrightnessPCT = (float)(lPeriod_ms - tpLed->tPriData.lTimeCount_ms) / (float)lRiseUpTime_ms;
}
else
{
fBrightnessPCT = 0.0f;
tpLed->tPriData.lTimeCount_ms = 0;
}
//调光曲线
fBrightnessPCT = fBrightnessPCT * fBrightnessPCT;
//亮度控制
{
int32_t lTempCheck = tpLed->tConfig.lOnVal - tpLed->tConfig.lOffVal;
if(lTempCheck >= -1 && lTempCheck <= 1)//io模式
{
int32_t lPeriod_ms = (int32_t)(1000 / MIN_BRIGHTNESS_HZ);
int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,(uint8_t)(fBrightnessPCT * 100.0f));
lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
}
else//pwm模式
{
if(lTempCheck > 1)
{
lReturnVal = (int32_t)(fBrightnessPCT * (float)lTempCheck + (float)tpLed->tConfig.lOffVal);
}
else if(lTempCheck < -1)
{
lReturnVal = (int32_t)(fBrightnessPCT * -(float)lTempCheck - (float)tpLed->tConfig.lOffVal);
}
}
}
tpLed->tPriData.lTimeCount_ms++;
return lReturnVal;
}
/******************************************************************
* 函数名: lLedDisplayByteCtrl()
* 功 能: 字节显示控制
* 输 入:
* tpLed:led指针
* 输 出: IO控制量
*/
static int32_t lLedDisplayByteCtrl(LedCtrl_T *tpLed)
{
int32_t lReturnVal = 0;
if(tpLed->tPriData.lCurDispBitNum == 0)
{
tpLed->tPriData.lTimeCount_ms = 0;
tpLed->tPriData.lCurDispBitNum++;
}
else if(tpLed->tPriData.lCurDispBitNum == 1)//起始位,常亮
{
lReturnVal = tpLed->tConfig.lOnVal;
if(tpLed->tPriData.lTimeCount_ms > START_BIT_DELAY_MS)
{
tpLed->tPriData.lTimeCount_ms = 0;
tpLed->tPriData.lCurDispBitNum++;
}
}
else if(tpLed->tPriData.lCurDispBitNum >= 2 && tpLed->tPriData.lCurDispBitNum <= 9)//数据位
{
uint8_t ucCurBitDisplayVal = (tpLed->ucValue >> (tpLed->tPriData.lCurDispBitNum - 2)) & 0x01;
int32_t lPeriod_ms = ucCurBitDisplayVal == 1 ? 1000 / BIT_1_TWINKLING_HZ : 1000 / BIT_0_TWINKLING_HZ;
int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,50);
lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
if(tpLed->tPriData.lTimeCount_ms > ONE_BIT_DELAY_MS)
{
tpLed->tPriData.lTimeCount_ms = 0;
tpLed->tPriData.lCurDispBitNum++;
}
}
else if(tpLed->tPriData.lCurDispBitNum == 10)//停止位
{
lReturnVal = tpLed->tConfig.lOffVal;
if(tpLed->tPriData.lTimeCount_ms > STOP_BIT_DELAY_MS)
{
tpLed->tPriData.lTimeCount_ms = 0;
tpLed->tPriData.lCurDispBitNum++;
}
}
else
{
tpLed->tPriData.lCurDispBitNum = 0;
}
tpLed->tPriData.lTimeCount_ms++;
return lReturnVal;
}
/******************************************************************
* 函数名: lLedRun()
* 功 能: 运行led,并返回IO控制量
* 输 入:
* tpLed:led指针
* 输 出: IO控制量
*/
int32_t lLedRun(LedCtrl_T *tpLed)
{
if(tpLed->tPriData.lTimeTrgger_ms == 0)
{
tpLed->eMode = tpLed->tPriData.eModeBackup;
tpLed->ucValue = tpLed->tPriData.ucValueBackup;
}
else if(tpLed->tPriData.lTimeTrgger_ms > 0)
{
tpLed->eMode = tpLed->tPriData.eModeExp;
tpLed->ucValue = tpLed->tPriData.ucValueExp;
}
else
{
tpLed->tPriData.lTimeTrgger_ms = -1;
}
tpLed->tPriData.lTimeTrgger_ms--;
switch(tpLed->eMode)
{
case BRIGHTNESS: //亮度范围:0-100,代表0%-100%
return lLedBrightnessCtrl(tpLed);
case TWINKLING: //闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
return lLedTwinklingCtrl(tpLed);
case BREATHING: //呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
return lLedBreathingCtrl(tpLed);
case DISPLAYBYTE: //字节显示
return lLedDisplayByteCtrl(tpLed);
default:
return tpLed->tConfig.lOffVal;
}
}
/******************************************************************
* 文件名: led_ctrl.h
* 内容简述:
* 控制led灯的亮灭,可实现4种状态,亮度调整,闪烁,呼吸灯,字节显示
* 文件历史:
* 版本号 日期 作者 说明
******************************************************************/
#ifndef __LED_CTRL_H
#define __LED_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/*枚举led驱动模式*/
typedef enum tagLED_MODE_E
{
BRIGHTNESS = 0, //亮度
TWINKLING, //闪烁
BREATHING, //呼吸灯
DISPLAYBYTE //字节显示
}LED_MODE_E;
/*根据实际硬件,设置lOnVal和lOffVal,IO为1或者0,PWM控制为定时器重装值*/
typedef struct tagLedConfig_T
{
int32_t lOnVal;
int32_t lOffVal;
}LedConfig_T;
/*运行所需内部变量*/
typedef struct tagLedPrivateData_T
{
int32_t lTimeCount_ms;//内部计时器
int32_t lCurDispBitNum; //字节显示模式中,用于标记当前显示的是哪位
int32_t lTimeTrgger_ms; //触发,计时器
LED_MODE_E eModeExp; //触发,期望模式
uint8_t ucValueExp; //触发,期望模式值
LED_MODE_E eModeBackup; //触发,备份当前模式
uint8_t ucValueBackup;//触发,备份当前值
}LedPrivateData_T;
/*描述一个led*/
typedef struct tagLedCtrl_T
{
LED_MODE_E eMode;
uint8_t ucValue;
LedConfig_T tConfig;
LedPrivateData_T tPriData;
}LedCtrl_T;
/*外部调用函数*/
void vLedInit(LedCtrl_T *tpLed,int32_t lOnVal,int32_t lOffVal,LED_MODE_E eMode,uint8_t ucValue);
uint8_t ucLedTriggerMode(LedCtrl_T *tpLed,LED_MODE_E eMode,uint8_t ucValue,int32_t lTime_ms);
int32_t lLedRun(LedCtrl_T *tpLed);
#ifdef __cplusplus
}
#endif
#endif LED都能被你玩出了花 感谢分享
感谢分享 Thank you
感谢分享
感谢分享! 点个灯而已,何必这么复杂 有用的自然有用 卧槽。。这也太难了吧 亮瞎眼了! 实际应用的话这样设计不合理, 应该采用定时器方式更新pwm值.
学习了,谢谢分享 pwm方式最省事 点个灯泡比我所有的程序都复杂:(
我们这些不懂程序的人该咋办。。。 太复杂,pwm+查表调亮度,省时省力。
页:
[1]