草庐IT

STM32使用ESP8266模块AT指令连接心知天气API获取天气信息

小蔡可耐 2023-11-14 原文

由于之前使用STM32单片机来开发一些物联网的小项目,接触到了WIFI模块ESP8266,所以写下来记录一下。本文主要介绍的是STM32通过发送AT指令集来控制ESP8266 WIFI模块连接WiFi并与心知天气API建立TCP连接获取天气信息。

一、硬件连接

ESP8266我使用的是正点原子的ATK-ESP8266,已经提前烧录好AT指令集固件,至于固件的烧录可以参考正点原子的教程或者去安可信官网查找相关资料即可。STM32单片机设计有USB转串口即可。

STM32 VCC    ->  ESP8266 VCC
STM32 TXD2   ->  ESP8266 RXD
STM32 RXD2   ->  ESP8266 TXD
STM32 GND    ->  ESP8266 GND

这里用到了两组串口,USART1用于打印调试信息到电脑的串口助手中;USART2用于主控与ESP8266的通信。串口配置代码直接沿用了正点原子提供的。在这里就不贴出来了。


二、连接WiFi

ESP8266有三种WiFi模式,分别是station模式,AP模式和station+AP模式。简单来说,station模式就是8266作为连接WiFi的设备;AP模式就是8266作为提供WiFi的设备,相当于手机的热点功能。连接WiFi最简单的步骤就两步:8266为station模式和连接WiFi。

设置WiFi模式

设置WiFi模式的AT指令有AT+CWMODEAT+CWMODE_CURAT+CWMODE_DEF。后面两种指令的区别是后缀为DEF的指令会将设置保存到flash中,重新上电不需要再次设置。第一种不带后缀的指令,官方文档写的是不建议使用,所以就用最后一种就行了。以下是官方文档的具体说明


连接WiFi

连接WiFi指令和设置WiFi模式指令一样有三个版本,这里使用AT+CWJAP_DEF来说明。

ssid是你要连接WiFi的名字,pwd是密码,bssid是当有多个相同名字WiFi区分用的。值得注意的是,WiFi名字或者密码有特殊符号要使用\进行转义。
所以,连接WiFi只需要发送以下指令即可:

//设置为station模式
AT+CWMODE_DEF=1\r\n
//连接WiFi
AT+CWJAP_DEF="你的WiFi名","你的WiFi密码"\r\n

三、建立TCP连接

TCP连接这里以连接心知天气获取天气信息为例。主要为3步:与心知天气网站建立TCP连接,开启透传,发送GET请求获取天气信息。

心知天气

心知天气是提供天气信息的API,可以使用GET请求获取JSON格式的天气信息,有免费的版本可用,非常适合嵌入式应用的开发。具体文档说明和账号申请可自行官网查看(https://www.seniverse.com) 。心知天气会为每个账户提供公钥和私钥,这里我们只用到私钥,只需替代掉接口网址中your_api_key为自己的私钥即可。

https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=zhaoqing&language=en&unit=c


建立TCP连接

建立TCP,UDP或SSL连接使用指令AT+CIPSTART,具体参数如下:

因为我们要使用透传与网站通信,所以TCP必须设置为单连接;连接类型为TCP;远端IP可以是心知天气的具体IP地址,也可以用域名api.seniverse.com来代替;心知天气提供该服务的端口号是80端口。最后,建立TCP连接的AT指令是:

//建立TCP连接,参数为 连接类型 远端IP 远端端口号
AT+CIPSTART="TCP","api.seniverse.com",80\r\n

开启透传

开启透传首先要使用AT+CIPMODE=mode设置传输模式,mode为0是普通传输模式,mode为1是透传模式。设置完成后使用指令AT+CIPSEND开始传输,具体指令参数说明如下:

开启透传后无需写发送数据的长度,直接发送AT+CIPSEND即可,8266返回>即表示成功进入透传,此时无法再发送AT指令,发送的字符将会被当做数据全部发送给对方。若要退出透传返回AT指令模式,则要单独发送+++,注意这里无需换行。

//设置传输模式为透传模式
AT+CIPMODE=1\r\n
//开始透传
AT+CIPSEND\r\n
//退出透传
+++

GET请求

在进入透传之后就可以发送我们的GET请求。在GET和空格后加上要访问的接口地址就可以获取到网站返回给我们的天气信息了。记得更改私钥和在后面加上换行。

GET https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=zhaoqing&language=en&unit=c\r\n


四、核心代码

//检测接收到的应答
uint8_t* Check_Command(char *str)
{
	char *strx = 0;
	if(USART2_RX_STA&0X8000)		//接收到一次数据了
	{ 
		USART2_RX_BUF[USART2_RX_STA&0X7FFF]=0;//添加结束符
		strx=strstr((const char*)USART2_RX_BUF,(const char*)str);
	}
	return (uint8_t *)strx;
}

//向8266发送命令
//cmd:发送的命令字符串
//ack:期待的应答结果
//waittime:等待时间(单位:10ms)
//返回值:1,发送成功(得到了期待的应答结果)
//       0,发送失败
uint8_t Send_Command(char *cmd, char *ack, uint8_t waittime)
{
	uint8_t res=1; 
	USART2_RX_STA=0;
	u2_printf("%s\r\n",cmd);	//发送命令
	if(ack&&waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			HAL_Delay(10);
			if(USART2_RX_STA&0X8000)//接收到期待的应答结果
			{
				if(Check_Command(ack))
				{
					printf("ack:%s\r\n",(uint8_t*)USART2_RX_BUF);
					break;//得到有效数据 
				}
				USART2_RX_STA=0;
			} 
		}
		if(waittime==0)res=0; 
	}
	return res;
}

//向8266发送数据
void Send_Data(char *data)
{
	USART2_RX_STA=0;
	u2_printf("%s",data);	//发送数据
}

char Rcv_Str[1024] = "NULL";

//建立TCP连接,并开启透传
void TCP_Connect()
{
	Send_Command("AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80","OK",50);
	HAL_Delay(500);
	//查询是否成功建立连接,成功则开启透传发送数据
	if(Send_Command("AT+CIPSTATUS","TCP",20))
	{
		Send_Command("AT+CIPMODE=1","OK",20);	//设置为透传模式
		Send_Command("AT+CIPSEND",">",20);	//开启透传
		HAL_Delay(1000);
		//发送GET请求
		Send_Data("GET https://api.seniverse.com/v3/weather/now.json?key=SJhnSCUV2ASZsxCzh&location=zhaoqing&language=zh-Hans&unit=c\r\n");
		HAL_Delay(1000);
		strcpy(Rcv_Str,(const char*)USART2_RX_BUF);	//将接收到的返回数据复制
	}
}

//退出透传,断开TCP连接
void TCP_Disconnect(void)
{
	//退出发送模式
	while((USART2->SR&0X40)==0);	//等待发送空
	USART2->DR='+';      
	HAL_Delay(15);					//大于串口组帧时间(10ms)
	while((USART2->SR&0X40)==0);	//等待发送空
	USART2->DR='+';      
	HAL_Delay(15);					//大于串口组帧时间(10ms)
	while((USART2->SR&0X40)==0);	//等待发送空
	USART2->DR='+';      
	HAL_Delay(1000);					//等待1s
	while(!Send_Command("AT","OK",20))//退出透传判断.
	{
		HAL_Delay(200);
	}
	//关闭透传模式
	Send_Command("AT+CIPMODE=0","OK",20);
	//断开TCP连接
	Send_Command("AT+CIPCLOSE","OK",20);
}
//主函数
int main(void)
{    
	HAL_Init();
    SystemClock_Config();
	USART1_Init(115200);
	USART2_Init(115200);
	
	HAL_Delay(1000);
	//测试ESP8266模块是否正常
	if(Send_Command("AT","OK",10))
	{
		printf("ESP8266 Is Ready\r\n");
	}
	else
	{
		printf("ESP8266 Not Ready\r\n");
	}
	//如果WIFI不是Station模式,则设置为Station模式
	if(!Send_Command("AT+CWMODE_DEF?","1",20))
	{
		Send_Command("AT+CWMODE_DEF=1","OK",20);
	}
	//查询WIFI是否连接,未连接则连接
	if(Send_Command("AT+CWJAP_DEF?","No AP",20))
	{
		HAL_Delay(500);
		Send_Command("AT+CWJAP_DEF=\"BieLai\",\"12345678\"","OK",50);
	}	
	HAL_Delay(1000);
	TCP_Connect();	//建立TCP连接
	printf("%s",Rcv_Str);	//打印网站返回的信息
	TCP_Disconnect();	//断开TCP连接
	
	while(1)
	{
		HAL_Delay(1000);		
	}

有关STM32使用ESP8266模块AT指令连接心知天气API获取天气信息的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  3. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  4. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

  5. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  6. ruby-on-rails - 在 Ruby (on Rails) 中使用 imgur API 获取图像 - 2

    我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path

  7. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  8. ruby - 导轨 4 : column reference "updated_at" is ambiguous with Postgres - 2

    我正在尝试使用“updated_at”字段的日期时间范围查询数据库。前端在JSON数组中发送查询:["2015-09-0100:00:00","2015-10-0223:00:00"]在RailsController中,我使用以下方法将两个字符串解析为DateTime:start_date=DateTime.parse(params[:date_range_arr][0])end_date=DateTime.parse(params[:date_range_arr][1])#...@events=@events.where('updated_atBETWEEN?AND?,start_d

  9. ruby-on-rails - 是否使用 API - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我的公司有一个巨大的数据库,该数据库接收来自多个来源的(许多)事件,用于监控和报告目的。到目前为止,数据中的每个新仪表板或图形都是一个新的Rails应用程序,在巨大的数据库中有额外的表,并且可以完全访问数据库内容。最近,有一个想法让外部(不是我们公司,而是姊妹公司)客户访问我们的数据,并且决定我们应该公开一个只读的RESTfulAPI来查询我们的数据。我的观点是-我们是否也应该为我们的自己

  10. ruby - Ruby 中的必应搜索 API - 2

    我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是

随机推荐