搭建开发环境
按照贴吧教程搭建开发环境,过程不多说,整体比较顺利。
不理解的是为啥写代码时ECLIPSE这么多XX和小虫虫啊,代码不能正常索引关联,但是编译过程是没有报错。这对强迫症来说太痛苦了,捣鼓半天没解决,望高手指点。
实在解决不了,后面看看能不能问豆包要个脚本将代码放进SourceInsight编辑,ESP32已这样搞定。

码代码
从参考历程入手
寻思这个BL602咱也不熟,直接使用SDK参考例程上手学习吧!
这里我导入的是demo pwm例程,计划用PWM控制三色灯实现调光、渐变、闪烁、混色之类的效果。导入过程如下:

核对硬件电路和代码发现示例的三路PWM输出脚刚好就是RGB三色灯控制脚,IO也不用配置了。

代码逻辑
逻辑框架
主要通过PWM_Channel_Set_Threshold2分别控制三路pwm占空比实现调光,具体为:
main
函数:
- GPIO 和 PWM 初始化
- 创建四个点灯任务,控制执行顺序
- 主循环(打印系统运行信息)
- 调光任务 1(
Task1
):
- 循环控制 R、G、B 灯周期性变亮变暗
- 切换任务到
Task2
- 闪灯任务 2(
Task2
):
- 循环控制 RGB 灯半亮交替闪烁
- 切换任务到
Task3
- 混色任务 3(
Task3
):
- 循环控制某灯渐亮,另一灯全亮,剩余灯熄灭
- 切换任务到
Task4
- 混色任务 4(
Task4
):
- 循环控制某灯渐亮,另外两灯全亮
- 切换任务到
Task1
代码展示
#include <FreeRTOS.h>
#include <task.h>
#include <blog.h>
#include <bl602.h>
#include <bl602_gpio.h>
#include <bl602_glb.h>
#include <bl_pwm.h>
#include <event_groups.h>
#define R_LED_PIN (14)
#define G_LED_PIN (17)
#define B_LED_PIN (3)
#define R_LED_PWM_CH (4)
#define G_LED_PWM_CH (2)
#define B_LED_PWM_CH (3)
#define R_FULL (1<<0)
#define G_FULL (1<<1)
#define B_FULL (1<<2)
#define PWM_PERIOD_VALUE (400)
#define ADJUST_DELAY (3)
#define RETRY_TIME (3)
#define PWM_Get_Channel_Reg(ch) (PWM_BASE+PWM_CHANNEL_OFFSET+(ch)*0x20)
#define PWM_STOP_TIMEOUT_COUNT (160*1000)
TaskHandle_t task1Handle, task2Handle, task3Handle, task4Handle;
int currentTask = 1;
/// @brief Copy from PWM_Smart_Configure. Use Bus Clock instead of External Crystal Clock for PWM Timer
/// @param ch PWM Channel
/// @param clkDiv PWM clock divider
/// @param period PWM period
/// @param threshold2
/// @return
BL_Err_Type PWM_Smart_Configure2(PWM_CH_ID_Type ch, uint16_t clkDiv, uint16_t period,uint16_t threshold2)
{
uint32_t tmpVal;
uint32_t timeoutCnt = PWM_STOP_TIMEOUT_COUNT;
/* Get channel register */
uint32_t PWMx = PWM_Get_Channel_Reg(ch);
tmpVal = BL_RD_REG(PWMx, PWM_CONFIG);
// if(BL_GET_REG_BITS_VAL(tmpVal, PWM_REG_CLK_SEL) != PWM_CLK_XCLK){
if(BL_GET_REG_BITS_VAL(tmpVal, PWM_REG_CLK_SEL) != PWM_CLK_BCLK){
BL_WR_REG(PWMx, PWM_CONFIG, BL_SET_REG_BIT(tmpVal, PWM_STOP_EN));
while(!BL_IS_REG_BIT_SET(BL_RD_REG(PWMx, PWM_CONFIG), PWM_STS_TOP)){
timeoutCnt--;
if(timeoutCnt == 0){
return TIMEOUT;
}
}
// tmpVal = BL_SET_REG_BITS_VAL(tmpVal, PWM_REG_CLK_SEL, PWM_CLK_XCLK);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, PWM_REG_CLK_SEL, PWM_CLK_BCLK);
}
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, PWM_OUT_INV, PWM_POL_NORMAL);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, PWM_STOP_MODE, PWM_STOP_GRACEFUL);
BL_WR_REG(PWMx, PWM_CONFIG, tmpVal);
/* Config pwm division */
BL_WR_REG(PWMx, PWM_CLKDIV, clkDiv);
/* Config pwm period and duty */
BL_WR_REG(PWMx, PWM_PERIOD, period);
BL_WR_REG(PWMx, PWM_THRE1, 0);
BL_WR_REG(PWMx, PWM_THRE2, threshold2);
return SUCCESS;
}
// 1. 分别控制R、G、B三色灯周期性变亮,再周期性变暗
void Task1(void *param)
{
for(uint8_t j=0;j<RETRY_TIME;j++)
{
// R 灯变亮再变暗
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
for (uint16_t cnt = PWM_PERIOD_VALUE; cnt > 0; cnt--)
{
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
// G 灯变亮再变暗
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
for (uint16_t cnt = PWM_PERIOD_VALUE; cnt > 0; cnt--)
{
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
// B 灯变亮再变暗
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
for (uint16_t cnt = PWM_PERIOD_VALUE; cnt > 0; cnt--)
{
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, cnt);
vTaskDelay(ADJUST_DELAY);
}
}
currentTask = 2;
vTaskResume(task2Handle);
vTaskSuspend(NULL);
}
// 2. 控制RGB三色灯半亮交替闪烁
void Task2(void *param)
{
if (currentTask == 2)
{
for(uint8_t j=0;j<RETRY_TIME;j++)
{
// R 半亮
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, PWM_PERIOD_VALUE / 2);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, 0);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, 0);
vTaskDelay(500);
// G 半亮
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, 0);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, PWM_PERIOD_VALUE / 2);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, 0);
vTaskDelay(500);
// B 半亮
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, 0);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, 0);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, PWM_PERIOD_VALUE / 2);
vTaskDelay(500);
}
currentTask = 3;
vTaskResume(task3Handle);
vTaskSuspend(NULL);
}
vTaskDelay(10);
}
// 3. 控制某颜色灯由熄灭逐渐全亮,同时某色灯全亮,剩下保持颜色熄灭,该逻辑三色都要轮流一遍
void Task3(void *param)
{
if (currentTask == 3)
{
for(uint8_t j=0;j<RETRY_TIME;j++)
{
// R 灯渐亮,G 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, 0);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
// G 灯渐亮,B 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, 0);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
// B 灯渐亮,R 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, 0);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
}
currentTask = 4;
vTaskResume(task4Handle);
vTaskSuspend(NULL);
}
vTaskDelay(10);
}
// 4. 控制某颜色灯由熄灭逐渐全亮,同时剩下两色某色灯全亮,该逻辑三色都要轮流一遍
void Task4(void *param)
{
if (currentTask == 4)
{
for(uint8_t j=0;j<RETRY_TIME;j++)
{
// R 灯渐亮,G 灯全亮,B 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, PWM_PERIOD_VALUE);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
// G 灯渐亮,R 灯全亮,B 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, PWM_PERIOD_VALUE);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
// B 灯渐亮,R 灯全亮,G 灯全亮
for (uint16_t cnt = 0; cnt <= PWM_PERIOD_VALUE; cnt++)
{
PWM_Channel_Set_Threshold2(B_LED_PWM_CH, cnt);
PWM_Channel_Set_Threshold2(R_LED_PWM_CH, PWM_PERIOD_VALUE);
PWM_Channel_Set_Threshold2(G_LED_PWM_CH, PWM_PERIOD_VALUE);
vTaskDelay(ADJUST_DELAY);
}
vTaskDelay(500);
}
currentTask = 1;
vTaskResume(task1Handle);
vTaskSuspend(NULL);
}
vTaskDelay(10);
}
int main(void)
{
GLB_GPIO_Cfg_Type cfg[3] = {
{
.drive = 0,
.smtCtrl = 1,
.gpioMode = GPIO_MODE_OUTPUT,
.pullType = GPIO_PULL_DOWN,
.gpioPin = 14, /// red
.gpioFun = 8,
},
{
.drive = 0,
.smtCtrl = 1,
.gpioMode = GPIO_MODE_OUTPUT,
.pullType = GPIO_PULL_DOWN,
.gpioPin = 17, /// green
.gpioFun = 8,
},
{
.drive = 0,
.smtCtrl = 1,
.gpioMode = GPIO_MODE_OUTPUT,
.pullType = GPIO_PULL_DOWN,
.gpioPin = 3, /// blue
.gpioFun = 8,
},
};
for (int i = 0; i < 3; i++) {
GLB_GPIO_Init(cfg + i);
PWM_CH_ID_Type ch = cfg[i].gpioPin % PWM_CH_MAX;
PWM_Channel_Disable(ch);
}
/// PWM Frequency = 80 Hz / Divider / Period
/// set pwm channel 2 for 50% duty, 40MHz
PWM_Smart_Configure2(2, 1, PWM_PERIOD_VALUE, 0);
PWM_Channel_Enable(2);
/// set pwm channel 3 for 75% duty, 5MHz
PWM_Smart_Configure2(3, 1, PWM_PERIOD_VALUE, 0);
PWM_Channel_Enable(3);
/// set pwm channel 3 for 10% duty, 1MHz
PWM_Smart_Configure2(4, 1, PWM_PERIOD_VALUE, 0);
PWM_Channel_Enable(4);
// ColorFullEvent=xEventGroupCreate();
// xEventGroupClearBits(ColorFullEvent,R_FULL|G_FULL);
xTaskCreate(Task1, "Task1", 1024, NULL, 15, &task1Handle);
vTaskSuspend(task1Handle);
xTaskCreate(Task2, "Task2", 1024, NULL, 15, &task2Handle);
vTaskSuspend(task2Handle);
xTaskCreate(Task3, "Task3", 1024, NULL, 15, &task3Handle);
vTaskSuspend(task3Handle);
xTaskCreate(Task4, "Task4", 1024, NULL, 15, &task4Handle);
vTaskSuspend(task4Handle);
vTaskResume(task1Handle);
for (;;)
{
vTaskDelay(pdMS_TO_TICKS(1000));
printf("system running! \r\n");
}
return 0;
}
流程图描述
- 开始:程序启动,进入
main
函数。
- GPIO 和 PWM 初始化:
- 定义并初始化 RGB 三色灯的 GPIO 配置数组
cfg
。
- 遍历
cfg
数组,对每个 GPIO 引脚进行初始化,并禁用对应的 PWM 通道。
- 分别配置 PWM 通道 2、3、4 的参数(频率、占空比等)并启用这些通道。
- 创建任务并控制执行顺序:
- 创建四个任务
Task1
、Task2
、Task3
、Task4
,并分别挂起它们。
- 恢复
Task1
任务的执行。
- 任务 1(
Task1
):
- 循环
RETRY_TIME
次。
- 控制 R 灯周期性变亮再变暗(通过改变 PWM 阈值并延时)。
- 控制 G 灯周期性变亮再变暗。
- 控制 B 灯周期性变亮再变暗。
- 任务完成后,设置
currentTask = 2
,恢复 Task2
任务并挂起自身。
- 任务 2(
Task2
):
- 当
currentTask == 2
时,循环 RETRY_TIME
次。
- 使 R 灯半亮,G 灯和 B 灯熄灭,延时 500ms。
- 使 G 灯半亮,R 灯和 B 灯熄灭,延时 500ms。
- 使 B 灯半亮,R 灯和 G 灯熄灭,延时 500ms。
- 任务完成后,设置
currentTask = 3
,恢复 Task3
任务并挂起自身。
- 任务 3(
Task3
):
- 当
currentTask == 3
时,循环 RETRY_TIME
次。
- 使 R 灯渐亮,G 灯全亮,B 灯熄灭(通过改变 PWM 阈值并延时),然后延时 500ms。
- 使 G 灯渐亮,B 灯全亮,R 灯熄灭,然后延时 500ms。
- 使 B 灯渐亮,R 灯全亮,G 灯熄灭,然后延时 500ms。
- 任务完成后,设置
currentTask = 4
,恢复 Task4
任务并挂起自身。
- 任务 4(
Task4
):
- 当
currentTask == 4
时,循环 RETRY_TIME
次。
- 使 R 灯渐亮,G 灯和 B 灯全亮(通过改变 PWM 阈值并延时),然后延时 500ms。
- 使 G 灯渐亮,R 灯和 B 灯全亮,然后延时 500ms。
- 使 B 灯渐亮,R 灯和 G 灯全亮,然后延时 500ms。
- 任务完成后,设置
currentTask = 1
,恢复 Task1
任务并挂起自身。
- 主循环:在
main
函数的主循环中,每隔 1000ms 打印 "system running! \r\n"。
- 结束:程序持续运行,不断循环执行上述任务。
点灯效果
见视频附件