杰里6969系列控制RGB彩灯模式

news2024/11/24 17:22:27

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循环。在再次进来的时候会重新初始化程序。

尝试使用全局变量保存参数,但是尝试了代码太臃肿,也不好操作。。。。试了挺多改法没成功,暂时没什么思路了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建多层级行索引,创建多层级行索引的DataFrameMultiIndex.from_product()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 创建多层级行索引, 创建多层级行索引的DataFrame MultiIndex.from_product() [太阳]选择题 使用pd.MultiIndex.from_product()&#xff0c;下列输出正确的是&#xff1a; import pandas as pd…

一键批量删除文件名中的空格,高效整理您的文件

你是否曾经因为文件名中多余的空格而烦恼&#xff1f;这些空格不仅影响了文件的美观&#xff0c;还可能导致一些不必要的错误。现在&#xff0c;我们向您介绍一款全新的工具&#xff0c;它可以帮助您一键批量删除文件名中的空格&#xff0c;让您的文件整理更加轻松、高效&#…

一款功能强大的web目录扫描器专业版

dirpro 简介 dirpro 是一款由 python 编写的目录扫描器&#xff0c;操作简单&#xff0c;功能强大&#xff0c;高度自动化。 自动根据返回状态码和返回长度&#xff0c;对扫描结果进行二次整理和判断&#xff0c;准确性非常高。 已实现功能 可自定义扫描线程 导入url文件进…

劲松中西医医院专家谭巍医生解读:生殖衣原体阳性是什么意思

生殖衣原体阳性是指生殖系统出现了衣原体感染。衣原体是我们身体中常见的菌群&#xff0c;生殖系统常见的衣原体有&#xff1a;沙眼衣原体&#xff0c;当然还包括一些支原体&#xff0c;如&#xff1a;人型支原体、解脲支原体等&#xff0c;都可引起生殖系统出现一系列的感染症…

华为L410上制作内网镜像模板02

原文链接&#xff1a;华为L410上制作离线安装软件模板02 hello&#xff0c;大家好啊&#xff0c;今天给大家带来第二篇在内网搭建Apache服务器&#xff0c;用于安装完内网操作系统后&#xff0c;在第一次开机时候&#xff0c;为系统安装软件的文章&#xff0c;今天给大家介绍在…

Linux常见指令:从基础到理论

前言 目录 前言 1. find指令 拓展 2. grep指令 拓展 sort指令 uniq指令 wc指令 3. zip/unzip指令 4. tar指令 5. uname指令 拓展 6. Linux常用热键 7. 关机 8. rz指令 拓展 scp指令 9. shell命令以及运行原理 Linux常见指令是使用Linux系统时必不可少的一部分。通过掌握…

【QML】Qt和QML获取操作系统类型

1. Qt获取系统类型 //方法 QSysInfo::productType()//举例&#xff1a; if(QSysInfo::productType() "windows") {qDebug() << "windows system"; }官方说明&#xff1a; [static] QString QSysInfo::productType() Returns the product name of …

【数据结构】树与二叉树(七):二叉树的遍历

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语5.1.4 树的表示 5.2 二叉树5.2.1 二叉树1. 定义2. 特点3. 性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉…

MySQL -- 事务管理

MySQL – 事务管理 文章目录 MySQL -- 事务管理一、理解事务1.如果CURD不加控制&#xff0c;会有什么问题2.事务的概念 二、MySQL中的事务1.事务的版本支持2.事务提交方式3.事务常见操作方式3.1.事务的开始与回滚3.2.证明未commit&#xff0c;客户端崩溃&#xff0c;MySQL自动会…

Vue脚手架学习笔记

视频 Vue脚手架学习笔记 1. 脚手架设置相关内容1.1 各文件的作用1.2 关闭语法检查 2. 组件的使用2.1 单文件组件的使用&#xff08;组件使用的三个步骤&#xff09;2.2 prop配置项&#xff1a;父向子传数据2.2.1 数组方式2.2.2 类型限制2.2.3 默认值、必要性 2.3 ref &#xf…

C# OpenCvSharp 玉米粒计数

效果 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_Demo {public partial class frmMain : Form{public frmMain(){InitializeComponent();}string fileFilter "*.*|*.bmp;…

2023年CCF非专业级别软件能力认证第二轮 (CSP-S)提高级C++语言试题

2023年CCF非专业级别软件能力认证第二轮 &#xff08;CSP-S&#xff09;提高级C语言试题 编程题第 1 题 问答题 密码锁&#xff08;lock&#xff09; 题目描述 小Y有一把五个拨圈的密码锁。如图所示&#xff0c;每个拨圈上是从0到9的数字。每个拨圈都是从0到9的循环&#xf…

【算法 | 模拟No.4】AcWing 756. 蛇形矩阵 AcWing 40. 顺时针打印矩阵

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

汉诺塔 --- 递归回溯算法练习一

目录 1. 什么叫汉诺塔 2. 分析算法原理 2.1. 当盘子的数量为1 2.2. 当盘子的数量为2 2.3. 当盘子的数量为3时 3. 编写代码 3.1. 挖掘重复子问题 3.2. 只关心某一个子问题如何处理 3.3. 递归的结束条件 3.4. 代码的编写 4. 递归展开图分析 1. 什么叫汉诺塔 力扣上的原…

Go并发编程(上)

目录 一、go语言当中的协程 二、MPG模型介绍 三、Goroutine 的使用 3.1 协程的开启 3.2 优雅地等待子协程结束 四、捕获子协程的panic 五、管道Channel 5.1、认识管道 5.2、Channel的遍历和关闭 5.3 、用管道实现生产者消费者模型 5.4、Channel一些使用细节和注意事…

揭秘!2024年热门的图标设计工具

在这个瞬息万变的世界里&#xff0c;设计师们对创新和实用的工具的渴望日益热切。我们需要时刻紧跟潮流&#xff0c;发掘和尝试最新&#xff0c;最有价值的图标设计工具&#xff0c;才能在剧烈的市场竞争中引人注目。以下是我们细心挑选的2024年图标设计工具的热门推荐&#xf…

CentOS 7 双网卡绑定热备 —— 筑梦之路

为什么需要&#xff1f; 1. 增强网络的可靠性 2. 保障服务的可持续性 3. 降低网卡故障带来的不良影响 有哪些模式&#xff1f; 模式0&#xff1a;轮询策略&#xff08;round robin&#xff09;&#xff0c;mode0&#xff0c;优点&#xff1a;流量提高一倍缺点&#xff1a;需要接…

《QT从基础到进阶·十五》用鼠标绘制矩形(QGraphicsView、QPainter、QGraphicsRectItem)

以下是鼠标绘制矩形最全的一种用法&#xff0c;完整源码将会放在最后面。 QT版本&#xff1a;5.15.2 VS版本&#xff1a;2019 1、在界面加载一张图片 界面的搭建选用QGraphicsView&#xff0c;自定义类GraphicsView继承QGraphicsView&#xff0c;在主程序中点击按钮打开 图片&…

opencv4笔记

图像二值化 全局法Threshold 大津法 大津法OSTU阈值类型——适用于双峰直方图 OTSU算法也称最大类间差法&#xff0c;由大津于1979年提出&#xff0c;被认为是图像分割中阈值选取的最佳算法&#xff0c;计算简单&#xff0c;不受图像亮度和对比度的影响&#xff0c;它是按图…

浅谈泛在电力物联网在智能配电系统应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;在社会经济和科学技术不断发展中&#xff0c;配电网实现了角色转变&#xff0c;传统的单向供电服务形式已经被双向能流服务形式取代&#xff0c;社会多样化的用电需求也得以有效满足。随着物联网技术的发展&am…