感谢电子发烧友论坛和武汉芯源所提供的CW32饭盒派开发板的测试机会。
CW32饭盒派是一款基于CW32F030C8T6的开发板。板载资源丰富:一电位器、蜂鸣器、3路用户按键、3路指示灯、USART接口、电源接口、下载接口等等,预留出了众多传感器接口,使平台可以无限灵活扩展,特别适合初学者入门学习和大学开展教学工作。该板卡没有网卡,如果希望进行智能物联网开发就需要另外接无线模块。今天开始,介绍如何将CW32饭盒派开发板和机智云的GE211 DTU转接板结合,实现CW32饭盒派开发板进行智能物联网应用开发。
GE211 是机智云自研的定制化转接板,使用 ESP32-C3-WROOM-02 通讯模块,适用于白色智能家电等设备应用。GE211内部已经烧录了机智云连云的代理软件GAgent固件,必须学习MQTT之类的协议,也不需要烧写任何软件就可以上手使用。GE211板卡带有一个串口,一般是把这个串口和家电设备的控制板串口相连接,由家电设备的控制板通过串口发送命令控制GE211的固件进行联网和绑定工作。有关GE211的更详细内容,可以参考我以前发的评测。
1. 机智云MCU代码的下载
机智云网站上提供了GE211模块的串口命令文档,不过一般来说,我们并不需要学习这些命令,也不需要手工编写控制GE211模块的代码。机智云平台相对于与其他平台的最大优势就是可以针对不同类型的MCU和CPU生成所需要控制代码,我们只需要将代码移植到我们的MCU平台并学习一个非常简单的API就可以实现所需要的功能。
如果从来没有在机智云定义过设备,首先需要访问机智云的开发者中心(https://dev.gizwits.com/zh-cn/developer/intro)注册账号,并创建智能设备。进入“产品开发”页面后,可以在左侧的菜单栏中进入“MCU开发”页面(如下图)。在该页面选择独立MCU方案。
在该页面的下方,可以选择所支持MCU类型,比如常见的STM32和Arduino。对于CW32,可以选择其他平台,Product Secret中填写页面左上角的PS。然后点击“生成代码包”。过一小段时间,平台就会生成CW32所需要的代码框架。
解压下载的代码包可以得到如下文件:
其中的MCU_COMMON_User_Guide _V0.4.pdf非常重要,介绍了移植代码的步骤,需要仔细阅读一下。Gizwits目录包括机智云的协议层,包括通信协议和用户事件处理的代码。Utils目录中包括工具层的代码。
下面是一些重要文件:
(1) gizwits_product.c
该文件为产品相关处理函数, 如
gizwitsEventProcess(), 数据采集 userHandle()函数和数据点初始化 userInit()函数。
(2) gizwits_product.h
该文件为 gizwits_product.c 的头文件, 如 HARDWARE_VERSION、 SOFTWARE_VERSION。
(3) gizwits_protocol.c
该文件为 SDK API 接口函数定义文件。
(4) gizwits_protocol.h
该文件为 gizwits_protocol.c 对应头文件,
相关 API 的接口声明均在此文件中。
Gizwits目录和Utils目录都需要加入工程中。
机智云的代码移植方案如下图所示。
我们以武汉芯源所提供的“实验六 UART--串口”工程为模板介绍如何将机智云的代码加到CW32的工程中。
2. 串口配置
机智云需要2个串口,一个用于调试,另一个用于和MCU通信。2个串口也可以合并 1个。CW32饭盒派有3个串口,所以我们用UART1作为调试串口,波特率设置为115200bps,UART2作为通信串口,波特率设置为9600bps。UART1_TX是PA08管脚,连接PC的RXD口,二UART1_RX是PA09管脚,连接PC的TXD口。UART2_TX是PA06管脚,UART2_RX是PA07管脚,分别连接GE211的RXD和TXD。
串口的初始化代码如下:
void UART_init(void)
{
GPIO_InitTypeDef
GPIO_InitStructure;
USART_InitTypeDef
USART_InitStructure;
RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_UART1,
ENABLE);
RCC_AHBPeriphClk_Enable(
RCC_AHB_PERIPH_GPIOA | RCC_AHB_PERIPH_GPIOB, ENABLE);
PA08_AFx_UART1TXD();
PA09_AFx_UART1RXD();
GPIO_InitStructure.Pins = GPIO_PIN_8;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pins = GPIO_PIN_9;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_Over = USART_Over_16;
USART_InitStructure.USART_Source = USART_Source_PCLK;
USART_InitStructure.USART_UclkFreq = 64000000;
USART_InitStructure.USART_StartBit = USART_StartBit_FE;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(CW_UART1, &USART_InitStructure);
RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_UART2,
ENABLE);
PA06_AFx_UART2TXD();
PA07_AFx_UART2RXD();
GPIO_InitStructure.Pins = GPIO_PIN_6;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pins = GPIO_PIN_7;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_Over = USART_Over_16;
USART_InitStructure.USART_Source = USART_Source_PCLK;
USART_InitStructure.USART_UclkFreq = 64000000;
USART_InitStructure.USART_StartBit = USART_StartBit_FE;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(CW_UART2, &USART_InitStructure);
USART_ITConfig(CW_UART2, USART_IT_RC, ENABLE);
NVIC_SetPriority(UART2_IRQn, 0);
NVIC_EnableIRQ(UART2_IRQn);
}
在接收数据的中断中,每次收到数据都需要调用gizPutData把它发送给机智云的代码。
void UART2_IRQHandler(void)
{
uint8_t value = 0;
if(USART_GetITStatus(CW_UART2, USART_IT_RC) != RESET)
{
USART_ClearITPendingBit(CW_UART2, USART_IT_RC);
value = USART_ReceiveData(CW_UART2); gizPutData(&value, 1);
}
}
在gizwits_product.c中,需要修改uartWrite函数,以确保发送数据给GE211模块。修改的部分如下:
for(i=0; i<len; i++)
{
while (USART_GetFlagStatus(CW_UART2, USART_FLAG_TXE) == RESET);
USART_SendData_8bit(CW_UART2, buf[i]);
if(i >=2 && buf[i] == 0xFF)
{
while (USART_GetFlagStatus(CW_UART2, USART_FLAG_TXE) == RESET);
USART_SendData_8bit(CW_UART2, 0x55);
}
}
3.定时器设置
机智云的代码需要一个1ms的定时器,我们将BTIM1设置为1ms。修改后的BTIM_init函数如下:
void BTIM_init(void)
{
BTIM_TimeBaseInitTypeDef BTIM_InitStruct;
__RCC_BTIM_CLK_ENABLE();
__disable_irq();
NVIC_EnableIRQ(BTIM1_IRQn);
__enable_irq();
BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
BTIM_InitStruct.BTIM_OPMode = BTIM_OPMode_Repetitive;
BTIM_InitStruct.BTIM_Period = 999; // 1ms
BTIM_InitStruct.BTIM_Prescaler = BTIM_PRS_DIV8;
BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
BTIM_ITConfig(CW_BTIM1, BTIM_IT_OV, ENABLE);
BTIM_Cmd(CW_BTIM1, ENABLE);
}
在BTIM1的中断函数BTIM1_IRQHandler中需要调用gizTimerMs函数。
void BTIM1_IRQHandler(void)
{
if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
{
BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);
gizTimerMs();
}
}
4. MCU主循环
机智云要求将下面的语句加入到while主循环中。这两个语句确保可以正常处理机智云相关的消息。
userHandle();
gizwitsHandle((dataPoint_t *)¤tDataPoint);
5. 按键进入SoftAp配网模式
要让GE211能够连接WiFi并连接云端服务器,还需要进行配网。所谓配网,就是通过手机上的App或者小程序告诉GE211模块所要连接的无线路由器的SSID和密码,然后GE211自动连接路由器并进行上网。机智云支持多种配网方式,这里我们以SoftAp配网为例。
我们使用KEY1作为用户进入SoftAp模式的按键,首先在GPIO_Configuration函数中加入下面的代码:
GPIO_InitStruct.IT = GPIO_IT_NONE; //KEY1 KEY2 KEY3
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_InitStruct.Pins = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
我们在主循环中加入查询KEY1状态的代码,如果用户按下KEY1就通知GE211进入到配网模式,代码如下:
if(GPIO_ReadPin(CW_GPIOB,GPIO_PIN_13) == GPIO_Pin_SET) key_1 = 0;
else if(key_1 == 0)
{
delay1ms(10);
if(GPIO_ReadPin(CW_GPIOB,GPIO_PIN_13) == GPIO_Pin_RESET)
{
key_1 = 1;
GIZWITS_LOG("KEY1 PRESS ,Soft AP mode\\\\n");
gizwitsSetMode(WIFI_SOFTAP_MODE);
}
}
6. 串口连接测试
我们先测试一下CW32和GE211的串口通信过程。如果想看到CW32和GE211通信的细节,建议加上PROTOCOL_DEBUG常量的定义,这样程序执行过程中会输出更多日志。
程序运行之后,我们按下KEY1,可以让GE211模块进入SoftAp配网模式,串口的调试日志如下图所示。
其中的WiFi2MCU是GE211模块发给CW32的,而CU2WiFi是CW32发给GE211模块的。如果想了解这些串口数据的含义,可以使用机智云提供的串口调试助手GAgent_Debugger。启动该软件后,可以在“工具”页面的“数据包检查”中分析GE211模块和CW32之间发送的数据包。比如我们分析CW32发送数据包“ff ff 00 06 09 00 00 00 01 10”。从下图的分析结果可以看到该命令是通知GE211模块进入配网模式的命令。
日志中的“WiFi status: in binding mode”表示模块已经进入到配网模式。我们可以从手机的WiFi列表中看到GE211开启的热点,就是名字中包括GAgent的那个。
至此,CW32和机智云GE211模块之间的串口测试已经成功,下次介绍如何实现配网和连云操作。