很多初学者觉得自己学的东西很基础,担心今后实际工作用不到。
有初学者问了这样的问题:单片机真正开发产品和学习的时候有什么差别,平时学的LED、ADC这些东西,在实际项目中会用到吗?
虽然技术更新迭代很快,但有很多基本的技术,仍然在实际项目中会用到,今天就拿LED为例来说说吧。
LED有哪些作用

拿状态指示灯来说,一个项目的LED状态指示灯可以直观明了的指示设备的运行状态,比如:运行、故障、待机、死机等常见状态。通过RGB,或者红黄绿不同颜色LED组合,可以实现更多状态的指示。
下面针对LED状态灯,说几点细节的内容。
LED状态灯实现
这里结合代码为大家分享一些项目中常见的LED状态灯的实现方法。
1.单色LED运行状态指示灯
通过闪烁(一亮一灭)指示设备运行的状态的指示灯,一个关键作用:设备有没有死机。
很多产品中都会用到,你买一个开发板,提供的综合例程也基本都有。
裸机情况下(一般状态机),在某一个状态实现LED闪烁:
int main(void){//系统初始化while(1){//do somethingswitch(State){case 状态1://do somethingbreak;case 状态2://do somethingbreak;···case 状态灯:ED_TOGGLE(); //LED闪烁break;}}}
RTOS情况下,新建一个状态灯线程,在线程里面直接控制即可:
void StatusLight_Task(void *pvParameters){static TickType_t xLastWakeTime;//初始化xLastWakeTime = xTaskGetTickCount();for(;;){//do somethingLED_TOGGLE(); //LED闪烁vTaskDelayUntil(&xLastWakeTime, 500);}}
2.单色LED渐变
LED渐变在生活中其实也有一些场景在用,呼吸灯、键盘等,其实原来也很简单,就是控制LED亮度。
控制方法有很多,电压、PWM都能达到控制LED亮度的效果。当然,现在还有控制LED渐变的专有芯片。

但是,对于单片机项目来说,单片机自身就能实现,如果单独用一个芯片,就显得有点多余。
使用DAC输出模拟量可以实现,但如果多路就不现实,因此这种方法不常见。
常见的是PWM控制IO高低电平(从而控制电压),这种对于单片机来说有两种方法:
定时器硬件PWM
控制GPIO口高低电平
a.定时器硬件PWM
一个定时器输出PWM波形的同时,还需要一个定时器定时更新PWM输出占空比(修改亮度)。
b.控制GPIO口高低电平
这个方法就比较简单,控制IO口高低电平时间,只是这个时间需要结合整个项目业务逻辑(特别是裸机情况下),不能出现“卡机”情况。
当然,在RTOS情况下,业务逻辑就比较简单,单独一个线程:
LED_ON();vTaskDelay(TimesON);LED_OFF();vTaskDelay(TimesOFF);
这里TimesON 和 TimesOFF是需要结合项目情况修改的变量(比如渐变时间)。
3.多色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);}}
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(); //灭灯}}
最后


声明: