stm32實作mqtt的發布和訂閱遇到的問題和需要注意的地方
本文中使用的是正點原子的stm32f407系列,使用的是KEIL+stm32cubemx的構建方式,其中硬體驅動和lwip可以通過stm32cubemx直接配置進來,由此可以減少在底層驅動上消耗時間,可以更加專注于應用層的開發,
1.首先要讓stm32單片機連上網,同時要清楚自己的網線另一頭是接在什么地方的,如果是路由器上那么他是支持DHCP的方式來動態分配分配IP地址的,但是如果是交換機那就要看交換機是否具有DHCP的功能,一般情況下交換機是沒有DHCP功能的,那就只能使用靜態IP的分配的方式,同時自己分配的網段要和你的主機一致,不然也是連不上網的,
同時還需要注意的是stm32f407有三個網路相關的引腳被復用了 他們分別是:
PG14 ETH_TXD1
PG13 ETH_TXD0
PG11 ETH_TX_EN
還有ETH_RESET引腳需要在以太網初始化時用到
PD3 ETH_RESET
ETH_RESET要在ethernetif.c檔案下面的low_level_init()中使用到,如下面的代碼所示
static void low_level_init(struct netif *netif)
{
HAL_StatusTypeDef hal_eth_init_status;
/* Init ETH */
uint8_t MACAddr[6] ;
heth.Instance = ETH;
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
heth.Init.Speed = ETH_SPEED_100M;
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
heth.Init.PhyAddress = LAN8720A_PHY_ADDRESS;
MACAddr[0] = 0x02;
MACAddr[1] = 0x00;
MACAddr[2] = 0x00;
MACAddr[3] = 0x00;
MACAddr[4] = 0x00;
MACAddr[5] = 0x00;
heth.Init.MACAddr = &MACAddr[0];
heth.Init.RxMode = ETH_RXPOLLING_MODE;
heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
/* USER CODE BEGIN MACADDRESS */
HAL_GPIO_WritePin(ETH_RESET_GPIO_Port,ETH_RESET_Pin,GPIO_PIN_RESET);
HAL_Delay(55);
HAL_GPIO_WritePin(ETH_RESET_GPIO_Port,ETH_RESET_Pin,GPIO_PIN_SET);
/* USER CODE END MACADDRESS */
*另外還有在while回圈中一定要在250ms內呼叫一次MX_LWIP_Process()函式同時輪詢呼叫 ethernetif_set_link(netif_default)函式,引數為extern struct netif netif_default;需要在main()函式之前定義好,
2.成功連上網后初始化mqtt有關變數,注意mqtt_info一定是全域變數,否則在后面的API函式中不能夠作為引數進行傳遞,
mqtt_client_t* lwip_mqtt;
struct mqtt_connect_client_info_t mqtt_info =
{
"9999",
NULL,
NULL,
60,
NULL,
NULL,
0,
0
};
然后在所有驅動初始化完成之后呼叫下面的函式,給lwip_mqtt動態分配空間
lwip_mqtt = mqtt_client_new();
然后連接mqtt服務器
uint8_t mqtt_init(mqtt_client_t *client)
{
err_t err;
ip_addr_t my_ip_addr;
//memset(&mqtt_info,0,sizeof(mqtt_info));
ip4_addr_set_u32(&my_ip_addr, ipaddr_addr("XXX.XXX.XXX.XXX"));
//mqtt_set_inpub_callback(lwip_mqtt,mqtt_incoming_publish_cb,mqtt_incoming_data_cb,&mqtt_info);
/**********************************************************************************************************
mqtt_client_connect函式
arg1:mqtt句柄,arg2:mqtt服務器地址 arg3:埠號,arg4:連接回呼函式,arg5:引入引數arg arg6:mqtt_info句柄
************************************************************************************************************/
err = mqtt_client_connect(client,(const ip_addr_t*) &my_ip_addr,XXXX,mqtt_connect_cb,&mqtt_info,&mqtt_info);
if(err != ERR_OK)
{
printf("mqtt connect err,ecode %d\r\n",err);
return -1;
}
return 0;
}
這里要注意:
1.原來使用IP4_ADDR()除錯的時候發現得到的IP地址不正確,使用ip4_addr_set_u32()才是正確的
2.mqtt_set_inpub_callback一定要在mqtt_connect_cb()回呼函式之后再使用,否則訂閱的主題有發布的資料也不能夠觸發mqtt_incoming_data_cb()回呼函式,懷疑是MQTT連接之前設定回呼函式失敗,
3.還有就是MEMP_NUM_SYS_TIMEOUT這個定義需要再加上2,就像下圖所示,因為要將MQTT的超時時間算在里面,

然后是mqtt_connect_cb()回呼函式
void mqtt_connect_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
LWIP_UNUSED_ARG(client);//消除警告
//struct mqtt_connect_client_info_t* client_info = (struct mqtt_connect_client_info_t*)arg;
mqtt_set_inpub_callback(lwip_mqtt,mqtt_incoming_publish_cb,mqtt_incoming_data_cb,arg);
if(status == MQTT_CONNECT_ACCEPTED)
{
printf("mqtt 連接成功\r\n");
/*訂閱或者不訂閱topic函式 引數1:client句柄,引數2:topic,引數3:qos,引數4:回呼函式,引數5:是否訂閱
1:sub 0:unsub
*/
mqtt_sub_unsub(client,"test123",0,mqtt_sub_request_cb,&mqtt_info,1);
}
}
LWIP_UNUSED_ARG()是為了消除引數未使用的警告,
下面這個回呼函式是用來處理訂閱和取消訂閱的請求的
void mqtt_sub_request_cb(void *arg, err_t err)
{
printf("訂閱成功\r\n");
printf("errcode:%d\r\n",err);
}
下面是mqtt_incoming_data_cb()回呼函式,這個是用來處理訂閱主題中所訂閱到的資訊是什么,
void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
printf("接受到的資料為:%s\r\n",data);
}
下面的回呼函式是用來處理哪個主題發布的資訊
void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
printf("Incoming publish at topic \" %s \" with total length %u\r\n", topic, (unsigned int)tot_len);
}
最后是實作定時發布的功能,一秒發布一次資料
u32_t timer;
u32_t current_timer;
char payload[20] = "hello everyone!";
timer = HAL_GetTick();
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
MX_LWIP_Process();
ethernetif_set_link(netif_default);
current_timer = HAL_GetTick();
if(current_timer-timer > 1000)
{
timer = current_timer;
/****************************************************************************************
MQTT 發布函式
arg1:mqtt句柄 arg2:發布主題 arg3:發布內容 arg4:發布內容大小 arg5:qos訊息質量 arg6:醫囑訊息
arg7:MQTT發布回呼函式 arg8:引入引數,
***************************************************************************************/
mqtt_publish(lwip_mqtt,"test456",payload,strlen(payload),0,0,mqtt_pub_request_cb,&mqtt_info);
}
}
另外MQTT_OUTPUT_RINGBUF_SIZE是MQTT發布訊息txbuffer的大小,MQTT_VAR_HEADER_BUFFER_LEN是MQTT訂閱主題接收訊息的rxbuffer的大小
MQTT_OUTPUT_RINGBUF_SIZE默認是256byte,MQTT_VAR_HEADER_BUFFER_LEN默認是128byte,如果要發送大一點的資料空間就不夠了,可以修改大小但是不能改的過于大,自己嘗試過1024byte就會出錯,這個問題的原因是的opt.h中的MEM_SIZE不夠了,stm32cubemx默認初始生成的是1600byte,我們可以對他進行修改,這樣就能夠滿足大資料量的主題發布和接收了
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/332169.html
標籤:其他
上一篇:啟明分享|IDO-SBC2D06開發板功能介紹SD卡
下一篇:零代碼編程開發檔案
