自习室灯光系统

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE );
//2、配置分频,因为最大不能超过14MHz 72/6=12
RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//3、配置GPIOA和ADC结构体 PA5 作为模拟通道输入引脚                         
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);	

ADC_DeInit(ADC1); //复位ADC1

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 2;	//顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
//4、使能ADC1
ADC_Cmd(ADC1, ENABLE);
//5、校准并等待校准结束
ADC_ResetCalibration(ADC1);	//使能复位校准  
 
while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束

ADC_StartCalibration(ADC1);	 //开启AD校准

while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束

}

void Adc2_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;

// 1、开启时钟ADC2的时钟和GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 2、配置分频,因为最大不能超过14MHz 72/6=12
RCC_ADCCLKConfig(RCC_PCLK2_Div6);   // 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
// 3、配置GPIOB和ADC结构体 PB0 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        // 模拟输入引脚
GPIO_Init(GPIOB, &GPIO_InitStructure);

ADC_DeInit(ADC2); // 复位ADC2

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  // ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;       // 模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 顺序进行规则转换的ADC通道的数目
ADC_Init(ADC2, &ADC_InitStructure); // 根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
// 4、使能ADC2
ADC_Cmd(ADC2, ENABLE);
// 5、校准并等待校准结束
ADC_ResetCalibration(ADC2); // 使能复位校准

while (ADC_GetResetCalibrationStatus(ADC2)); // 等待复位校准结束

ADC_StartCalibration(ADC2); // 开启AD校准

while (ADC_GetCalibrationStatus(ADC2)); // 等待校准结束

}

uint16_t AD_GetValue(u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期

ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
 
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果

}

uint16_t AD2_GetValue(u8 ch)
{
// 设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC2, ch, 1, ADC_SampleTime_239Cycles5); // ADC2, ADC通道, 采样时间为239.5周期

ADC_SoftwareStartConvCmd(ADC2, ENABLE); // 使能指定的ADC2的软件转换启动功能

while (!ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC)); // 等待转换结束

return ADC_GetConversionValue(ADC2); // 返回最近一次ADC2规则组的转换结果

}

//多获取几次数据求平均值更稳定
uint16_t Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=AD_GetValue(ch);
delay_ms(5);
}
return temp_val/times;
}

uint16_t Get_Adc2_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=AD2_GetValue(ch);
delay_ms(5);
}
return temp_val/times;
}


根据上面的代码可以实现自动控制灯光的亮度,但出于节能减排的目的,希望在无人的时候能实现自动关灯,在有人的时候才会开灯,所以又加了一个人体红外检测函数,对区域内是否有人进行检测



#include “HC_501.h”

void HC_501_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB端口时钟

					//定义一个设置GPIO的结构体变量	
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;					//设置PB4,PB5,PB6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    	//设置PB4,PB5,PB6引脚为浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);            		 	//初始化GPIOB

}

void HC_501_Check(void)
{
if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4))
{
TIM_SetCompare2(TIM4,0);
}
if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5))
{
TIM_SetCompare3(TIM4,0);
}
if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6))
{
TIM_SetCompare4(TIM4,0);
}
}


基于以上三个代码就可以实现自动控灯的目的,在有人且光照强度较低的时候实现自动开灯


接下来还要实现手动控制灯的亮度,手动控制有两种,一种是用电容开关,点击电容开关时可以切换灯的状态,比如开灯或者关灯,长按电容开关时可以改变灯的亮度



#include “key.h”
#include “delay.h”
#include <stdio.h>

int flag =0;
int count1 = 0;
int count2 = 0;
int count3 = 0;
int led1 = 0;
int led2 = 0;
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);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

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

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

pic,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);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-h4iu0jX1-1715797724341)]

[外链图片转存中…(img-QmJSl7AN-1715797724342)]

[外链图片转存中…(img-70gG62sA-1715797724342)]

[外链图片转存中…(img-Dgg7hlkf-1715797724343)]

[外链图片转存中…(img-XUXpd4s0-1715797724343)]

[外链图片转存中…(img-tSBuNODW-1715797724344)]

[外链图片转存中…(img-UjHa3iyC-1715797724345)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

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

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

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值