机智云官方生成的MCU代码(hal库)移植为STM32标准库教程
手上刚好有STM32F103VCT6和ESP8266模块想要接入机智云,但是由于不熟悉HAL库,于是参考机智云官方提供的文档,移植STM32固件库,以下是移植步骤:
生成"通用平台代码"
下载并解压
将Gizwits和Utils复制进自己创建好的STM32工程内
工程内加入文件和路径
打开机智云生成的main函数,并将其覆盖自己创建工程的main函数
编写串口和定时器
串口通讯要求:
波特率:9600
8位数据长
1个停止位
无奇偶校验位
无硬件流控制
收发模式
MCU方案需要用户实现一个串口,用于设备MCU与WIFI模组之间数据通信。在串口中断服务函数中调用 gizPutData() 函数实现串口数据的接收并且写入协议层数据缓冲区。串口发送函数和中断服务函数如下
/**
* USART2发送len个字节.
* buf:发送区首地址
* len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
**/
void USART2_Send_Data(u8 *buf,u16 len)
{
u16 t;
for(t=0;t<len;t++) //循环发送数据
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2,buf[t]);
}
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
}
/**
* USART2中断服务函数和串口发送报文函数实现如下:
**/
void USART2_IRQHandler(void) //串口2中断服务程序
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);//等待数据发送完成
aRxBuffer = USART_ReceiveData(USART2);
gizPutData((uint8_t *)&aRxBuffer,1);//**需定义全局变量aRxBuffer,数据类型为 uint8_t,gizPutData函数位于 gizwits_protocol.c 中**
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
}
另外,需要编写串口的发送函数, uartWrite() 函数中调用串口发送函数。需要特别注意的是 gizwits_product.c 文件中 uartWrite() 函数是伪函数,用户需根据自己实现的串口发送函数完善 uartWrite(),请注意相关注释信息,以防出错。具体实现如下:
注意:示例中的 0x55 条件处理,即出现0xFF的数据时后面要加 0x55,这个操作一定要保留。
int32_t uartWrite(uint8_t *buf, uint32_t len)
{
uint32_t i = 0;
uint8_t temp=0x55;
if(NULL == buf)
{
return -1;
}
#ifdef PROTOCOL_DEBUG
GIZWITS_LOG("MCU2WiFi[%4d:%4d]: ", gizGetTimerCount(), len);
for(i=0; i<len; i++)
{
GIZWITS_LOG("%02x ", buf[i]);
}
GIZWITS_LOG("\n");
#endif
for(i=0; i<len; i++)
{
//USART_SendData(UART, buf[i]);//STM32 test demo
//Serial port to achieve the function, the buf[i] sent to the module
USART2_Send_Data(buf+i,1);//需添加串口发送函数
if(i >=2 && buf[i] == 0xFF)
{
//Serial port to achieve the function, the 0x55 sent to the module
//USART_SendData(UART, 0x55);//STM32 test demo
//0x55 条件处理,即出现0xFF的数据时后面要加 0x55
USART2_Send_Data(&temp,1);//需添加串口发送函数
}
}
return len;
}
如果用户需要打印日志调试信息,用户需实现GIZWITS_LOG函数,只需修改 gizwits_protocol.h 中对应的宏定义即可,如下:
#define GIZWITS_LOG printf //<运行日志打印
/* 网上有 printf 函数的使用教程,这边不再赘述 */
定时器要求:1ms中断一次
定时器中断服务函数如下
//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//是更新中断
{
gizTimerMs();//gizTimerMs位于 gizwits_product.c 中
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIM2更新中断标志
}
}
配置入网功能(必要)
根据串口协议文档规定,MCU可以向模组发送命令为 ESP8266 配网, 调用 gizwitsSetMode(配网模式) 就能进入配网模式,该函数位于 gizwits_protocol.c 中,gizwitsSetMode() 函数功能说明如下:
/**
* @brief WiFi配置接口
* 用户可以调用该接口使WiFi模组进入相应的配置模式或者复位模组
* @param[in] mode 配置模式选择:0x0,模组复位;0x01,SoftAp模式;0x02,AirLink模式
* @return 错误命令码
*/
int32_t gizwitsSetMode(uint8_t mode);
我使用 WIFI_AIRLINK_MODE 模式配网,并且配网时打开提示灯
//外部中断8服务程序
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line8) != RESET)
{
//AirLink mode 一键配网模式
GIZWITS_LOG("KEY2 PRESS LONG ,AirLink mode\n");
Led_Open(ReminderLed);//开启提示灯
gizwitsSetMode(WIFI_AIRLINK_MODE);
EXTI_ClearITPendingBit(EXTI_Line8); //清除LINE8上的中断标志位
}
}
设置好配网模式后,在 gizwits_product. c 文件的 gizwitsEventProcess() 函数内获得WIFI状态,并做相应的逻辑处理。
例如: 配网成功后关闭提示灯
case WIFI_CON_ROUTER:
Led_Close(ReminderLed);//配网成功,关闭提示灯
break;
数据下行控制
云端(App)下发数据给MCU, 数据点方式将转换成数据点事件,开发者只需要在 gizwits_product. c 文件的 gizwitsEventProcess () 相应事件下作具体处理即可。
以APP实现控制LED为例,如下:
int8_t gizwitsEventProcess(eventInfo_t *info, uint8_t *gizdata, uint32_t len)
{
uint8_t i = 0;
dataPoint_t *dataPointPtr = (dataPoint_t *)gizdata;
moduleStatusInfo_t *wifiData = (moduleStatusInfo_t *)gizdata;
protocolTime_t *ptime = (protocolTime_t *)gizdata;
#if MODULE_TYPE
gprsInfo_t *gprsInfoData = (gprsInfo_t *)gizdata;
#else
moduleInfo_t *ptModuleInfo = (moduleInfo_t *)gizdata;
#endif
if((NULL == info) || (NULL == gizdata))
{
return -1;
}
for(i=0; i<info->num; i++)
{
switch(info->event[i])
{
case EVENT_LivingLed:
currentDataPoint.valueLivingLed = dataPointPtr->valueLivingLed;
GIZWITS_LOG("Evt: EVENT_LivingLed %d \n", currentDataPoint.valueLivingLed);
if(0x01 == currentDataPoint.valueLivingLed)
{
//user handle
Led_Open(LivingLed);
}
else
{
//user handle
Led_Close(LivingLed);
}
break;
case EVENT_BedroomLed:
currentDataPoint.valueBedroomLed = dataPointPtr->valueBedroomLed;
GIZWITS_LOG("Evt: EVENT_BedroomLed %d \n", currentDataPoint.valueBedroomLed);
if(0x01 == currentDataPoint.valueBedroomLed)
{
//user handle
Led_Open(BedroomLed);
}
else
{
//user handle
Led_Close(BedroomLed);
}
break;
// .........以下代码省略
数据上行控制
该工程源码在 Gizwits\gizwits_product.c 文件的 userHandle() 函数中实现传感器数据上报,原则上用户只需要关心如何采集数据。当需要上报传感器数据时,调用 userHandle() 即可
以灯的状态赋值为例( 只读型数据点 的操作会被云端自动生成),如下:
/**
* 用户数据获取
* 此处需要用户实现除可写数据点之外所有传感器数据的采集,可自行定义采集频率和设计数据过滤算法
* @param none
* @return none
*/
void userHandle(void)
{
currentDataPoint.valueLivingLed = 0x01;
}
参考链接:http://docs.gizwits.com/zhcn/deviceDev/GoKit3_DEV_SDK_Common_transplant.html