IOT台灯软件设计
本帖最后由 skyworth74 于 2021-7-4 14:00 编辑<p> IOT台灯基础架构</p>
<p> 要实现IOT功能、因为蓝牙不能直接连上物联网,必须通过网关进行连接进行转换,IOT蓝牙台灯架构如下:</p>
<p>1、蓝牙和网关通讯功能,所有控制命令和设备参数通过BLE和发送给网关网关再把IOT台灯的参数上报云端服务器、通过手机APP把数据通过网关转换后发给IOT台灯执行、还有就是没有网络的时候在家APP直接通过BLE和IOT台灯进行通讯实现台灯功能。</p>
<p>2、台灯功能实现和命令执行</p>
<p>因为网关通讯协议涉及公司机密本次大赛不把协议内容进行具体阐述,只进行APP和BLE直接通讯进行控制、和台灯功能实现。台灯采用一线归零技术进行LED的控制,本次比赛采用WS2812 进行LED驱动实现调光调色功能。WS2812可以通过一根GPIO就可以实现控制每个像素点三基色 256级亮度显示和多级级联功能。下面实现的是WS2812的时序控制共能</p>
<p>#define WS1258_GPIO 0<br />
#define WS2812_EN_GPIO 1<br />
#define _nop_() __NOP()<br />
#define PERCENT 1<br />
#define T0H (350+150/PERCENT) //0.35us<br />
#define T0L (800+150/PERCENT) //0.8us<br />
#define T1H (700+150/PERCENT) //0.7us<br />
#define T1L (600+150/PERCENT) //0.6us<br />
#define RESTIME 2400<br />
void delay_us(uint32_t ns)<br />
{<br />
uint32_t i =0;<br />
while(ns){<br />
ns--;<br />
for(i=100;i>1;i--){<br />
_nop_();<br />
}<br />
}</p>
<p>}<br />
void ledGpioInit(void)<br />
{</p>
<p> Sys_DIO_Config(WS1258_GPIO, DIO_MODE_GPIO_OUT_0);<br />
Sys_DIO_Config(WS2812_EN_GPIO, DIO_MODE_GPIO_OUT_0);</p>
<p><br />
}<br />
void ledGpio(gpio_status_e on)<br />
{<br />
if (GPIO_HIGH==on){<br />
Sys_GPIO_Set_High(WS1258_GPIO);<br />
}else{<br />
Sys_GPIO_Set_Low(WS1258_GPIO);<br />
}</p>
<p><br />
}</p>
<p>void onsemLedEnable(xt_ledenable_e enable)<br />
{<br />
if (enable==LEDENABLE){<br />
Sys_GPIO_Set_High(WS2812_EN_GPIO);<br />
}else{<br />
Sys_GPIO_Set_Low(WS2812_EN_GPIO);<br />
}<br />
}<br />
//-------------------------------------------------------------------------------<br />
//-------------------------------------------------------------------------------<br />
//子程序名称:ResetDateFlow(void)<br />
//功能:复位,为下一次发送做准备,<br />
//说明:将DI置位为0后,延时约65us<br />
//-------------------------------------------------------------------------------<br />
//-------------------------------------------------------------------------------<br />
void ResetDataFlow(void)<br />
{<br />
unsigned char i,j;<br />
ledGpio(GPIO_LOW);//DI=0; <br />
delay_us(RESTIME);<br />
}</p>
<p>//发送3BYTE的数据给LED 控制RGB<br />
static void WS2811_SendByte(uint32_t dat)//<br />
{<br />
uint8_t i = 0;<br />
uint32_t temp =dat;<br />
for(i=0;i<24;i++)<br />
{<br />
if(temp&0x800000) //<br />
{<br />
//LINEZERO_GPIO_Port->BSRR = (uint32_t)LINEZERO_Pin;<br />
ledGpio(GPIO_HIGH); <br />
_nop_(); <br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
//delay_us(T1H);<br />
//LINEZERO_GPIO_Port->BRR = (uint32_t)LINEZERO_Pin;<br />
ledGpio(GPIO_LOW); //DI=0;<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
//delay_us(T1L);<br />
}<br />
else <br />
{<br />
//LINEZERO_GPIO_Port->BSRR = (uint32_t)LINEZERO_Pin;<br />
ledGpio(GPIO_HIGH);<br />
//delay_us(T0H);<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
//LINEZERO_GPIO_Port->BRR = (uint32_t)LINEZERO_Pin;<br />
ledGpio(GPIO_LOW); //DI=0;<br />
//delay_us(T0L);<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
_nop_();<br />
}<br />
temp=(temp<<1); <br />
}</p>
<p><br />
}</p>
<p><br />
//把RGB打包发送</p>
<p>void send_data(uint8_t r,uint8_t g,uint8_t b)<br />
{<br />
uint8_t i;<br />
uint32_t para =0;<br />
para= (r<<16|g<<8|b);<br />
WS2811_SendByte(para);</p>
<p> //ResetDataFlow(); <br />
}</p>
<p>//应用直接调用函数</p>
<p>void ledDriver(RGB_T rgb[],uint8_t lens )<br />
{ <br />
uint8_t i=0;<br />
if (rgb==NULL||lens<1){<br />
return;<br />
}<br />
<br />
ResetDataFlow(); //发送帧复位信号<br />
for (i=0;i<lens;i++){//sizeof(rgb)/sizeof(rgb)<br />
send_data(rgb<i>.r,rgb<i>.g ,rgb<i>.b);<br />
}<br />
ResetDataFlow(); //发送帧复位信号<br />
}</i></i></i></p>
<p><i><i><i> 下图是单线归零时序图,用简单的逻辑分析仪抓到的波形图</i></i></i></p>
<p> </p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> </i></i></i></p>
本帖最后由 skyworth74 于 2021-7-4 15:29 编辑
<p>实现了单线归零驱动以后需要开始编写手机APP和BLE通讯的程序,onsemi提供的demo程序里面选择了</p>
<p>freertos_ble_peripheral_server_bond 这个例程,通过简单改造就可以实现通讯功能,选取里面</p>
<p>#define CS_CHAR_LONG_RX_UUID { 0x24, 0xdc, 0x0e, 0x6e, 0x04, 0x40, \<br />
0xca, 0x9e, 0xe5, 0xa9, 0xa3, 0x00, \<br />
0xb5, 0xf3, 0x93, 0xe0 }<br />
#define CS_CHAR_LONG_TX_UUID { 0x24, 0xdc, 0x0e, 0x6e, 0x05, 0x40, \<br />
0xca, 0x9e, 0xe5, 0xa9, 0xa3, 0x00, \<br />
0xb5, 0xf3, 0x93, 0xe0 }</p>
<p><br />
两个特征值直接就可以通过手机APP BLE调试APP进行测试,只需要在这两个特征值里面找到两个callback 函数 CUSTOMSS_RXLongCharCallback()</p>
<p>把接受度到的数据加入到fifo的队列里面。然后通过freetos创建一个新的task 把fifo收到的数据进行解析</p>
<p>uint8_t CUSTOMSS_RXLongCharCallback(uint8_t conidx, uint16_t attidx, uint16_t handle,<br />
uint8_t *to, const uint8_t *from, uint16_t length,<br />
uint16_t operation)<br />
{<br />
memcpy(to, from, length);<br />
#if RSL10_DEBUG<br />
PRINTF("\n\rRXLongCharCallback (%d): ", conidx, length);<br />
for (int i = 0; i < length; i++)<br />
{<br />
PRINTF("%02x ", app_env_cs.from_air_buffer_long<i>);<br />
}<br />
#endif /* if RSL10_DEBUG */<br />
PRINTF("\r\n");</i></p>
<p><i> /* Update TX long characteristic with the inverted version of<br />
* RX long characteristic just received */<br />
if(operation == GATTC_WRITE_REQ_IND)<br />
{ //把数据放入fifo 缓冲里面<br />
smartLightProtocolDataInsert((void *)app_env_cs.from_air_buffer_long, length);<br />
}<br />
return ATT_ERR_NO_ERROR;<br />
}</i></p>
<p><i>在freertos里面创建一个任务</i></p>
<p><i>osThreadNew(ledDriverThread, NULL, &thread_led_attr);</i></p>
<p><i>__NO_RETURN void ledDriverThread(void *argument)<br />
{<br />
EFFECT_MODE effectMode = PARTY;<br />
xt_protocol_data_t *ble_protocol_data=& sg_ble_protocol_data;<br />
/* creation of rgbQueue */<br />
rgbQueueHandle = osMessageQueueNew (1, sizeof(LIGHT_ATTR), &rgbQueue_attributes);<br />
</i></p>
<p><i> for(;;)<br />
{<br />
osDelay(10);<br />
if(1==onsemi_fifo_HaveData(&fifo_dev)){<br />
smartLightProtocolDataRead();<br />
PRINTF("%s header=%x\r\n",__func__,ble_protocol_data->header);<br />
if (HEADER_0==ble_protocol_data->header&&HEADER_1==ble_protocol_data->header){<br />
effectMode = ble_protocol_data->cmd;<br />
}<br />
}<br />
switch(effectMode)<br />
{<br />
case NIGHT:<br />
send_data(0x55,0xaa,0x55);<br />
PRINTF("NIGHT\r\n");<br />
break;<br />
case VOICE_CONTROL:</i></p>
<p><i> //在这里实现把咪头采集到的声音进行傅里叶变化,计算出频率和震幅然后通过数据归一化处理实现等效控制</i></p>
<p><i> break;<br />
case FLASH_MODE:<br />
break;<br />
}<br />
<br />
}<br />
}</i><br />
下图蓝牙收到数据命令,解析出来的命令模式台灯进入夜晚模式</p>
<p><i> </i></p>
<p><i> </i></p>
<p><br />
<i> </i></p>
<p><i> </i></p>
<p>期待楼主后续</p>
页:
[1]