软件参考:ESP32开发指南目录(开源一小步出品)https://blog.csdn.net/qq_24550925/article/details/85933563
2020-07-29
好久不见,又回来了。重新开始学习。
http获取天气预报
#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "esp_smartconfig.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "cJSON.h"
/*
===========================
宏定义
===========================
*/
#define false 0
#define true 1
#define errno (*__errno())
//http组包宏,获取天气的http接口参数
#define WEB_SERVER "api.thinkpage.cn"
#define WEB_PORT "80"
#define WEB_URL "/v3/weather/now.json?key="
#define host "api.thinkpage.cn"
#define APIKEY "g3egns3yk2ahzb0p"
#define city "suzhou"
#define language "en"
/*
===========================
全局变量定义
===========================
*/
//http请求包
static const char *REQUEST = "GET "WEB_URL""APIKEY"&location="city"&language="language" HTTP/1.1\r\n"
"Host: "WEB_SERVER"\r\n"
"Connection: close\r\n"
"\r\n";
//wifi链接成功事件
static EventGroupHandle_t wifi_event_group;
//天气解析结构体
typedef struct
{
char cit[20];
char weather_text[20];
char weather_code[2];
char temperatur[3];
}weather_info;
weather_info weathe;
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "sc";
static const char *TAG1 = "u_event";
static const char *HTTP_TAG = "http_task";
void smartconfig_example_task(void *parm);
void http_get_task(void *pvParameters);
static esp_err_t event_handler(void *ctx, system_event_t *event);
#define LED_IO 22
#define KEY_REC_IO 36
#define KEY_MODE_IO 39
uint8_t key_value = 0;
uint16_t timer_ms_cnt = 0;
uint16_t timer_1s_cnt = 0;
uint8_t led_flag = 0;
//定时器句柄
esp_timer_handle_t fw_timer_handle = 0;
void read_key(void);
void fw_timer_cb(void *arg);
static void user_app(void *pvParameters);
void app_main()
{
printf("app_main!\n");
/* 建议保留此输出打印SDK版本,用于以后出问题了可以有溯源 */
ESP_LOGI("app_main","the esp32 sdk version :%s\n", esp_get_idf_version());
//选择 IO
gpio_pad_select_gpio(LED_IO);
gpio_pad_select_gpio(KEY_REC_IO);
gpio_pad_select_gpio(KEY_MODE_IO);
//设置 IO 为输出
gpio_set_direction(LED_IO, GPIO_MODE_OUTPUT);
gpio_set_level(LED_IO, 1);//不亮
//设置按键 IO 输入
gpio_set_direction(KEY_REC_IO, GPIO_MODE_INPUT);
gpio_set_direction(KEY_MODE_IO, GPIO_MODE_INPUT);
//定时器结构体初始化
esp_timer_create_args_t fw_timer =
{
.callback = &fw_timer_cb, //回调函数
.arg = NULL, //参数
.name = "fw_timer" //定时器名称
};
//定时器创建、启动
esp_err_t err = esp_timer_create(&fw_timer, &fw_timer_handle);
err = esp_timer_start_periodic(fw_timer_handle, 1 * 1000);//1ms回调
if(err == ESP_OK)
{
printf("fw timer cteate and start ok!\r\n");
}
ESP_ERROR_CHECK(nvs_flash_init());
tcpip_adapter_init();
//事件组
wifi_event_group = xEventGroupCreate();
//注册wifi事件
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
//wifi设置:默认设置,等待sc配置
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
//sta模式
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
//启动wifi
ESP_ERROR_CHECK(esp_wifi_start());
//新建一个app任务
xTaskCreate(&user_app, //任务函数名
"user_app", //任务名
2048, //栈大小,单位为字,即4个字节,设置太小堆栈会溢出
NULL, //任务形参
8, //优先级,数值越大,优先级越高
NULL //句柄
);
}
void read_key(void)
{
static uint8_t cnt1 = 50;
static uint8_t cnt2 = 50;
if(gpio_get_level(KEY_REC_IO)==0)//按键按下
cnt1++;
else
cnt1--;
if(gpio_get_level(KEY_MODE_IO)==0)//按键按下
cnt2++;
else
cnt2--;
if(cnt1 > 52)
{
cnt1 = 50;
key_value |= 0x01;
}
else if(cnt1 < 48)
{
cnt1 = 50;
key_value &= ~0x01;
}
if(cnt2 > 52)
{
cnt2 = 50;
key_value |= 0x02;
}
else if(cnt2 < 48)
{
cnt2 = 50;
key_value &= ~0x02;
}
}
void fw_timer_cb(void *arg)
{
timer_ms_cnt++;
timer_1s_cnt++;
}
/*
* wifi事件
* @param[in] event :事件
* @retval esp_err_t :错误类型
* @note 修改日志
* Ver0.0.1:
hx-zsj, 2018/08/10, 初始化版本\n
*/
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id)
{
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_START");
//创建smartconfig任务
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_GOT_IP");
//sta链接成功,set事件组
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_DISCONNECTED");
//断线重连
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
/*smartconfig事件回调
* @param[in] status :事件状态
* @retval void :无
* @note 修改日志
* Ver0.0.1:
hx-zsj, 2018/08/10, 初始化版本\n
*/
static void sc_callback(smartconfig_status_t status, void *pdata)
{
switch (status)
{
case SC_STATUS_WAIT: //等待配网
ESP_LOGI(TAG, "SC_STATUS_WAIT");
break;
case SC_STATUS_FIND_CHANNEL: //扫描信道
ESP_LOGI(TAG, "SC_STATUS_FINDING_CHANNEL");
break;
case SC_STATUS_GETTING_SSID_PSWD: //获取到ssid和密码
ESP_LOGI(TAG, "SC_STATUS_GETTING_SSID_PSWD");
break;
case SC_STATUS_LINK: //连接获取的ssid和密码
ESP_LOGI(TAG, "SC_STATUS_LINK");
wifi_config_t *wifi_config = pdata;
//打印账号密码
ESP_LOGI(TAG, "SSID:%s", wifi_config->sta.ssid);
ESP_LOGI(TAG, "PASSWORD:%s", wifi_config->sta.password);
//断开默认的
ESP_ERROR_CHECK(esp_wifi_disconnect());
//设置获取的ap和密码到寄存器
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_config));
//连接获取的ssid和密码
ESP_ERROR_CHECK(esp_wifi_connect());
break;
case SC_STATUS_LINK_OVER: //连接上配置后,结束
ESP_LOGI(TAG, "SC_STATUS_LINK_OVER");
//
if (pdata != NULL)
{
uint8_t phone_ip[4] = {0};
memcpy(phone_ip, (uint8_t *)pdata, 4);
ESP_LOGI(TAG, "Phone ip: %d.%d.%d.%d\n", phone_ip[0], phone_ip[1], phone_ip[2], phone_ip[3]);
}
//发送sc结束事件
xEventGroupSetBits(wifi_event_group, ESPTOUCH_DONE_BIT);
break;
default:
break;
}
}
/*smartconfig任务
* @param[in] void :wu
* @retval void :无
* @note 修改日志
* Ver0.0.1:
hx-zsj, 2018/08/10, 初始化版本\n
*/
void smartconfig_example_task(void * parm)
{
EventBits_t uxBits;
//使用ESP-TOUCH配置
ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH));
//开始sc
ESP_ERROR_CHECK(esp_smartconfig_start(sc_callback));
while (1)
{
//死等事件组:CONNECTED_BIT | ESPTOUCH_DONE_BIT
uxBits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
//sc结束
if (uxBits & ESPTOUCH_DONE_BIT)
{
ESP_LOGI(TAG, "smartconfig over");
esp_smartconfig_stop();
xTaskCreate(http_get_task, "http_get_task", 4096, NULL, 3, NULL);
vTaskDelete(NULL);
}
//连上ap
if (uxBits & CONNECTED_BIT)
{
ESP_LOGI(TAG, "WiFi Connected to ap");
}
}
}
/*解析json数据 只处理 解析 城市 天气 天气代码 温度 其他的自行扩展
* @param[in] text :json字符串
* @retval void :无
* @note 修改日志
* Ver0.0.1:
hx-zsj, 2018/08/10, 初始化版本\n
*/
void cjson_to_struct_info(char *text)
{
cJSON *root,*psub;
cJSON *arrayItem;
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "results");
arrayItem = cJSON_GetArrayItem(psub,0);
cJSON *locat = cJSON_GetObjectItem(arrayItem, "location");
cJSON *now = cJSON_GetObjectItem(arrayItem, "now");
if((locat!=NULL)&&(now!=NULL))
{
psub=cJSON_GetObjectItem(locat,"name");
sprintf(weathe.cit,"%s",psub->valuestring);
ESP_LOGI(HTTP_TAG,"city:%s",weathe.cit);
psub=cJSON_GetObjectItem(now,"text");
sprintf(weathe.weather_text,"%s",psub->valuestring);
ESP_LOGI(HTTP_TAG,"weather:%s",weathe.weather_text);
psub=cJSON_GetObjectItem(now,"code");
sprintf(weathe.weather_code,"%s",psub->valuestring);
//ESP_LOGI(HTTP_TAG,"%s",weathe.weather_code);
psub=cJSON_GetObjectItem(now,"temperature");
sprintf(weathe.temperatur,"%s",psub->valuestring);
ESP_LOGI(HTTP_TAG,"temperatur:%s",weathe.temperatur);
//ESP_LOGI(HTTP_TAG,"--->city %s,weather %s,temperature %s<---\r\n",weathe.cit,weathe.weather_text,weathe.temperatur);
}
}
//ESP_LOGI(HTTP_TAG,"%s 222",__func__);
cJSON_Delete(root);
}
/*http任务
* @param[in] pvParameters :无
* @retval void :无
* @note 修改日志
* Ver0.0.1:
hx-zsj, 2018/08/10, 初始化版本\n
*/
void http_get_task(void *pvParameters)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
int s, r;
char recv_buf[1024];
char mid_buf[1024];
int index;
while(1) {
//DNS域名解析
int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(HTTP_TAG, "DNS lookup failed err=%d res=%p\r\n", err, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
//打印获取的IP
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
//ESP_LOGI(HTTP_TAG, "DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
//新建socket
s = socket(res->ai_family, res->ai_socktype, 0);
if(s < 0) {
ESP_LOGE(HTTP_TAG, "... Failed to allocate socket.\r\n");
close(s);
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
//连接ip
if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
ESP_LOGE(HTTP_TAG, "... socket connect failed errno=%d\r\n", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
freeaddrinfo(res);
//发送http包
if (write(s, REQUEST, strlen(REQUEST)) < 0) {
ESP_LOGE(HTTP_TAG, "... socket send failed\r\n");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
//清缓存
memset(mid_buf,0,sizeof(mid_buf));
//获取http应答包
do {
bzero(recv_buf, sizeof(recv_buf));
r = read(s, recv_buf, sizeof(recv_buf)-1);
strcat(mid_buf,recv_buf);
} while(r > 0);
//json解析
cjson_to_struct_info(mid_buf);
//关闭socket,http是短连接
close(s);
//延时一会
for(int countdown = 10; countdown >= 0; countdown--) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
static void user_app(void *pvParameters)
{
static uint8_t key_value_tmp = 0;
while(1)
{
if(timer_ms_cnt > 10) //10ms
{
timer_ms_cnt -= 10;
read_key();
}
if(key_value_tmp != key_value)
{
key_value_tmp = key_value;
printf("\r\nkey_value = 0x%.2x \n",key_value);
}
if(timer_1s_cnt >= 1000) //1s
{
timer_1s_cnt -= 1000;
if(led_flag)
{
led_flag = 0;
gpio_set_level(LED_IO, 1); //led亮
}
else
{
led_flag = 1;
gpio_set_level(LED_IO, 0); //led灭
}
}
vTaskDelay(10/ portTICK_RATE_MS);
}
}