int led3 = 0;
int light1 = 0;
int light2 = 0;
int light3 = 0;
extern void KEY1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);//选择 GPIO 管脚用作外部中断线路
/*参数格式:参数1:GPIO_PortSourceGPIOX,X可以是A、B、C、D、E
参数2:GPIO_PinSourceN,N可以是0~15 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断请求模式
EXTI_InitStructure.EXTI_Line = EXTI_Line1; //外部中断线
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //设置输入线路上降沿为中断请求
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);//初始化
NVIC_InitStructure.NVIC_IRQChannel =EXTI1_IRQn; //外部中断线1的中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;//抢占优先级最高
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
extern void KEY2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);//选择 GPIO 管脚用作外部中断线路
/*参数格式:参数1:GPIO_PortSourceGPIOX,X可以是A、B、C、D、E
参数2:GPIO_PinSourceN,N可以是0~15 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断请求模式
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //外部中断线
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //设置输入线路上降沿为中断请求
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);//初始化
NVIC_InitStructure.NVIC_IRQChannel =EXTI4_IRQn; //外部中断线2的中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;//抢占优先级最高
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
extern void KEY3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//选择 GPIO 管脚用作外部中断线路
/*参数格式:参数1:GPIO_PortSourceGPIOX,X可以是A、B、C、D、E
参数2:GPIO_PinSourceN,N可以是0~15 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断请求模式
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //外部中断线
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //设置输入线路上降沿为中断请求
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);//初始化
NVIC_InitStructure.NVIC_IRQChannel =EXTI3_IRQn; //外部中断线1的中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;//抢占优先级最高
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI1_IRQHandler(void)//中断函数的格式
{
if (EXTI_GetITStatus(EXTI_Line1)==SET)//判断是否为EXTI1进来,返回值为 SET or RESET
{
light1 = 1;//灯一启动自动模式
if(++count1 %2)
flag = 1;
else
led1 = 0;
TIM_SetCompare2(TIM4,led1);
EXTI_ClearITPendingBit(EXTI_Line1);//清除中断函数的标志位,否则程序将一直卡在中断函数中
}
}
void EXTI4_IRQHandler(void)//中断函数的格式
{
if (EXTI_GetITStatus(EXTI_Line4)==SET)//判断是否为EXTI1进来,返回值为 SET or RESET
{
light2 = 1;//灯二启动自动模式
if(++count2 %2)
flag = 2;
else
led2 = 0;
TIM_SetCompare3(TIM4,led2);
EXTI_ClearITPendingBit(EXTI_Line4);//清除中断函数的标志位,否则程序将一直卡在中断函数中
}
}
void EXTI3_IRQHandler(void)//中断函数的格式
{
if (EXTI_GetITStatus(EXTI_Line3)==SET)//判断是否为EXTI1进来,返回值为 SET or RESET
{
light3 = 1;//灯三启动自动模式
if(++count3 %2)
flag = 3;
else
led3 = 0;
TIM_SetCompare4(TIM4,led3);
EXTI_ClearITPendingBit(EXTI_Line3);//清除中断函数的标志位,否则程序将一直卡在中断函数中
}
}
void KEY_Led(void)
{
switch(flag)
{
case 1:
flag = 0;led1 = 10;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1))
{
TIM_SetCompare2(TIM4,led1++);
delay_ms(100);
if(led1>=100)
{
led1 = 1;
}
}
break;
case 2 :
flag = 0;led2 = 10;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4))
{
TIM_SetCompare3(TIM4,led2++);
delay_ms(100);
if(led2>=100)
{
led2 = 1;
}
}
break;
case 3 :
flag = 0;led3 = 10;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3))
{
TIM_SetCompare4(TIM4,led3++);
delay_ms(100);
if(led3>=100)
{
led3 = 1;
}
}
break;
default :
flag = 0;
break;
}
}
最后还要进行远程控制,这里主要使用的是阿里云平台的物联网,它是基于MQTT发布订阅协议实现开发板和网络的通信的,所以首先是要使用ESP8266进行联网,让开发板连接到互联网中
#include “esp8266.h”
#include <stdio.h>
//定义全局变量
volatile uint32_t esp8266_transparent_transmission_sta=0;
//配置通信串口
void esp8266_init(void)
{
USART3_Config(115200);
}
/* 配置WiFi连接热点 */
int32_t Esp8266_Init(void)
{
int32_t ret;
//esp8266_wifi利用串口3通信,前期已配置串口3
//esp8266_init();
//退出透传模式,才能输入AT指令
ret=esp8266_exit_transparent_transmission();
if(ret)
{
printf("esp8266_exit_transparent_transmission fail\r\n");
return -1;
}
printf("esp8266_exit_transparent_transmission success\r\n");
delay_ms(1000);
//复位模块
ret=esp8266_reset();
if(ret)
{
printf("esp8266_reset fail\r\n");
return -2;
}
printf("esp8266_reset success\r\n");
delay_ms(1000);delay_ms(1000);
//检查ESP8266是否正常
ret=esp8266_check();
if(ret)
{
printf("esp8266_check fail\r\n");
return -3;
}
printf("esp8266_check success\r\n");
delay_ms(1000);delay_ms(1000);
//关闭回显
ret=esp8266_enable_echo(0);
if(ret)
{
printf("esp8266_enable_echo(0) fail\r\n");
return -4;
}
printf("esp8266_enable_echo(0)success\r\n");
delay_ms(1000);delay_ms(1000);
//连接热点
ret = esp8266_connect_ap(WIFI_SSID,WIFI_PASSWORD);
if(ret)
{
printf("esp8266_connect_ap fail\r\n");
return -5;
}
printf("esp8266_connect_ap success\r\n");
delay_ms(1000);delay_ms(1000);
return 0;
}
//发送AT指令
void esp8266_send_at(char *str)
{
//清空接收缓冲区
memset((void *)Rx3Buffer,0, sizeof Rx3Buffer);
//清空接收计数值
Rx3Counter = 0;
//串口3发送数据
Usart_SendString(USART3, str);
}
//发送字节
void esp8266_send_bytes(uint8_t *buf,uint8_t len)
{
Usart_SendBytes(USART3, buf,len);
}
//发送字符串
void esp8266_send_str(char *buf)
{
Usart_SendString(USART3, buf);
}
/* 查找接收数据包中的字符串 */
int32_t esp8266_find_str_in_rx_packet(char *str,uint32_t timeout)
{
char *dest = str;
char *src = (char *)&Rx3Buffer;
//等待串口接收完毕或超时退出,strstr()寻找相应字符串,如果未找到则返回 Null;
while((strstr(src,dest)==NULL) && timeout) //while(找到了 != NULL && timeout == 0),退出循环;
{
delay_ms(1);
timeout--;
}
if(timeout)
return 0; //查找到了相关数据
//printf("asdasd\r\n");
return -1;
}
/* 检查ESP8266是否正常 */
int32_t esp8266_check(void)
{
esp8266_send_at(“AT\r\n”);
if(esp8266_find_str_in_rx_packet("OK",10000))
return -1;
return 0;
}
/* 复位 */
int32_t esp8266_reset(void)
{
esp8266_send_at(“AT+RST\r\n”);
if(esp8266_find_str_in_rx_packet("OK",10000))
return -1;
return 0;
}
/* 回显打开或关闭 */
int32_t esp8266_enable_echo(uint32_t b)
{
if(b)
esp8266_send_at(“ATE1\r\n”);
else
esp8266_send_at(“ATE0\r\n”);
if(esp8266_find_str_in_rx_packet("OK",5000))
return -1;
return 0;
}
/* 退出透传模式 */
int32_t esp8266_exit_transparent_transmission (void)
{
esp8266_send_at (“+++”);
//退出透传模式,发送下一条AT指令要间隔1秒
delay_ms(1000);
//记录当前esp8266工作在非透传模式
esp8266_transparent_transmission_sta = 0;
return 0;
}
/* 进入透传模式 */
int32_t esp8266_entry_transparent_transmission(void)
{
//进入透传模式
esp8266_send_at(“AT+CIPMODE=1\r\n”);
if(esp8266_find_str_in_rx_packet(“OK”,5000))
return -1;
delay_ms(1000);delay_ms(1000);
//开启发送状态
esp8266_send_at("AT+CIPSEND\r\n");
if(esp8266_find_str_in_rx_packet("OK",5000))
return -2;
delay_ms(1000);delay_ms(1000);
//记录当前esp8266工作在透传模式
esp8266_transparent_transmission_sta = 1;
return 0;
}
/* 检测连接状态 */
int32_t esp8266_check_connection_status(void)
{
esp8266_send_at(“AT+CIPSTATUS\r\n”);
if(esp8266_find_str_in_rx_packet("STATUS:3",10000))
if(esp8266_find_str_in_rx_packet("OK",10000))
return -1;
return 0;
}
/**
- 功能:连接热点
- 参数:
-
ssid:热点名
-
pwd:热点密码
- 返回值:
-
连接结果,非0连接成功,0连接失败
- 说明:
-
失败的原因有以下几种(UART通信和ESP8266正常情况下)
-
1. WIFI名和密码不正确
-
2. 路由器连接设备太多,未能给ESP8266分配IP
/
int32_t esp8266_connect_ap(char ssid,char* pswd)
{
#if 0
//不建议使用以下sprintf,占用过多的栈
char buf[128]={0};
//设置为STATION模式
esp8266_send_at("AT+CWMODE_CUR=1\r\n");
if(esp8266_find_str_in_rx_packet("OK",10000))
return -1;
esp8266_send_at("AT+CIPMUX=0\r\n");
if(esp8266_find_str_in_rx_packet("OK",1000))
return -2;
sprintf(buf,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pswd);
esp8266_send_at(buf);
if(esp8266_find_str_in_rx_packet("OK",5000))
if(esp8266_find_str_in_rx_packet("CONNECT",5000))
return -2;
#else
//设置为Station模式
esp8266_send_at(“AT+CWMODE_CUR=1\r\n”);
if(esp8266_find_str_in_rx_packet(“OK”,1000))
return -1;
esp8266_send_at("AT+CIPMUX=0\r\n");
if(esp8266_find_str_in_rx_packet("OK",1000))
return -2;
//连接热点
esp8266_send_at("AT+CWJAP_CUR=");
esp8266_send_at("\"");esp8266_send_at(ssid);esp8266_send_at("\"");
esp8266_send_at(",");
esp8266_send_at("\"");esp8266_send_at(pswd);esp8266_send_at("\"");
esp8266_send_at("\r\n");
//连接热点,务必等待该条指令返回WIFI GOT IP,表示连接成功后,再发送下面的指令;
while(esp8266_find_str_in_rx_packet("WIFI GOT IP",5000));
#endif
return 0;
}
/**
- 功能:使用指定协议(TCP/UDP)连接到服务器
- 参数:
-
mode:协议类型 "TCP","UDP"
-
ip:目标服务器IP
-
port:目标是服务器端口号
- 返回值:
-
连接结果,非0连接成功,0连接失败
- 说明:
-
失败的原因有以下几种(UART通信和ESP8266正常情况下)
-
1. 远程服务器IP和端口号有误
-
2. 未连接AP
-
3. 服务器端禁止添加(一般不会发生)
/
int32_t esp8266_connect_server(char mode,char* ip,uint16_t port)
{
#if 0
//使用MQTT传递的ip地址过长,不建议使用以下方法,否则导致栈溢出
//AT+CIPSTART=“TCP”,“a10tC4OAAPc.iot-as-mqtt.cn-shanghai.aliyuncs.com”,1883,该字符串占用内存过多了
char buf[128]={0};
//连接服务器
sprintf((char*)buf,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);
esp8266_send_at(buf);
#else
char buf[16]={0};
esp8266_send_at(“AT+CIPSTART=”);
esp8266_send_at(“”“); esp8266_send_at(mode); esp8266_send_at(”“”);
esp8266_send_at(“,”);
esp8266_send_at(“”“); esp8266_send_at(ip); esp8266_send_at(”“”);
esp8266_send_at(“,”);
sprintf(buf,“%d”,port);
esp8266_send_at(buf);
esp8266_send_at(“\r\n”);
#endif
if(esp8266_find_str_in_rx_packet("CONNECT",5000))
if(esp8266_find_str_in_rx_packet("OK",5000))
return -1;
return 0;
}
/* 断开服务器 */
int32_t esp8266_disconnect_server(void)
{
esp8266_send_at(“AT+CIPCLOSE\r\n”);
if(esp8266_find_str_in_rx_packet("CLOSED",2000))
if(esp8266_find_str_in_rx_packet("OK",2000))
return -1;
return 0;
}
/* 使能多链接 */
int32_t esp8266_enable_multiple_id(uint32_t b)
{
char buf[32]={0};
sprintf(buf,"AT+CIPMUX=%d\r\n", b);
esp8266_send_at(buf);
if(esp8266_find_str_in_rx_packet("OK",5000))
return -1;
return 0;
}
/* 创建服务器 */
int32_t esp8266_create_server(uint16_t port)
{
char buf[32]={0};
sprintf(buf,"AT+CIPSERVER=1,%d\r\n", port);
esp8266_send_at(buf);
if(esp8266_find_str_in_rx_packet("OK",5000))
return -1;
return 0;
}
/* 关闭服务器 */
int32_t esp8266_close_server(uint16_t port)
{
char buf[32]={0};
sprintf(buf,"AT+CIPSERVER=0,%d\r\n", port);
esp8266_send_at(buf);
if(esp8266_find_str_in_rx_packet("OK",5000))
return -1;
return 0;
}
/*
以下为简单框架设置Esp8266_WiFi模块为AP模式进行工作,即设置AP局域网
*/
void Wifi_Init(void)
{
USART3_sendstr(USART3,“AT+CWMODE=2\r\n”);//设置为 softAP+station 共存模式
delay_ms(500);
USART3_sendstr(USART3,"AT+RST\r\n");//重启
delay_ms(1500);
USART3_sendstr(USART3,"AT+CIPAP=\"192.168.1.1\"\r\n");//设置IP:192.168.1.1
delay_ms(500);
USART3_sendstr(USART3,"AT+CWSAP=\"CZJ\",\"12345678\",5,0\r\n");//设置wifi名称是CZJ,密码12345678,最多5个人同时连接,连接时无需密码;
delay_ms(500);
USART3_sendstr(USART3,"AT+CIPMUX=1\r\n");//启动多连接
delay_ms(500);
USART3_sendstr(USART3,"AT+CIPSERVER=1,8080\r\n");//设置端口8080
delay_ms(500);
printf("wifi_init end\n");//串口1输出提示;
}
//wifi模块发送语句—每次固定发送num个字节
void wifisend(char *buf,int num)
{
//每次wifi模块发送数据的时候,都事先发送一个固定前缀
char sendfront[32];//定义前缀的缓冲区
sprintf(sendfront,“AT+CIPSEND=0,%d\r\n”,num);//组合字符串
USART3_sendstr(USART3,sendfront);
delay_ms(5);
USART3_sendstr(USART3,buf);
}
//发送len长度的字符串
void USART3_sendlenth(USART_TypeDef* USARTx, uint8_t *Data,uint8_t Len)
{
while(Len–){ //判断是否到达字符串结束符
USART_SendData(USARTx, Data++);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET); //等待发送完
}
}
//发送一个完整的字符串
void USART3_sendstr(USART_TypeDef USARTx, char *Data)
{
//循环发送1个字节,直到准备发送的字节是’\0’,也就是字符串末尾,停止发送
while(*Data!=0){
USART_SendData(USARTx, *Data);
Data++;
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
}
}
最后是连入阿里云,并进行数据的上传和下发
#include “mqtt.h”
char mqtt_post_msg[526];
uint32_t mqtt_tx_len;
const uint8_t g_packet_heart_reply[2] = {0xc0,0x00};
//配置MQTT链接阿里云
int Mqtt_Connect_Aliyun(void)
{
int ret = 0;
//连接到目标TCP服务器
ret =esp8266_connect_server(“TCP”,MQTT_BROKERADDRESS,1883);
if(ret)
{
printf(“esp8266_connect_server fail\r\n”);
return -5;
}
printf(“esp8266_connect_server success\r\n”);
delay_ms(300);
//检测连接状态
ret = esp8266_check_connection_status();
if(ret)
{
printf("esp8266_check_connection_status fail\r\n");
//重新连接热点
while(Esp8266_Init());
}
printf("esp8266_check_connection_status success\r\n");
delay_ms(1000);
//进入透传模式
ret = esp8266_entry_transparent_transmission();
if(ret)
{
printf("esp8266_entry_transparent_transmission fail\r\n");
return -6;
}
printf("esp8266_entry_transparent_transmission success\r\n");
delay_ms(1000);delay_ms(1000);
//MQTT接入云端
if(mqtt_connect(MQTT_CLIENTID, MQTT_USARNAME, MQTT_PASSWD))
{
printf("mqtt_connect fail\r\n");
return -7;
}
printf("mqtt_connect success\r\n");
delay_ms(1000);
//MQTT订阅主题
if(mqtt_subscribe_topic(MQTT_SUBSCRIBE_TOPIC,0,1))
{
printf("mqtt_subscribe_topic fail\r\n");
return -8;
}
printf("mqtt_subscribe_topic success\r\n");
return 0;
}
//MQTT连接服务器的打包函数
int32_t mqtt_connect(char *client_id,char *user_name,char *password)
{
uint8_t encodedByte = 0;
uint32_t client_id_len = strlen(client_id);
uint32_t user_name_len = strlen(user_name);
uint32_t password_len = strlen(password);
uint32_t data_len;
uint32_t cnt =2;
uint32_t wait=0;
mqtt_tx_len =0;
//可变报头+Payload 每个字段包含两个字节的长度标识
data_len = 10 + (client_id_len+2) + (user_name_len+2) + (password_len+2);
//固定报头
//控制报文类型
Tx3Buffer[mqtt_tx_len++] = 0x10; //MQTT Message Type CONNECT
//剩余长度(不包括固定头部)
do
{
encodedByte = data_len % 128;
data_len = data_len / 128;
//if there are more data to encode, set the top bit of this byte
if( data_len > 0 )
encodedByte = encodedByte | 128;
Tx3Buffer[mqtt_tx_len++] = encodedByte;
} while( data_len > 0 );
//可变报头
//协议名
Tx3Buffer[mqtt_tx_len++] = 0; // Protocol Name Length MSB
Tx3Buffer[mqtt_tx_len++] = 4; // Protocol Name Length LSB
Tx3Buffer[mqtt_tx_len++] = 'M'; // ASCII Code for M
Tx3Buffer[mqtt_tx_len++] = 'Q'; // ASCII Code for Q
Tx3Buffer[mqtt_tx_len++] = 'T'; // ASCII Code for T
Tx3Buffer[mqtt_tx_len++] = 'T'; // ASCII Code for T
//协议级别
Tx3Buffer[mqtt_tx_len++] = 4; // MQTT Protocol version = 4
//连接标志
Tx3Buffer[mqtt_tx_len++] = 0xc2; // conn flags
Tx3Buffer[mqtt_tx_len++] = 0; // Keep-alive Time Length MSB
Tx3Buffer[mqtt_tx_len++] = 60; // Keep-alive Time Length LSB 60S心跳包
Tx3Buffer[mqtt_tx_len++] = BYTE1(client_id_len);// Client ID length MSB
Tx3Buffer[mqtt_tx_len++] = BYTE0(client_id_len);// Client ID length LSB
memcpy(&Tx3Buffer[mqtt_tx_len],client_id,client_id_len);
mqtt_tx_len += client_id_len;
if(user_name_len > 0)
{
Tx3Buffer[mqtt_tx_len++] = BYTE1(user_name_len); //user_name length MSB
Tx3Buffer[mqtt_tx_len++] = BYTE0(user_name_len); //user_name length LSB
memcpy(&Tx3Buffer[mqtt_tx_len],user_name,user_name_len);
mqtt_tx_len += user_name_len;
}
if(password_len > 0)
{
Tx3Buffer[mqtt_tx_len++] = BYTE1(password_len); //password length MSB
Tx3Buffer[mqtt_tx_len++] = BYTE0(password_len); //password length LSB
memcpy(&Tx3Buffer[mqtt_tx_len],password,password_len);
mqtt_tx_len += password_len;
}
while(cnt--)
{
memset((void *)Rx3Buffer,0,sizeof(Rx3Buffer));
Rx3Counter=0;
mqtt_send_bytes(Tx3Buffer,mqtt_tx_len);
//等待3s时间
wait=3000;
while(wait--)
{
delay_ms(1);
//检查连接确认固定报头
if((Rx3Buffer[0]==0x20) && (Rx3Buffer[1]==0x02))
{
if(Rx3Buffer[3] == 0x00)
{
printf("连接已被服务器端接受,连接确认成功\r\n");
//连接成功
return 0;
}
else
{
switch(Rx3Buffer[3])
{
case 1:printf("连接已拒绝,不支持的协议版本\r\n");
break;
case 2:printf("连接已拒绝,不合格的客户端标识符\r\n");
break;
case 3:printf("连接已拒绝,服务端不可用\r\n");
break;
case 4:printf("连接已拒绝,无效的用户或密码\r\n");
break;
case 5:printf("连接已拒绝,未授权\r\n");
break;
default:printf("未知响应\r\n");
break;
}
return 0;
}
}
}
}
return -1;
}
/**
- @brief MQTT订阅/取消订阅数据打包函数
- @param topic 主题
- @param qos 消息等级
- @param whether: 订阅/取消订阅请求包
- @retval 0:成功;
-
1:失败;
*/
int32_t mqtt_subscribe_topic(char *topic,uint8_t qos,uint8_t whether)
{
uint8_t encodedByte=0;
uint32_t cnt=2;
uint32_t wait=0;
uint32_t topiclen = strlen(topic);
uint32_t data_len = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度
mqtt_tx_len=0;
//固定报头
//控制报文类型
if(whether)
Tx3Buffer[mqtt_tx_len++] = 0x82; //消息类型和标志订阅
else
Tx3Buffer[mqtt_tx_len++] = 0xA2; //取消订阅
//剩余长度
do
{
encodedByte = data_len % 128;
data_len = data_len / 128;
//if there are more data to encode, set the top bit of this byte
if ( data_len > 0 )
encodedByte = encodedByte | 128;
Tx3Buffer[mqtt_tx_len++] = encodedByte;
} while ( data_len > 0 );
//可变报头
Tx3Buffer[mqtt_tx_len++] = 0; //消息标识符 MSB
Tx3Buffer[mqtt_tx_len++] = 0x01; //消息标识符 LSB
//有效载荷
Tx3Buffer[mqtt_tx_len++] = BYTE1(topiclen); //主题长度 MSB
Tx3Buffer[mqtt_tx_len++] = BYTE0(topiclen); //主题长度 LSB
memcpy(&Tx3Buffer[mqtt_tx_len],topic,topiclen);
mqtt_tx_len += topiclen;
if(whether)
{
Tx3Buffer[mqtt_tx_len++] = qos; //QoS级别
}
while(cnt--)
{
Rx3Counter=0;
memset((void *)Rx3Buffer,0,sizeof(Rx3Buffer));
mqtt_send_bytes(Tx3Buffer,mqtt_tx_len);
wait=3000; //等待3s时间
while(wait--)
{
delay_ms(1);
//检查订阅确认报头
if(Rx3Buffer[0]==0x90)
{
printf("订阅主题确认成功\r\n");
//获取剩余长度
if(Rx3Buffer[1]==3)
{
printf("Success - Maximum QoS 0 is %02X\r\n",Rx3Buffer[2]);
printf("Success - Maximum QoS 2 is %02X\r\n",Rx3Buffer[3]);
printf("Failure is %02X\r\n",Rx3Buffer[4]);
}
//获取剩余长度
if(Rx3Buffer[1]==2)
{
printf("Success - Maximum QoS 0 is %02X\r\n",Rx3Buffer[2]);
printf("Success - Maximum QoS 2 is %02X\r\n",Rx3Buffer[3]);
}
//获取剩余长度
if(Rx3Buffer[1]==1)
{
printf("Success - Maximum QoS 0 is %02X\r\n",Rx3Buffer[2]);
}
//订阅成功
return 0;
}
}
}
if(cnt)
return 0;//订阅成功
return -1;
}
/**
- @brief MQTT订阅/取消订阅数据打包函数
- @param topic 主题
- @param message 消息
- @param qos 消息等级
- @retval 0:成功;
-
1:失败;
*/
uint32_t mqtt_publish_data(char *topic, char *message, uint8_t qos)
{
//static
uint16_t id=0;
uint32_t topicLength = strlen(topic);
uint32_t messageLength = strlen(message);
uint32_t data_len;
uint8_t encodedByte;
mqtt_tx_len=0;
//有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
//QOS为0时没有标识符
//数据长度 主题名 报文标识符 有效载荷
if(qos) data_len = (2+topicLength) + 2 + messageLength;
else data_len = (2+topicLength) + messageLength;
//固定报头
//控制报文类型
Tx3Buffer[mqtt_tx_len++] = 0x30; // MQTT Message Type PUBLISH
//剩余长度
do
{
encodedByte = data_len % 128;
data_len = data_len / 128;
// if there are more data to encode, set the top bit of this byte
if ( data_len > 0 )
encodedByte = encodedByte | 128;
Tx3Buffer[mqtt_tx_len++] = encodedByte;
} while ( data_len > 0 );
Tx3Buffer[mqtt_tx_len++] = BYTE1(topicLength); //主题长度MSB
Tx3Buffer[mqtt_tx_len++] = BYTE0(topicLength); //主题长度LSB
memcpy(&Tx3Buffer[mqtt_tx_len],topic,topicLength); //拷贝主题
mqtt_tx_len += topicLength;
//报文标识符
if(qos)
{
Tx3Buffer[mqtt_tx_len++] = BYTE1(id);
Tx3Buffer[mqtt_tx_len++] = BYTE0(id);
id++;
}
memcpy(&Tx3Buffer[mqtt_tx_len],message,messageLength);
mqtt_tx_len += messageLength;
mqtt_send_bytes(Tx3Buffer,mqtt_tx_len);
//Qos等级设置的是00,因此阿里云物联网平台是没有返回响应信息的;
return mqtt_tx_len;
}
//设备状态上报
void mqtt_report_devices_status(void)
{
uint8_t led1_state = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_3) ? 0:1;
uint8_t led2_state = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_4) ? 0:1;
uint8_t NO_state = GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5) ? 0:1;
//把开发板相关的状态变量利用sprintf函数存放到一个数组里,再把该数组利用MQTT协议打包成消息报文
//根据实际平台数据对应的设备信息,更改以下信息;
sprintf(mqtt_post_msg,
"{\"method\":\"thing.service.property.set\",\"id\":\"1597870845\",\"params\":{\
\"light1\":%d,\
\"light2\":%d,\
\"light3\":%d,\
},\"version\":\"1.0.0\"}",
led1,
led2,
led3);
//上报信息到平台服务器
mqtt_publish_data(MQTT_PUBLISH_TOPIC,mqtt_post_msg,0);
}
//MQTT发送数据
void mqtt_send_bytes(uint8_t *buf,uint32_t len)
{
esp8266_send_bytes(buf,len);
}
//发送心跳包
int32_t mqtt_send_heart(void)
{
uint8_t buf[2]={0xC0,0x00};
uint32_t cnt=2;
uint32_t wait=0;
#if 0
mqtt_send_bytes(buf,2);
return 0;
#else
while(cnt–)
{
mqtt_send_bytes(buf,2);
memset((void *)Rx3Buffer,0,sizeof(Rx3Buffer));
Rx3Counter=0;
wait=3000;//等待3s时间
while(wait--)
{
delay_ms(1);
//检查心跳响应固定报头
if((Rx3Buffer[0]==0xD0) && (Rx3Buffer[1]==0x00))
{
printf("心跳响应确认成功,服务器在线。\r\n");
return 0;
}
}
}
printf("心跳响应确认失败,服务器离线\r\n");
return -1;
#endif
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
unter=0;
wait=3000;//等待3s时间
while(wait--)
{
delay_ms(1);
//检查心跳响应固定报头
if((Rx3Buffer[0]==0xD0) && (Rx3Buffer[1]==0x00))
{
printf("心跳响应确认成功,服务器在线。\r\n");
return 0;
}
}
}
printf("心跳响应确认失败,服务器离线\r\n");
return -1;
#endif
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-xK8NRpJW-1715797688482)]
[外链图片转存中…(img-au5iWRGC-1715797688483)]
[外链图片转存中…(img-MaXpURRy-1715797688483)]
[外链图片转存中…(img-e2PrOKwI-1715797688484)]
[外链图片转存中…(img-h0yu82pb-1715797688485)]
[外链图片转存中…(img-ngjGVZYh-1715797688486)]
[外链图片转存中…(img-Tt4hsir7-1715797688487)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!