基于AC6969的蓝牙控制RGB彩灯(开源,代码文末)

目录

1.任务前置准备

1.1 实现初步思路与流程框图

1.2 RGB彩灯原理

1.3 主控芯片引脚作用图

1.4 驱动板原理图

2. 任务实现流程

外设:

程序:

逐步调试思路

3. 程序实现代码

3.0 蓝牙发送数据格式

3.1 点亮一盏LED

定义函数

使用实例

3.2 控制彩灯的亮度

蓝牙协议形式

定义函数

使用实例

3.3 控制彩灯的颜色

蓝牙协议形式

定义函数

使用实例

3.4 控制灯的开关,并且记忆灯原来的亮度和颜色

蓝牙协议形式

定义函数

使用实例

3.5通过外部音源控制灯颜色的亮度

蓝牙协议形式

函数定义

使用实例

3.6 蓝牙控制颜色跳变的顺序

蓝牙协议形式

函数定义

3.7 蓝牙控制颜色渐变的顺序

蓝牙协议形式

函数定义

3.8 主要数据处理函数

4.0 源代码


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

猜你喜欢

转载自blog.csdn.net/qq_51519091/article/details/134171753