本帖最后由 dql2016 于 2021-7-12 19:37 编辑
本次项目中有一个照明控制节点,用于演示通过在RGB灯泡内集成RSL10蓝牙模块进而通过微信小程序控制。在踩了前面无数坑之后,实现各个节点的功能就变得十分简单了,为了充分利用手头资源,照明控制节点中的RGB灯泡采用涂鸦智能推出的具有arduino uno v3接口的RGB扩展板,这样就可以直接插到同样具有 arduino uno v3接口的RSL10-002GEVB开发板上,如下图所示:
涂鸦的照明开发板(PWM+I2C)可实现五路照明功能,带有暖光,冷白及 RGB 灯珠和相应的控制芯片。RGB 控制采用 SM726EB,DC-DC 降压型 I2C控制线性恒流调光芯片。冷白,暖白控制采用 SLM211A DC-DC 降压型 PWM 线性恒流调光控制芯片。原理图如下所示:
由于RSL10-002GEVB板卡上面对应的IO并不支持PWM功能,因此本次项目演示没有使用到冷白,暖白控制,使用了I2C接口控制RGB颜色。整个系统框图如下:
RSL10-002GEVB实现的主要功能是:上电后向周围广播,等待中央设备连接,连接成功后,接收中央设备下发的控制指令,进行RGB灯光颜色的调整。SM726EB这个国产芯片网上搜索不到任何资料,最后还是在github上找到了一个应该是它同系列的芯片SM16716的驱动,稍加改造,没想到驱动成功了,使用两个GPIO即IO7、IO8 模拟i2c驱动如下:
#define XLGT_03 3
void delay_us(uint32_t us)
{
uint32_t n=15;
while(n--);
}
void delay_ms(uint32_t ms)
{
delay_us(1000*ms);
}
#define D_LOG_SM726EB "SM726EB: "
struct SM726EB {
uint8_t pin_clk;
uint8_t pin_dat;
uint8_t pin_sel;
bool enabled;
} sm726eb;
void SM726EB_SendBit(uint8_t v)
{
if(v==0)
{
Sys_GPIO_Set_Low(sm726eb.pin_dat);
}
else
{
Sys_GPIO_Set_High(sm726eb.pin_dat);
}
delay_us(1);
Sys_GPIO_Set_High(sm726eb.pin_clk);
delay_us(1);
Sys_GPIO_Set_Low(sm726eb.pin_clk);
}
void SM726EB_SendByte(uint8_t v)
{
uint8_t mask;
for (mask = 0x80; mask; mask >>= 1)
{
SM726EB_SendBit(v & mask);
}
}
void SM726EB_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b)
{
if (sm726eb.pin_sel < 99)
{
bool should_enable = (duty_r | duty_g | duty_b);
if (!sm726eb.enabled && should_enable)
{
sm726eb.enabled = true;
Sys_GPIO_Set_High(sm726eb.pin_sel);
delay_us(1000);
SM726EB_Init();
}
else if (sm726eb.enabled && !should_enable)
{
sm726eb.enabled = false;
Sys_GPIO_Set_Low(sm726eb.pin_sel);
}
}
PRINTF("Update; rgb=%02x%02x%02x\n", duty_r, duty_g, duty_b);
SM726EB_SendBit(1);
SM726EB_SendByte(duty_r);
SM726EB_SendByte(duty_g);
SM726EB_SendByte(duty_b);
SM726EB_SendBit(0);
SM726EB_SendByte(0);
SM726EB_SendByte(0);
SM726EB_SendByte(0);
}
void SM726EB_Init(void)
{
for (uint32_t t_init = 0; t_init < 50; ++t_init) {
SM726EB_SendBit(0);
}
}
void Sm16716ModuleSelected(void)
{
sm726eb.pin_clk = 7;
sm726eb.pin_dat = 8;
sm726eb.pin_sel = 15;
Sys_DIO_Config(sm726eb.pin_clk, DIO_MODE_GPIO_OUT_0);
Sys_GPIO_Set_Low(sm726eb.pin_clk);
Sys_DIO_Config(sm726eb.pin_dat, DIO_MODE_GPIO_OUT_0);
Sys_GPIO_Set_Low(sm726eb.pin_dat);
if (sm726eb.pin_sel < 99)
{
Sys_DIO_Config(sm726eb.pin_sel, DIO_MODE_GPIO_OUT_0);
Sys_GPIO_Set_Low(sm726eb.pin_sel);
}
else
{
SM726EB_Init();
}
}
成功驱动效果如下,可以任意控制RGB颜色显示:
RSL10-002GEVB端程序基于例程peripheral_server实现,在主循环中解析微信小程序下发的数据后驱动RGB即可。
if (cs_env[i].rx_value_changed)
{
PRINTF("[%s:%d %s]==== get data from phone start_hdl:0x%04x ====\n",__FILE__,__LINE__,__FUNCTION__,cs_env[i].start_hdl);
for (int j=0;j<cs_env[i].rx_len;j++)
{
PRINTF("[%s:%d %s]==== get data from phone %d:0x%02x ====\n",__FILE__,__LINE__,__FUNCTION__,j,cs_env[i].rx_value[j]);
}
r=cs_env[i].rx_value[0]*10+cs_env[i].rx_value[1];
g=cs_env[i].rx_value[2]*10+cs_env[i].rx_value[3];
b=cs_env[i].rx_value[4]*10+cs_env[i].rx_value[5];
SM726EB_Update(r, g, b);
cs_env[i].rx_value_changed=false;
}
RSL10-002GEVB端程序没有什么难度和新意,比较麻烦的是微信小程序的设计,由于是第一次接触微信小程序,很多概念都不熟悉,想搜索都不知道搜什么,微信小程序照明节点控制界面主要实现RGB拾色器,即用户选定一个颜色,及时的将它发送给RSL10-002GEVB端。
这里需要十分注意的是数据格式的问题,在微信小程序中我主要使用的是十六进制字符串:
// 显示取色器
toPick: function () {
this.setData({
pick: true
})
},
//取色结果回调
pickColor(e) {
let myrgb = e.detail.color;
console.log('选择的颜色:'+myrgb)//rgb(100,200,210)
//给蓝牙页面发送数据
event.emit('LightControlSendData2Device',myrgb);
this.setData({
rgb: myrgb
})
},
在蓝牙数据收发控制界面将数据发送出去:
//灯光控制页面发来的RGB数据
event.on('LightControlSendData2Device', this, function(data) {
//另外一个页面传过来的data是16进制字符串形式
console.log("要发送给蓝牙设备的数据:"+data);
var a=data;
var b = a.indexOf("(")
var c = a.indexOf(")")
var d = a.substring(c,b+1)//100,200,230
var e=d.substring(0,d.indexOf(","));
console.log("分词R:"+parseInt(e,10))
var f=d.substring(d.indexOf(",")+1,d.lastIndexOf(",")+1);
console.log("分词G:"+parseInt(f,10))
var g=d.substring(d.length,d.lastIndexOf(",")+1);
console.log("分词B:"+parseInt(g,10))
var myrgb=this.myStringToHex(parseInt(e,10).toString(16))+this.myStringToHex(parseInt(f,10).toString(16))+this.myStringToHex(parseInt(g,10).toString(16));
console.log("myrgb:"+myrgb)
//var buffer = new ArrayBuffer(5)
//var dataView = new Uint8Array(buffer)
var buffer=that.stringToBytes(myrgb);
wx.writeBLECharacteristicValue({
deviceId: app.globalData._deviceId,//蓝牙设备 id
serviceId: app.globalData._serviceId,//蓝牙特征值对应服务的 uuid
characteristicId: app.globalData._writeCharacteristicId,//蓝牙特征值的 uuid
value: buffer,//ArrayBuffer 蓝牙设备特征值对应的二进制值
success: function (res) {//接口调用成功的回调函数
console.log('发送成功')
},
fail: function(res) {//接口调用失败的回调函数
//发送蓝牙数据失败
console.log('发送失败')
}
}
)
})
},
主界面有2个小按钮用于单独控制某个灯,一个灯泡图标按钮用于控制所有灯,在实际中可以模拟控制单路和多路的效果。
主界面如下:
开启的效果:
最后来看看测试视频吧:
总结:其实如前面的帖子所述,实现了微信小程序和RSL10之间的蓝牙数据双向收发,其它的几乎所有功能就是在这个的基础上的包装了。
|