基于STM32的android蓝牙控制LED灯!!!

前言

使用STM32控制LED灯很简单,这次将通过android应用,连接对应的蓝牙模块,进行数据传输,以此来达到手机控制开发板LED的亮灭,颜色切换以及亮度调节。

一、环境介绍

(1)单片机采用:STM32F103RCT6或者F1其他系列单片机
(2)通信方式:采用蓝牙通信,某宝上常见的HC-05等等
(3)开发软件:keil5
(4)硬件连接功能:蓝牙模块和STM32串口相连接
(5)LED:WS28120B

二、功能说明

程序运行,打开手机APP,连接到蓝牙模块,通过手机端按钮或滑动条改变LED的亮度及颜色

三、硬件设计

STM32与蓝牙模块之间通过串口连接,手机app就使用正常的蓝牙连接功能。LED与STM32的普通IO口相连。具体方式如下图所示:
在这里插入图片描述
LED采用的是WS2812B,如下图所示:
在这里插入图片描述
多个WS2812B采用串联方式,由前一个LED的DOUT和下一个LED的DIN相串。

四、软件设计

4.1 WS28120B驱动

  1. 芯片手册
    简单来说,芯片手册就是最好的资料。这里网上随处可见这个灯的手册,里面大致的内容包括了产片概述、时序图、连接方式、数据传输方式。通过阅读可知道:
    数据协议采用单线归零码的通讯方式,像素点在上电复位后,DIN端接收从MCU传输过来的数据(这里为STM32)。首先送过来的24bit数据被第一个像素点提取后,送到内部的数据锁存器,剩余的通过内部电路整形放大后通过DOUT往下一像素点传输。
  2. 控制程序
/*
num:灯数量
GRB_Data:颜色数据
*/
void PWM_WS2812B_Write_24Bits(uint16_t num,uint32_t GRB_Data)
{
  uint8_t i,j;
  for(j = 0; j < num; j++)
  {
  	for(i = 0; i < DATA_SIZE; i++)
	{
		/*因为数据发送的顺序是GRB,高位先发,所以从高位开始判断,判断后比较值先放入缓存数组*/
		Single_LED_Buffer[i+j*DATA_SIZE] = ((GRB_Data << i) & 0x800000) ? T1H : T0H;
	}
  }
}
/*点亮红灯*/
void PWM_WS2812B_Red(uint16_t num)
{
	PWM_WS2812B_Write_24Bits(num,0x00ff00);
	PWM_WS2812B_Show(num);
}

怎样发送num24+reset位数据呢? 由于WS2812的 0码 和 1码 并不是我们正常的 0 和 1,他是高低电平占不同的占空比,因此需要用PWM来模拟 0码 和 1码。当需要发送 0码 或 1码 时,我们只需要改变定时器的CCRx寄存器,来改变占空比,PWM频率800KHZ。
DMA则是搬运,将事先弄好的 num24+reset位 对应的占空比值传送给 TIMx的CCRx寄存器。这样PWM输出的就是对应的颜色值了。

4.2 串口协议

因为我们最终是要通过手机APP来控制灯的亮灭,通讯方式又是串口,所以我们需要自定义一个协议帧来达到控制效果,这里给出一种方式。初始化蓝牙部分就不再多说,先看协议:

一帧数据包含:帧头,数据,帧尾
数据位:单独控制灯的亮灭至变低八位,00 01或者00 10、00 02或者00 20;
数据位:调节亮度,高八位代码控制的哪种颜色,低八位代表亮度0-255,01 50或者02 50

例如:

帧头数据帧尾
5A A500 01A0
5A A501 50A0

协议很简单,但是够用 就行,接下来看一下代码如何实现,如下代码所示:

void USART2_IRQHandler(void)  
{
	uint16_t res;    
    if(USART_GetITStatus(USART2, USART_IT_RXNE))   
    {
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);		
		if(g_usart_cnt>5)g_usart_cnt=0;		
        res = USART_ReceiveData(USART2);  	
        //while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);        
		g_usart_buf[g_usart_cnt] = res;
		g_usart_cnt++;
		if(res == 0xA0 && g_usart_cnt == 5) /*判断帧尾以及数据长度*/
		{	
			if(g_usart_buf[2] == 0x00)	/*区分是控制亮灭还是调节亮度*/
			{
				switch(g_usart_buf[3])
				{
					case 0x01:usart_rx_flag = 1;break;
					case 0x10:usart_rx_flag = 2;break;
					case 0x02:usart_rx_flag = 3;break;
					case 0x20:usart_rx_flag = 4;break;
					case 0x03:usart_rx_flag = 5;break;
					case 0x30:usart_rx_flag = 6;break;
				}
			}
			else if(g_usart_buf[2] == 0x01)
			{
				usart_rx_flag = 7;
				red_value = g_usart_buf[3];	/*将亮度值存入变量*/
			}
			else if(g_usart_buf[2] == 0x02)
			{
				usart_rx_flag = 8;
				green_value = g_usart_buf[3];
			}
			else if(g_usart_buf[2] == 0x03)
			{
				usart_rx_flag = 9;
				blue_value = g_usart_buf[3];
			}				
		}
		if(g_usart_cnt == 5)
		{
			for(g_usart_cnt=0;g_usart_cnt<5;g_usart_cnt++)	//清空缓冲区
			{
				g_usart_buf[g_usart_cnt] = 0;
			}
			g_usart_cnt = 0;
		}
	}
}

//这里有个问题是,我们发送的数据是0x000000,是一个24bit,所以我们在传值的时候需要进行移位操作,如下:
PWM_WS2812B_Write_24Bits(30,green_value<<16);
PWM_WS2812B_Show(30);

4.3 android程序

1.蓝牙建立连接的必须要求

1.打开蓝牙;这可是最重要的一步
2.查找附近已配对或可用设备
3.连接设备
4.设备间数据交换

2.常用蓝牙API如下:

BluetoothAdapter代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。
BlueDevice代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。
BluetoothSocket代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。
BluetoothServerSocket代表一个开放的服务器socket,它监听接受的请求(与TCP ServerSocket类似)。为了连接两台Android设备,一个设备必须使用这个类开启一个服务器socket。当一个远程蓝牙设备开始一个和该设备的连接请求,BluetoothServerSocket将会返回一个已连接的BluetoothSocket,接受该连接。

3.使用蓝牙需要在配置文件Androidmanifest.xml 中注册两种权限:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
其中,权限1在得到默认蓝牙适配器时需要,即BluetoothAdapter  mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter( )
权限2在mBluetoothAdapter.enable( )或者mBluetoothAdapter.disable( ) 时需要使用到。

4.app设计
这次的android小程序主要就是连接蓝牙,接收指令,发送指令。界面随便写写,有功能就行。先上图片:
在这里插入图片描述
就很简单的连接设备,按钮控制开关以及滑条控制亮度,这种页面应该是难不倒各位朋友。网上也有很多类似的界面或者源码,这里不过多阐述,重点来看看通信方式:

//发送函数,以十六进制发送
private void SendStr(String sendStr){
    byte[] bytes = new byte[sendStr.length() / 2];
    for (int i = 0; i < sendStr.length() / 2; i++) {
        String subStr = sendStr.substring(i * 2, i * 2 + 2);
        bytes[i] = (byte) Integer.parseInt(subStr, 16);
    }
    mConnectedThread.write(bytes);
}

//由于我这里水平有限,就没有通过结构体方式传输,而是字符串,我就取一个例子,其他都是一样的操作
//控制亮灭
public void onSwitchCheck(CompoundButton view, boolean isChanged) {
    switch (view.getId()) {
        case R.id.switchAll:
            if(txtIsConnected.getText().equals("已连接")){
                if (isChanged) {//turn on
                    SendStr("5AA50000A0");
                }else {//turn off
                    SendStr("5AA500FFA0");
                }
            }else{
                switchAll.setChecked(false);
            }
            break;
    }
}

//控制亮度
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
   if(txtIsConnected.getText().equals("已连接")){
        SendStr("5AA503"+String.format("%02X",progress)+"A0");
    }else{
        seekBar.setProgress(2);
    }
}

这里只是给出核心代码,其他的就是xml文件以及一起蓝牙连接的文件,这种网上有更为详细的代码以及说明。

总结

首先感谢大家看到这里,简单总结一下
注意:上述内容只是简单的通过手机APP控制单片机LED的操作,对于里面内容有误请大家及时提出,我好更正。因为是没事的时候做这个小设计,并没有深入开发,过程中的代码不够成熟,只是简单实现功能,多多理解。源码 869838299

当然,在自己调试过程中遇到任何问题,欢迎大家和我沟通。系统可能还有许多BUG没有解决,大家参考的时候酌情参考。当然这个项目后续可以拓展的点很多:

1.购买实际的大功率灯,真正做到实物的控制
2.增加串口协议复杂度,实现更多好玩儿的操作
3.添加wifi模块,将单片机接入网络,实现异地控制
4.增加语音芯片,做到语音控制

最后,写这个是为了记录一下做这个设计以来的想法,感谢大家阅览。

  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值