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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合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%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!