基于ESP32-S2-mini实现的本地气象台
本项目利用基于ESP32-S2-mini,通过vscode中的esp-idf explorer模块完成编程,利用OLED显示当前本地的日期,温度以及天气。
标签
嵌入式系统
FPGA
显示
2022寒假在家练
aaari
更新2022-03-03
北京理工大学
1086

平台介绍

本次使用的音频处理平台,是基于乐鑫官方模块ESP32-S2-Mini-1制作的。该模块由一颗ESP32S2的处理器,和一颗可以运行在80M的QPI上的Flash以及一些外围电路组成。ESP32S2是一颗单核的Xtensa32的处理器,能运行在240MHz的主频上。官方提供了esp-idf和Arduino等开发框架,本次我在这使用esp-idf作为开发框架开发。

模块可以广泛应用于下面的一些领域:

  • 通用低功耗 IoT 传感器 Hub
  • 通用低功耗 IoT 数据记录器
  • USB 设备
  • 语音识别
  • 图像识别
  • Mesh 网络
  • 家庭自动化
  • 智慧楼宇
  • 工业自动化
  • 健康/医疗/看护
  • Wi-Fi 玩具
  • 可穿戴电子产品
  • 零售 & 餐饮
  • 智能 POS 应用

OLED原理介绍

OLED(Organic Light-Emitting Diode),又称为有机电激光显示、有机发光半导体(Organic Electroluminescence Display,OLED)。OLED属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。OLED在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光。

项目目标

  • 利用OLED显示
  • 显示当前本地的时间、温度和气象信息

设计思路

FpgFyTXoh7M3HpKXp4dazGP0C_yW

ESP32功能的核心以及大多可拓展模块都是基于其WIFI连接这一功能实现的,而本地气象台这一功能的本质就是通过WIFI从HTTP网页获知本人所在地的气象数据,经过类似爬虫原理的数据解析,从网页上的信息中筛选出我们需要的地区,时间,气温,天气等信息,并通过OLED显示出来。

具体实现过程

这里用ssd-1306的OLED驱动芯片,并通过软件模拟IIC使OLED能够应对复杂多变的输出结果的要求。

void ssd1306_oled_WrDat(unsigned char data)
{
    unsigned char i=8;
    //ssd1306_oled_CS=0;;
    gpio_set_level(SSD1306_DC,1);;
    gpio_set_level(SSD1306_SCL,0);;
    vTaskDelay(1 / portTICK_RATE_MS/1000);   
    // delay_1us(); 
    while(i--)
    {
        if(data&0x80){gpio_set_level(SSD1306_SDA,1);}
        else{gpio_set_level(SSD1306_SDA,0);}
        gpio_set_level(SSD1306_SCL,1); 
        vTaskDelay(1 / portTICK_RATE_MS/1000);
    // delay_1us(); 
        //asm("nop");            
        gpio_set_level(SSD1306_SCL,0);;    
        data<<=1;    
    }
    //ssd1306_oled_CS=1;
}

void ssd1306_oled_WrCmd(unsigned char cmd)
{
    unsigned char i=8;
    
    //ssd1306_oled_CS=0;;
    gpio_set_level(SSD1306_DC,0);;
    gpio_set_level(SSD1306_SCL,0);;
    vTaskDelay(1 / portTICK_RATE_MS/1000);
    // delay_1us(); 
    while(i--)
    {
        if(cmd&0x80){gpio_set_level(SSD1306_SDA,1);}
        else{gpio_set_level(SSD1306_SDA,0);;}
        gpio_set_level(SSD1306_SCL,1);;
     vTaskDelay(1 / portTICK_RATE_MS/1000);
    // delay_1us(); 
        gpio_set_level(SSD1306_SCL,0);;    
        cmd<<=1;;   
    } 
    //ssd1306_oled_CS=1;
}


void ssd1306_oled_Set_Pos(unsigned char x, unsigned char y)
{ 
    ssd1306_oled_WrCmd(0xb0+y);
    ssd1306_oled_WrCmd(((x&0xf0)>>4)|0x10);
    ssd1306_oled_WrCmd((x&0x0f)); 
} 
void ssd1306_oled_Fill(unsigned char bmp_data)
{
    unsigned char y,x;
    
    for(y=0;y<8;y++)
    {
        ssd1306_oled_WrCmd(0xb0+y);
        ssd1306_oled_WrCmd(0x01);
        ssd1306_oled_WrCmd(0x10);
        for(x=0;x<X_WIDTH;x++)
            ssd1306_oled_WrDat(bmp_data);
    }
}
void ssd1306_oled_CLS(void)
{
    unsigned char y,x;	
    for(y=0;y<8;y++)
    {
        ssd1306_oled_WrCmd(0xb0+y);
        ssd1306_oled_WrCmd(0x01);
        ssd1306_oled_WrCmd(0x10); 
        for(x=0;x<X_WIDTH;x++)
            ssd1306_oled_WrDat(0);
    }
}


void ssd1306_oled_PutPixel(unsigned char x,unsigned char y)
{
    unsigned char data1;  
    
    ssd1306_oled_Set_Pos(x,(unsigned char)(y>>3)); 
    data1 =(unsigned char)(0x01<<(y%8)); 	
    ssd1306_oled_WrCmd((unsigned char)(0xb0+(y>>3)));
    ssd1306_oled_WrCmd((unsigned char)(((x&0xf0)>>4)|0x10));
    ssd1306_oled_WrCmd((unsigned char)((x&0x0f)|0x00));
    ssd1306_oled_WrDat(data1); 	 	
}

void ssd1306_oled_Rectangle(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char gif)
{
    unsigned char n; 
    
    ssd1306_oled_Set_Pos(x1,y1>>3);
    for(n=x1;n<=x2;n++)
    {
        ssd1306_oled_WrDat(0x01<<(y1%8)); 			
        if(gif == 1) 	vTaskDelay(50 / portTICK_RATE_MS);
    }  
    ssd1306_oled_Set_Pos(x1,y2>>3);
    for(n=x1;n<=x2;n++)
    {
        ssd1306_oled_WrDat(0x01<<(y2%8)); 			
        if(gif == 1) 	vTaskDelay(5 / portTICK_RATE_MS);
    }
    
}  

void ssd1306_oled_P6x8Str(unsigned char x,unsigned char y, char ch[])
{
    unsigned char c=0,i=0,j=0;      
    while (ch[j]!='\0')
    {    
        c =ch[j]-32;
        if(x>126){x=0;y++;}
        ssd1306_oled_Set_Pos(x,y);    
        for(i=0;i<6;i++)     
            ssd1306_oled_WrDat(F6x8[c][i]);  
        x+=6;
        j++;
    }
}
 
void ssd1306_oled_P8x16Str(unsigned char x,unsigned char y, char ch[])
{
    unsigned char c=0,i=0,j=0;
    
    while (ch[j]!='\0')
    {    
        c =ch[j]-32;
        if(x>120){x=0;y++;}
        ssd1306_oled_Set_Pos(x,y);    
        for(i=0;i<8;i++)     
            ssd1306_oled_WrDat(F8X16[c*16+i]);
        ssd1306_oled_Set_Pos(x,y+1);    
        for(i=0;i<8;i++)     
            ssd1306_oled_WrDat(F8X16[c*16+i+8]);  
        x+=8;
        j++;
    }
}

这里的代码段大部分都是收集资料所得,而非手动编制,我也是耗费大量精力才获取到通过ssd-1306驱动芯片和IIC驱动OLED的方法。

网络连接模块

      if(err != 0 || res == NULL) {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        /* Code to print the resolved IP.

           Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
        
        s = socket(res->ai_family, res->ai_socktype, 0);
        if(s < 0) {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
            ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

 这里给出对DNS服务以及socket套接字的连接及其检查的代码段,其他服务的相应功能实现与其大同小异。

数据的解析并输出

      if(json_weather!=NULL)
        {
            printf("json_weather\r\n");
            
            cJSON *json_weather_results = cJSON_GetObjectItem(json_weather,"results");
            if(json_weather_results != NULL)
            {
                printf("json_weather_results json\r\n");
                cJSON *json_weather_array = cJSON_GetArrayItem(json_weather_results,0);
                if(json_weather_array != NULL)
                {
                    printf("json_weather_array json array\r\n");
                    cJSON *json_weather_location = cJSON_GetObjectItem(json_weather_array,"location");
                    if(json_weather_location!=NULL)
                    {
                        cJSON *json_weather_city = cJSON_GetObjectItem(json_weather_location,"name");
                        if(json_weather_city!=NULL)
                        printf("city:%s\r\n",json_weather_city->valuestring);
                        strcpy(city,json_weather_city->valuestring);
                    }

                    cJSON *json_weather_now = cJSON_GetObjectItem(json_weather_array,"now");
                    if(json_weather_now!=NULL)
                    {
                        cJSON *json_weather_text = cJSON_GetObjectItem(json_weather_now,"text");
                        if(json_weather_now!=NULL)
                        printf("weather:%s\r\n",json_weather_text->valuestring);
                        strcpy(weather_name,json_weather_text->valuestring);
                        
                        cJSON *json_weather_temperature = cJSON_GetObjectItem(json_weather_now,"temperature");
                        if(json_weather_temperature!=NULL)
                        printf("temperature :%s\r\n",json_weather_temperature->valuestring);
                        strcpy(temperature,json_weather_temperature->valuestring);
                    }
                }
            }
        }
        else
        {
            printf("json_weather\r\n");
        }

数据的解析如上述所说,主要是通过json形式获取,并从中提取出相应的城市,时间,天气,温度的信息,数据的输出比较简单,在此略过。

结果展示

FmoMhiie5_dghIS94ljiWi_0yNyA

最终,通过上述思路及其实现过程,实现了对于城市,日期,温度以及天气的输出。

遇到的困难及问题解决方案

在配置ESP32-S2的开发环境以的过程中,我就遇到了很大的困难。用老师所讲到的方法配置环境,更换了两台机器,重新安装了很多次Git,esp-idf也无济于事,总是在安装编译工具链的时候Python遇到Traceback错误,最终也只能无奈放弃了这一条路径。最终,通过在网络上大量搜集资料,访问论坛,利用VSCode环境成功将ESP32-S2的开发环境搭建了下来,通过后续开发和测试,也证明了环配置是正确的。

在使OLED输出正确信息的过程中,我也遭遇了一些困难。也是在网络上多方查找资料,试验了多个方法,才选择了对我前期对信息筛选的代码有较高适配性的一种方法。在这里用ssd-1306的OLED驱动芯片,并通过软件模拟IIC使OLED能够应对复杂多变的输出结果的要求。

未来的计划与建议

对于ESP32-S2-mini1这块板子,实现本地气象台仅仅是利用了其WIF模块以及USB接口,对于其更为丰富的音频信号处理等功能没有涉及。在这之外,此芯片在物联网方面的应用也极为广泛。因此,这块板子的开发还有很多方面是值得我去继续尝试的。同时,我也会继续学习嵌入式系统及FPGA开发的知识,涉猎更多更广泛的芯片,实现更多的功能。

软硬件
元器件
ESP32-S2-MINI-1
2.4GHz Wi­Fi (802.11 b/g/n) 模组, 内置ESP32­S2系列芯片,Xtensa® 单核32位LX7微处理器, 内置芯片叠封4MB flash,可叠封2MB PSRAM, 37个GPIO,丰富的外设, 板载PCB天线或外部天线连接器
附件下载
寒假在家一起练esp_32音频处理.rar
团队介绍
北京理工大学 高钰奇
团队成员
aaari
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号