本帖最后由 lilijin1995 于 2022-8-16 14:04 编辑
【APM32E103xE测评】基于APM32E103的RGB七彩渐变呼吸灯附送渐变算法并配置1ms Systick移植了MultiTimer
非常荣幸在“二姨家”申请到了“APM32E103ZE MINI板”,由于手头上有一个简单的控灯项目,所以直接想在APM32E103ZE跑跑看;
本贴分以下几个部分:
硬件主要有12V的RGB灯板和RGB-MOS管驱动板;如下图
另有原理图如下:
软件主要分两部分:
1. MultiTimer移植: MultiTimer是开源项目 ,一款可无限扩展的软件定时器,作者0x1abin,目前收获 95 个 star,遵循 MIT 开源许可协议。MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
首先需要配置Systick为1ms中断一次SysTick_Config(SystemCoreClock / 1000),
int main(void)
{
SysTick_Config(SystemCoreClock / 1000);
Board_Init();
while(1)
{
MultiTimerYield();
}
}
并在SysTick_Handler中自加
void SysTick_Handler(void)
{
tick++;
}<span style="background-color: rgb(255, 255, 255);"> </span>
接着我们添加MultiTimer代码
#include "MultiTimer.h"
#include <stdio.h>
/* Timer handle list head. */
static MultiTimer* timerList = NULL;
/* Timer tick */
static PlatformTicksFunction_t platformTicksFunction = NULL;
int MultiTimerInstall(PlatformTicksFunction_t ticksFunc)
{
platformTicksFunction = ticksFunc;
return 0;
}
int MultiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData)
{
if (!timer || !callback ) {
return -1;
}
MultiTimer** nextTimer = &timerList;
/* Remove the existing target timer. */
for (; *nextTimer; nextTimer = &(*nextTimer)->next) {
if (timer == *nextTimer) {
*nextTimer = timer->next; /* remove from list */
break;
}
}
/* Init timer. */
timer->deadline = platformTicksFunction() + timing;
timer->callback = callback;
timer->userData = userData;
/* Insert timer. */
for (nextTimer = &timerList;; nextTimer = &(*nextTimer)->next) {
if (!*nextTimer) {
timer->next = NULL;
*nextTimer = timer;
break;
}
if (timer->deadline < (*nextTimer)->deadline) {
timer->next = *nextTimer;
*nextTimer = timer;
break;
}
}
return 0;
}
int MultiTimerStop(MultiTimer* timer)
{
MultiTimer** nextTimer = &timerList;
/* Find and remove timer. */
for (; *nextTimer; nextTimer = &(*nextTimer)->next) {
MultiTimer* entry = *nextTimer;
if (entry == timer) {
*nextTimer = timer->next;
break;
}
}
return 0;
}
int MultiTimerYield(void)
{
MultiTimer* entry = timerList;
for (; entry; entry = entry->next) {
/* Sorted list, just process with the front part. */
if (platformTicksFunction() < entry->deadline) {
return (int)(entry->deadline - platformTicksFunction());
}
/* remove expired timer from list */
timerList = entry->next;
/* call callback */
if (entry->callback) {
entry->callback(entry, entry->userData);
}
}
return 0;
}
最后我们直接开两个定时器即两个线程,一个作为按键扫描,一个作为灯光的控制
#include "Board.h"
#if defined (APM32E103_MINI)
#include "Board_APM32E103_MINI.c"
#include "RGB.h"
#include "KEY.h"
volatile uint64_t tick = 0;
MultiTimer timer1;
MultiTimer timer2;
uint64_t PlatformTicksGetFunc(void)
{
return tick;
}
void RGBTimer1Callback(MultiTimer* timer, void *userData)
{
switch(RGB_Eff)
{
case DYN_RGB:
{
GradientDreamColor();
}
break;
case DYN_RED:
{
GradientDreamSingleColor(DYN_RED);
}
break;
case DYN_ORANGE:
{
GradientDreamSingleColor(DYN_ORANGE);
}
break;
case DYN_YELLOW:
{
GradientDreamSingleColor(DYN_YELLOW);
}
break;
case DYN_GREE:
{
GradientDreamSingleColor(DYN_GREE);
}
break;
case DYN_CYAN:
{
GradientDreamSingleColor(DYN_CYAN);
}
break;
case DYN_BLUE:
{
GradientDreamSingleColor(DYN_BLUE);
}
break;
case DYN_PURPLE:
{
GradientDreamSingleColor(DYN_PURPLE);
}
break;
case STATICK_RED:
{
SetRGB_PWM(0xFF,0x00,0x00);
}
break;
case STATICK_ORANGE:
{
SetRGB_PWM(225,69,0);
}
break;
case STATICK_YELLOW:
{
SetRGB_PWM(0xFF,0xFF,0x00);
}
break;
case STATICK_GREEN:
{
SetRGB_PWM(0x00,0xFF,0x00);
}
break;
case STATICK_CYAN:
{
SetRGB_PWM(0x00,0xFF,0xFF);
}
break;
case STATICK_BLUE:
{
SetRGB_PWM(0x00,0x00,0xFF);
}
break;
case STATICK_PURPLE:
{
SetRGB_PWM(0xFF,0x00,0xFF);
}
break;
case STATICK_WHITE:
{
SetRGB_PWM(0xFF,0xFF,0xFF);
}
break;
case STATICK_BLACK:
{
SetRGB_PWM(0x00,0x00,0x00);
}
break;
default:
break;
}
MultiTimerStart(timer, 10, RGBTimer1Callback, userData);
}
2. KEY驱动:
#include "KEY.h"
#include "main.h"
void KEY_Init(void)
{
GPIO_Config_T GPIO_ConfigStruct;
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
GPIO_ConfigStruct.pin = GPIO_PIN_0|GPIO_PIN_1; //PB0--TMR3_CH3
GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;
GPIO_Config(GPIOA, &GPIO_ConfigStruct);
}
u8 KEY_Handler(void)
{
static u8 key1bounce=0,key2bounce=0;
u8 key=0;
if(GPIO_ReadInputBit(GPIOA,GPIO_PIN_0)==BIT_RESET)
{
key1bounce=1;
}else{
if(key1bounce)
{
key|=0x01;
}
key1bounce=0;
}
if(GPIO_ReadInputBit(GPIOA,GPIO_PIN_1)==BIT_RESET)
{
key2bounce=1;
}else{
if(key2bounce)
{
key|=0x02;
}
key2bounce=0;
}
return key;
}
3. RGB驱动:
/*!
* [url=home.php?mod=space&uid=288409]@file[/url] RGB.c
*
* [url=home.php?mod=space&uid=247401]@brief[/url] This file provides firmware functions to manage Leds and push-buttons
*
* [url=home.php?mod=space&uid=895143]@version[/url] V1.0.0
*
* [url=home.php?mod=space&uid=212281]@date[/url] 2021-07-26
*
*/
#include "RGB.h"
#include "main.h"
//RGB
RGB_LED_EFFECT RGB_Eff=DYN_RGB;
void RGB_Init(void)
{
GPIO_Config_T GPIO_ConfigStruct;
TMR_BaseConfig_T TMR_TimeBaseStruct;
TMR_OCConfig_T OCcongigStruct;
RCM_EnableAPB2PeriphClock((RCM_APB2_PERIPH_T)(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOB));
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
GPIO_ConfigStruct.pin = GPIO_PIN_6|GPIO_PIN_7;//PA6--TMR3_CH1
GPIO_ConfigStruct.mode = GPIO_MODE_AF_PP; //PA7--TMR3_CH2
GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA, &GPIO_ConfigStruct);
GPIO_ConfigStruct.pin = GPIO_PIN_0; //PB0--TMR3_CH3
GPIO_ConfigStruct.mode = GPIO_MODE_AF_PP;
GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOB, &GPIO_ConfigStruct);
TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
TMR_TimeBaseStruct.division = 71;
TMR_TimeBaseStruct.period = 255;
TMR_ConfigTimeBase(TMR3, &TMR_TimeBaseStruct);
OCcongigStruct.idleState = TMR_OC_IDLE_STATE_RESET;
OCcongigStruct.mode = TMR_OC_MODE_PWM1;
OCcongigStruct.nIdleState = TMR_OC_NIDLE_STATE_RESET;
OCcongigStruct.nPolarity = TMR_OC_NPOLARITY_HIGH;
OCcongigStruct.outputNState = TMR_OC_NSTATE_ENABLE;
OCcongigStruct.outputState = TMR_OC_STATE_ENABLE;
OCcongigStruct.polarity = TMR_OC_POLARITY_HIGH;
OCcongigStruct.pulse = 0;
TMR_ConfigOC1(TMR3, &OCcongigStruct);
TMR_ConfigOC2(TMR3, &OCcongigStruct);
TMR_ConfigOC3(TMR3, &OCcongigStruct);
TMR_ConfigOC1Preload(TMR3, TMR_OC_PRELOAD_ENABLE);
TMR_ConfigOC2Preload(TMR3, TMR_OC_PRELOAD_ENABLE);
TMR_ConfigOC3Preload(TMR3, TMR_OC_PRELOAD_ENABLE);
TMR_EnableAUTOReload(TMR3);
TMR_Enable(TMR3);
TMR_EnablePWMOutputs(TMR3);
}
void SetRGB_PWM(u16 R,u16 G,u16 B)
{
TMR3->CC1=R;
TMR3->CC2=G;
TMR3->CC3=B;
}
const u8 R[8]= {255,191,127,0,0,0,150,255};
const u8 G[8]= {0,69,127,255,127,0,2,0};
const u8 B[8]= {0,0,0,0,127,255,134,0};
unsigned char abs0(int num)
{
if(num>0) return num;
num = -num;
return (unsigned char) num;
}
u8 ColorToColor(u8 r0,u8 g0,u8 b0, u8 r1,u8 g1,u8 b1,float* RedStep,float* GreenStep,float* BlueStep)
{
unsigned char Red0, Green0, Blue0; // 起始三原色
unsigned char Red1, Green1, Blue1; // 结果三原色
int RedMinus, GreenMinus, BlueMinus; // 颜色差(color1 - color0)
u8 NStep;
//unsigned long color; // 结果色
// 绿 红 蓝 三原色分解
Red0 = r0;
Green0 = g0;
Blue0 = b0;
Red1 = r1;
Green1 = g1;
Blue1 = b1;
// 计算需要多少步(取差值的最大值)
RedMinus = Red1 - Red0;
GreenMinus = Green1 - Green0;
BlueMinus = Blue1 - Blue0;
NStep = ( abs0(RedMinus) > abs0(GreenMinus) ) ? abs0(RedMinus):abs0(GreenMinus);
NStep = ( NStep > abs0(BlueMinus) ) ? NStep:abs0(BlueMinus);
// 计算出各色步进值
RedStep[0] = (float)RedMinus / NStep;
GreenStep[0] = (float)GreenMinus / NStep;
BlueStep[0] = (float)BlueMinus / NStep;
// 渐变开始
// for(i=0; i<NStep; i++)
// {
// Red1 = Red0 + (int)(RedStep * i);
// Green1 = Green0 + (int)(GreenStep * i);
// Blue1 = Blue0 + (int)(BlueStep * i);
//
// //color = Green1<<16 | Red1<<8 | Blue1; // 合成 绿红蓝
// SetPWM_for_RGB(Red1,Green1,Blue1);
//
// DelayMs(1); // 渐变速度
// }
// 渐变结束
return NStep;
}
void GradientDreamSingleColor(RGB_LED_EFFECT type)
{
unsigned char Red, Green, Blue; // 结果三原色
static u8 first=0,tick=0,cStep=0,tp=1,rgb=0;
static float RedStep, GreenStep, BlueStep;
static RGB_LED_EFFECT typelast=DYN_RED;
if(typelast!=type)
{
SetRGB_PWM(0,0,0);
}
typelast=type;
if(first==0)
{
first=1;
switch(type)
{
case DYN_RED:
{
rgb=0;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_ORANGE:
{
rgb=1;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_YELLOW:
{
rgb=2;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_GREE:
{
rgb=3;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_CYAN:
{
rgb=4;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_BLUE:
{
rgb=5;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
case DYN_PURPLE:
{
rgb=6;
if(tp==0)
{
tp=1;
cStep=ColorToColor(R[rgb],G[rgb],B[rgb],0,0,0,&RedStep,&GreenStep,&BlueStep);
} else {
tp=0;
cStep=ColorToColor(0,0,0,R[rgb],G[rgb],B[rgb],&RedStep,&GreenStep,&BlueStep);
}
}
break;
default:
break;
}
} else {
if(tick<cStep)
{
if(tp==0)
{
Red =0+ (int)(RedStep * tick);
Green = 0+ (int)(GreenStep * tick);
Blue = 0+(int)(BlueStep *tick);
} else {
Red =R[rgb] + (int)(RedStep * tick);
Green = G[rgb] + (int)(GreenStep * tick);
Blue = B[rgb] + (int)(BlueStep *tick);
}
SetRGB_PWM(Red,Green,Blue);
} else {
tick=0;
first=0;
}
tick++;
}
}
void GradientDreamColor(void)
{
unsigned char Red, Green, Blue; // 结果三原色
static u8 first=0,i=0,tick=0,cStep=0;
static float RedStep, GreenStep, BlueStep;
static u16 delaytick=0;
if(delaytick++>5)
{
delaytick=0;
if(first==0)
{
first=1;
cStep=ColorToColor(R[i],G[i],B[i],R[i+1],G[i+1],B[i+1],&RedStep,&GreenStep,&BlueStep);
} else {
if(tick<cStep)
{
Red =R[i] + (int)(RedStep * tick);
Green = G[i] + (int)(GreenStep * tick);
Blue = B[i] + (int)(BlueStep *tick);
SetRGB_PWM(Red,Green,Blue);
} else {
tick=0;
if(++i>=7)
{
i=0;
}
first=0;
}
tick++;
}
}
}
最后实验可以看我们的视频:
https://www.bilibili.com/video/BV1ZT411A77M/?vd_source=2bbde87de845d5220b1d8ba075c12fb0
并附上代码
|