基于stm32作品设计:多功能氛围灯、手机APP无线控制ws2812,MCU无线升级程序

作品哔哩哔哩视频:https://www.bilibili.com/video/BV1Yb4y1a7AQ#reply5536921990
资料链接:
蓝牙彩灯v1.01资料链接:
CSDN:
https://download.csdn.net/download/mbs520/25149435
百度网盘:
https://pan.baidu.com/s/14Vout7Q2P6JBDZCCd8Gm6w
提取码:b7it

蓝牙彩灯v1.03资料链接:
https://download.csdn.net/download/mbs520/25150035
取走记得点赞~
有问题可以在评论区发表或者私信
在这里插入图片描述

实物链接:https://m.tb.cn/h.56p8Lt8?tk=jLixWYHUq6z CZ0001

一、作品背景

在智能的2021年代,年轻的小伙伴都患上了懒惰的症状,我也一样。
有一个难以入眠的夜晚,我打开了王者荣耀,我习惯了玩手机都要开着灯打,这样可以减少对眼睛的损伤,终于,赢了好几把,时间已经到了凌晨2点半,我也开始有了睡意,当我放下手机,准备闭眼入睡时,发现灯光格外耀眼,心烦意乱,实在不想按下那下床走好几步才能触碰到的开关,但是房间的设计就是这样,无法改变。无奈的我还是挣扎地下床按下了开关,这才安心入睡。
作为学电子专业的我并不妥协,我一定要设计一个不下床就可以关掉的灯。

二、功能设计与实现过程

(一)功能设计
1、可以用按键控制灯的亮灭、亮度以及切换颜色
2、可以用按键控制灯的6种以上显示样式
4、设计一个外壳,让它更加美观
5、设计一个手机APP,实现按键的所有功能以及能够调节灯的任意颜色
6、设计一个手机APP升级单片机程序功能,能够把单片机程序保存到某个版本的手机APP中,手机APP点击升级,就可以完成对单片机程序的升级。
(二)实现的过程
1、设计一个按键与单片机连接,编写多功能按键(单击、双击、长按)来控制灯的亮灭、亮度以及切换颜色以及6种以上显示样式

2、用CAD绘制一个与PCB大小合适的外壳,交给淘宝定制

3、用QT编写一个安卓APP,利用蓝牙模块与单片机进行通信,完成控制与升级的功能

三、实现基础功能

(一)、首先是要选材

1、LED选择:WS2812
既然是想做任意颜色的灯,那么毫无疑问选择最普遍的WS2812,24位全彩RGB彩灯,可以发出2^24=16777215种颜色。
在这里插入图片描述

2、单片机选择:STM32G0
在当今MCU那么稀贵的情况下,当然是要为自己的腰包考虑,WS2812的驱动时钟大概需要800KHZ,速度要求很高,首先选择stm32,看了一下价格,选择了和蔼可亲的stm32g030c8t6,6元还包邮
在这里插入图片描述
3、通信模块选择:蓝牙模块JDY-31
要手机控制灯,首先想到用蓝牙模块,价格考虑,选择全网最便宜的蓝牙模块JDY-31,比起HC-05,它更加小巧,就是连接速度不是很快
在这里插入图片描述

有了这3个主要材料,我们就可以开始设计一下原理图

(二)、原理图设计

1、单片机需要3.3V供电,首先设计一个电源部分,先用usb进行供电5V给ws2812,再用降压芯片降压到3.3V供给MCU,
在这里插入图片描述

2、设计一个单片机最小系统,以及预留一个下载接口,方便使用ST-LINK进行下载程序
在这里插入图片描述
3、然后要连接一个蓝牙和一个按键作为控制,再预留一个LED作为指示灯
在这里插入图片描述
4、RGB灯的电路设计,这里两组LED,用两个IO口控制,防止LED过多导致信号失真
在这里插入图片描述
这样一张原理图就设计好啦

(二)、第一版本PCB设计

1、根据原理图给定相应的封装导入PCB,再进行布局与布线,设计好一块给淘宝客服能够打印出来的PCB图纸
2D:
在这里插入图片描述

3D:
在这里插入图片描述
然后交给淘宝,这里推荐嘉立创,便宜,质量也高。
这是打印出来的第一板PCB:
在这里插入图片描述

(三)、焊接PCB板

1、打印出PCB之后,当然是要把元器件焊接到PCB板上,第一块板焊接的时候先不用一次性全部焊接上去,先焊接电源部分,看看电源芯片是否能够正常工作,比如我画的这块板子USB母座封装与原理图不对应,导致正负极直接反向,就很容易导致元器件损坏,检测完电压正常之后,再焊接其他元器件

在这里插入图片描述

(四)编写单片机程序

单片机程序包含了很多知识
1、轻量级多任务系统
2、蓝牙数据自定义控制协议、蓝牙无线升级单片机
3、多种控制方式按键+蓝牙
4、多功能按键,单击、双击、长按
5、ws2812串联控制
6、呼吸灯算法
7、颜色渐变算法

/****************************************
* 函数名称: DIS_TASK()
* 输入参数: 无
* 输出参数: 无
* 功    能: 显示任务
*
*****************************************/

void DIS_TASK(void)
{
	static u8 r=0,g=0,b=0,a=0,dir=0;
	static int i,cnt=0;
	static int color_rgb;
    SCHTaskBegin(); //开始固定格式一定要的
    while (1)
    {
		if(SysState.Dis_flag == 1)//可以更新显示
		{
					/***********************静态*******************************/
					if(SysState.Dismode == DisMode_Static)//静态
					{
						SysState.Dis_flag = 0;
						RGB_Refresh(SysState.StaticRgb,LED_NUM);//显示
						RGB2_Refresh(SysState.StaticRgb,LED_NUM);//显示
					}
					
					/***********************呼吸*******************************/
					else if(SysState.Dismode == DisMode_Breathe)//呼吸
					{
						SysState.Dedlay_Time=20;
						if(dir==0)
						{
							a += (1+a*10/0xff);
							if(a > 0xf0)dir = 1;
						}else if(dir)
						{
							a -= (1+a*10/0xff);
							if(a <= 4)dir = 0;
						}
						
						r = ((SysState.StaticRgb>>16)%0x100)*a/0xff;
						g = ((SysState.StaticRgb>>8)%0x100)*a/0xff;
						b = ((SysState.StaticRgb>>0)%0x100)*a/0xff;
						color_rgb = (r<<16) + (g<<8) + b;
						printf("%d %d %d %d\r\n",r,g,b,a);
						RGB_Refresh(color_rgb,LED_NUM);//显示
						RGB2_Refresh(color_rgb,LED_NUM);//显示
						SCHCurTaskDly(SysState.Dedlay_Time);
					}
					
					/***********************闪烁*******************************/
					else if(SysState.Dismode ==DisMode_Twinkle)//闪烁
					{
						SysState.Dedlay_Time=200;//*SysState.Dedlay_Ratio/0x0f;;
						RGB_Refresh(SysState.StaticRgb,LED_NUM);
						RGB2_Refresh(SysState.StaticRgb,LED_NUM);
						SCHCurTaskDly(SysState.Dedlay_Time);
						RGB_Refresh(0,LED_NUM);
						RGB2_Refresh(0,LED_NUM);
						SCHCurTaskDly(SysState.Dedlay_Time);
					}
					
					/***********************渐变*******************************/
					else if(SysState.Dismode ==DisMode_GraChange)//渐变
					{
						extern u8 GraChange_flag;
						SysState.Dedlay_Time=100;//*SysState.Dedlay_Ratio/0x0f;
						RgbAlg(&SysState.StaticRgb,&GraChange_flag);//渐变算法
						RGB_Refresh(SysState.StaticRgb,LED_NUM);//显示
						RGB2_Refresh(SysState.StaticRgb,LED_NUM);//显示
						SCHCurTaskDly(SysState.Dedlay_Time);
					}
					
					/***********************蹦迪*******************************/
					else if(SysState.Dismode == DisMode_DiscoDance)//蹦迪
					{
						SysState.Dedlay_Time=20;//*SysState.Dedlay_Ratio/0x0f;
						RGB_Refresh(Static_DisColor[cnt],LED_NUM);
						RGB2_Refresh(Static_DisColor[cnt],LED_NUM);
						SCHCurTaskDly(SysState.Dedlay_Time);
						RGB_Refresh(0,LED_NUM);
						RGB2_Refresh(0,LED_NUM);
						SCHCurTaskDly(SysState.Dedlay_Time*50);
					}
					
					/***********************流水*******************************/
					else if(SysState.Dismode == DisMode_RunWater)//流水
					{
						static int i=0,flag=0;
						SysState.Dedlay_Time=100;
						i++;
						if(i == LED_NUM)
						{
							i=0;flag=!flag;
						}
						if(flag){		//设置颜色		
							RGB_Refresh(SysState.StaticRgb,i+1);
							RGB2_Refresh(SysState.StaticRgb,i+1);
							SysState.Dedlay_Time=50;//*SysState.Dedlay_Ratio/0x0f;
							SCHCurTaskDly(SysState.Dedlay_Time);
						}
						else{		//灭
							RGB_Refresh(0,i+1);
							RGB2_Refresh(0,i+1);
							SysState.Dedlay_Time=50;//*SysState.Dedlay_Ratio/0x0f;
							SCHCurTaskDly(SysState.Dedlay_Time);
						}
						
					}
					
					/***********************用户*******************************/
					else if(SysState.Dismode ==DisMode_User1)  //用户
					{
						SysState.Dedlay_Time=1000;
						RGB_Refresh(SysState.StaticRgb,1);
						RGB2_Refresh(0,1);
						SCHCurTaskDly(SysState.Dedlay_Time);
						RGB2_Refresh(SysState.StaticRgb,1);
						RGB_Refresh(0,1);
						SCHCurTaskDly(SysState.Dedlay_Time);
					}
		}
		SCHCurTaskDly(10);
    }
    SCHTaskEnd();  //结束固定格式一定要的
}

(五)下载程序验证

下载程序后测试ws2812是否正常工作

四、外壳设计

(一)CAD图纸设计

感觉没有一个外壳会很难看,添加一个外壳,让世界变得美丽
在这里插入图片描述在这里插入图片描述

这中间的洞尺寸有误:5乘7改7乘7

在这里插入图片描述

(二)磨砂亚克力板

淘宝搜磨砂亚克力板定制,发送CAD图纸给师傅,就可以给你做了
这是做好的亚克力板,是按照PCB板尺寸量身定做的
在这里插入图片描述

五、重新设计PCB

重新布局设计出来第3版本成品板:PCBV1.3
在这里插入图片描述
这是打样后焊接好的样子:
在这里插入图片描述

六、QT安卓APP设计

(一)界面设计

在这里插入图片描述

(二)QT程序设计

展示部分代码:


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    this->Start_Init();
    this->File_Init();
    this->BuleTooth_Init();
    this->Label_Init();
    this->PushButton_Init();
    this->ColorSlider_Init();
    this->setFocus();
}

MainWindow::~MainWindow()
{
    bin_save(FileInfo);
    delete ui;
}

//起始代码
void MainWindow::Start_Init()
{
    //设置背景图片
    this->setStyleSheet("QMainWindow{border-image: url(:/pic/btmenuv2.jpg);}");
    //获取屏幕大小
    QScreen *screen = QApplication::screens().at(0);
    src_w = screen->size().width();
    src_h = screen->size().height();
    if(src_w <= 0  || src_h <= 0)
    {
        src_h = 2267;src_w = 1080;
        this->setGeometry(0,0,src_w,src_h);//1080   2267
        qDebug() << "src get err ======== "<< src_w <<src_h << endl;
    }
    else
    {
        this->setGeometry(0,0,src_w,src_h);//1080   2267
        qDebug() << "src get ok ======== "  << src_w <<src_h << endl;
    }

}

//蓝牙初始化
void MainWindow::BuleTooth_Init(void)
{
    //蓝牙连接初始化代码
    timer_conflag = new QTimer;
    ptimer = new QTimer;
    //QBluetoothDeviceDiscoveryAgent 这个是指扫描周围蓝牙设备!
    discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
    //QBluetoothLocalDevice 是指配置获取设备的蓝牙状态信息等!
    localDevice = new QBluetoothLocalDevice();
    //QBluetoothSocket指进行链接蓝牙设备,读写信息!
    socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);

    //多窗口初始化
    btcwindow = new BTMainWindow(this);
    btcwindow->hide();
    aboutwindow = new AboutMainWindow(this);
    aboutwindow->hide();

    connect(socket,
           SIGNAL(readyRead()),
           this,
           SLOT(readBluetoothDataEvent())
           );
    connect(socket,
           SIGNAL(connected()),
           this,
           SLOT(bluetoothConnectedEvent())
           );
    connect(socket,
           SIGNAL(disconnected()),
           this,
           SLOT(bluetoothDisconnectedEvent())
           );

    localDevice->powerOn();//打开蓝牙
    discoveryAgent->start();//开始扫描
}




//颜色条初始化
void MainWindow::ColorSlider_Init(void)
{
    QColor color;
    color.setRgb(0x00,0x00,0x00);
    colorslider_R = new ColorSlider(this);
    colorslider_G = new ColorSlider(this);
    colorslider_B = new ColorSlider(this);
    colorslider_A = new ColorSlider(this);

    colorslider_R->init(ColorSlider::RGB,ColorSlider::RED,color,0x00,0xFF);qDebug() << color << endl;
    colorslider_G->init(ColorSlider::RGB,ColorSlider::GREEN,color,0x00,0xff);qDebug() << color << endl;
    colorslider_B->init(ColorSlider::RGB,ColorSlider::BLUE,color,0x00,0xff);qDebug() << color << endl;
    colorslider_A->init(ColorSlider::RGB,ColorSlider::ALPHA,color,0x00,0xff);qDebug() << color << endl;

    colorslider_R->setGeometry(100,200,880,60);
    colorslider_G->setGeometry(100,400,880,60);
    colorslider_B->setGeometry(100,600,880,60);
    colorslider_A->setGeometry(100,800,880,60);
}
//按钮初始化
void MainWindow::PushButton_Init(void)
{
    //刷新定时器
    static QColor last_Color;
    time1= new QTimer(this);
    time1->start(1000);
    connect(time1,&QTimer::timeout,[=](){

       time1->start(100);
       if(Connect_Flag == 1)//连接指示
       {
           Connect_Flag = 0;
           btcwindow->hide();
           this->show();
           QMessageBox::information(this,tr("提示"),tr("蓝牙连接成功!"));

           QByteArray arrayData;    //发送空指令
           QString s = QString("NONE\r\n");
           qDebug() << s << endl;
           arrayData = s.toUtf8();
           socket->write(arrayData);
           s.clear();
           arrayData.clear();
       }
       if(last_Color != Color_sum)//发送指令
       {
           update();//更新
           unsigned int color_d =   ((Color_sum.alpha()/16)<<24)+(Color_sum.red()<<16) + (Color_sum.green()<<8)
                         + (Color_sum.blue()<<0) ;
           QByteArray arrayData;
           QString s = QString("COLOR:%1\r\n").arg(color_d);
           qDebug() << s << endl;
           arrayData = s.toUtf8();
           socket->write(arrayData);
           s.clear();
           arrayData.clear();
       }
       last_Color = Color_sum;

    });
    //色块按钮
    // QPushButton *phbutton[10];
    for(int i=0; i<10; i++)
    {
        int r,g,b;
        r = FileInfo->color_tab[i]>>16;
        g = (FileInfo->color_tab[i]>>8)%256;
        b = FileInfo->color_tab[i]%256;
        phbutton[i] = new QPushButton(this);
        if(i<5)phbutton[i]->setGeometry(90+i*200*src_w/1080,1600*src_h/2267,100*src_w/1080,100*src_h/2267);
        else if(i>=5)phbutton[i]->setGeometry(90+(i-5)*200*src_w/1080,1800*src_h/2267,100*src_w/1080,100*src_h/2267);
        QString s = QString("background-color: rgb(%1, %2, %3);").arg(r).arg(g).arg(b);
        phbutton[i]->setStyleSheet(s);
        phbutton[i]->setWindowFlags(Qt::WindowStaysOnTopHint);
        connect( phbutton[i],&myPushButton::clicked,[=](){
            int r,g,b;
            if(SaveColorFlag != 0)
            {
                r = Color_sum.red();
                g = Color_sum.green();
                b = Color_sum.blue();
                SaveColorFlag = 0;
                update();
                FileInfo->color_tab[i] = (r<<16)+(g<<8)+b;
                QString s = QString("background-color: rgb(%1, %2, %3);").arg(r).arg(g).arg(b);
                phbutton[i]->setStyleSheet(s);
            }
            else
            {
                r = FileInfo->color_tab[i]>>16;
                g = (FileInfo->color_tab[i]>>8)%256;
                b = FileInfo->color_tab[i]%256;
                Color_sum.setRgb(r,g,b,Color_sum.alpha());
                ColorSlider_paint_Flag = 2;
            }
        });
    }

(三)APP功能设计

1、主界面功能

按钮功能说明
连接按钮进入蓝牙连接界面/双击连接设备
关于按钮进入软件介绍/升级MCU界面
红色滑动条调节红色色彩
绿色滑动条调节绿色色彩
蓝色滑动条调节蓝色色彩
灰白滑动条调节总体亮度
颜色预览球预览当前显示颜色
颜色快捷显示单击可以显示按钮颜色
显示模式显示模式切换
底部信息显示显示接收到的信息/欢迎信息
连接信息显示显示当前连接状态

先点颜色预览球,会出现保存选择框,
再点击颜色选择按钮,即可保存当前调节好的颜色在这里插入图片描述

2、蓝牙连接界面

按钮功能说明
设备连接选择双击连接设备
返回按钮返回主界面

1、连接成功自动返回主界面
2、自动连接功能:打开APP无需动作,自动找寻蓝牙彩灯设备自动连接,无需手动连接
在这里插入图片描述

3、关于界面

按钮功能说明
作者信息显示只读
返回按钮返回主界面
显示版本蓝牙彩灯应答信号 例如1.2版本闪红灯1次,绿灯两次
升级MCU连接好蓝牙,点击升级,可以使单片机软件升到当前版本,软件版本一样切勿反复升级,可能升级失败
升级进度条显示升级进度 单片机升级失败后需要进入升级模式重新升级,否则将无法正常使用。
在这里插入图片描述

4、升级代码提示

显示类型显示内容
升级失败蓝牙彩灯显示红色
升级成功蓝牙彩灯显示绿色
升级过程蓝牙彩灯显示淡蓝色进度

在这里插入图片描述

  • 34
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
基于STM32WS2812带驱动是一种通过STM32控制器来控制WS2812带的方法。WS2812是一种数字可编程RGB LED带。与传统的RGB LED带相比,WS2812具有更高的亮度、更丰富的颜色以及更灵活的控制方式。 在实现基于STM32WS2812带驱动时,首先需要将STM32WS2812带连接起来。通常使用的连接方式是通过单线串行通信协议(比如WS2812协议)连接。这需要将STM32的单个IO口与WS2812带的DIN(数据输入)引脚相连。 然后,需要在STM32上编程实现WS2812带的控制逻辑。首先,需要配置STM32的GPIO引脚为输出模式,并设置输出频率以满足WS2812的通信速率要求。 接下来,在STM32程序中,通过发送一系列特定的数据序列来控制WS2812带的颜色。这些数据序列包含带的控制命令和对应的RGB颜色值。通常,每个WS2812珠需要24位数据来表示RGB颜色。 在程序中,首先通过STM32的GPIO口向WS2812带发送重置信号,然后按照一定的时序和数据格式发送数据,实现对带的亮灭和颜色控制。发送数据时,需要按照一定的协议将数据转换为对应的电平信号,并严格控制信号的时序。 通过不断发送数据,可以实现对WS2812带的各种控制效果,如单色、多色和动态变化等。 综上所述,基于STM32WS2812带驱动是一种利用STM32控制器通过串行通信协议控制WS2812带的方法。通过在STM32上编程实现相应的控制逻辑和数据传输,可以实现对WS2812带的各种颜色和亮度控制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

化作尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值