自习室灯光系统(1)

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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合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%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值