Contributed by sujingliang, organized by Ai-Thinker
[Ai-WB2 Review] BLE+PWM RGB LED Control
1. RGB LED Control APP Found an app that can control RGB LEDs over BLE
Its BLE RGB control command format is as follows:
| 0x4e | 0x4f | 0x30 | 0x4 | 0xc5 | 0x0 | 0xff | 0xff | 0xf1 |
|---|---|---|---|---|---|---|---|---|
| Fixed format | Fixed format | Fixed format | Fixed format | RED | GREEN | BLUE | ALPHA | Unknown |
The command is 9 bytes in total The first four bytes are fixed at 0x4e 0x4f 0x30 0x4, and can be used to determine whether the following data is an RGB control command Byte 5 is RED Byte 6 is GREEN Byte 7 is BLUE Byte 8 is ALPHA Byte 9 is not understood and is not used
2. Writing the BLE Slave Program Use applications/bluetooth/ble_slave as the template.
- Add PWM RGB LED control code pwmled.h
Click to expand full code
#ifndef __PWM_LED_H__
#define __PWM_LED_H__
// pwmled.h
#include <bl602.h>
#include <bl602_gpio.h>
#include <bl_pwm.h>
BL_Err_Type
PWM_Smart_Configure2
(PWM_CH_ID_Type ch, uint16_t clkDiv, uint16_t period,uint16_t threshold2)
;
void
pwm_led_init
(
void
)
;
void
pwm_led_set
(uint8_t red,uint8_t green,uint8_t blue)
;
void
rgb_control
(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
;
#endifBL_Err_Type PWM_Smart_Configure2(PWM_CH_ID_Type ch, uint16_t clkDiv, uint16_t period,uint16_t threshold2); Configure PWM parameters
void pwm_led_init(void); Initialize PWM
void pwm_led_set(uint8_t red,uint8_t green,uint8_t blue); Set the 3 RGB LEDs
void rgb_control(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); Control the 3 RGB LEDs with alpha added
pwmled.cfunction implementation
Click to expand full code
#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
"pwmled.h"
#define
PWM_Get_Channel_Reg
(ch)
(PWM_BASE+PWM_CHANNEL_OFFSET+(ch)*
0x20
)
#define
PWM_STOP_TIMEOUT_COUNT
(
160
*
1000
)
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
,
},
};
/// @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;
}
void
pwm_led_init
(
void
)
{
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);
}
}
void
pwm_led_set
(uint8_t red,uint8_t green,uint8_t blue)
{
PWM_Smart_Configure2(
2
,
80
,
255
, green);
PWM_Channel_Enable(
2
);
PWM_Smart_Configure2(
3
,
80
,
255
, blue);
PWM_Channel_Enable(
3
);
PWM_Smart_Configure2(
4
,
80
,
255
, red);
PWM_Channel_Enable(
4
);
}
void
rgb_control
(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
{
uint8_t t_red,t_green,t_blue;
// 应用透明度/亮度
t_red = red*alpha/
255
;
t_green = green*alpha/
255
;
t_blue = blue*alpha/
255
;
pwm_led_set(t_red,t_green,t_blue);
}2. Modify ble_interface.c as follows
Click to expand full code
static
ssize_t
ble_uuid1_write_val
(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const
void
*buf, u16_t len, u16_t offset,
u8_t flags)
{
uint8_t *recv_buffer;
recv_buffer = pvPortMalloc(sizeof(uint8_t) * len);
memcpy(recv_buffer, buf, len);
printf(
"recv ble data len: %d\r\n"
, len);
if
(recv_buffer[
0
]==
0x4e
&&recv_buffer[
1
]==
0x4f
&&recv_buffer[
2
]==
0x30
&&recv_buffer[
3
]==
0x04
){
//pwm_led_set(recv_buffer[4],recv_buffer[5],recv_buffer[6]);
rgb_control(recv_buffer[
4
],recv_buffer[
5
],recv_buffer[
6
],recv_buffer[
7
]);
printf(
"pwm_led_set\r\n"
);
}
for
(
size_t
i
=
0
; i < len; i++)
{
printf(
"0x%x "
, recv_buffer[i]);
}
printf(
"\r\n"
);
vPortFree(recv_buffer);
return
len;
}What was added is:
Click to expand full code
if
(recv_buffer[
0
]==
0x4e
&&recv_buffer[
1
]==
0x4f
&&recv_buffer[
2
]==
0x30
&&recv_buffer[
3
]==
0x04
){
//pwm_led_set(recv_buffer[4],recv_buffer[5],recv_buffer[6]);
rgb_control(recv_buffer[
4
],recv_buffer[
5
],recv_buffer[
6
],recv_buffer[
7
]);
printf(
"pwm_led_set\r\n"
);
}That is, when UUID1 receives a write value, it checks whether the first 4 bytes are 0x4e 0x4f 0x30 0x4, and if so, calls rgb_control to change the RGB LED color.
3. Running Run the APP on the phone
Scan for BLE and connect
Change the uuid to match the configuration
Once in the interface, it can be operated.
After operating, the serial output is:

