目录
1.任务前置准备
1.1 实现初步思路与流程框图
程序的实现思路:单片机与手机app之间通过蓝牙实现通讯,通过点击屏幕上的对应色块然后app会把对应的RGB值发送到单片机。然后单片机会对数据进行解析然后把数字量转换为模拟量,然后通过PWM控制IO口输出不同的电压以此来达到控制RGB灯
1.2 RGB彩灯原理
之所以叫RGB,是因为这个LED是由红(Red)、绿(Green)和蓝(Blue)三色组成,可以通过调整三个LED中每个灯的亮度就能产生不同的颜色。
RGB灯有4个引脚,R、G、B三个引脚连接到LED灯的一端,还有一个引脚是共用的正极(vcc)或者共用的阴极(gnd)。假设这里选用的是共阴RGB。R、G、B其实就是三个LED的正极,把它们的负极拉到一个公共引脚上了,它们公共引脚是负极,所以称之为共阴RGB。
RGB灯如何使用呢?如何实现变色呢?
RGB只是简单的把三个颜色的LED灯封装在一个LED中。只要当做三个灯使用就可以了。我们都知道红色、绿色、蓝色是三原色,单片机通过PWM口对三种颜色明暗的调节,analogWrite(value)语句,就能让LED调出任何你想要的颜色。使用PWM可以产生0~255之间的全部颜色,共16777216种颜色(256×256×256),市面上那些说自己有1000万种颜色的灯就是这个原理。
1.3 主控芯片引脚作用图
1.4 驱动板原理图
由原理图可以得知
R的引脚采用LED0/PB5,也就是定时器3的PWM输出;
G的引脚采用PB3,也就是定时器2的PWM输出;
B的引脚采用PA3,定时器5的PWM输出;
RF接蓝牙天线,OSCO与OSC接蓝牙模块的输入输出引脚
2. 任务实现流程
外设:
蓝牙模块,定时器,RGB彩灯
程序:
所必须包含头文件
对应蓝牙模块IO口引脚初始化;
蓝牙通讯协议的实现;
数据的处理
对应定时器输出PWM引脚的初始化;
时刻根据处理好的数据输出占空比频率不一样的pwm波
彩灯根据输入的PWM波,发出亮度不一样或者闪烁频率不一样的光
逐步调试思路
1.实现可以通过烧录程序来控制LED灯的亮灭和颜色变化
2.实现可以通过蓝牙APP控制LED灯的亮灭
3.实现可以通过蓝牙APP控制LED灯的颜色
4.整合优化代码和功能
3. 程序实现代码
前排提示,我写的代码比较多宏定义,大家看看思路就好
3.0 蓝牙发送数据格式
3.1 点亮一盏LED
定义函数
使用实例
led_pin_set_enable(LED_RED_PIN);
这里其实就是调用SDK包里的api函数,来让所控制的引脚输出高电平或者低电平。
3.2 控制彩灯的亮度
蓝牙协议形式
定义函数
这里调用timer_pwm_init()这个函数来对对应得引脚进行PWM的输出。这里根据函数的第三个参数的值/10000,就是所对应的占空比百分比。其实这里的思路主要就是比如说控制信息为80,这时候需要亮度为最亮的80%。如果大家的占空比都设置为80%,此时会破坏原来的颜色比例,这时候只要乘上原来的比例也就是RGB值除以颜色最大值就行了。
使用实例
setLedBrightness(buffer[2]);
3.3 控制彩灯的颜色
蓝牙协议形式
定义函数
其实这里的思路主要就是比如说控制信息为80,这时候需要亮度为最亮的80%。如果大家的占空比都设置为80%,此时会破坏原来的颜色比例,这时候只要乘上原来的比例也就是RGB值除以颜色最大值就行了
使用实例
handleColorChange(buffer[3], buffer[4], buffer[5]);
3.4 控制灯的开关,并且记忆灯原来的亮度和颜色
蓝牙协议形式
定义函数
和上面一样的思路,都是利用一个全局变量随时记录RGB值,在使用的时候随时调用
使用实例
handleSwitchLight(buffer[2]);
3.5通过外部音源控制灯颜色的亮度
蓝牙协议形式
函数定义
和上面一样的思路,都是利用一个全局变量随时记录RGB值,在使用的时候随时调用
使用实例
handleColor_brightnessChange(buffer[2], buffer[3], buffer[4], buffer[5]);
3.6 蓝牙控制颜色跳变的顺序
蓝牙协议形式
这个厂家给的app里并未设置,需要自己自行在上位机编写发送的数据帧形式。
函数定义
// 定义全局指针变量
volatile u8 *global_bt_receive_buffer;
volatile u16 global_length;
// 宏定义全局变量,用来规定在数组的第几个元素开始提取跳变RGB数据
#define global_Bluetooth_protocol_header_text_length_RGB_change_suddenly 8
volatile u8 time_flag_suddenly = 1;
/*****************************************************************************************************************************************************************************************************************
*Function Name: handleColor_arrayChange_suddenly
*Purpose: 对传入的一维数组进行数据的处理,提取除识别字节以外的设定数据来作用于RGB灯跳变效果
*Params:
* @u8 *bt_receive_buffer 定义一个指针变量用来传递蓝牙数据数组的地址
* @u16 length 传入的数组长度
*Return: None
*****************************************************************************************************************************************************************************************************************/
void handleColor_arrayChange_suddenly(u8 *bt_receive_buffer, u16 length)
{
static int i = global_Bluetooth_protocol_header_text_length_RGB_change_suddenly;
printf("跳变控制函数\n");
if ((i < (length - 2)) && (time_flag_suddenly == 1))
{
handleColorChange(bt_receive_buffer[i], bt_receive_buffer[i + 1], bt_receive_buffer[i + 2]);
printf("for循环里lllllllllllllllllll\n");
time_flag_suddenly = 0;
i = i + 3;
// delay_2ms(200);
}
if (i > (length - 2))
{
i = global_Bluetooth_protocol_header_text_length_RGB_change_suddenly;
}
printf("handleColor_arrayChange_suddenly颜色跳变颜色跳变颜色跳变颜色跳变\n");
}
u16 timer_id_color_change_suddenly = 0;
u16 timer_id_color_change_gradually = 0;
void *private_data = NULL; // 设置私有参数为NULL
u32 timeout_msec = 10; // 设置定时时间为10毫秒
u8 priority = 1; // 设置优先级为1
void timeout_callback(void *priv)
{
static u16 i = 0;
printf("颜色跳变回调函数\n");
i = i + 10;
if (i == 1000)
{
time_flag_suddenly = 1;
i = 0;
}
handleColor_arrayChange_suddenly(global_bt_receive_buffer, global_length);
}
因为在发送数据时,在发送一次数据后需要RGB灯的颜色循环跳变,并且由于使用的是实时操作系统。所以不能在颜色变化后使用例如delay_MS这种死延时。否则会因为堵塞导致无法及时对看门狗进行喂狗导致系统崩溃。
我这里采用的是利用一个定时器,每隔1000ms就执行一次这个函数,达到颜色跳变的效果。现在在做完之后感觉time_flag_suddenly这个参数可以省略掉了。不过灯带被我拆了,那就先不测试,
global_Bluetooth_protocol_header_text_length_RGB_change_suddenly是一个蓝牙数据的识别字节。只要在宏定义里进行修改就可以做到在第几个字节进行提取了。
3.7 蓝牙控制颜色渐变的顺序
蓝牙协议形式
这个厂家给的app里并未设置,需要自己自行在上位机编写发送的数据帧形式
函数定义
// 定义全局指针变量
volatile u8 time_flag_gradually = 0;
// 定义全局变量,用来规定在数组的第几个元素开始提取渐变RGB数据
#define header_text_length_RGB_change_gradually 9
#define global_Bluetooth_protocol_header_text_length_RGB_change_gradually header_text_length_RGB_change_gradually-1
/*****************************************************************************************************************************************************************************************************************
*Function Name: handleColor_arrayChange_gradually
*Purpose: 对传入的一维数组进行数据的处理,提取除识别字节以外的设定数据来作用于RGB灯渐变效果
*Params:
* @u8 *bt_receive_buffer 定义一个指针变量用来传递蓝牙数据数组的地址
* @u16 length 传入的数组长度
*Return: None
*notice global_Bluetooth_protocol_header_text_length_RGB_change_gradually为全局变量用来输入蓝牙识别字节所占字节
*****************************************************************************************************************************************************************************************************************/
void handleColor_arrayChange_gradually(u8 *bt_receive_buffer, u16 length)
{
printf("handleColor_arrayChange_gradually颜色渐变颜色渐变颜色渐变\n");
static int j = 0;
static int i = global_Bluetooth_protocol_header_text_length_RGB_change_gradually;
u8 STEPS = 100;
static u8 i_balance = 3;
static flag = 1;
if ((i < (length - 5)) && (time_flag_gradually == 0))
{
// 获取初始亮度i-
u8 initial_red_value = bt_receive_buffer[i];
u8 initial_green_value = bt_receive_buffer[i + 1];
u8 initial_blue_value = bt_receive_buffer[i + 2];
u8 target_red_value = bt_receive_buffer[i + 3];
u8 target_green_value = bt_receive_buffer[i + 4];
u8 target_blue_value = bt_receive_buffer[i + 5];
printf("i的值为-----------i的值为-----------i的值为-----------i的值为-----------i的值为-----------i的值为-----------i的值为-----------i的值为-----------%d\n", i);
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_red_value);
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_green_value);
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_blue_value);
printf("initial_red_value----initial_red_value----initial_red_value----initial_red_value----initial_red_value----%d\n", initial_red_value);
printf("initial_green_value-----initial_green_value-------initial_green_value-------initial_green_value-------%d\n", initial_green_value);
printf("initial_blue_valueinitial_blue_valueinitial_blue_valueinitial_blue_valueinitial_blue_valueinitial_b%d\n", initial_blue_value);
// 计算每个颜色通道的增量
// 逐步更新颜色值,使其渐变到目标值
if ((j < STEPS) && (time_flag_gradually == 0))
{
u8 red_increment = (target_red_value - initial_red_value) * j / STEPS;
u8 green_increment = (target_green_value - initial_green_value) * j / STEPS;
u8 blue_increment = (target_blue_value - initial_blue_value) * j / STEPS;
u8 current_red_value = initial_red_value + red_increment;
u8 current_green_value = initial_green_value + green_increment;
u8 current_blue_value = initial_blue_value + blue_increment;
handleColorChange(current_red_value, current_green_value, current_blue_value);
// delay_2ms(24); // 延时一段时间,控制灯的变化速度
printf("红色值当前增量%d\n", red_increment);
printf("绿色值当前增量%d\n", green_increment);
printf("蓝色值当前增量%d\n", blue_increment);
time_flag_gradually = 1;
printf("jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj===================%d\n", j);
j++;
}
if (j >= STEPS)
{
j = 0;
i = i + 3;
}
printf("第一组 RGB 值已经渐变到第二组一样\n");
}
if (i >= (length - 5))
{
u8 initial_red_value = bt_receive_buffer[length - 3];
u8 initial_green_value = bt_receive_buffer[length - 2];
u8 initial_blue_value = bt_receive_buffer[length - 1];
u8 target_red_value = bt_receive_buffer[global_Bluetooth_protocol_header_text_length_RGB_change_gradually];
u8 target_green_value = bt_receive_buffer[global_Bluetooth_protocol_header_text_length_RGB_change_gradually + 1];
u8 target_blue_value = bt_receive_buffer[global_Bluetooth_protocol_header_text_length_RGB_change_gradually + 2];
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_red_value);
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_green_value);
printf("target_red_value------------------target_red_value---------------target_red_value%d\n", target_blue_value);
printf("initial_red_value----initial_red_value----initial_red_value----initial_red_value----initial_red_value----%d\n", initial_red_value);
printf("initial_green_value-----initial_green_value-------initial_green_value-------initial_green_value-------%d\n", initial_green_value);
printf("initial_blue_valueinitial_blue_valueinitial_blue_valueinitial_blue_valueinitial_blue_valueinitial_b%d\n", initial_blue_value);
if ((j < STEPS) && (time_flag_gradually == 0))
{
u8 red_increment = (target_red_value - initial_red_value) * j / STEPS;
u8 green_increment = (target_green_value - initial_green_value) * j / STEPS;
u8 blue_increment = (target_blue_value - initial_blue_value) * j / STEPS;
u8 current_red_value = initial_red_value + red_increment;
u8 current_green_value = initial_green_value + green_increment;
u8 current_blue_value = initial_blue_value + blue_increment;
handleColorChange(current_red_value, current_green_value, current_blue_value);
printf("红色值当前增量%d\n", red_increment);
printf("绿色值当前增量%d\n", green_increment);
printf("蓝色值当前增量%d\n", blue_increment);
time_flag_gradually = 1;
printf("jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj===================%d\n", j);
j++;
}
if (j >= STEPS)
{
j = 0;
i = global_Bluetooth_protocol_header_text_length_RGB_change_gradually;
}
}
}
u32 timeout_msec_gradually = 4; // 设置定时时间为10毫秒
/*渐变定时器*/
void timeout_callback_gradually(void *priv)
{
// 每16ms
static u8 i = 4;
printf("回调函数渐变%d\n", time_flag_gradually);
i = i + 4;
if (i == 16)
{
time_flag_gradually = 0;
i = 0;
}
handleColor_arrayChange_gradually(global_bt_receive_buffer, global_length);
}
颜色渐变和颜色跳变的实现思路大致一样,不过不一样的是颜色渐变需要对两个渐变颜色之间的RGB值进行一个步长值的计算。要不就会造成颜色变化起来不像渐变的效果。并且如果想要达到循环渐变的效果,颜色跳变的只需要将颜色的下标值重置为初始值。但是颜色渐变的采用相同的方法进行重置的话,会导致出现从最后一个颜色跳变到第一个颜色。我采用的方法是渐变到最后一个颜色后,手动再把颜色由最后一个颜色渐变到第一个颜色,再把下标变回去。
3.8 主要数据处理函数
switch (buffer[0])
{
case 1:
if (buffer[1] == 1)
{
handleSwitchLight(buffer[2]);
}
break;
case 4:
if (buffer[1] == 1) // 调色盘控制颜色
{
usr_timer_del(timer_id_color_change_gradually);
timer_id_color_change_gradually = 0;
usr_timer_del(timer_id_color_change_suddenly);
timer_id_color_change_suddenly = 0;
handleColorChange(buffer[3], buffer[4], buffer[5]);
}
if (buffer[1] == 2) // 颜色跳变
{
}
else if (buffer[1] == 3) // 单亮度控制
{
setLedBrightness(buffer[2]);
}
else if (buffer[1] == 4) // 八段改变亮度
{
ModehandleBrightnessChange(buffer[2]);
}
break;
case 6:
if (buffer[1] == 4)
{
handleColor_brightnessChange(buffer[2], buffer[3], buffer[4], buffer[5]);
}
break;
case 56:
if (buffer[4] == 10)
{
usr_timer_del(timer_id_color_change_gradually);
timer_id_color_change_gradually = 0;
if (timer_id_color_change_suddenly == 0)
{
timer_id_color_change_suddenly = usr_timer_add(private_data, &timeout_callback, timeout_msec, priority);
}
usr_timer_dump();
}
else if (buffer[4] == 2)
{
usr_timer_del(timer_id_color_change_suddenly);
timer_id_color_change_suddenly = 0;
if (timer_id_color_change_gradually == 0)
{
// 添加超时定时器
app_task_put_key_msg(KEY_TIMER_COLOR_MODE_SWITCH, 0);
timer_id_color_change_gradually = usr_timer_add(private_data, &timeout_callback_gradually, timeout_msec_gradually, priority);
}
usr_timer_dump();
}
break;
default:
// 其他情况下需要执行的操作
break;
}
这里主要就是利用switch case语句来进行对蓝牙数据接收缓冲里面的数据进行逐字节的判定。根据接收到的不同字节来执行不同的语句,这里要注意不同的操作之间记得删除其他状态创建的定时器,否则定时器会存在整个程序周期,到定时时间执行可能会干扰其他语句。
4.0 源代码
链接:https://pan.baidu.com/s/13AHNHbkAzTNP-u8rMu_pqQ?pwd=jk16
提取码:jk16