ESP32音频开发板--基于ESP32的WIFI气象计和电子日历
本项目主要使用WIFI进行网络连接,获取网络时间和并且获取当地的气象情况。将数据再OLED上面显示出来,使用ESP-IDF进行开发。将项目分解只是分为 OLED驱动,WIFI连接,SNTP获取和气象获取。完成这些任务,就完成了这个项目
标签
嵌入式系统
ESP32
WiFi
esp-idf
2022寒假在家练
Sherlock
更新2022-03-01
山东大学
1334

一,项目综述

本项目主要使用WIFI进行网络连接,获取网络时间和并且获取当地的气象情况。将数据再OLED上面显示出来,使用ESP-IDF进行开发。下面是显示的效果FkA5k59mlNNb8LOz-2souh1c05ND

 

二,项目分解

2.1.OLED驱动显示

本屏所用的驱动IC 为SSD1306;其具有内部升压功能;所以在设计的时候不需要再专一设计

升压电路;当然了本屏也可以选用外部升压,具体的请详查数据手册。SSD1306 的每页包含了

128 个字节,总共 8 页,这样刚好是 128*64 的点阵大小。这点与1.3 寸OLED 驱动IC SSD1106

稍有不同,SSD1106 每页是132 个字节,本次使用ESP32驱动SSD1306 进行SPI通信使用。

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size:选择字体 12/16/24
//取模方式 逐列式
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
{
	u8 i,m,temp,size2,chr1;
	u8 y0=y;
	size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
	chr1=chr-' ';  //计算偏移后的值
	for(i=0;i<size2;i++)
	{
		if(size1==12)
        {temp=asc2_1206[chr1][i];} //调用1206字体
		else if(size1==16)
        {temp=asc2_1608[chr1][i];} //调用1608字体
		else if(size1==24)
        {temp=asc2_2412[chr1][i];} //调用2412字体
		else return;
				for(m=0;m<8;m++)           //写入数据
				{
					if(temp&0x80)OLED_DrawPoint(x,y);
					else OLED_ClearPoint(x,y);
					temp<<=1;
					y++;
					if((y-y0)==size1)
					{
						y=y0;
						x++;
						break;
         			}
				}
  }
}


//显示字符串
//x,y:起点坐标  
//size1:字体大小 
//*chr:字符串起始地址 
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
{
	while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
	{
		OLED_ShowChar(x,y,*chr,size1);
		x+=size1/2;
		if(x>128-size1)  //换行
		{
			x=0;
			y+=2;
        }
		chr++;
  }
}

2.2.WIFI连接

个过程整体比较简单,联网过程可以参考官网教程。这是官网上面的初始化的函数其中SSID 是WIFI的名字,另外的password是密码。

wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,

            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };

2.3.气象信息获取

获取天气和温度我们可以通过心知天气的API进行。

主要步骤为:

  • 通过esp32的wifi库连接到互联网
  • 通过esp32的http库,向心知天气的服务器发送请求获取天气和温度的数据,获取到的数据格式为json
  • 对json格式的数据进行解析,然后就能获取需要的内容了 。json是一种特殊的数据结构,esp32中有一个内置的库,叫做cjson,用来处理json格式的数据,并且获取内容。

esp32连接互联网的步骤大致可以分为:

  • 配置wifi连接参数
  • 注册wifi连接事件
  • 完成wifi连接事件

http属于网络层的协议,具体的访问过程就是:

  • 对目标主机的URL进行解析,通过DNS服务变成ip地址
  • 基于ip地址和端口,目标主机与源主机建立TCP连接
  • 通过TCP协议,利用套接字把http请求报文从源主机发送到目标主机
  • 源主机根据http请求返回回应报文

连接关闭对于esp32来说,就是esp32通过get方法,向URL为https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c的心知天气的服务器发送http请求,然后就会得到相应的天气数据。

esp32也是可以通过这种比较底层的方法,用套接字的方法访问心知天气的服务器获取数据的,但是不如http client的库简单,因为http client库隐藏了协议层的实现内容。

//02-1 定义需要的变量
      char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};   //用于接收通过http协议返回的数据
    int content_length = 0;  //http协议头的长度
    

    //02-2 配置http结构体
   
   //定义http配置结构体,并且进行清零
    esp_http_client_config_t config ;
    memset(&config,0,sizeof(config));

    //向配置结构体内部写入url
    static const char *URL = "https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c";
    config.url = URL;

    //初始化结构体
    esp_http_client_handle_t client = esp_http_client_init(&config);	//初始化http连接

    //设置发送请求 
    esp_http_client_set_method(client, HTTP_METHOD_GET);

    //02-3 循环通讯

    while(1)
    {


    // 与目标主机创建连接,并且声明写入内容长度为0
    //因为如果是post请求,会在报文的头部后面跟着要向服务器发送的数据
    //而对于get方法,发送的内容都在URL里面,都在报文头部,不需要定义后面的部分,因此写入长度就是0
    esp_err_t err = esp_http_client_open(client, 0);

    //如果连接失败
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
    } 
    //如果连接成功
    else {

        //读取目标主机的返回内容的协议头
        content_length = esp_http_client_fetch_headers(client);

        //如果协议头长度小于0,说明没有成功读取到
        if (content_length < 0) {
            ESP_LOGE(TAG, "HTTP client fetch headers failed");
        } 

        //如果成功读取到了协议头
        else {

            //读取目标主机通过http的响应内容
            int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
            if (data_read >= 0) {

                //打印响应内容,包括响应状态,响应体长度及其内容
                ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
                esp_http_client_get_status_code(client),				//获取响应状态信息
                esp_http_client_get_content_length(client));			//获取响应信息长度
                printf("data:%s\n", output_buffer);
			
            } 
            //如果不成功
            else {
                ESP_LOGE(TAG, "Failed to read response");
            }
        }
    }

    //关闭连接
    esp_http_client_close(client);

    //延时,因为心知天气免费版本每分钟只能获取20次数据
    vTaskDelay(3000/portTICK_PERIOD_MS);

    }
	

2.4.SNTP

们有时候需要获取实时时间的需求,esp32内部提供了RTC组件,能够完成系统时间的获取。同时结合SNTP进行网络时间校正,可以获取精准的时间。

  该部分使用的时候,一般是按照这样的思路,首先esp32连接好wifi以后,通过sntp网络时间库进行系统时间校正,然后通过RTC模块,设置好时区,可以对SNTP获得到的时间进行变换。然后对于得到的时间,可以通过time.h自带的一些时间格式转换函数,进行时间转换。
ntp时间戳是该协议的重要内容,是一个64位无符号浮点数组成,前面32位表示整数,后面32位表示小数。单位是秒。时间是相对于1900年1月0点开始到现在所经过的秒数。它能表示的最大数字是4,294,967,295秒.SNTP 协议是用来同步本地的时间到 unix 时间戳.通常嵌入式设备上电, 连接 AP(access point), 获取 IP 地址后, 就需要使用 SNTP 协议获取全球时间.以便于下一步的应用交互和使用.SNTP工作原理比较简单, 通俗来说, 就是设备向 SNTP server 发送一包 SNTP 请求,服务器收到请求后回复一包 SNTP reply. 其中 SNTP reply 中就含有 unix 时间戳.

tatic const char *TAG1 = "sntp";



static void esp_initialize_sntp(void)
{
    ESP_LOGI(TAG1, "Initializing SNTP");
    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "ntp1.aliyun.com");
    //sntp_language(en);
    

    sntp_init();
}

void esp_wait_sntp_sync(void)
{
    char strftime_buf[64];
    esp_initialize_sntp();

    // wait for time to be set
    time_t now = 0;
    struct tm timeinfo = { 0 };
    int retry = 0;
     setenv("TZ", "CST-8", 1);
    tzset();

    while (timeinfo.tm_year < (2019 - 1900)) {
        //ESP_LOGD(TAG1, "Waiting for system time to be set... (%d)", ++retry);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        time(&now);
        localtime_r(&now, &timeinfo);
    }

    // set timezone to China Standard Time
    //setenv("TZ", "CST-8", 1);
    //tzset();

    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
    ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);

}

三,软件整体流程

FgFnQOQWdgoCg5q9H5t00NDOglh8

 

 

四,效果展示

最上面显示的是日期

后面是时钟 最后是天气和温度

FkA5k59mlNNb8LOz-2souh1c05ND

五,项目心的

这次还是遇到了很多问题,但都解决了

首先是OLED的显示,最开始打算将OLED的屏幕替换成IPS屏幕(还在路上)使用LVGL进行显示,最后还是选择了移植OLED的库。

然后是天气的获取,首先是最后选择的是心知天气,本来要显示的是济宁(jining),但是他返回的是集宁(jining),在内蒙古乌兰察布市。但是随着自己。剩下的就是WIFI 的连接,还算顺利,然后是SNTP的获取也还算顺利

我还会更新后续的题目.......以及自己的新的玩法,敬请期待........

下面是工程完全代码:

可以直接编译使用,记得要改wifi

链接:https://pan.baidu.com/s/1wgyy0B8kgxf85bvyIEeUhA
提取码:dwqz
--来自百度网盘超级会员V4的分享

团队介绍
一只小菜鸡
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号