最近在研究CH32V307的闆子,這個闆子性能還是非常強大的。CH32V307是基于32位RISC-V設計的互聯型微控制器,配備了硬體堆棧區、快速中斷入口,在标準RISC-V基礎上大大提高了中斷響應速度。加入單精度浮點指令集,擴充堆棧區,具有更高的運算性能。
看看CH32V307在物聯網控制方面的應用如何,這就就做了一些相關的測試。使用CH32V307和ESP8266實作阿裡雲物聯網平台的連接配接,并能遠端控制CH32V307開發闆上的LED燈的通斷。
首先要建立的是下位機的設計,這裡就不再贅述如何序列槽燒錄ESP8266的AT固件了,網上有很多可以參考的設計。
現在有MQTT固件,使用也簡答。我沒有使用這類固件,使用的是正常的AT固件。通過TCP建立連接配接,然後與MQTT broker聯系的。
CH32V307與ESP8266使用的是序列槽2的通信,這裡需要配置波特率為115200,并開啟相關的中斷。
void USART2_CFG(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStructure = {0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
/* USART2 TX-->A.2 RX-->A.3 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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_Tx | USART_Mode_Rx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART2, ENABLE);
}
并将指令發送到ESP8266和接收ESP266的資料
void USART2_IRQHandler(void)
{
u8 uartR=0;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
uartR= USART_ReceiveData(USART2);
if(USART1_RX_STA<USART1_MAX) //還可以接收資料
{
usart1_rxbuf[USART1_RX_STA++]=uartR; //記錄接收到的值
} else
{
USART1_RX_STA=0; //計數歸零
}
}
}
初始化ESP8266的時候需要,配置ESP8266位STA模式并與路由器建立連接配接。
uint8_t ESP8266_Init(void)
{
//清空發送和接收數組
memset(usart1_txbuf,0,sizeof(usart1_txbuf));
memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));
ESP8266_ExitUnvarnishedTrans(); //退出透傳
Delay_Ms(500);
ESP8266_ATSendString("AT+RST\r\n");
Delay_Ms(2000);
if(ESP8266_Check()==0) //使用AT指令檢查ESP8266是否存在
{
return 0;
}
memset(usart1_rxbuf,0,sizeof(usart1_rxbuf)); //清空接收緩沖
ESP8266_ATSendString("ATE1\r\n"); //關閉回顯
if(FindStr((char*)usart1_rxbuf,"OK",500)==0) //設定不成功
{
return 0;
}
return 1; //設定成功
}
這裡用到是strstr的指令,判斷是否有我們要求的傳回值。FindStr這裡的代碼是這樣規劃的。
通過多次示範,判斷是否收到資料,如果沒有收到資料或者不一樣的資料,則判斷不正确。
uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
{
int retry_nms_t = retry_nms; //逾時時間
while(strstr((char*)usart1_rxbuf,src)== NULL && retry_nms_t)//等待序列槽接收完畢或逾時退出
{
Delay_Ms(10);retry_nms_t--;
}
printf(usart1_rxbuf);
if(retry_nms_t>=0) return 1;
return 0;
}
然後就是需要去連接配接WIFI子產品了。需要提前寫入路由器的名稱和代碼
uint8_t ESP8266_ConnectAP(char* ssid,char* pswd)
{
uint8_t cnt=5;
while(cnt--)
{
memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));
ESP8266_ATSendString("AT+CWMODE_CUR=1\r\n"); //設定為STATION模式
if(FindStr((char*)usart1_rxbuf,"OK",200) != 0)
{
break;
}
}
if(cnt == 0)
return 0;
cnt=2;
while(cnt--)
{
memset(usart1_txbuf,0,sizeof(usart1_txbuf));//清空發送緩沖
memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));//清空接收緩沖
sprintf((char*)usart1_txbuf,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pswd);//連接配接目标AP
ESP8266_ATSendString((char*)usart1_txbuf);
if(FindStr((char*)usart1_rxbuf,"GOT IP",8000)!=0) //連接配接成功且配置設定到IP
{
return 1;
}
}
return 0;
}
在編寫代碼之前,我們要先搭建好阿裡雲物聯網平台,建立産品和裝置。
要建立裝置,裝置名稱随便起。
建立産品以後,需要建立的是物模型。因為我們隻是做一個簡單的LED的控制和狀态顯示,是以隻添加了一個LED即可。
在産品裡面就是需要建立裝置了,這裡裝置名稱随便起,但是必須是英文,後面需要用到的。
點選檢視裝置的三元素,填寫到程式中,生産使用者名 ID和密碼。
我們接着回複編寫我們的程式,連接配接阿裡雲。
這裡需要的是阿裡雲的IP位址,https://help.aliyun.com/product/30520.html 具體的應用架構,可以看到這裡。
if(ESP8266_ConnectServer("TCP",ServerIP,1883)!=0)
{
printf("Conn to MQTT Server !\r\n");
}
else printf("Connto MQTT Fail!\r\n");
這裡是生成三要素的代碼。
void AliIoT_Parameter_Init(void)
{
char temp[128]; //計算加密的時候,臨時使用的緩沖區
memset(ClientID,128,0); //用戶端ID的緩沖區全部清零
sprintf(ClientID,"%s|securemode=3,signmethod=hmacsha1|",DEVICENAME); //建構用戶端ID,并存入緩沖區
ClientID_len = strlen(ClientID); //計算用戶端ID的長度
memset(Username,128,0); //使用者名的緩沖區全部清零
sprintf(Username,"%s&%s",DEVICENAME,PRODUCTKEY); //建構使用者名,并存入緩沖區
Username_len = strlen(Username); //計算使用者名的長度
memset(temp,128,0); //臨時緩沖區全部清零
sprintf(temp,"clientId%sdeviceName%sproductKey%s",DEVICENAME,DEVICENAME,PRODUCTKEY); //建構加密時的明文
utils_hmac_sha1(temp,strlen(temp),Passward,DEVICESECRE,DEVICESECRE_LEN); //以DeviceSecret為秘鑰對temp中的明文,進行hmacsha1加密,結果就是密碼,并儲存到緩沖區中
Passward_len = strlen(Passward); //計算使用者名的長度
memset(ServerIP,128,0);
sprintf(ServerIP,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",PRODUCTKEY); //建構伺服器域名
//sprintf(ServerIP,"106.54.182.59"); //建構伺服器域名
ServerPort = 1883;
至于如何使用MQTT連接配接 Broker,這裡也不贅述了,有代碼,直接應用即可。
MQTT_Connect(ClientID, Username, Passward)
連接配接以後,可以看到,裝置已經顯示上線了。
我們在序列槽上也可以看到輸出的日志。
這裡是定時上傳LED狀态到阿裡雲物聯網平台的。固定的json格式,不能修改,根據前面定義的物模型編寫的。
if(Connnect_flag==1) {//有用戶端連接配接,發送到用戶端
sprintf(s_temp,"{\"id\":1,\"params\":{\"led\":%d},\"version\":\"1.0\",\"method\":\"thing.event.property.post\"}",
led_state);
MQTT_PublishData(P_TOPIC_NAME,s_temp,0);
}
這裡顯示的就是LED的狀态。目前裝置為關閉狀态。
我們可以使用裝置模式實作控制指令的下發。
當我們選擇LED為關閉或者開啟狀态的時候,在單片機上就會收到這樣的資料。
裡面json資料"\"led\":1"或者"\"led\":0"便是對LED的狀态控制。
我們在程式連判斷一下,接收到資料是哪個,就可以對相應的LED進行控制了
if(strstr(usart1_rxbuf+4,"\"led\":1"))led_state=1;
else if(strstr(usart1_rxbuf+4,"\"led\":0"))led_state=0;
if(led_state==0)GPIO_SetBits(GPIOE,GPIO_Pin_5);
else GPIO_ResetBits(GPIOE,GPIO_Pin_5);
來看看開發闆的驗證吧。綠色框就是LED狀态的變化。附上源代碼
---------------------
作者:51xlf
連結:https://bbs.21ic.com/icview-3239654-1-1.html
來源:21ic.com
此文章已獲得原創/原創獎标簽,著作權歸21ic所有,任何人未經允許禁止轉載。