1、任务目标
实现可以接收到APP传输过来的数据,可以通过传输的数据前几个字节识别到所需要控制的模式,然后提取数据的后几个字节来分别对RGB灯进行不同的的PWM波控制,从而实现跳变和渐变的效果。
2.跳变(分布调试记录)
2.1 实现RGB灯循环跳变
void handleColor_arrayChange_suddenly(u8 *bt_receive_buffer, u32 length, int *color_mode_record, int color1)
{
int i = 8;
printf("通过数组控制灯颜色状态\n");
for (int i = 8; i < (length - 2); i = i + 3)
{
handleColorChange(bt_receive_buffer[i], bt_receive_buffer[i + 1], bt_receive_buffer[i + 2]);
printf("for循环里lllllllllllllllllll\n");
delay_2ms(200);
}
printf("正在通过数组快捷控制灯颜色和亮度handleColor_arrayChange\n");
}
该函数的作用:对需要执行跳变模式时,它会遍历接收到的数组bt_receive_buffer,从第九个字节开始对数据进行处理,并以每次3个字节(byte)的方式调用handleColorChange函数来改变灯的颜色态,也就是按照RGB的顺序赋值。在每次改变颜色之后,它还调用了delay_2ms函数来进行延时操作。
接收到的数据
思路1-----现象1-----原因1-----解决思路1------解决代码1
思路1:首先在while(1)里调用这个函数,先达到可以循环控制RGB灯跳变。再再改为类似while(flag)的形式,来实现退出该循环的效果。
现象1:在while(1)死循环里,LED灯在循环跳遍几轮后程序崩溃,并且通过delay_2ms()这个延时函数观察发现程序崩溃并不出现在运行第几遍,更倾向于固定时间。
原因1:忽略了该程序移植了RTOS操作系统,在某一个比较短的时刻会进行喂狗操作,但是由于该延时为死延时,也被称为堵塞延时。无法及时进行喂狗,所以会对程序进行重启
解决思路1:调用一个定时器,在对应的回调函数timeout_callback中,每10ms检查一下是否满足执行handleColor_arrayChange_suddenly 函数的条件。通过静态局部变量 i 追踪时间,当i达到1000时,因为定时器设置值为10,每计数一次加10,等到1000也刚好是1000ms。此时会对标志位置1,然后就可以执行handleColor_arrayChange_suddenly 函数中的for循环一次。当for循环结束以后会对标志位置0,读取数组的指针会往后移动三个字节同时,回调函数中的i会被重置为0,以便下一次1000ms延时。
其实简单来说,就是每10ms扫描一下,是否满足执行handleColor_arrayChange_suddenly 函数,每1000ms改变标志位。使得满足执行handleColor_arrayChange_suddenly 函数的条件齐全。
解决代码1:
void handleColor_arrayChange_suddenly(u8 *bt_receive_buffer, u32 length, int *color_mode_record, int color1)
{
static int i = 8;
printf("通过数组控制灯颜色状态\n");
for (; (i < (length - 2)) && (time_flag == 1); i = i + 3)
{
handleColorChange(bt_receive_buffer[i], bt_receive_buffer[i + 1], bt_receive_buffer[i + 2]);
printf("for循环里lllllllllllllllllll\n");
time_flag = 0;
// delay_2ms(200);
}
if (i > (length - 2))
{
i = 8;
}
printf("正在通过数组快捷控制灯颜色和亮度handleColor_arrayChange\n");
}
void timeout_callback(void *priv)
{
static u16 i = 0;
printf("回调函数\n");
i = i + 10;
if (i == 1000)
{
printf("ifififiifiifififiififififi\n");
time_flag = 1;
i = 0;
}
handleColor_arrayChange_suddenly(bt_receive_buffer, length,record, color1);
}
现象2-----原因2-----解决思路2-----解决代码2
现象2:灯快速闪烁熄灭
原因2: handleColor_arrayChange_suddenly(bt_receive_buffer, length,record, color1);这里调用函数时传入的参数为局部变量。需要传入实际的参数。
解决思路2:在执行前先传入一次实参,然后利用全局变量保存下来,方便回调函数中使用。
解决代码2:
// 定义全局指针变量
u8 *global_bt_receive_buffer;
int global_length;
int *global_color_mode_record;
int global_color1;
volatile u8 time_flag = 1;
u16 timer_id = 123;
void *private_data = NULL; // 设置私有参数为NULL
u32 timeout_msec = 10; // 设置定时时间为10毫秒
u8 priority = 1; // 设置优先级为1
void handleColor_arrayChange_suddenly(u8 *bt_receive_buffer, u32 length, int *color_mode_record, int color1)
{
static int i = 8;
printf("通过数组控制灯颜色状态\n");
for (; (i < (length - 2)) && (time_flag == 1); i = i + 3)
{
handleColorChange(bt_receive_buffer[i], bt_receive_buffer[i + 1], bt_receive_buffer[i + 2]);
printf("for循环里lllllllllllllllllll\n");
time_flag = 0;
// delay_2ms(200);
}
if (i > (length - 2))
{
i = 8;
}
printf("正在通过数组快捷控制灯颜色和亮度handleColor_arrayChange\n");
global_bt_receive_buffer = bt_receive_buffer;
global_length = length;
global_color_mode_record;
global_color1 = color1;
}
void timeout_callback(void *priv)
{
static u16 i = 0;
printf("回调函数\n");
i = i + 10;
if (i == 1000)
{
printf("ifififiifiifififiififififi\n");
time_flag = 1;
i = 0;
}
handleColor_arrayChange_suddenly(global_bt_receive_buffer, global_length, global_color_mode_record, global_color1);
}
case 56:
if (buffer[4] == 10)
{
handleColor_arrayChange_suddenly(buffer, buffer_size, color_mode_record, 0); // 五色跳变
u16 timer_id = usr_timer_add(private_data, &timeout_callback, timeout_msec, priority);
printf("%d\n", timer_id);
}
现象3-----原因3-----解决思路3-----解决代码3
现象3:可以实现循环亮灭。但是在多次发送跳变指令后灯闪烁速度加快。并且在发送其他指令时依旧没有结束跳变。
原因3:在执行其他模式时并没有对上一个模式所使用的定时器进行删除操作,并且在重复执行自身时也没有对上次使用的定时器进行删除操作。
解决思路3:设立一个类似互斥量的标志位,但是这个是实时操作系统,想使用互斥量来实现,只有获得互斥量的才可以进行操作。不过在尝试了一下,还是决定先用标志位实现,毕竟不太熟悉。就在每个case的前面增加删除其他定时器的代码,并且将其他定时器可以被创建的标志位置零,以便下次直接使用。增加对应的渐变代码。
解决代码3:
// 定义全局指针变量
u8 *global_bt_receive_buffer_gradually;
u32 global_length_gradually;
volatile u8 time_flag_gradually = 1;
/* 通过数组控制灯颜色和亮度,现象为颜色渐变*/
void handleColor_arrayChange_gradually(u8 *bt_receive_buffer, u32 length)
{
// 获取初始亮度
u8 initial_red_value = bt_receive_buffer[0];
u8 initial_green_value = bt_receive_buffer[1];
u8 initial_blue_value = bt_receive_buffer[2];
printf("通过数组控制灯颜色状态\n");
static int i = 5;
static int j = 0;
u8 STEPS = 30;
for (; (i < (length - 5))&&(time_flag_gradually == 1); i = i + 3)
{
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];
// 计算每个颜色通道的增量
int red_increment = (target_red_value - initial_red_value) / STEPS;
int green_increment = (target_green_value - initial_green_value) / STEPS;
int blue_increment = (target_blue_value - initial_blue_value) / STEPS;
// 逐步更新颜色值,使其渐变到目标值
for (; (j < STEPS) && (time_flag_gradually == 1); j++)
{
printf("jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n");
u8 current_red_value = initial_red_value + (red_increment * j);
u8 current_green_value = initial_green_value + (green_increment * j);
u8 current_blue_value = initial_blue_value + (blue_increment * j);
printf("回调函数渐变hddddddddddddddddddddddddddddddddddddddddddddd%d\n", time_flag_gradually);
handleColorChange(current_red_value, current_green_value, current_blue_value);
time_flag_gradually = 0;
// delay_2ms(24); // 延时一段时间,控制灯的变化速度
}
if (j >= STEPS)
{
printf("j >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPSj >= STEPS\n");
j = 0;
}
printf("第一组 RGB 值已经渐变到第二组一样\n");
// 更新初始亮度为目标亮度,以便下一组渐变
initial_red_value = target_red_value;
initial_green_value = target_green_value;
initial_blue_value = target_blue_value;
}
if (i > length - 5)
{
printf("i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5i>length - 5\n");
i = 5;
}
printf("jssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\n");
global_bt_receive_buffer_gradually = bt_receive_buffer;
global_length_gradually = length;
}
u32 timeout_msec_gradually = 1000; // 设置定时时间为10毫秒
void timeout_callback_gradually(void *priv)
{
// 每10ms
printf("回调函数渐变\n");
printf("回调函数渐变%d\n", time_flag_gradually);
printf("time_flag_gradually != 0time_flag_gradually != 0time_flag_gradually != 0time_flag_gradually != 0time_flag_gradually != 0\n");
time_flag_gradually = 1;
handleColor_arrayChange_gradually(global_bt_receive_buffer_gradually, global_length_gradually);
}
现象4---------原因4------------解决思路4-------------------解决代码4ga
现象4:该模式本来是实现RGB灯渐变,但是并未出现未更改时RGB灯渐变的效果。而是在定时器定时1s时改变一遍颜色,颜色并未一点一点地往目标颜色靠近,而是一下子到了另外比较大的一个颜色。类似颜色跳变
原因4:推测是每次调用该函数时,由于函数一开始会对某些变量进行初始化
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];
但是在该变化之前理应执行小的for循环里面所有可能值。
解决思路:把所有涉及到的数字都打印出来看
3.今日疑惑
改了很多版,都有其奇奇怪怪的问题,并不能更好地实现,现在贴出代码来进行结构梳理
原代码思路:
记录六个字节,前三个为起始字节,后三个为目标字节。根据插值还有步长可以算出每个通道每次增加的值。每加一次进行适当的延时,到达目标值后切换,记录当前值为起始值,目标值为下三个不超过范围的的字节。循环即可达成颜色渐变。
现的代码思路:
通过设定的定时器产生一个标志位。小的for循环等待标志位的到来,然后开始运行一遍,然后标志位改变退出循环,等待下一个标志位的到来。但是仔细推敲一下问题很多,因为外面还有一个大的for循环。在再次进来的时候会重新初始化程序。
尝试使用全局变量保存参数,但是尝试了代码太臃肿,也不好操作。。。。试了挺多改法没成功,暂时没什么思路了。