点击查看代码
/**
*********************************************************************************
* @file main.c
* @author
* @version
* @date 2024/07/23
* @brief
*********************************************************************************
**/
#include "stm32f4xx.h" //必须包含
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
uint8_t u3_recvbuf[512] = {0}; //WIFI的接收缓冲区
uint32_t u3_recvcnt = 0; //接收缓冲器的计数器
uint8_t u3_sendbuf[1024] = {0}; //WIFI的发送缓冲区
uint32_t u3_sendcnt = 0; //发送缓冲器的计数器
#define BYTE0(data) ( *( (char *)&data + 0 ) )
#define BYTE1(data) ( *( (char *)&data + 1 ) )
#define BYTE2(data) ( *( (char *)&data + 2 ) )
#define BYTE3(data) ( *( (char *)&data + 3 ) )
//需要根据自己的修改
#define CLIENT_ID "k1ltu6J15a3.dht11|securemode=2,signmethod=hmacsha256,timestamp=1721893050123|"
#define USERNAME "dht11&k1ltu6J15a3"
#define PASSWD "bd56fb03f88bd2c5f3aad6035a3f467f5e98d4d3a37bfa8091c05398b8d46ed0"
#define PUBLISH_TOPIC "/sys/k1ltu6J15a3/dht11/thing/event/property/post"
//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART1_IRQHandler(void)
{
uint8_t data;
//判断中断是否发生
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//从USART1中接收一个字节
data = USART_ReceiveData(USART1); //一次只能接收一个字节
//把接收到的数据转发出去
USART_SendData(USART1,data);
}
}
//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART3_IRQHandler(void)
{
//判断中断是否发生
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//从USART3中接收一个字节
u3_recvbuf[u3_recvcnt++] = USART_ReceiveData(USART3); //一次只能接收一个字节
}
}
//延时微秒 注意:Systick是24bit的递减计数器 约等于798915us,所以参数不可以超过这个值
void delay_us(u32 nus)
{
SysTick->CTRL = 0; // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
SysTick->LOAD = (nus * 21) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
SysTick->VAL = 0; // 清除当前数值寄存器的值
SysTick->CTRL = 1; // 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
SysTick->CTRL = 0; // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
}
//延时毫秒 注意:Systick是24bit的递减计数器 约等于798ms,所以参数不可以超过这个值
void delay_ms(u32 nms)
{
SysTick->CTRL = 0; // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
SysTick->LOAD = (nms * 21*1000) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
SysTick->VAL = 0; // 清除当前数值寄存器的值
SysTick->CTRL = 1; // 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
SysTick->CTRL = 0; // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
}
void USART1_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开了GPIO端口时钟 PA9和PA10
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置GPIO引脚 注意:复用模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置串口参数+对串口初始化
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure);
//配置NVIC参数 + 对NVIC初始化
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择USART1的中断源,接收到数据则触发中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//打开串口
USART_Cmd(USART1, ENABLE);
}
void USART3_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开了GPIO端口时钟 PB10和PB11
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
//打开USART3的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11 , GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10 , GPIO_AF_USART3);
//配置GPIO引脚 注意:复用模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_10;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//配置串口参数+对串口初始化
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure);
//配置NVIC参数 + 对NVIC初始化
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择USART3的中断源,接收到数据则触发中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
//打开串口
USART_Cmd(USART3, ENABLE);
}
//利用串口发送一个字符串
void USART1_SendString(const char *str)
{
while(*str)
{
USART_SendData(USART1,*str++);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
}
//利用串口发送一个字符串
void USART3_SendString(const char *str)
{
while(*str)
{
USART_SendData(USART3,*str++);
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );
}
}
//利用串口发送n字节
void USART3_SendBytes(const char *str,uint32_t len)
{
while(len--)
{
USART_SendData(USART3,*str++);
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );
}
}
//MQTT的CONNECT报文,目的是用于连接服务器,并且该报文必须是第一个
bool mqtt_connect(char *clientid,char *username,char *passwd)
{
uint32_t cnt = 0;
uint32_t clientid_len = strlen(clientid); //客户端id的长度
uint32_t username_len = strlen(username); //用户名的长度
uint32_t passwd_len = strlen(passwd); //密码的长度
//用于存储剩余长度 剩余长度 = 可变报头(10) + 有效载荷(客户端id长度 + 2 + 用户名长度 + 2 + 密码长度 + 2)
uint32_t remain_length = 10 + (2+clientid_len) + (2+username_len) + (2+passwd_len);
//1.对发送/缓冲区进行初始化
memset((char *)u3_sendbuf,0,1024);
u3_sendcnt = 0;
//2.固定报头
u3_sendbuf[u3_sendcnt++] = 0x10; //CONNECT
//3.对剩余长度进行编码
do
{
uint8_t encodedByte = remain_length % 128;
remain_length = remain_length / 128;
// if there are more data to encode, set the top bit of this byte
if ( remain_length > 0 )
{
encodedByte = encodedByte | 128;
}
u3_sendbuf[u3_sendcnt++] = encodedByte;
}
while ( remain_length > 0 );
//4.可变报头
u3_sendbuf[u3_sendcnt++] = 0; //协议名称
u3_sendbuf[u3_sendcnt++] = 4;
u3_sendbuf[u3_sendcnt++] = 'M';
u3_sendbuf[u3_sendcnt++] = 'Q';
u3_sendbuf[u3_sendcnt++] = 'T';
u3_sendbuf[u3_sendcnt++] = 'T';
u3_sendbuf[u3_sendcnt++] = 4; //协议版本
u3_sendbuf[u3_sendcnt++] = 0xC2; //连接标志
u3_sendbuf[u3_sendcnt++] = 0; //保持连接
u3_sendbuf[u3_sendcnt++] = 120; //保持2分钟
//5.有效载荷 都是字符串 每个字符串前面都有2字节用于表示字符串长度 客户端id 用户名 密码
u3_sendbuf[u3_sendcnt++] = BYTE1(clientid_len); //MSB
u3_sendbuf[u3_sendcnt++] = BYTE0(clientid_len); //LSB
memcpy(&u3_sendbuf[u3_sendcnt],clientid,clientid_len);
u3_sendcnt += clientid_len;
u3_sendbuf[u3_sendcnt++] = BYTE1(username_len); //MSB
u3_sendbuf[u3_sendcnt++] = BYTE0(username_len); //LSB
memcpy(&u3_sendbuf[u3_sendcnt],username,username_len);
u3_sendcnt += username_len;
u3_sendbuf[u3_sendcnt++] = BYTE1(passwd_len); //MSB
u3_sendbuf[u3_sendcnt++] = BYTE0(passwd_len); //LSB
memcpy(&u3_sendbuf[u3_sendcnt],passwd,passwd_len);
u3_sendcnt += passwd_len;
//7.等待接收服务器的响应报文
while(1)
{
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
//6.把CONNECT报文发送
USART3_SendBytes((char *)u3_sendbuf,u3_sendcnt);
USART1_SendString("send ok\r\n"); //为了测试
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
if(u3_recvbuf[0] == 0x20 && u3_recvbuf[1] == 0x02)
{
//成功
if(u3_recvbuf[3] == 0x00)
{
USART1_SendString("连接已接受,连接已被服务端接受\r\n"); //为了测试
return true;
}
//异常
else
{
switch(u3_recvbuf[3])
{
case 0x01: USART1_SendString("连接已拒绝,不支持的协议版本\r\n"); break;
case 0x02: USART1_SendString("连接已拒绝,不合格的客户端标识符\r\n"); break;
case 0x03: USART1_SendString("连接已拒绝,服务端不可用\r\n"); break;
case 0x04: USART1_SendString("连接已拒绝,无效的用户名或密码\r\n"); break;
case 0x05: USART1_SendString("连接已拒绝,未授权\r\n"); break;
}
}
}
}
return false;
}
//发布 服务等级固定=0,则不需要报文标志符,另外服务器也不会进行响应
void mqtt_publish(char *topic,char *databuf)
{
uint32_t cnt = 0;
uint32_t topic_len = strlen(topic); //主题的长度
uint32_t databuf_len = strlen(databuf); //有效载荷的长度
//用于存储剩余长度 剩余长度 = 可变报头 + 有效载荷
uint32_t remain_length = (2+topic_len) + (databuf_len);
//1.对发送/缓冲区进行初始化
memset((char *)u3_sendbuf,0,1024);
u3_sendcnt = 0;
//2.固定报头
u3_sendbuf[u3_sendcnt++] = 0x30; //PUBLISH
//3.对剩余长度进行编码
do
{
uint8_t encodedByte = remain_length % 128;
remain_length = remain_length / 128;
// if there are more data to encode, set the top bit of this byte
if ( remain_length > 0 )
{
encodedByte = encodedByte | 128;
}
u3_sendbuf[u3_sendcnt++] = encodedByte;
}
while ( remain_length > 0 );
//4.可变报头
u3_sendbuf[u3_sendcnt++] = BYTE1(topic_len); //MSB
u3_sendbuf[u3_sendcnt++] = BYTE0(topic_len); //LSB
memcpy(&u3_sendbuf[u3_sendcnt],topic,topic_len);
u3_sendcnt += topic_len;
//5.有效载荷
memcpy(&u3_sendbuf[u3_sendcnt],databuf,databuf_len);
u3_sendcnt += databuf_len;
//6.把PUBLISH报文发送
USART3_SendBytes((char *)u3_sendbuf,u3_sendcnt);
USART1_SendString(" publish send ok\r\n"); //为了测试
}
void mqtt_keepalive(void)
{
uint8_t buf[2] ={0xC0,0x00};
//1.对发送/缓冲区进行初始化
memset((char *)u3_sendbuf,0,1024);
u3_sendcnt = 0;
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
USART3_SendBytes((char *)buf,2);
if(u3_recvbuf[0] == 0xD0 && u3_recvbuf[1] == 0x00)
{
USART1_SendString("心跳响应\r\n"); //为了测试
}
}
int main()
{
//1.硬件的初始化
USART1_Config(9600);
USART3_Config(115200);
//退出透传 +++
USART3_SendString("+++");
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
//2.配置ESP8266参数
USART3_SendString("AT\r\n"); //测试指令
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
//设置模式 STA
USART3_SendString("AT+CWMODE_CUR=1\r\n");
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
//热点名称:lmx 热点密码:12345678
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
USART3_SendString("AT+CWJAP_DEF=\"lmx\",\"12345678\"\r\n"); //连接热点 需要修改
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
//连接服务器,阿里云物联网平台的服务器的URL:iot-06z00iiy4zswde1.mqtt.iothub.aliyuncs.com 端口:1883
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
USART3_SendString("AT+CIPSTART=\"TCP\",\"iot-06z00hfdtkxecfe.mqtt.iothub.aliyuncs.com\",1883\r\n"); //需要修改
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
//使能透传
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
USART3_SendString("AT+CIPMODE=1\r\n"); //进入透传 >出现之后,才表示进入透传
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
//进入透传
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
USART3_SendString("AT+CIPSEND\r\n"); //进入透传 >出现之后,才表示进入透传
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
USART1_SendString((char *)u3_recvbuf);
//发送CONNECT
memset((char *)u3_recvbuf,0,512);
u3_recvcnt = 0;
mqtt_connect(CLIENT_ID,USERNAME,PASSWD);
while(1)
{
//数据上报 JSON格式
mqtt_publish(PUBLISH_TOPIC,"{\"id\":\"123\",\"version\":\"1.0\",\"params\":{\"temp\":20},\"method\":\"thing.event.property.post\"}");
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
mqtt_keepalive();
}
}