基于STM32舞台彩灯控制器设计app控制系统
1、系统功能介绍
- 本设计由STM32单片机+RGB驱动电路+舵机模块+红外检测模块+蓝牙模块+电源电路组成。
- 1、通过手机APP可设置系统三种模式
- 2、模式一,用户可以自定义常亮模式与定时模式。
- 在此模式下,用户可设置灯光亮度等级,定时时间等级,LED颜色,多级角度。
- 3、模式二与模式三是固定的灯光模式,更具不同位置的红外检测装置返回的信息,舵机会转向不同的角度。
2、演示视频
- 演示视频:https://www.bilibili.com/video/BV1fg4y127kW
- 资料在视频简介中获取
3、系统框图
4、系统电路介绍
4.1、STM32单片机最小系统设计
- STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位、支持实时仿真和跟踪的微控制器。选择此款控制芯片是因为本系统设计并非追求成本的最低或更小的功耗,而是在实现本设计功能的前提下能够提供更丰富的接口和功能以便于设计实验系统各实验项目所需的外围扩展电路。此款控制芯片在完成单片机课程的学习后上手较为容易,在医疗器械中应用广泛,具有很好的学习、实验研究价值。
- 单片机最小系统电路图如下图所示
- 实物图:
4.2、舵机控制电路设计
-
舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。
-
舵机工作原理:
-
控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。
-
实物图
4.3、WS2812 RGB彩灯控制电路设计
-
WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
-
矩阵键盘按键电路设计如下图所示:
-
实物图:
5、程序设计
5.1、WS2812控制彩灯颜色
/**
* color_length 每种颜色渐变最大长度,总颜色长度:color_length * 3
* return 颜色数据总长度
*/
uint32_t set_Color_Loop(uint8_t color_length)
{
uint8_t i = 0;
RGB = (uint32_t*)malloc(color_length*3*sizeof(uint32_t));//分配数组大小,(所有渐变色颜色长度)
color_length -= 1;
for( i=0;i<=color_length;i++)
{
RGB[i] = (((0xff/color_length)*i)<<8)|((0xff/color_length)*(color_length-i)); //蓝到绿
RGB[color_length + 1 +i] = (((0xff/color_length)*i)<<16)|((0xff/color_length)*(color_length-i))<<8; //绿到红
RGB[((color_length+1)*2) +i] = ((0xff/color_length)*i)|((0xff/color_length)*(color_length-i))<<16; //红到蓝
}
return color_length*3;
}
5.2、解析手机APP蓝牙数据,设置RGB灯亮度、颜色、舵机角度
/*
************************************************************
* 函数名称: Set_Light_Color_Angle
*
* 函数功能: 设置RGB灯 亮度 颜色 舵机角度
*
* 入口参数: 无
*
* 返回参数: 0
*
* 说明:
************************************************************
*/
void Set_Light_Color_Angle()
{
//亮度量
switch(USART_RX_BUF[4])
{
case Light_one: Light_Number = 5; break;
case Light_two: Light_Number = 10; break;
case Light_three: Light_Number = 15; break;
case Light_fore: Light_Number = 20; break;
case Light_five: Light_Number = 26; break;
}
// //颜色量
switch(USART_RX_BUF[5])
{
case Color_black: Color_Number = 0; break;
case Color_Red: Color_Number = 1; break;
case Color_Orange: Color_Number = 2; break;
case Color_Yellow: Color_Number = 3; break;
case Color_Green: Color_Number = 4; break;
case Color_Ching: Color_Number = 5; break;
case Color_Blue: Color_Number = 6; break;
case Color_Purple: Color_Number = 7; break;
}
//角度量
if(Angle_Add == USART_RX_BUF[6])
{
Angle_Number += 10;
if(Angle_Number >= 1900)
{
Angle_Number = 1900;
}
}
else if(Angle_Down == USART_RX_BUF[6])
{
Angle_Number -= 10;
if(Angle_Number <= 1750)
{
Angle_Number = 1750;
}
}
/*
发送设置好的亮度与颜色数据
*/
switch(Color_Number)
{
case 0: WS2812_send(rgb0,7); break;
case 1: WS2812_send(&rgb_Red[Light_Number],7); break;
case 2: WS2812_send(&rgb_Orange[Light_Number],7); break;
case 3: WS2812_send(&rgb_Yellow[Light_Number],7); break;
case 4: WS2812_send(&rgb_Green[Light_Number],7); break;
case 5: WS2812_send(&rgb_Ching[Light_Number],7); break;
case 6: WS2812_send(&rgb_Blue[Light_Number],7); break;
case 7: WS2812_send(&rgb_Purple[Light_Number],7); break;
}
}
5.3、定时器初始化,设置PWM模式
- 定时器初始化为pwm模式,控制舵机
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM3 Channel2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
6、手机APP代码
6.1、初始化蓝牙并记录已配对的蓝牙设备
private void init() {
if(mBluetoothAdapter == null){
Toast.makeText(this, "BlueTooth is unsupport!", Toast.LENGTH_LONG).show();
return;
}
if(!mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.enable();
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if(pairedDevices.size() > 0){
for(BluetoothDevice device:pairedDevices){
mPairedMap.put(device.getAddress(), new Device(device,BluetoothDevice.BOND_BONDED));
}
mDeviceList.addAll(mPairedMap.values());
}
}
6.2、与单片机蓝牙设备建立连接
private void connect(final BluetoothDevice device) {
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
try {
Util.mSocket = device.createRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
e.printStackTrace();
}
new Thread(){
@Override
public void run() {
mBluetoothAdapter.cancelDiscovery();
try {
Util.mSocket.connect();
Intent intent = new Intent(DEVICE_CONNECT);
intent.putExtra("mac", device.getAddress());
intent.putExtra("status", STATUS_CONNECTED);
sendBroadcast(intent);
Util.isConnected = true;
} catch (IOException e) {
try {
Util.mSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
Intent intent = new Intent(DEVICE_CONNECT);
intent.putExtra("mac", device.getAddress());
intent.putExtra("status", STATUS_NOT_CONNECTED);
sendBroadcast(intent);
e.printStackTrace();
Util.isConnected = false;
}
super.run();
}
}.start();
}