stm32 mqtt

记录两种是stm32 mqtt实现方法

1.使用keil自带库MQTTPacket实现

安装install

安装完成后点击运行时环境按钮

选中MQTTpacket

代码实现添加和使用

首先包含头文件  #include "MQTTPacket.h"
static MQTTTransport mytransport;  //定义MQTT全局传输结构体
static uint8_t  mqtt_parse_buf[1024]   = {0};  临时解析数据数组大小自己看数据包大小

实现两个函数:
//4g发送数据  阻塞发送
void transport_sendPacketBuffer(unsigned char* buf, int buflen)
{
	HAL_UART_Transmit(&huart_4g, buf, buflen, 5000);
	HAL_UART_Receive_IT(&huart_4g, &temp_value_4g, 1);
}
//4g获取数据  没有数据返回0
int transport_getdatanb(void *sck, unsigned char* buf, int count)  
{
	if(mqtt_4f_buf_index >= count && HAL_GetTick() - mqtt_4g_tick >= 3) {
		memcpy(buf, mqtt_4g_buf, count);
		memcpy(mqtt_4g_buf, mqtt_4g_buf + count, mqtt_4f_buf_index - count);  //复制到前面
		mqtt_4f_buf_index = mqtt_4f_buf_index - count;
		return count;
	}
	return 0;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == HUART_4G){
		mqtt_4g_buf[mqtt_4f_buf_index++] = temp_value_4g;
		mqtt_4f_buf_index = mqtt_4f_buf_index >= sizeof(mqtt_4g_buf) ? 0 : mqtt_4f_buf_index;  //超出缓冲区
		HAL_UART_Receive_IT(&huart_4g, &temp_value_4g, 1);
		mqtt_4g_tick = HAL_GetTick();
	}
}

发送采用阻塞,接收采用中断,发送完成后必须重新开始中断接收不然会出现不能接收的现象。

数据通信采用4G串口透传,其他方式以此类推都可以使用

先初始化4G模块或者其他模块或者socket
初始化连接到服务器
//MQTT init
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
	int buflen = sizeof(mqtt_parse_buf);
	mytransport.getfn = transport_getdatanb;
	mytransport.state = 0;
	//
	data.keepAliveInterval = 180;
	data.cleansession = 1;
	data.clientID.cstring = CCID;    //clientId唯一id
	data.username.cstring = "admin";
	data.password.cstring = "123456";
	//连接
	int len = MQTTSerialize_connect(mqtt_parse_buf, buflen, &data);
	transport_sendPacketBuffer(mqtt_parse_buf, len);

	//等待确认
	while(1) {
		int frc = MQTTPacket_readnb(mqtt_parse_buf, buflen, &mytransport);
		if (frc == CONNACK){
			unsigned char sessionPresent, connack_rc;
			if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, mqtt_parse_buf, buflen) != 1 || connack_rc != 0){
				printf("Unable to connect, return code %d\n", connack_rc);
				Soft_Reset();
			}
			break;
		}
		else if (frc == -1) {
			printf("mqtt login error\n");
		}
	}
	printf("MQTT OK");

初始换完成后执行MQTT循环

void MQTT_4G_POLL(void)
{
	static uint8_t no_reply_count = 0;
	static uint32_t mqtt_poll_tick = 0;
	static int len = 0, buflen = sizeof(mqtt_parse_buf);

	int msgtype = MQTTPacket_readnb(mqtt_parse_buf, buflen, &mytransport);
	switch(msgtype) {
		case -1:
			mqtt_4f_buf_index = 0;
			mytransport.state = 0;
			break;
		case PUBLISH:
		{
			unsigned char dup;
			int qos, len = 0;
			unsigned char retained;
			unsigned short msgid;
			int payloadlen_in = 0;
			unsigned char* payload_in;
			MQTTString receivedTopic;
			MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic, &payload_in, &payloadlen_in, mqtt_parse_buf, sizeof(mqtt_parse_buf));
			
			mqtt_recive_publish(receivedTopic.lenstring.data, receivedTopic.lenstring.len, (char *)payload_in, payloadlen_in);
			if(qos == 1) {
				len = MQTTSerialize_ack(mqtt_parse_buf, sizeof(mqtt_parse_buf), PUBACK, dup, msgid);
				transport_sendPacketBuffer(mqtt_parse_buf, len);
			}
			if(qos == 2) {
				len = MQTTSerialize_ack(mqtt_parse_buf, sizeof(mqtt_parse_buf), PUBREC, dup, msgid);
				transport_sendPacketBuffer(mqtt_parse_buf, len);
			}
			break;
		}
		case SUBACK:
		{
			unsigned short packet_id = 0;
			int count = 0, req_qos = 0;
			if(MQTTDeserialize_suback(&packet_id, 1, &count, &req_qos, mqtt_parse_buf, sizeof(mqtt_parse_buf)) == 1 && packet_id > 0) {
				//printf("subsucess:%d\n", subscribe_devices[254]);
			}
			break;
		}
		case PINGRESP:
			no_reply_count = 0;  //收到心跳回复
			break;
		default:
			break;
	}
	//50s 发送心跳
	if(HAL_GetTick() - mqtt_poll_tick > 50000) {

		if(no_reply_count > 3) {
			Soft_Reset();
		}			
		len = MQTTSerialize_pingreq(mqtt_parse_buf, buflen);
		transport_sendPacketBuffer(mqtt_parse_buf, len);
		no_reply_count++;
		mqtt_poll_tick = HAL_GetTick();  //更新检测时间
	}
}


发布和订阅函数实现

//发布消息
static void publish(char * topic, unsigned char * payload) 
{
	MQTTString topicString = MQTTString_initializer;
	topicString.cstring = topic;
	int len = MQTTSerialize_publish(mqtt_parse_buf, sizeof(mqtt_parse_buf), 0, 0, 0, 0, topicString, payload, strlen((char *)payload));
  transport_sendPacketBuffer(mqtt_parse_buf, len);
}
//订阅
static void subscribe(char * subtopic_buf)
{
	static uint16_t picket_id = 1;
	
	MQTTString topicString = MQTTString_initializer;
	int req_qos = 1, len = 0;
	int buflen = sizeof(mqtt_parse_buf);
	//订阅
	topicString.cstring = subtopic_buf;
	len = MQTTSerialize_subscribe(mqtt_parse_buf, buflen, 0, ++picket_id, 1, &topicString, &req_qos);
	transport_sendPacketBuffer(mqtt_parse_buf, len);
}






 

 

2 LWIP MQTT

#define MEMP_NUM_SYS_TIMEOUT 8 

 

MQTT连接失败,报错:CONNECTION_REFUSED_NOT_AUTHORIZED;

用户名和密码没有通过验证,新版本mqttconnect()中没有用户名和密码的代码,添加后就可以正常连接了。

err_t
mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, mqtt_connection_cb_t cb, void *arg,
                    const struct mqtt_connect_client_info_t *client_info)
{
  err_t err;
  size_t len;
  u16_t client_id_length;
  /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */
  u16_t remaining_length = 2 + 4 + 1 + 1 + 2;
  u8_t flags = 0, will_topic_len = 0, will_msg_len = 0;

  LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL);
  LWIP_ASSERT("mqtt_client_connect: ip_addr != NULL", ip_addr != NULL);
  LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL);
  LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL);

  if (client->conn_state != TCP_DISCONNECTED) {
    LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n"));
    return ERR_ISCONN;
  }

  /* Wipe clean */
  memset(client, 0, sizeof(mqtt_client_t));
  client->connect_arg = arg;
  client->connect_cb = cb;
  client->keep_alive = client_info->keep_alive;
  mqtt_init_requests(client->req_list);

  /* Build connect message */
  if (client_info->will_topic != NULL && client_info->will_msg != NULL) {
    flags |= MQTT_CONNECT_FLAG_WILL;
    flags |= (client_info->will_qos & 3) << 3;
    if (client_info->will_retain) {
      flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
    }
    len = strlen(client_info->will_topic);
    LWIP_ERROR("mqtt_client_connect: client_info->will_topic length overflow", len <= 0xFF, return ERR_VAL);
    LWIP_ERROR("mqtt_client_connect: client_info->will_topic length must be > 0", len > 0, return ERR_VAL);
    will_topic_len = (u8_t)len;
    len = strlen(client_info->will_msg);
    LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL);
    will_msg_len = (u8_t)len;
    len = remaining_length + 2 + will_topic_len + 2 + will_msg_len;
    LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL);
    remaining_length = (u16_t)len;
  }

  /* Don't complicate things, always connect using clean session */
  flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;

  len = strlen(client_info->client_id);
  LWIP_ERROR("mqtt_client_connect: client_info->client_id length overflow", len <= 0xFFFF, return ERR_VAL);
  client_id_length = (u16_t)len;
  len = remaining_length + 2 + client_id_length;
  LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL);
  remaining_length = (u16_t)len;
	//添加 用户验证
	if(client_info->client_user != NULL) {
		flags |= MQTT_CONNECT_FLAG_USERNAME;
		len = remaining_length + 2 + strlen(client_info->client_user);
	}
	remaining_length = (u16_t)len;
	if(client_info->client_pass != NULL) {
		flags |= MQTT_CONNECT_FLAG_PASSWORD;
		len = remaining_length + 2 + strlen(client_info->client_pass);
	}
	remaining_length = (u16_t)len;
	//
  if (mqtt_output_check_space(&client->output, remaining_length) == 0) {
    return ERR_MEM;
  }

  client->conn = tcp_new();
  if (client->conn == NULL) {
    return ERR_MEM;
  }

  /* Set arg pointer for callbacks */
  tcp_arg(client->conn, client);
  /* Any local address, pick random local port number */
  err = tcp_bind(client->conn, IP_ADDR_ANY, 0);
  if (err != ERR_OK) {
    LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err));
    goto tcp_fail;
  }
  LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%"U16_F"\n", ipaddr_ntoa(ip_addr), port));

  /* Connect to server */
  err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb);
  if (err != ERR_OK) {
    LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err));
    goto tcp_fail;
  }
  /* Set error callback */
  tcp_err(client->conn, mqtt_tcp_err_cb);
  client->conn_state = TCP_CONNECTING;

  /* Append fixed header */
  mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_CONNECT, 0, 0, 0, remaining_length);
  /* Append Protocol string */
  mqtt_output_append_string(&client->output, "MQTT", 4);
  /* Append Protocol level */
  mqtt_output_append_u8(&client->output, 4);
  /* Append connect flags */
  mqtt_output_append_u8(&client->output, flags);
  /* Append keep-alive */
  mqtt_output_append_u16(&client->output, client_info->keep_alive);
  /* Append client id */
  mqtt_output_append_string(&client->output, client_info->client_id, client_id_length);
  /* Append will message if used */
  if ((flags & MQTT_CONNECT_FLAG_WILL) != 0) {
    mqtt_output_append_string(&client->output, client_info->will_topic, will_topic_len);
    mqtt_output_append_string(&client->output, client_info->will_msg, will_msg_len);
  }
	//添加用户验证
	if((flags & MQTT_CONNECT_FLAG_USERNAME) != 0) {
		mqtt_output_append_string(&client->output, client_info->client_user, strlen(client_info->client_user));
	}
	if((flags & MQTT_CONNECT_FLAG_PASSWORD) != 0)	{
		mqtt_output_append_string(&client->output, client_info->client_pass, strlen(client_info->client_pass));
	}
  return ERR_OK;

tcp_fail:
  tcp_abort(client->conn);
  client->conn = NULL;
  return err;
}

 

连接发布接收函数

void socket_subscribe(char *topic)
{
	static char subscribe_topic[255][32] = {0};
	if(strlen(topic) <= 32) {
		if(mqtt_client_is_connected(&client)) {
			mqtt_subscribe(&client, topic, 1, NULL, NULL);
		}
	}
}
void socket_publish(char * topic, unsigned char * payload) 
{
	if(mqtt_client_is_connected(&client)) {
		mqtt_publish(&client, topic, (char *)payload, strlen((char *)payload), 1, 0, NULL, NULL);
	}
}

static const char *g_topic = NULL;
static u32_t g_topic_len = 0;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
	if(topic != NULL) {
		g_topic = topic;
		g_topic_len = strlen(g_topic);
	}		
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
  if(flags & MQTT_DATA_FLAG_LAST) {
			mqtt_recive_publish(g_topic, g_topic_len, (char *)data, len);
  } 
}

static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
  if(status == MQTT_CONNECT_ACCEPTED) {
    mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);

		printf("sucessed\n");
  } else {
		printf("dis sucessed\n");
		mqtt_socket_connect(client);
	}
}

static void mqtt_socket_connect(mqtt_client_t *client)
{
	
	static struct mqtt_connect_client_info_t ci;
	static char client_id[32];
  memset(&ci, 0, sizeof(ci));

	sprintf(client_id, "Network%04X%04X%04X", (*((uint32_t *)0x1FFF7A10 + 0)), (*((uint32_t *)0x1FFF7A10 + 1)), (*((uint32_t *)0x1FFF7A10 + 2)));
	printf("%s\n", client_id);
  ci.client_id = client_id;
	ci.client_user = "admin";
  ci.client_pass = "123456";
	ci.keep_alive = 60;
	ci.will_topic = NULL;
  mqtt_client_connect(client, &mqtt_ip, 1883, mqtt_connection_cb, NULL, &ci);
}

SIM7600CE TCP流程

//硬件上一定要把给模块断电的功能加上!

//如果是一个单独电源芯片给模块供电,可以把电源芯片的使能脚引到MCU上,控制模块断电,如果这样不行,建议用MOS管做开关,由MCU控制MOS管,给模块断电。MOS管压降只有0.1V,而且MOS管能通过的电流大。需要重启时,正常情况下,使用POWERKEY关机开机来重启模块,但我们不排除在极端情况下,POWERKEY无效,这时RESET也可能无效,就需要给模块断电来解决。而反复断电可能导致模块文件系统损坏

//即:需要重启模块时,正常情况用POWERKEY,POWERKEY 无效再断电



//初始化流程!
//1.开机之后循环发送"AT",每500毫秒发一次,一般发两三个之后就能收到OK了,表示串口通了
//2.收到正确应答后,发AT+CPIN?,如果没收到正确应答,就循环发送,每500毫秒发一次,最多发20次
//3.当AT+CPIN?收到正确应答后,发AT+CSQ,如果没收到正确应答,就循环发送,每500毫秒发一次,最多发100次
//4.当AT+CSQ收到正确应答后(CSQ的值只要是非零就是正确应答),发AT+CGREG?,如果没收到正确应答,就循环发送,每500毫秒发一次,最多发100次
//5.当AT+CGREG?收到正确应答后(0,1和0,5都是正确应答),表示模块初始化及注册网络已成功,这时才可进行数据连接!
//注意!以上初始化流程必须执行,当模块处于网络不好的条件下,注册时间会延长,如果不执行,可能会在不知道模块是否已注册上网络的情况下开始数据连接,
//导致数据连接不成功,不成功后重启模块,又重连,导致反复重启死循环
//以上命令超时时间为500毫秒,如果发送AT命令500毫秒后仍得不到响应,视为超时。
//所有AT命令均可在AT手册中搜到,以查看具体用法


//以上初始化流程在所有对7100的应用中都必须加上


//以下命令回复的超时时间除了特别说明的,剩下全为500毫秒
//发送 AT,测试串口或USB口是否通
AT
OK
//查询SIM卡是否已准备就绪
AT+CPIN?
+CPIN: READY//必须判断READY与否

OK//不能判断OK
//查询信号强度
AT+CSQ
+CSQ: 17,99//必须判断前一个数字,来确定信号强度,比如这里是17(范围0-31,31表示信号最强),后一个数字不用判断

OK//不能判断OK
//查询网络是否附着上
AT+CGREG?
+CGREG: 0,1//必须判断0,1或0,5才是正确的

OK//不能判断OK,0,1/0,2/0,3/0,5等等都会回OK
//到此初始化检测通过,说明模块可以正常工作了
//查询版本号
AT+SIMCOMATI
Manufacturer: SIMCOM INCORPORATED
Model: SIMCOM_SIM7100C
Revision: 4534B03SIM7100C
SIM7100C_4534_150326_V1.00
QCN: 
IMEI: 866154020007660
+GCAP: +CGSM
DeviceInfo: 200,170

OK
//查询网络设置
AT+CNMP?
+CNMP: 2

OK
//查询当前网络
AT+CPSI?
+CPSI: LTE,Online,460-00,0x1816,27551521,245,EUTRAN-BAND40,38950,5,5,-68,-1046,-778,19

OK
//CMNET是中国移动,3GNET是联通,电信是CTNET
AT+CGDCONT=1,"IP","CMNET"
OK
AT+CSOCKSETPN=1
OK
AT+CIPMODE=0
OK
AT+NETOPEN
OK//不能判断OK

+NETOPEN: 0//默认超时时间120秒,必须出现0,才说明NETOPEN成功,如果该数字不是0,说明打开失败
AT+IPADDR
+IPADDR: 10.21.110.228//只要有IP,就说明NETOPEN成功

OK
AT+CIPOPEN=0,"TCP","116.247.119.165",9336//非阻塞式 
OK//不能判断OK

+CIPOPEN: 0,0//默认超时时间120秒,这条表示在通道0上,链接服务器成功。前一个数字表示通道号,后一个数字必须为0,才说明CIPOPEN成功,如果该数字不是0,说明CIPOPEN失败
AT+CIPSEND=0,5
>ABCDE
OK//不能判断OK

+CIPSEND: 0,5,5//默认超时时间120秒,这条表示在通道0上,要发5个,实际也发送了5个,需要判断收到这条,才表示发送成功
AT+CIPCLOSE=0//关闭通道0的SOCKET链接

OK

+CIPCLOSE: 0,0//默认超时时间120秒,表示模块和服务器的SOCKET链接关闭了
AT+NETCLOSE//释放模块IP地址

OK

+NETCLOSE: 0//默认超时时间120秒,表示模块将IP地址释放了

 

 

 

 

 

 

 

 

 

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值