小熊派GD32開發(6)— NBIoT模擬CoAP協議將數據上傳到EMQ

NBIoT模擬CoAP協議將數據上傳到EMQ

關於UDP模擬CoAP協議可以參考:NBIoT模組NB35-A開發(3)— 使用UDP模擬CoAP協議連接到EMQ

一、NBIoT啓動後準備

新建【Application】文件,並在裏面新建app_nbiot.capp_nbiot.h文件。
首先,在NBIoT模組啓動後後創建一個UDPcocket,在app_nbiot.c編寫啓動函數:

int udp_socket;

/* 描述:NBIoT啓動函數,在NBIoT啓動後,我們需要等待其駐網,然後查詢IP
		 得到IP後,申請一個UDPsocket
 * 參數:無
 * 返回值:0表示啓動成功,-1表示啓動失敗 */
int NB_Start(void)
{
	char res_buf[256];
	int cnt = 0, t = 0;
	/* 查詢是否駐網,查詢15次*/
	for(cnt = 0 ; cnt < 15; cnt++)
	{
		u1_printf("AT+CGATT?\r\n");
		for(t = 0; t < 1000; t++)
		{
			if(USART1_RX_NUM > 0) break;
			delay_1ms(1);
		}
		if(USART1_RX_NUM > 0)
		{
			USART1_RX_NUM = 0;
			if(Find_string((char *)rx1_date_buf,"+CGATT:","\r\nOK\r\n",res_buf)>0)
				if(res_buf[0] == '1') break;
		}
		delay_1ms(2000);
	}
	if(cnt == 15) return -1;
	
	/* 查詢IP地址,查詢15次*/
	for(cnt = 0 ; cnt < 15; cnt++)
	{
		u1_printf("AT+CGPADDR\r\n");
		for(t = 0; t < 1000; t++)
		{
			if(USART1_RX_NUM > 0) break;
			delay_1ms(1);
		}
		if(USART1_RX_NUM > 0)
		{
			USART1_RX_NUM = 0;
			if(Find_string((char *)rx1_date_buf,"+CGPADDR:0,","\r\nOK",res_buf)>0)
			{
				printf("\r\nNBIoT IP addr: %s\r\n",res_buf);
				break;
			}
		}
		delay_1ms(1000);
	}
	if(cnt == 15) return -1;
	
	/* 申請一個UDPsocket*/
	for(cnt = 0 ; cnt < 15; cnt++)
	{
		u1_printf("AT+NSOCR=DGRAM,17,0\r\n");
		for(t = 0; t < 1000; t++)
		{
			if(USART1_RX_NUM > 0) break;
			delay_1ms(1);
		}
		if(USART1_RX_NUM > 0)
		{
			USART1_RX_NUM = 0;
			if(Find_string((char *)rx1_date_buf,"\r\n","\r\nOK",res_buf)>0)
			{
				udp_socket = res_buf[0] - '0';
				printf("\r\nudp_socket: %d\r\n",udp_socket);
				break;
			}	
		}
		delay_1ms(1000);
	}
	if(cnt == 15) return -1;
	return 0;
}

其中,用到的尋找字符串函數爲

/* 描述:尋找特定字符串
 * 參數 *pcBuf:需要進行操作的字符串
 * 參數 *left :需要搜索的字符串的左邊的標識符
 * 參數 *right: 需要搜索的字符串的右邊的標識符
 * 參數 *pcRes:輸出參數,尋找到的字符串
 * 返回值:返回尋找到的字符串長度,0表示失敗   */
int Find_string(char *pcBuf,char *left,char *right, char *pcRes)
{
	int str_len = 0;
    char *pcBegin = NULL;
    char *pcEnd = NULL;
    pcBegin = strstr(pcBuf, left);					/* 找到左側數據 */
    pcEnd = strstr(pcBegin+strlen(left), right);	/* 找到右側數據 */
    if(pcBegin == NULL || pcEnd == NULL || pcBegin > pcEnd)
    {
        printf("string name not found!\n");
        return 0;
    }
    else
    {
        pcBegin += strlen(left);
		str_len = pcEnd-pcBegin;
        memcpy(pcRes, pcBegin, str_len);
		pcRes[str_len] = '\0';
        return str_len;
    }
}

然後我們在主函數中調用,編譯下載運行,可以看到,創建UDPsocket成功,從啓動到創建UDPsocket成功一共花了16秒
在這裏插入圖片描述

二、UDP模擬CoAP協議上報數據

在app_nbiot.c編寫上報函數:

/* 描述:NBIoT模擬CoAP上報數據
 * 參數 *ipaddr :服務器的IP地址字符串
 * 參數 *topic  :EMQ轉換成MQTT協議後的主題,不能大於15個字符長度
 * 參數 *payload:有效負載,即我們真正想要上傳的數據
 * 返回值:無
 */
int NB_Send_data(char * ipaddr, char * topic, char * payload)
{
	static uint16_t msg_id = 100;
	static char udp_data[256];
	static char palyload_hex[256];
	static char topic_hex[256];
	static char res_buf[256];
	int t = 0;
	msg_id++;
	str2hex(topic,topic_hex);
	str2hex(payload,palyload_hex);
	sprintf(udp_data,"4203%04x5562b46d7174740%01x%s49633d636c69656e743105753d746f6d08703d736563726574ff%s",
						msg_id,strlen(topic)%16,topic_hex,palyload_hex);
	u1_printf("AT+NSOST=%d,%s,5683,%d,%s\r\n",udp_socket,ipaddr,strlen(udp_data)/2,udp_data);
}

裏面用到了字符串轉16進制格式函數

/* 描述:將字符轉換爲16進制格式
 * 參數 *str:需要轉換的字符串
 * 參數 *hex:轉換後的16進制格式
 * 返回值:無					*/
void str2hex(char* str, char* hex)
{
    const char* cHex = "0123456789abcdef";
    int i=0;
    for(int j =0; str[j] != '\0'; j++)
    {
        unsigned int a =  (unsigned int) str[j];
        hex[i++] = cHex[(a & 0xf0) >> 4];
        hex[i++] = cHex[(a & 0x0f)];
    }
    hex[i] = '\0';
}

三、每隔1秒上報一次數據

我們設置一個定時器,定時1秒,

timer5_init(10000,12000);	/* 定時1000ms*/

然後在定時器中斷服務函數裏將上報標誌置1

uint8_t update_flag = 0;
void TIMER5_IRQHandler(void)
{
	timer_flag_clear(TIMER5,TIMER_FLAG_UP);		/* 定時器更新中斷的標識位需要手動清除 */
	if (update_flag == 0) update_flag = 1;
}

然後再主函數中,首先調用啓動函數,若啓動超時,則復位

	while(NB_Start())
	{
		u1_printf("AT+NRB\r\n");	/* 重啓*/
		while(USART1_RX_NUM == 0) 
			;
		if(USART1_RX_NUM >0)
		{
			printf("NBIoT: %s\r\n",rx1_date_buf);
			USART1_RX_NUM = 0;
		}
	}
	printf("start OK\r\n");

然後當update_flag置1的時候上報數據,並處理返回值

    while(1)
	{
		if(update_flag  == 1)
		{
			update_flag = 0;
			times++;
			LED(times%2);
			sprintf(data_buf,"I am NBIoT , %d.",times);
			NB_Send_data("39.96.35.207", "topic1", data_buf);
			printf("Data send to EMQ...\r\n");
		}
		if(USART1_RX_NUM >0)
		{
			USART1_RX_NUM = 0;
			if(Find_string((char *)rx1_date_buf,"+NSONMI:","\r\n",res_buf)>0)
			{
				u1_printf("AT+NSORF=%d,%d\r\n",udp_socket,res_buf[2]-'0');
			}
			printf("NBIOT: %s\r\n",rx1_date_buf);			
		}
		if(USART_RX_NUM >0)
		{
			USART_RX_NUM = 0;
			u1_printf("%s",rx0_date_buf);			
		}	
    }

編譯,運行程序,可以在EMQ平臺接收到數據:
在這裏插入圖片描述

四、代碼

完整代碼我存放在碼雲,可以查看:https://gitee.com/william_william/GD32.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章