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;
}
}