当前位置:   article > 正文

52单片机连接ESP8266烧入固件使用MQTT协议将温湿度上传至OneNET云平台_51单片机和esp8266之间收发数据用的什么通信协议

51单片机和esp8266之间收发数据用的什么通信协议

52单片机连接ESP8266烧入固件使用MQTT协议连接OneNET云平台

20240410备注:非常抱歉我不能帮助各位解决问题,我已经好多年不看嵌入式的东西了,本文只提供参考,遇见问题还得大家去搜索自己解决。

参考:
-----------------------------------------------------------------------------------------
创建一个 MQTT 协议产品:
版权声明:本文为CSDN博主「Yonas-Luo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_17351161/article/details/107716689
------------------------------------------------------------------------------------------
ESP8266固件库烧录(AT固件库与Node固件库):
版权声明:本文为CSDN博主「风铃叶雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jidudong0673/article/details/105222924
------------------------------------------------------------------------------------------
将c52单片机的串口设置为115200波特率:
版权声明:本文为CSDN博主「Day____Day____Up」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37281289/article/details/80304532
-------------------------------------------------------------------------------------------
STM32单片机ESP8266发送数据到WiFi接收端代码实现:
版权声明:本文为CSDN博主「花开莫与流年错_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_17242837/article/details/72464956
--------------------------------------------------------------------------------------------
基于8266WIFI模块实现智能手机与51单片机的通信入门:
版权声明:本文为CSDN博主「IamDaodaoLi」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/IamDaodaoLi/article/details/79715074
-----------------------------------------------------------------------------------------------
ESP8266MOD、刷可以使用AT指令的固件、作为客户端向贝壳云端发送固定数据:
版权声明:本文为CSDN博主「FightingBoom」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fightingboom/article/details/83315486
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

固件烧入

本文使用刷入 OneNET 提供的 ESP8266 固件的方法,你甚至不需要了解MQTT协议,既可实现远程控制。使用 STC89C52+ESP8266 来接入云平台。

硬件:ESP8266-01S和USB转串口模块

esp8266 模块型号为:ESP8266-01s,它的Flash 大小为 8M ,这是一个重要的参数,在刷新固件时需要使用到
esp8266有8个引脚分别做一下介绍

引脚功能
VCC3.3V电源
GND接地
RX数据接收
TX数据发送
EN高电平工作;低电平模块供电关掉
RST外部Reset信号,低电平复位,高电平工作(默认高)(有的命名为CH_PD)
IO0工作模式选择:悬空:FlashBoot,工作模式;下拉:UARTDownload,下载模式
IO2(1)开机上电时必须为高电平,禁止硬件下拉;(2)内部默认已拉高

ESP8266和串口连接

串口模块ESP8266模块
VCC3.3VVCC(3.3V) 和CH_PD
TXRX
RXTX
GNDGND
注:烧入固件时IO0接GND才能烧写成功

ESP8266和MCU连接

MCUESP8266模块
VCC3.3VVCC(3.3V) 和CH_PD
TXRX
RXTX
GNDGND
注:这样连接MCU和ESP就可以正常通信了

固件烧入

烧入的固件使用的是:大佬分享的 https://open.iot.10086.cn/bbs/thread-25723-1-1.html
烧入固件使用的工具是:flash_download_tool
我下载后的百度云链接:链接:https://pan.baidu.com/s/1cU6NJoDb2b3bks-KPYmK1Q
提取码:8023

软件

需要的软件
在这里插入图片描述

在这里插入图片描述
除了COM(串口和电脑连接的端口号)
其余选择必须和图片一样
注意:esp8266-01sflash大小是8M,FLASH SIZE必须是8Mbit
比特率是115200
最后点击START等待下在完成

测试AT指令,使用的电脑串口助手和esp8266通信测试

需要注意的是
所有AT指令均需加上\r\n作为结束。
所有AT指令回复均已\r\n作为结束.
注:只介绍部分指令的工能不做过多赘述esp8266的反馈信息(想了解更多信息就参考【ESP8266-直连OneNET-内置协议】中的文件【OneNET接入固件-MQTT-AT指令说明文档-v1.1.docx】百度云链接分享中有)

AT指令作用
AT+IOTSTATUS查询与OneNET连接状态
AT+CIPSTATUS查询WIFI连接状态
AT+CWJAP=ssid,password手动链接WiFi
AT+IOTCFG=devid,proid,auth_info连接OneNET(devid 为设备DI,proid 为产品ID,auth_info为鉴权信息)
AT+IOTSEND=a,b,c,(d)发送数据流 【a:(0:数据是数值类型)(1:数据是字符串类型)(2:数据是gps)】【b:数据流名】【c:数据值】【d:数据值 (只有上传GPS时才会用到)】
AT+IOTSTATUS查询OneNET连接状态
收到不合法的AT指令+Event:ERROR Cmd

注:最好把自己使用到的指令都试一试,联网和不联网、连接onenet和不连接onenet时esp回馈信息是不一样的,建议自己尝试

程序

**我写的程序只有上传数据,没有onenet控制MCU功能,需要注意没有onenet控制MCU功能,**
  • 1

使用的STC89C52单片机一般产生的波特率是9600,但是烧入这个固件ESP8266串口通信波特率是115200,为了使MCU和ESP 通信正常使用定时器2产生115200的波特率

主函数

main.c

#include "usart.h"
#include "esp8266.h"
#include "timer0.h"

//sbit led1=P2^0;
//sbit led2=P2^1;
sbit led3=P2^2;

void main_delayms(uint xms)
{
	uint i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<120;j++);
}

void main()
{
	uchar temp=20;
	uchar hum=40;

	count_m=0;//定时器0计数
	count_s=0;
	time0_flag=0;

	Rx_len=0;
	Rx_data_len=0;

	Timer0_Init();
	set52_baudrate(11.0592, 115200);//串口初始化
	ESP_Init();//esp8266初始化

//	led1=1;
//	led2=1;
	led3=1;
	main_delayms(5000);
	while(1)
	{
		temp ++ ;//做实验使用的所以数据是随机生成的
		hum ++ ;
		if(temp>=30)temp=20;
		if(hum>=95)hum=40;
//		led1=1;
//		led2=0;
		ESP_Send_Data(temp,hum);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

串口程序

usart.c

#include "usart.h"

uchar idata RxBuf[70];
uchar idata TxBuf[70];

uchar RIflag;
uchar TIflag;
uchar Rx_len;
uchar Rx_data_len;
/*波特率为9600*/
//void UART_init(void)
//{
//    SCON = 0x50;        //串口方式1
// 
//    TMOD = 0x20;        // 定时器使用方式2自动重载
//    TH1 = 0xFD;    //9600波特率对应的预设数,定时器方式2下,TH1=TL1
//    TL1 = 0xFD;
// 
//    TR1 = 1;//开启定时器,开始产生波特率
//}

/**自定义波特率产生函数**/
/*
frequency:晶振频率,11.0592
baudrate: 需要的波特率,115200
*/
void set52_baudrate(float frequency, long int baudrate)
{
	uint itmp;
	uchar tlow,thigh;

	TMOD =0x20;
	itmp=(int)(65536-(frequency*1000000)/(baudrate*32));
	thigh=itmp/256;
	tlow=itmp%256;
	SCON=0x5c;
	T2CON=0x30;
	RCAP2H=thigh;
	RCAP2L=tlow;
	TH2=thigh;
	TL2=tlow;
	TR2=1;  //set ok
	//REN=1;
	ET2=1;  //T2中断
	EA=1;	//总中断
	ES=1;	//串口中断
	PS=1;	//
}
 
/*发送一个字符*/
void UART_send_byte(uchar dat)
{
	ES=0;//关闭中断,新添加的
	SBUF = dat;       //把数据放到SBUF中
	while (TI == 0);//未发送完毕就等待
	TI = 0;    //发送完毕后,要把TI重新置0
	ES=1;//关闭中断,新添加的
}
 
/*发送一个字符串*/
void UART_send_string(uchar *buf)
{
	while (*buf != '\0')
	{
		UART_send_byte(*buf++);
	}
}

///*串口接收一个字节数据*/
//void UART_receive_string( uchar *RxBuffer )
//{
//	ES=0;
//	*RxBuffer = SBUF;
//	ES=1;
//}
//
/*串口中断*/
void USART_interrupt() interrupt 4
{
	uchar ss;
	if(RI==1)//接收中断
	{
		RI=0;		
		ss=SBUF;
		if(ss!='\n')//esp返回的字符串是以\r\n为结尾的
		{
			 RxBuf[Rx_len]=ss;
			 Rx_len++;			 
		}
		else
		{
			ES=0;//每次接收完成就将中断关闭
			RIflag=1;//一个字符串几首完成才会将此标志位置为1

			strcat(RxBuf,"\r\n");
			Rx_len=Rx_len+2;
			Rx_data_len=Rx_len;
			Rx_len=0;
		}
	}
	if(TI==1)//发送中断
	{
		TI=0;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105

usart.h

#include"reg52.h"
#include"stdio.h"
#include"stdlib.h"
#include"intrins.h"
#include <string.h>

#ifndef __USART__H
#define __USART__H

#define uchar unsigned char
#define uint unsigned int

extern uchar idata RxBuf[70] ;
extern uchar idata TxBuf[70] ;

extern uchar RIflag;
extern uchar TIflag;
extern uchar Rx_len;
extern uchar Rx_data_len;

#define usart_buf_size strlen(RxBuf)

//void UART_init();//初始化串口
void set52_baudrate(float frequency, long int baudrate);
void UART_send_byte(uchar dat);//发送一个字节数据

void UART_send_string(uchar *buf);//发送一个字符串
//void UART_receive_string( uchar *RxBuffer );//接收字符串,


#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

ESP8266程序

esp8266.c

#include"reg52.h"
#include"esp8266.h"
#include "usart.h"
#include "timer0.h"

uchar idata ESP_Send_Temp[]="AT+IOTSEND=0,Temp,28\r\n";
uchar idata ESP_Send_Hum[]="AT+IOTSEND=0,Hum,54\r\n";

sbit led1=P2^0;
sbit led2=P2^1;
sbit led5=P2^4;//esp指示灯,会是一闪一闪的,表示esp正常工作呢

void esp_delayms(uint xms)
{
	uint i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<120;j++);
}

uchar Check_ESP_connect_onenet()//和onenet连接时返回1,没有连接时返回0
{
	ES=1;
	RIflag=0;
	memset(RxBuf,0,usart_buf_size);
	UART_send_string(AT_IOTSTATUS);//查询与OneNET连接状态
	esp_delayms(test_time);
	if(RIflag==1)
	{
		RIflag=0;
		if(RxBuf[1]=='I' && RxBuf[2]=='O' && RxBuf[3]=='T' && RxBuf[12]=='0')//连接着onenet呢
		{
			memset(RxBuf,0,usart_buf_size);
			Rx_data_len=0;
			ES=0;
			return 1;
		}
		else
		{
			memset(RxBuf,0,usart_buf_size);
			Rx_data_len=0;
			ES=0;
			return 0;
		}
	}
	ES=0;
	return 0;
}

void ESP_connect_IOTCFG()//和onenet连接
{
	ES=1;
	RIflag=0;
	memset(RxBuf,0,usart_buf_size);
	UART_send_string(AT_IOTCFG);//配置登录信息
	esp_delayms(test_time);
	if(RIflag==1)
	{
		ES=0;
		RIflag=0;
		if(RxBuf[7]=='O' && RxBuf[8]=='n' && RxBuf[9]=='e' && RxBuf[14]=='L')//成功登陆onenet
		{
			memset(RxBuf,0,usart_buf_size);
			Rx_data_len=0;
		}

		else//没有连接WiFi时,连接不成功,没有连接成功
		{
			memset(RxBuf,0,usart_buf_size);
			Rx_data_len=0;
		}
	}
	ES=0;//没有接收到反馈信息
}

/*检查esp是否接入WiFi*/
uchar ESP_AP_Check()
{
	led5=1;
		
	ES=1;//打开中断,
	esp_delayms(2);	
	RIflag=0;
	memset(RxBuf,0,usart_buf_size);

	UART_send_string(AT_CIPSTATUS);//发送AT指令判断是否连接WiFi
	esp_delayms(test_time);
	if(RIflag==1)//接收到esp返回信息,串口接收到数据之后产生中断,在中断中将此标志位置为1
	{
		RIflag=0;
//		UART_send_string(strcat(RxBuf,"\r\n"));//把接收到的信息返回

		if(RxBuf[1]=='S' && RxBuf[2]=='T' && RxBuf[3]=='A' && RxBuf[8]=='5')//WiFi连接状态,是5说明连接WiFi成功  +STATUS:5
		{
			memset(RxBuf,0,usart_buf_size);
			Rx_data_len=0;

			ES=0;//关闭中断
			if(Check_ESP_connect_onenet()==0)//返回值是0说明没有和onenet连接
			{
				if(time0_flag==1)//定时器时间,3分钟重新连接一次
				{
					time0_flag=0;
					ESP_connect_IOTCFG();//WiFi连接的时候判断是否和服务器连接着呢
					esp_delayms(1000);
				}
				return 1;
			}
			else//返回值是1说明和onenet连接呢
			{
				return 1;
			}
		}
		else//检测出来和WiFi没有连接
		{
			return 0;
		}
	}
	ES=0;
	return 0;
}

void ESP_Init()
{
	uchar f;
	ES=0;
	memset(RxBuf,0,usart_buf_size);
	f = ESP_AP_Check();
	ESP_connect_IOTCFG();//先发送一下,就算没有连接上,连接WiFi后也会自动连接onenet
}

/*MCU向ESP发送温湿度数据*/
void ESP_RX_Data(uchar temp, uchar hum)
{	
	ES=1;
	
	ESP_Send_Temp[18]='0'+temp/10;
	ESP_Send_Temp[19]='0'+temp%10;
	if(ESP_Send_Temp[17]!=',')
		ESP_Send_Temp[17]=',';	
	UART_send_string(ESP_Send_Temp);

	esp_delayms(10);

	memset(TxBuf,0,usart_buf_size);
	ESP_Send_Hum[17]='0'+hum/10;
	ESP_Send_Hum[18]='0'+hum%10;
	if(ESP_Send_Hum[16]!=',')
		ESP_Send_Hum[16]=',';	
	UART_send_string(ESP_Send_Hum);

	esp_delayms(5);

	ES=0;
}

void ESP_Send_Data(uchar temp, uchar hum)
{
	uchar esp_ap=0;
	led1=1;
	led2=0;
	esp_ap=ESP_AP_Check();
	if(esp_ap==1)//WiFi正确连接
	{
		esp_ap=0;
		ESP_RX_Data(temp,hum);
		esp_delayms(100);
		led1=0;
		led2=1;
	}


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172

esp8266.h

#include"reg52.h"

#define uchar unsigned char //宏定义一个无符号的char类型
#define uint unsigned int //宏定义一个无符号的int类型

#ifndef __ESP8266__H
#define __ESP8266__H

#define	test_time 1000

/*******AT指令说明*********/
//我只是用到这几个AT命令
#define AT_CIPSTATUS "AT+CIPSTATUS\r\n"  //查询WIFI连接状态
#define AT_CIPSTATUS_Event "+STATUS:5\r\n"  //接入成功

#define AT_CWJAP "AT+CWJAP=YJ8023,12345678\r\n"  //手动接入AP
#define AT_CWJAP_Event "+Event:WIFI CONNECTED\r\n"  //接入成功

#define AT_IOTCFG "AT+IOTCFG=713051942,422751,0625\r\n"  //配置登录信息
#define AT_IOTCFG_Event "+Event:OneNET Link:PROID: 422751,AUIF: 0625,DEVID:713051942\r\n"  //成功登陆

#define AT_IOTSTATUS "AT+IOTSTATUS\r\n"  //查询与OneNET连接状态
#define AT_IOTSTATUS_Event "+IOT:status:0\r\n"  //如还未接入路由就发送指令登录OneNET时

extern uchar idata ESP_Send_Temp[];
extern uchar idata ESP_Send_Hum[];
/****************/
uchar Check_ESP_connect_onenet();
uchar ESP_AP_Check();
void ESP_connect_IOTCFG();
void ESP_Init();
void ESP_RX_Data(uchar temp, uchar hum);//是子函数
void ESP_Send_Data(uchar temp, uchar hum);//在主函数调用
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

定时器0

timer0.c

#include "timer0.h"

uchar count_s;
uchar count_m;
uchar time0_flag;

void Timer0_Init(void)
{
    TMOD |= 0x01;//设置定时器为工作方式1  C/T位为1的时候是计数器模式,为0的时候是定时器模式,前四位是定时器1,后四位是定时器0
    TL0 = (65536 - 1000)%256;    //装初值,低8位
    TH0 = (65536 - 1000)/256;   //高8位
    ET0 = 1;    //开定时器的中断
    TR0 = 1;    //开定时器
    EA = 1;     //开总中断
}

void Timer0(void) interrupt 1
{
    TL0 = (65536 - 45872)%256;    //装初值,低8位//初值是1000即1ms
    TH0 = (65536 - 45872)/256;   //高8位   //50ms中断一次
    count_s++;
    if(count_s == 20)//一秒钟
    {
        count_s = 0;
		count_m++;//60就是1分钟
		if(count_m==60 * 3)
		{
			count_m=0;
			time0_flag=1;
		}
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

timer0.h

#include"reg52.h"
#include"stdio.h"
#include"stdlib.h"
#include"intrins.h"

#define uchar unsigned char //宏定义一个无符号的char类型
#define uint unsigned int //宏定义一个无符号的int类型

#ifndef __TIMER0__H
#define __TIMER0__H

extern uchar count_s;
extern uchar count_m;
extern uchar time0_flag;

void Timer0_Init(void);


#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我写的程序不好可以优化地方很多,但是达到了我的预期,我时间紧张就没有做过多修改,分享出来是为了让时间紧凑的人不至于走太多的弯路,谢谢大家观看,有意见请提出来,评论区回复不一定会及时,但是看到会及我所能帮你解决问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/440833
推荐阅读
相关标签
  

闽ICP备14008679号