点灯大师:闪烁、亮度调节、呼吸灯

11.20更新

距离这篇文章第一次发布已经过去快半年了,led操作的思想还是面向对象,用结构体的方式对灯进行管理,后面不管有多少个灯,都可以通过这套逻辑来进行,即使业务变了,单片机换了,都可以无缝衔接。根据实际项目经验,亮度调节和呼吸灯很少用,用的最多的是闪烁,还有定时关(例如上电先亮多久再去关灯),所以删掉比较复杂的亮度调节和呼吸灯(定时运行的基频要到100us,51单片机没法运行,只有32位单片机才能扛得住)。

led.h

#ifndef __LED_H
#define	__LED_H

#include "sys.h"

typedef enum {
	ledOn = 0,
	ledOff,
	ledBlink,
	ledTimedOff,
} ledState;

typedef struct {
	u8 bUpdateFlag : 1;	//	ledOn,ledOff,ledToggle时生效,防止程序空转浪费CPU资源
	u8 num;
	ledState 	state;
	u16 time;		//	在ledTimeSet()赋值
					//	ledBlink时对应闪烁时长, 单位ms;	
					//	ledOn,ledOff,ledToggle时无效
	u16 u16Cnt;
} LED_S;


void LED_Init(void);
void LedSet(LED_S *ledx, ledState state);
void LedTimeSet(LED_S *ledx, ledState state,u16 time);
void LedLoopTask(void);

extern LED_S ledG;
extern LED_S ledR;

#endif	//__LED_H

led.c

#include "sys.h"

LED_S ledG;
LED_S ledR;

static void Led_On(u8 num)
{
	switch( num ){
		case 1:
			RB0 = 1;
			break;
		case 2:
			RB1 = 1;
			break;
	}
}

static void Led_Off(u8 num)
{
	switch( num ){
		case 1:
			RB0 = 0;
			break;
		case 2:
			RB1 = 0;
			break;
	}
}

static void Led_Toggle(u8 num)
{
	switch( num ){
		case 1:
			RB0 ^= 1;
			break;
		case 2:
			RB1 ^= 1;
			break;
	}
}

void LED_Init()
{	
	ledG.num 	= 1;
	ledR.num 	= 2;
}

void LedSet(LED_S *ledx, ledState state)
{
	ledx->state = state;
	ledx->bUpdateFlag = 1;
}

void LedTimeSet(LED_S *ledx, ledState state, u16 time)
{
	ledx->state = state;
	ledx->time = time;
	ledx->u16Cnt = 0;
	ledx->bUpdateFlag = 1;
	Led_On(ledx->num);
}


static void ledxLoopTask(LED_S *ledx)
{		
	if ( 0 == ledx->bUpdateFlag ) {
		return;
	}	
	
	switch ( ledx->state )
	{
		case ledOn:
			ledx->bUpdateFlag = 0;
			Led_On(ledx->num);
			break;
		case ledOff:
			ledx->bUpdateFlag = 0;
			Led_Off(ledx->num);
			break;
		case ledBlink:
			if(ledx->u16Cnt < ledx->time){
				ledx->u16Cnt++;
			} else {
				ledx->u16Cnt = 0;
				Led_Toggle(ledx->num);				
			}	
			break;	
		case ledTimedOff:
			if(ledx->u16Cnt < ledx->time){
				ledx->u16Cnt++;
			} else {
				ledx->u16Cnt = 0;
				ledx->bUpdateFlag = 0;
				Led_Toggle(ledx->num);				
			}
	}
}

void LedLoopTask(void)
{
	ledxLoopTask(&ledG);
	ledxLoopTask(&ledR);
}


前言:


点灯大师当然要把灯用到极致,这里用操作系统的思想分时间片给led灯执行程序,在不占用太多cpu资源的情况下做到闪烁、占空比、呼吸灯,且可以多个led灯程序复用,跟单片机相关性不强,可移植性强。

本人使用的单片机芯片型号是AT32F413

有纰漏请指出,转载请说明。

学习交流请发邮件 1280253714@qq.com
 

程序源码

led.h

#ifndef __LED_H
#define __LED_H	 
#include "includes.h"

typedef enum {
	ledOn = 0,
	ledOff,
	ledToggle,
	ledBlink,
	ledBreath,
	ledDuty,
} ledState;


typedef struct {
	bool bUpdateFlag;	//	ledOn,ledOff,ledToggle时生效,防止程序空转浪费CPU资源
	bool bBreathFlag;	//	0为吸气,1为呼气
	ledState 	state;
	u8	num;
	u16	breathCnt;	//	呼吸灯的临时计数值
	u16 time;	//	在ledTimeSet()赋值
				//	ledBlink时对应闪烁时长, 单位ms;	
				//	ledDuty时对应占空比,25即为25%占空比,最大值为100
				//	ledBreath时对应呼或吸时长,一般呼气1500ms,吸气1500ms,单位为ms,
				//		为了减少cpu的负担,每次进入loopTask为100us,故在呼吸灯模式的time最好不超过2500
				//	ledOn,ledOff,ledToggle时无效
	u16 u16StartTick;
	u32 u32Cnt;
} LED_S;

#define LED1_PIN                GPIO_Pins_7
#define LED1_GPIO               GPIOF
#define LED1_GPIO_RCC_CLK       RCC_APB2PERIPH_GPIOF

#define LED2_PIN                GPIO_Pins_6
#define LED2_GPIO               GPIOF
#define LED2_GPIO_RCC_CLK       RCC_APB2PERIPH_GPIOF

#define   __LED1_ON       do{LED1_GPIO->BSRE = LED1_PIN;}while(0)
#define   __LED1_OFF       do{LED1_GPIO->BRE = LED1_PIN;}while(0)

#define   __LED2_ON       do{LED2_GPIO->BSRE = LED2_PIN;}while(0)
#define   __LED2_OFF       do{LED2_GPIO->BRE = LED2_PIN;}while(0)

#define   __LED1_TOGGLE       do{LED1_GPIO->OPTDT ^= LED1_PIN;}while(0)
#define   __LED2_TOGGLE       do{LED2_GPIO->OPTDT ^= LED2_PIN;}while(0)

void LED_Init(void);
void ledSet(LED_S *ledx, ledState state);
void ledTimeSet(LED_S *ledx, ledState state,u16 time);
void ledLoopTask(void);

extern LED_S led1;
extern LED_S led2;

#endif

led.c

#include "includes.h"

LED_S led1;
LED_S led2;

static void LED_GPIO_Init(void)
{
	GPIO_InitType GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(LED1_GPIO_RCC_CLK | LED2_GPIO_RCC_CLK, ENABLE);
    GPIO_PinsRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

	GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
	
    GPIO_InitStructure.GPIO_Pins = LED1_PIN;
    GPIO_Init(LED1_GPIO, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pins = LED2_PIN;
    GPIO_Init(LED2_GPIO, &GPIO_InitStructure);
	
	__LED1_OFF;
	__LED2_OFF;
}


void LED_Init()
{	
	led1.num = 1;
	led2.num = 2;
	LED_GPIO_Init();
}

void ledSet(LED_S *ledx, ledState state)
{
	ledx->state = state;
	ledx->bUpdateFlag = 1;
}

void ledTimeSet(LED_S *ledx, ledState state, u16 time)
{
	ledx->state = state;
	if ( state == ledBreath ){
		ledx->time = time/10;
	} else {
		ledx->time = time;
	}
	ledx->bUpdateFlag = 1;
}

static void ledxLoopTask(LED_S *ledx)
{
	if ( 0 == ledx->bUpdateFlag ) {
		return;
	}
	
	u16 timeInterval = 0;
	u16 u16StopTick = GetT2Cnt();	//	GetT2Cnt()即TMR2->CNT;
	if (led1.u16StartTick > u16StopTick){
		timeInterval = u16StopTick + (0xFFFF - ledx->u16StartTick);
	} else {
		timeInterval = (u16StopTick - ledx->u16StartTick);
	}
	if (timeInterval <= 100) {	//	100us进一次
		return;
	}
	ledx->u16StartTick = GetT2Cnt();	
	
	switch ( ledx->state ){
		case ledOn:
			ledx->bUpdateFlag = 0;
			switch( ledx->num ){
				case 1:
					__LED1_ON;
					break;
				case 2:
					__LED2_ON;
					break;
			}
			break;
		case ledOff:
			ledx->bUpdateFlag = 0;
			switch( ledx->num ){
				case 1:
					__LED1_OFF;
					break;
				case 2:
					__LED2_OFF;
					break;
			}
			break;
		case ledToggle:
			ledx->bUpdateFlag = 0;
			switch( ledx->num ){
				case 1:
					__LED1_TOGGLE;
					break;
				case 2:
					__LED2_TOGGLE;
					break;
			}
			break;
		case ledBlink:
			if( ledx->u32Cnt < ledx->time*10 ){
					ledx->u32Cnt++;
					return;
			} else {
					ledx->u32Cnt = 0;	
			}
			switch( ledx->num ){
				case 1:
					__LED1_TOGGLE;
					break;
				case 2:
					__LED2_TOGGLE;
					break;
			}
			break;
		case ledDuty:
			if ( 0 == ledx->time ){return;};
			if( ledx->u32Cnt <= ledx->time ){
				switch( ledx->num ){
				case 1:
					__LED1_ON;
					break;
				case 2:
					__LED2_ON;
					break;
				}
			} else if ( ledx->u32Cnt < 100 ) {
				switch( ledx->num ){
				case 1:
					__LED1_OFF;
					break;
				case 2:
					__LED2_OFF;
					break;
				}	
			} else {
				ledx->u32Cnt = 0;
			}
			ledx->u32Cnt++;
			break;
		case ledBreath:
			ledx->u32Cnt++;
			if( ledx->u32Cnt < ledx->breathCnt ){
				switch( ledx->num ){
				case 1:
					__LED1_ON;
					break;
				case 2:
					__LED2_ON;
					break;
				}
			} else if ( ledx->u32Cnt < ledx->time ) {
				switch( ledx->num ){
				case 1:
					__LED1_OFF;
					break;
				case 2:
					__LED2_OFF;
					break;
				}	
			} else {
				if ( 0 == ledx->bBreathFlag ){
					if ( ledx->breathCnt < (ledx->time/3) ){	//	模拟log函数
						ledx->breathCnt++;
					} else {
						ledx->breathCnt += 3;
					}
					if ( ledx->breathCnt >= ledx->time ){
						ledx->bBreathFlag = 1;
					}
				} else {
					if ( ledx->breathCnt < (ledx->time/3) ){	//	模拟log函数
						ledx->breathCnt--;
					} else {
						ledx->breathCnt -= 3;
					}
					if ( ledx->breathCnt <= 0 ){
						ledx->bBreathFlag = 0;
					}
				}
				ledx->u32Cnt = 0;
			}
			break;
	}
}


void ledLoopTask(void)
{
	ledxLoopTask(&led1);
	ledxLoopTask(&led2);
}

main.c

#include "includes.h"

u8 TestTemp = 0;
static void testPro(void);

int main(void)
{ 
    TimerOsInit();
	LED_Init();
    while (1)
    {		
		testPro();
		ledLoopTask();
    }
}

u16 temp=0;
static void testPro(void)
{
    if(!TestTemp){return;}
    switch(TestTemp){
		case 1:
			ledSet(&led1,ledOn);
			TestTemp = 0;
			break;
		case 2:
			ledSet(&led1,ledOff);
			TestTemp = 0;
			break;
		case 3:
			ledSet(&led1,ledToggle);
			TestTemp = 0;
			break;
		case 4:
			ledTimeSet(&led1,ledBlink,temp);
			TestTemp = 0;
			break;
		case 5:
			ledTimeSet(&led1,ledDuty,temp);
			TestTemp = 0;
			break;
		case 6:
			ledTimeSet(&led1,ledBreath,temp);
			TestTemp = 0;
			break;
		case 7:
			ledSet(&led2,ledOn);
			TestTemp = 0;
			break;
		case 8:
			ledSet(&led2,ledOff);
			TestTemp = 0;
			break;
		case 9:
			ledSet(&led2,ledToggle);
			TestTemp = 0;
			break;
		case 10:
			ledTimeSet(&led2,ledBlink,temp);
			TestTemp = 0;
			break;
		case 11:
			ledTimeSet(&led2,ledDuty,temp);
			TestTemp = 0;
			break;
		case 12:
			ledTimeSet(&led2,ledBreath,temp);
			TestTemp = 0;
			break;
	}
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值