芯源半导体CW32
直播中

zealsoft

3年用户 649经验值
擅长:可编程逻辑,嵌入式技术
私信 关注

【CW32饭盒派开发板试用体验】利用机智云模块联网(1)

感谢电子发烧友论坛和武汉芯源所提供的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方案。
image001.png

在该页面的下方,可以选择所支持MCU类型,比如常见的STM32和Arduino。对于CW32,可以选择其他平台,Product Secret中填写页面左上角的PS。然后点击“生成代码包”。过一小段时间,平台就会生成CW32所需要的代码框架。
image003.png

解压下载的代码包可以得到如下文件:

image005.png

其中的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目录都需要加入工程中。

机智云的代码移植方案如下图所示。

image007.png

我们以武汉芯源所提供的“实验六 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; //PA8 
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; //PA9 
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; //PA6
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; //PA7
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)
{
  /* USER CODE BEGIN */
  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);		
	}

  /* USER CODE END */
}

在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]);//STM32 test demo
        //Serial port to achieve the function, the buf[i] sent to the module
        if(i >=2 && buf[i] == 0xFF)
        {
          //Serial port to achieve the function, the 0x55 sent to the module
					while (USART_GetFlagStatus(CW_UART2, USART_FLAG_TXE) == RESET);
          USART_SendData_8bit(CW_UART2, 0x55);//STM32 test demo
        }
    }

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)
{
  /* USER CODE BEGIN */
 if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
  {
    BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);
		gizTimerMs();
	}
  /* USER CODE END */
}

4. MCU主循环

机智云要求将下面的语句加入到while主循环中。这两个语句确保可以正常处理机智云相关的消息。

userHandle();
gizwitsHandle((dataPoint_t *)&currentDataPoint);

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;  //KEY1
		 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常量的定义,这样程序执行过程中会输出更多日志。
image009.png

程序运行之后,我们按下KEY1,可以让GE211模块进入SoftAp配网模式,串口的调试日志如下图所示。
image011.png

其中的WiFi2MCU是GE211模块发给CW32的,而CU2WiFi是CW32发给GE211模块的。如果想了解这些串口数据的含义,可以使用机智云提供的串口调试助手GAgent_Debugger。启动该软件后,可以在“工具”页面的“数据包检查”中分析GE211模块和CW32之间发送的数据包。比如我们分析CW32发送数据包“ff ff 00 06 09 00 00 00 01 10”。从下图的分析结果可以看到该命令是通知GE211模块进入配网模式的命令。
image013.png

日志中的“WiFi status: in binding mode”表示模块已经进入到配网模式。我们可以从手机的WiFi列表中看到GE211开启的热点,就是名字中包括GAgent的那个。
image015.jpg

至此,CW32和机智云GE211模块之间的串口测试已经成功,下次介绍如何实现配网和连云操作。

更多回帖

发帖
×
20
完善资料,
赚取积分