sonicfirr 发表于 2022-8-17 13:50

【Beetle ESP32-C3】六、OLED、AHT10和TCP(Arduino)

<div class='showpostmsg'><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本篇记录一个较复杂案例的实现,ESP32 C3的硬I<sup>2</sup>C驱动OLED和AHT10,测得温湿度显示到OLED上,并且连接WiFi,建立TCP连接向远端TCP Server发送温湿度值。</p>

<h2><b>1、ESP32 C3的硬I</b><b><sup>2</sup></b><b>C</b></h2>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ESP32 C3的硬I<sup>2</sup>C默认为IO8-SDA和IO9-SCL,本例就不做改动了。具体的管脚分配,可以在Arduino-ESP32 Package的源码中找到,位于:&ldquo;..\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.4\variants\esp32c3\pins_arduino.h&rdquo;&mdash;&mdash;一般Arduino的开发板管脚定义都在对应开发板目录(路径中的esp32c3)的pins_arduino.h头文件中。</p>

<p>&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图6-1&nbsp;pins_arduino.h中的I<sup>2</sup>C管脚定义</p>

<p align="center">&nbsp;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C3管脚资源有限,所以OLED和AHT10连接到同一个I<sup>2</sup>C上,通过器件地址相互区分就可以了。实际这个案例初始是受到DFROBOT在线文档的示例启发,只不过文档用的SHT30(https://wiki.dfrobot.com.cn/_SKU_DFR0868_Beetle_ESP32_C3#target_17)。本人没有这个传感器,所以换成AHT10。正好AHT10和OLED的线序一致,在面包板上连接还挺方便。</p>

<p>&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图6-2&nbsp;管脚连接</p>

<p align="center">&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图6-3&nbsp;实物连接</p>

<p align="center">&nbsp;</p>

<h2><b>2、AHT10库和u8g2库</b></h2>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AHT10和OLED的驱动直接下载的库,AHT10是Adafruit_AHTX0 V2.0.2,u8g2是V2.31.2。</p>

<p>&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图6-4&nbsp;库安装</p>

<p align="center">&nbsp;</p>

<h2><b>3、完整代码</b></h2>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;项目采取每秒测量温湿度,同时板载LED闪烁以指示程序运行中。每测量6次求平均值,然后分别在OLED、串口和TCP Server三端输出。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试过程发现一个问题,就是6次测量中,第一次的温度值总是很离谱,都在四十七、八度的样子。结果平均值就达到32度,一度让本人怀疑是不是空调坏了。解决方法也很简单粗暴,6次测量直接舍去第一次,改5次求平均。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当然原因本人没有研究,猜想可能是没有在6次测量开始时进行AHT10启动引起的。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另一个情况就是求平均值后,小数位数会增加(单次测量仅两位),使用u8g2.print()函数会出错造成ESP32重启,这个猜想可能是位数增加造成的内存溢出问题。于是改用dtostrf()函数将float类型平均值转为字符串,再用u8g2.drawStr()函数显示。</p>

<p>&nbsp;</p>

<pre>
<code>#include &lt;Arduino.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;WiFiClient.h&gt;
#include &lt;U8g2lib.h&gt;
#include &lt;Wire.h&gt;
#include &lt;Adafruit_AHTX0.h&gt;

#define LED 10                      //板载LED管脚
#define LEN 6                     //测量LEN次求平均

float temp = 0;                     //温度平均值
float humi = 0;                     //湿度平均值
float temparr = {0};         //LEN次温度测量值数组
float humiarr = {0};         //LEN次湿度测量值数组
char str = {0};                  //字符串缓存用于OLED显示
uint8_t times = 0;                  //测量计数器,每LEN次求平均
Adafruit_AHTX0 aht;               //aht实例
const char *ssid = "yourssid";      //WIFI名称
const char *password = "yourpsw";   //密码
const uint16_t port = 1234;         //TCP Server端口
const char *host = "192.168.31.74"; //TCP Server IP

/*
---显示屏硬件I2C接口---
U8G2_R0 不旋转,横向,绘制方向从左到右
U8G2_R1 顺时针旋转90度,绘制方向从上到下
U8G2_R2 顺时针旋转180度,绘制方向从右到左
U8G2_R3 顺时针旋转270度,绘制方向从下到上
U8G2_MIRROR 正常显示镜像内容(v2.6.x版本以上使用)   
            注意:U8G2_MIRROR需要与setFlipMode()配搭使用.
U8x8_PIN_NONE 表示引脚为空,不会使用复位引脚
---显示屏硬件SPI接口---
cs 按引脚接上即可(引脚可自己选择)
dc 按引脚接上即可(引脚可自己选择)
*/
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

void setup() {
/* 初始化LED(板载 IO10控制)*/
pinMode(LED, OUTPUT);

/* 初始化UART0(板载USB-UART)*/
Serial.begin(115200);

/* 初始化u8g2及OLED          */
u8g2.begin();
/*
drawStr()默认字符的左下角为坐标标准,
setFontPosTop()改为左上角为坐标标准。
*/
u8g2.setFontPosTop();

/* AHT10初始化               */
if(!aht.begin()) {
    Serial.println("Could not find AHT");
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_osb18_tf);
    u8g2.drawStr(5,10,"no AHT");
    u8g2.sendBuffer();
    while(1) delay(10);
}
Serial.println("AHT10 or AHT20 found");

/* WiFi初始化,连接AP         */
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
}
Serial.println("WiFi connected!");
}

void loop() {
/* 读取温湿度                */
sensors_event_t aht_humi, aht_temp;
aht.getEvent(&amp;aht_humi, &amp;aht_temp);
temparr = aht_temp.temperature;
humiarr = aht_humi.relative_humidity;

/* 每LEN次计算平均值,做三端输出*/
if(times++ &gt;= LEN) {   
    times = 0;         //计数器复位
   
/* 求得平均值          */
    temp = 0;
    humi = 0;
    for(int i=0; i&lt;LEN; i++) { //LEN次测量值求和
      temp += temparr;
      humi += humiarr;
      Serial.print("temp: ");//输出每次温度值及当前和
      Serial.print(temparr);
      Serial.print(", tempsum: ");
      Serial.print(temp);
      Serial.println("");
      Serial.print("humi: ");//输出每次湿度值及当前和
      Serial.print(humiarr);
      Serial.print(", humisum: ");
      Serial.print(humi);
      Serial.println("");
      Serial.println("-----------------------------");
    }
    temp = (temp-temparr) / 5.0;//第一次温度值总是很大,所以减掉
    humi = (humi-humiarr) / 5.0;//为了保持一致,湿度也减掉第一次
    memset(temparr, 0, LEN);
    memset(humiarr, 0, LEN);

/* 串口显示温湿度       */
    Serial.print("Temperature: ");
    Serial.print(temp);
    Serial.println(" degrees C");
    Serial.print("Humidity: ");
    Serial.print(humi);
    Serial.println("% rH");

/* TCP发送温湿度值      */
    WiFiClient client;                //TCP Client 实例
    if(!client.connect(host, port)) { //连接失败串口消息
      Serial.println("Connection failed.");
    } else {                        //连接成功发送到TCP Server
      client.print("Temperature: ");
      client.print(temp);
      client.println(" degrees C");
      client.print("Humidity: ");
      client.print(humi);
      client.println("% rH");
      client.stop();                  //断开连接
    }

/* OLED显示温湿度       */
    u8g2.clearBuffer();//清屏幕
   
//OLED显示温度
    u8g2.setFont(u8g2_font_osb18_tf); //选择字体
    u8g2.drawStr(5, 10, "Temp");      //显示Temp字符
    u8g2.setFont(u8g2_font_t0_18b_tr);
    memset(str, 0, 6);
    dtostrf(temp, 6, 2, str);
    u8g2.drawStr(75, 15, str);
//    u8g2.setCursor(75, 15);
//    u8g2.print(temp);//temp平均值若小数部分长,会出错

//OLED显示湿度
    u8g2.setFont(u8g2_font_osb18_tf);   
    u8g2.drawStr(5, 40, "Humi");
    u8g2.setFont(u8g2_font_t0_18b_tr);
    memset(str, 0, 6);
    dtostrf(humi, 6, 2, str);
    u8g2.drawStr(75, 45, str);
//    u8g2.setCursor(75, 45);
//    u8g2.print(humi);

//此句使得OLED真正显示出来
    u8g2.sendBuffer();      
}

/* 指示灯翻转                */
digitalRead(LED) ? digitalWrite(LED, LOW) : digitalWrite(LED, HIGH);
/* 延时1s                   */
delay(1000);
}</code></pre>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

lugl4313820 发表于 2022-8-17 16:27

两个结合在一起,画的图很美,怎么摆弄出来的?

sonicfirr 发表于 2022-8-17 19:59

lugl4313820 发表于 2022-8-17 16:27
两个结合在一起,画的图很美,怎么摆弄出来的?

<p>GUI是DFROBOT的案例给出的,都是u8g2库的预制字体</p>
页: [1]
查看完整版本: 【Beetle ESP32-C3】六、OLED、AHT10和TCP(Arduino)