您当前的位置: 首页 >  单片机

张巧龙

暂无认证

  • 0浏览

    0关注

    1208博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

只会用单片机点灯,很丢人吗?

张巧龙 发布时间:2021-10-30 11:20:00 ,浏览量:0

要学嵌入式,关注 ↓↓↓ @我要学嵌入式,嵌入式猛男的加油站。

作者 | strongerHuang

微信公众号 | 嵌入式专栏

很多初学者觉得自己学的东西很基础,担心今后实际工作用不到。有初学者问了这样的问题:单片机真正开发产品和学习的时候有什么差别,平时学的LED、ADC这些东西,在实际项目中会用到吗?

虽然技术更新迭代很快,但有很多基本的技术,仍然在实际项目中会用到,今天就拿LED为例来说说吧。

01 

LED有哪些作用?

别小看LED,它在实际生活中应用很广泛的。

首先就是以LED为光源的项目,比如呼吸灯、广告灯、LED显示屏等,这类控制LED亮灭(闪烁),或者亮度渐变。

再次就是LED背光灯,像液晶背光灯、按键背光灯等,这种也是需要控制LED变化的。我之前做过有按键的项目,按键背光灯需要渐变、配合音效控制LED不同频率闪烁,目的就是为了达到更好的体验效果。

再再次,LED作为指示灯,电源指示灯、状态指示灯,这种就和接近初学者的学习时的LED灯,但这种却在项目中很常见。

a3191d361af03c56f5e171ee344860e5.gif

拿状态指示灯来说,一个项目的LED状态指示灯可以直观明了的指示设备的运行状态,比如:运行、故障、待机、死机等常见状态。通过RGB,或者红黄绿不同颜色LED组合,可以实现更多状态的指示。

下面针对LED状态灯,说几点细节的内容。

02 

LED状态灯的实现

这里结合代码为大家分享一些项目中常见的LED状态灯的实现方法。

1.单色LED运行状态指示灯

通过闪烁(一亮一灭)指示设备运行的状态的指示灯,一个关键作用:设备有没有死机。

很多产品中都会用到,你买一个开发板,提供的综合例程也基本都有。

裸机情况下(一般状态机),在某一个状态实现LED闪烁:

int main(void)
{
  //系统初始化
  while(1)
  {
    //do something
    switch(State)
    {
      case 状态1:
        //do something
      break;


      case 状态2:
        //do something
      break;
      ·
      ·
      ·
      case 状态灯:
        ED_TOGGLE();  //LED闪烁
      break;
    }
  }
}

RTOS情况下,新建一个状态灯线程,在线程里面直接控制即可:

void StatusLight_Task(void *pvParameters)
{
  static TickType_t xLastWakeTime; //初始化
  xLastWakeTime = xTaskGetTickCount();
  for(;;)
  {//do something
    LED_TOGGLE();   //LED闪烁
    vTaskDelayUntil(&xLastWakeTime, 500);
  }
}

03 

单色LED渐变

LED渐变在生活中其实也有一些场景在用,呼吸灯、键盘等,其实原来也很简单,就是控制LED亮度。

控制方法有很多,电压、PWM都能达到控制LED亮度的效果。当然,现在还有控制LED渐变的专有芯片。

d67a81203f7816542e3a180a47e7f086.gif

但是,对于单片机项目来说,单片机自身就能实现,如果单独用一个芯片,就显得有点多余。

使用DAC输出模拟量可以实现,但如果多路就不现实,因此这种方法不常见。

常见的是PWM控制IO高低电平(从而控制电压),这种对于单片机来说有两种方法:

  • 定时器硬件PWM

  • 控制GPIO口高低电平

a.定时器硬件PWM

一个定时器输出PWM波形的同时,还需要一个定时器定时更新PWM输出占空比(修改亮度)。

b.控制GPIO口高低电平

这个方法就比较简单,控制IO口高低电平时间,只是这个时间需要结合整个项目业务逻辑(特别是裸机情况下),不能出现“卡机”情况。

当然,在RTOS情况下,业务逻辑就比较简单,单独一个线程:

LED_ON();
vTaskDelay(TimesON);
LED_OFF();
vTaskDelay(TimesOFF);

这里TimesON 和 TimesOFF是需要结合项目情况修改的变量(比如渐变时间)。

04 

多色LED,多种运行状态

一个设备在没有显示屏指示状态的时候,通过LED指示状态也是一种方法,比如:红、黄、绿三色,分别常灭、常亮、闪烁三种状态。

这种相对第一种单色固定状态要复杂一点,但实现起来也不难,方法也有很多。

这里分享一些思路:创建一个线程,一个结构体,轮询各种LED状态,根据应用修改其各种状态,以及闪烁时间等。

LED状态结构体:

typedef struct
{
  uint8_t  Mode;                  //模式
  uint8_t  Status;                //当前状态
  uint16_t OffTimes;              //灭时间
  uint16_t OnTimes;               //亮时间(ms)
  uint16_t Counter;               //计数(计时)
  void (*OffFun)(void);           //灭函数接口
  void (*OnFun)(void);            //亮函数接口
}SL_TypeDef;
/* 状态灯 */

LED状态主线程:

void StatusLight_Task(void *pvParameters)
{
  static TickType_t xLastWakeTime;
  xLastWakeTime = xTaskGetTickCount();


  for(;;)
  {
    SL_Scan(&sSLG_Structure);      //红灯
    SL_Scan(&sSLY_Structure);      //黄灯
    SL_Scan(&sSLR_Structure);      //绿灯


    vTaskDelayUntil(&xLastWakeTime, SL_TASK_PERIOD);
  }
}

这里结构体也是方便统一管理,其中SL_Scan浏览(扫描)函数的参数通过传递结构体指针,是为了方便读取并修改其中变量。

当然,SL_Scan 浏览函数具体实现,就与你应用有关:

static void SL_Scan(SL_TypeDef *SL_Struct)
{
  /* 常灭模式 */
  if(SL_MODE_OFF == SL_Struct->Mode)
  {
    SL_Struct->Status = SL_STATUS_OFF;           //状态置为"灭"
    SL_Struct->OffFun();                         //灭灯
  }
  /* 常亮模式 */
  else if(SL_MODE_ON == SL_Struct->Mode)
  {
    SL_Struct->Status = SL_STATUS_ON;            //状态置为"亮"
    SL_Struct->OnFun();                          //亮灯
  }
  /* 闪烁模式 */
  else if(SL_MODE_FLICKER == SL_Struct->Mode)
  {
    /* 在灭状态 */
    if(SL_STATUS_OFF == SL_Struct->Status)
    {
      SL_Struct->Counter++;
      if(SL_Struct->Counter >= SL_Struct->OffTimes)
      {
        SL_Struct->Counter = 0;
        SL_Struct->OnFun();                      //亮灯
        SL_Struct->Status = SL_STATUS_ON;        //状态置为"亮"
      }
    }
    /* 在亮状态 */
    else if(SL_STATUS_ON == SL_Struct->Status)
    {
      SL_Struct->Counter++;
      if(SL_Struct->Counter >= SL_Struct->OnTimes)
      {
        SL_Struct->Counter = 0;
        SL_Struct->OffFun();                     //灭灯
        SL_Struct->Status = SL_STATUS_OFF;       //状态置为"灭"
      }
    }
    else
    {
      SL_Struct->Status = SL_STATUS_OFF;         //状态置为"灭"
    }
  }
  /* 未知模式 */
  else
  {
    SL_Struct->Status = SL_STATUS_OFF;           //状态置为"灭"
    SL_Struct->OffFun();                         //灭灯
  }
}

05 

最后

以上的控制LED的状态,其实是一个项目中很小的一个模块,还有更复杂的LED实现和控制方法,相信做过这一块的同学就比较了解。

当然,LED在项目中是微不足道的一个模块,但是,如果针对莫个人设计一块LED的产品,那就意义非凡了。

c1a852a61bcbd5eff60e17f75bb03072.png

d0dec23cf94baee1db7576cb19712606.png

上面这种,相信很多暖(zhi)男都做过,就是不知道,最终那个女孩子感动了没有?如果感动了,那这个LED项目就是一生中非常重要的项目。

-END-

对了,前两天在小号做了个抽奖,送20份礼品,11月1号开奖,没有参与的朋友可以参与一波。

NUCLEO-U575ZI-Q 开发板 * 1块
电烙铁焊台套件  * 1套
焊枪 * 2份
万用表 * 4份
蓝牙耳机 * 2份
保温杯 * 2份
Type-C快充头  * 4份
无线鼠标* 4份

关注回复【STM32U5】,即可参与。字母都是大写哦。

猛男学嵌入式,关注@我要学嵌入式,嵌入式男人的加油站。

关注
打赏
1665727216
查看更多评论
立即登录/注册

微信扫码登录

0.0441s