搜索
bottom↓
回复: 14

分享,自己用的led闪烁程序。

[复制链接]

出20入62汤圆

发表于 2022-11-9 00:20:10 | 显示全部楼层 |阅读模式
使用方式:
主要有三个函数:
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
        }
}



  1. /******************************************************************
  2. * 文件名: led_ctrl.c
  3. * 内容简述:
  4. * 控制led灯的亮灭,可实现4种状态,亮度调整,闪烁,呼吸灯,字节显示
  5. * 文件历史:
  6. * 版本号 日期 作者 说明
  7. ******************************************************************/

  8. #include "led_ctrl.h"

  9. #define MIN_BRIGHTNESS_HZ       40      //亮度控制频率,测试电路板上led灯在40hz看起来不闪烁
  10. #define MAX_TWINKLING_HZ        50      //闪烁频率,赫兹
  11. #define MIN_TWINKLING_HZ        1       //闪烁频率,赫兹
  12. #define MAX_BREATHING_S         10      //呼吸灯时间,秒
  13. #define MIN_BREATHING_S         1       //呼吸灯时间,秒
  14. #define START_BIT_DELAY_MS      1000    //启动位延时时间,毫秒
  15. #define ONE_BIT_DELAY_MS        1000    //1位显示时间
  16. #define STOP_BIT_DELAY_MS       1000    //停止位延时时间,毫秒
  17. #define BIT_1_TWINKLING_HZ      20      //1的显示频率
  18. #define BIT_0_TWINKLING_HZ      5       //0的显示频率

  19. static int32_t lLedBrightnessCtrl(LedCtrl_T *tpLed);
  20. static int32_t lLedTwinklingCtrl(LedCtrl_T *tpLed);
  21. static int32_t lLedBreathingCtrl(LedCtrl_T *tpLed);
  22. static int32_t lLedDisplayByteCtrl(LedCtrl_T *tpLed);

  23. /******************************************************************
  24. * 函数名: ledInit()
  25. * 功 能: 初始化配置
  26. * 输 入:
  27. * tpLed:led指针
  28. * lOnVal:设置点亮电平值,如果是pwm,这两个值的为pwm定时器重装数
  29. * lOffVal:设置熄灭电平值,如果是pwm,这两个值的为pwm定时器重装数
  30. * eMode:
  31.     BRIGHTNESS  亮度
  32.     TWINKLING   闪烁
  33.     BREATHING   呼吸灯
  34.     DISPLAYBYTE 字节显示
  35. * ucValue:
  36.     BRIGHTNESS  亮度范围:0-100,代表0%-100%
  37.     TWINKLING   闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
  38.     BREATHING   呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
  39.     DISPLAYBYTE 字节显示范围:0x00~0xFF,起始位1秒常亮,低位在前显示,1快闪,0慢闪,停止位2秒常灭
  40. * 输 出: 无
  41. */
  42. void vLedInit(LedCtrl_T *tpLed,int32_t lOnVal,int32_t lOffVal,LED_MODE_E eMode,uint8_t ucValue)
  43. {
  44.     tpLed->tConfig.lOnVal = lOnVal;
  45.     tpLed->tConfig.lOffVal = lOffVal;
  46.     tpLed->eMode = eMode;
  47.     tpLed->ucValue = ucValue;
  48.     tpLed->tPriData.lTimeCount_ms = 0;
  49.     tpLed->tPriData.lCurDispBitNum = 0;
  50.     tpLed->tPriData.lTimeTrgger_ms = -1;
  51.     tpLed->tPriData.eModeExp = tpLed->eMode;
  52.     tpLed->tPriData.ucValueExp = tpLed->ucValue;
  53.     tpLed->tPriData.eModeBackup = tpLed->eMode;
  54.     tpLed->tPriData.ucValueBackup = tpLed->ucValue;
  55. }

  56. /******************************************************************
  57. * 函数名: vLedTriggerMode()
  58. * 功 能: 触发led模式,永久修改模式,或者触发一定时间再恢复之前模式
  59. * 输 入:
  60. * tpLed:led指针
  61. * eMode:
  62.     BRIGHTNESS  亮度
  63.     TWINKLING   闪烁
  64.     BREATHING   呼吸灯
  65.     DISPLAYBYTE 字节显示
  66. * ucValue:
  67.     BRIGHTNESS  亮度范围:0-100,代表0%-100%
  68.     TWINKLING   闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
  69.     BREATHING   呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
  70.     DISPLAYBYTE 字节显示范围:0x00~0xFF,起始位1秒常亮,低位在前显示,1快闪,0慢闪,停止位2秒常灭
  71. * lTime:触发新的模式持续时间,单位,毫秒。注意,如果为0,则永久修改模式
  72. * 输 出: 成功设置,返回0,失败,返回1
  73. */
  74. uint8_t ucLedTriggerMode(LedCtrl_T *tpLed,LED_MODE_E eMode,uint8_t ucValue,int32_t lTime_ms)
  75. {
  76.     if(tpLed->tPriData.lTimeTrgger_ms == -1)
  77.     {
  78.         tpLed->tPriData.eModeExp = eMode;
  79.         tpLed->tPriData.ucValueExp = ucValue;
  80.         if(lTime_ms == 0)
  81.         {
  82.             tpLed->tPriData.eModeBackup = tpLed->eMode;
  83.             tpLed->tPriData.ucValueBackup = tpLed->ucValue;
  84.         }
  85.         else
  86.         {
  87.             tpLed->tPriData.eModeBackup = tpLed->tPriData.eModeExp;
  88.             tpLed->tPriData.ucValueBackup = tpLed->tPriData.ucValueExp;
  89.         }
  90.         tpLed->tPriData.lTimeTrgger_ms = lTime_ms;
  91.         return 0;
  92.     }
  93.     else
  94.     {
  95.         return 1;
  96.     }
  97. }

  98. /******************************************************************
  99. * 函数名: lLedSoftPWMGenerator()
  100. * 功 能: 模拟PWM发生器
  101. * 输 入:
  102. * lTimeCount_ms:定时器时间,可以大于lPeriodSet_ms,会自动计算余数用于调整占空比,毫秒
  103. * lPeriodSet_ms:周期时间,毫秒
  104. * lDutyRatio_PCT:百分比,0-100
  105. * 输 出: 当前输出电平,1高,0低
  106. */
  107. static int32_t lLedSoftPWMGenerator(int32_t lTimeCount_ms,int32_t lPeriodSet_ms,uint8_t ucDutyRatioSet_PCT)
  108. {
  109.     int32_t lHighLevelTime_ms = lPeriodSet_ms * ucDutyRatioSet_PCT / 100;
  110.     if((lTimeCount_ms % lPeriodSet_ms) < lHighLevelTime_ms)
  111.     {
  112.         return 1;
  113.     }
  114.     else
  115.     {
  116.         return 0;
  117.     }
  118. }

  119. /******************************************************************
  120. * 函数名: lLedBrightnessCtrl()
  121. * 功 能: 亮度控制
  122. * 输 入:
  123. * tpLed:led指针
  124. * 输 出: IO控制量
  125. */
  126. static int32_t lLedBrightnessCtrl(LedCtrl_T *tpLed)
  127. {
  128.     int32_t lReturnVal = 0;
  129.     int32_t lTempCheck = tpLed->tConfig.lOnVal - tpLed->tConfig.lOffVal;
  130.     if(lTempCheck >= -1 && lTempCheck <= 1)//io模式
  131.     {
  132.         int32_t lPeriod_ms = (int32_t)(1000 / MIN_BRIGHTNESS_HZ);
  133.         int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,tpLed->ucValue);
  134.         lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
  135.         tpLed->tPriData.lTimeCount_ms++;
  136.         if(tpLed->tPriData.lTimeCount_ms > lPeriod_ms)
  137.         {
  138.             tpLed->tPriData.lTimeCount_ms = 0;
  139.         }
  140.     }
  141.     else//pwm模式
  142.     {
  143.         if(lTempCheck > 1)
  144.         {
  145.             lReturnVal = tpLed->ucValue / 100 * lTempCheck + tpLed->tConfig.lOffVal;
  146.         }
  147.         else if(lTempCheck < -1)
  148.         {
  149.             lReturnVal = tpLed->ucValue / 100 * -lTempCheck - tpLed->tConfig.lOffVal;
  150.         }
  151.     }
  152.     return lReturnVal;
  153. }

  154. /******************************************************************
  155. * 函数名: lLedTwinklingCtrl()
  156. * 功 能: 闪烁控制
  157. * 输 入:
  158. * tpLed:led指针
  159. * 输 出: IO控制量
  160. */
  161. static int32_t lLedTwinklingCtrl(LedCtrl_T *tpLed)
  162. {   
  163.     int32_t lTemp_Hz = 0;
  164.     int32_t lReturnVal = 0;
  165.     int32_t lPeriod_ms = 0;
  166.     int32_t lPWMLevel = 0;
  167.     lTemp_Hz = tpLed->ucValue < MIN_TWINKLING_HZ ? MIN_TWINKLING_HZ : tpLed->ucValue;
  168.     lTemp_Hz = tpLed->ucValue > MAX_TWINKLING_HZ ? MAX_TWINKLING_HZ : tpLed->ucValue;
  169.     lPeriod_ms = 1000 / lTemp_Hz;
  170.     lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,50);
  171.     lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
  172.     tpLed->tPriData.lTimeCount_ms++;
  173.     if(tpLed->tPriData.lTimeCount_ms > lPeriod_ms)
  174.     {
  175.         tpLed->tPriData.lTimeCount_ms = 0;
  176.     }
  177.     return lReturnVal;
  178. }

  179. /******************************************************************
  180. * 函数名: lLedBreathingCtrl()
  181. * 功 能: 呼吸灯控制
  182. * 输 入:
  183. * tpLed:led指针
  184. * 输 出: IO控制量
  185. */
  186. static int32_t lLedBreathingCtrl(LedCtrl_T *tpLed)
  187. {   
  188.     int32_t lPeriod_ms = 0;
  189.     int32_t lRiseUpTime_ms = 0;
  190.     int32_t lReturnVal = 0;   
  191.     float fBrightnessPCT = 0.0f;
  192.     lPeriod_ms = tpLed->ucValue < MIN_BREATHING_S ? MIN_BREATHING_S * 1000 : tpLed->ucValue * 1000 ;
  193.     lPeriod_ms = tpLed->ucValue > MAX_BREATHING_S ? MAX_BREATHING_S * 1000 : tpLed->ucValue * 1000 ;
  194.     lRiseUpTime_ms = lPeriod_ms / 2;
  195.     //亮度切换
  196.     if(tpLed->tPriData.lTimeCount_ms <= lRiseUpTime_ms)//由暗变亮
  197.     {
  198.         fBrightnessPCT = (float)(tpLed->tPriData.lTimeCount_ms) / (float)lRiseUpTime_ms;
  199.     }
  200.     else if(tpLed->tPriData.lTimeCount_ms > lRiseUpTime_ms && tpLed->tPriData.lTimeCount_ms <= lPeriod_ms)//由亮变暗
  201.     {
  202.         fBrightnessPCT = (float)(lPeriod_ms - tpLed->tPriData.lTimeCount_ms) / (float)lRiseUpTime_ms;
  203.     }
  204.     else
  205.     {
  206.         fBrightnessPCT = 0.0f;
  207.         tpLed->tPriData.lTimeCount_ms = 0;
  208.     }
  209.     //调光曲线
  210.     fBrightnessPCT = fBrightnessPCT * fBrightnessPCT;
  211.     //亮度控制
  212.     {
  213.         int32_t lTempCheck = tpLed->tConfig.lOnVal - tpLed->tConfig.lOffVal;
  214.         if(lTempCheck >= -1 && lTempCheck <= 1)//io模式
  215.         {
  216.             int32_t lPeriod_ms = (int32_t)(1000 / MIN_BRIGHTNESS_HZ);
  217.             int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,(uint8_t)(fBrightnessPCT * 100.0f));
  218.             lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
  219.         }
  220.         else//pwm模式
  221.         {
  222.             if(lTempCheck > 1)
  223.             {
  224.                 lReturnVal = (int32_t)(fBrightnessPCT * (float)lTempCheck + (float)tpLed->tConfig.lOffVal);
  225.             }
  226.             else if(lTempCheck < -1)
  227.             {
  228.                 lReturnVal = (int32_t)(fBrightnessPCT * -(float)lTempCheck - (float)tpLed->tConfig.lOffVal);
  229.             }
  230.         }
  231.     }
  232.     tpLed->tPriData.lTimeCount_ms++;
  233.     return lReturnVal;
  234. }


  235. /******************************************************************
  236. * 函数名: lLedDisplayByteCtrl()
  237. * 功 能: 字节显示控制
  238. * 输 入:
  239. * tpLed:led指针
  240. * 输 出: IO控制量
  241. */
  242. static int32_t lLedDisplayByteCtrl(LedCtrl_T *tpLed)
  243. {   
  244.     int32_t lReturnVal = 0;
  245.     if(tpLed->tPriData.lCurDispBitNum == 0)
  246.     {
  247.         tpLed->tPriData.lTimeCount_ms = 0;
  248.         tpLed->tPriData.lCurDispBitNum++;
  249.     }
  250.     else if(tpLed->tPriData.lCurDispBitNum == 1)//起始位,常亮
  251.     {         
  252.         lReturnVal = tpLed->tConfig.lOnVal;
  253.         if(tpLed->tPriData.lTimeCount_ms > START_BIT_DELAY_MS)
  254.         {
  255.             tpLed->tPriData.lTimeCount_ms = 0;
  256.             tpLed->tPriData.lCurDispBitNum++;
  257.         }
  258.     }
  259.     else if(tpLed->tPriData.lCurDispBitNum >= 2 && tpLed->tPriData.lCurDispBitNum <= 9)//数据位
  260.     {
  261.         uint8_t ucCurBitDisplayVal = (tpLed->ucValue >> (tpLed->tPriData.lCurDispBitNum - 2)) & 0x01;
  262.         int32_t lPeriod_ms = ucCurBitDisplayVal == 1 ? 1000 / BIT_1_TWINKLING_HZ : 1000 / BIT_0_TWINKLING_HZ;
  263.         int32_t lPWMLevel = lLedSoftPWMGenerator(tpLed->tPriData.lTimeCount_ms,lPeriod_ms,50);
  264.         lReturnVal = lPWMLevel == 1 ? tpLed->tConfig.lOnVal : tpLed->tConfig.lOffVal;
  265.         if(tpLed->tPriData.lTimeCount_ms > ONE_BIT_DELAY_MS)
  266.         {
  267.             tpLed->tPriData.lTimeCount_ms = 0;
  268.             tpLed->tPriData.lCurDispBitNum++;
  269.         }
  270.     }
  271.     else if(tpLed->tPriData.lCurDispBitNum == 10)//停止位
  272.     {        
  273.         lReturnVal = tpLed->tConfig.lOffVal;
  274.         if(tpLed->tPriData.lTimeCount_ms > STOP_BIT_DELAY_MS)
  275.         {
  276.             tpLed->tPriData.lTimeCount_ms = 0;
  277.             tpLed->tPriData.lCurDispBitNum++;
  278.         }
  279.     }
  280.     else
  281.     {
  282.         tpLed->tPriData.lCurDispBitNum = 0;
  283.     }
  284.     tpLed->tPriData.lTimeCount_ms++;
  285.     return lReturnVal;
  286. }

  287. /******************************************************************
  288. * 函数名: lLedRun()
  289. * 功 能: 运行led,并返回IO控制量
  290. * 输 入:
  291. * tpLed:led指针
  292. * 输 出: IO控制量
  293. */
  294. int32_t lLedRun(LedCtrl_T *tpLed)
  295. {
  296.     if(tpLed->tPriData.lTimeTrgger_ms == 0)
  297.     {
  298.         tpLed->eMode = tpLed->tPriData.eModeBackup;
  299.         tpLed->ucValue = tpLed->tPriData.ucValueBackup;
  300.     }
  301.     else if(tpLed->tPriData.lTimeTrgger_ms > 0)
  302.     {
  303.         tpLed->eMode = tpLed->tPriData.eModeExp;
  304.         tpLed->ucValue = tpLed->tPriData.ucValueExp;
  305.     }
  306.     else
  307.     {
  308.         tpLed->tPriData.lTimeTrgger_ms = -1;
  309.     }
  310.     tpLed->tPriData.lTimeTrgger_ms--;
  311.     switch(tpLed->eMode)
  312.     {
  313.         case BRIGHTNESS:    //亮度范围:0-100,代表0%-100%
  314.             return lLedBrightnessCtrl(tpLed);
  315.         case TWINKLING:     //闪烁范围:Min_TWINKLING - MAX_TWINKLING,频率,单位Hz
  316.             return lLedTwinklingCtrl(tpLed);
  317.         case BREATHING:     //呼吸灯范围:Min_BREATHING - MAX_BREATHING,周期,单位秒
  318.             return lLedBreathingCtrl(tpLed);
  319.         case DISPLAYBYTE:   //字节显示
  320.             return lLedDisplayByteCtrl(tpLed);
  321.         default:
  322.             return tpLed->tConfig.lOffVal;
  323.     }
  324. }
复制代码


  1. /******************************************************************
  2. * 文件名: led_ctrl.h
  3. * 内容简述:
  4. * 控制led灯的亮灭,可实现4种状态,亮度调整,闪烁,呼吸灯,字节显示
  5. * 文件历史:
  6. * 版本号 日期 作者 说明
  7. ******************************************************************/

  8. #ifndef __LED_CTRL_H
  9. #define __LED_CTRL_H

  10. #ifdef __cplusplus
  11. extern "C" {
  12. #endif

  13. #include <stdint.h>

  14. /*枚举led驱动模式*/
  15. typedef enum tagLED_MODE_E
  16. {
  17.     BRIGHTNESS = 0, //亮度
  18.     TWINKLING,      //闪烁
  19.     BREATHING,      //呼吸灯
  20.     DISPLAYBYTE     //字节显示
  21. }LED_MODE_E;

  22. /*根据实际硬件,设置lOnVal和lOffVal,IO为1或者0,PWM控制为定时器重装值*/
  23. typedef struct tagLedConfig_T
  24. {
  25.     int32_t lOnVal;
  26.     int32_t lOffVal;
  27. }LedConfig_T;

  28. /*运行所需内部变量*/
  29. typedef struct tagLedPrivateData_T
  30. {
  31.     int32_t lTimeCount_ms;  //内部计时器
  32.     int32_t lCurDispBitNum; //字节显示模式中,用于标记当前显示的是哪位
  33.     int32_t lTimeTrgger_ms; //触发,计时器
  34.     LED_MODE_E eModeExp;    //触发,期望模式
  35.     uint8_t ucValueExp;     //触发,期望模式值
  36.     LED_MODE_E eModeBackup; //触发,备份当前模式
  37.     uint8_t ucValueBackup;  //触发,备份当前值
  38. }LedPrivateData_T;

  39. /*描述一个led*/
  40. typedef struct tagLedCtrl_T
  41. {  
  42.       LED_MODE_E eMode;
  43.     uint8_t ucValue;
  44.     LedConfig_T tConfig;
  45.     LedPrivateData_T tPriData;
  46. }LedCtrl_T;

  47. /*外部调用函数*/
  48. void vLedInit(LedCtrl_T *tpLed,int32_t lOnVal,int32_t lOffVal,LED_MODE_E eMode,uint8_t ucValue);
  49. uint8_t ucLedTriggerMode(LedCtrl_T *tpLed,LED_MODE_E eMode,uint8_t ucValue,int32_t lTime_ms);
  50. int32_t lLedRun(LedCtrl_T *tpLed);

  51. #ifdef __cplusplus
  52. }
  53. #endif

  54. #endif
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出100入85汤圆

发表于 2022-11-9 09:04:19 | 显示全部楼层
LED都能被你玩出了花

出0入42汤圆

发表于 2022-11-9 15:49:21 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2022-11-9 16:06:25 | 显示全部楼层

感谢分享 Thank you

出0入0汤圆

发表于 2022-11-9 16:07:28 | 显示全部楼层

感谢分享

出0入0汤圆

发表于 2022-11-11 08:16:41 | 显示全部楼层
感谢分享!

出0入114汤圆

发表于 2022-11-11 13:01:58 来自手机 | 显示全部楼层
点个灯而已,何必这么复杂

出0入25汤圆

发表于 2022-11-11 19:14:17 来自手机 | 显示全部楼层
有用的自然有用

出0入0汤圆

发表于 2022-11-11 21:35:39 | 显示全部楼层
卧槽。。这也太难了吧

出0入0汤圆

发表于 2022-11-11 21:56:00 | 显示全部楼层
亮瞎眼了!

出0入4汤圆

发表于 2022-11-12 00:30:57 | 显示全部楼层
实际应用的话这样设计不合理, 应该采用定时器方式更新pwm值.

出0入0汤圆

发表于 2022-11-14 22:49:27 来自手机 | 显示全部楼层
学习了,谢谢分享

出0入18汤圆

发表于 2022-11-14 22:55:31 来自手机 | 显示全部楼层
pwm方式最省事

出0入475汤圆

发表于 2022-11-14 23:27:12 来自手机 | 显示全部楼层
点个灯泡比我所有的程序都复杂:(
我们这些不懂程序的人该咋办。。。

出110入26汤圆

发表于 2022-11-15 01:10:26 | 显示全部楼层
太复杂,pwm+查表调亮度,省时省力。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-11 11:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表