• [外设篇]ESP8266-SDK教程(十)之DHT11、OLED1306


    真诚分享,技术交友,欢迎交流。

    Hi,大家好,写这篇文章的时候“IAMLIUBO的神奇物联网之旅”专栏关注人数已经有186人了,首先很感谢大家的关注和相信,开始写第一篇的文章的时候也没想过会有这么多人感兴趣,看到关注的人数越来越多,当然对文章的质量也要有更高的要求,力求每篇文章没有错别字和错误的叙述,也希望大家可以帮我一起勘误。写这些文章的目的就是希望可以帮助更多人,当然也收获了很多知友,也有很多知友加我微信咨询一些问题,希望我的每一个回答都对你有所帮助,这篇文章是外设篇的第一篇,也是知友小牛最近在微信咨询我的一点问题,这里就记录成文章跟大家分享一下。

    闲话少说,咱们开始来说正事,相信大家在做一些实际项目或者小发明创造的时候,多多少少都会用过温湿度传感器,或者说会采集温湿度数据加以展示和判断处理,那么我们这里说的DHT11就是一款非常不错的温湿度传感器,是广州奥松电子生产的一款温湿度传感器,在开发当中我是用的比较多的,上一张图给大家看一下。

    当然,这款传感器尺寸不是很小,做一些对尺寸要求比较严格的产品还是不怎么推荐的,一般做比较小的产品,还是比较推荐盛思瑞的SHT系列,当然价格就不是那么美丽了,但是精度相对来说还是比较不错的,当然对大小和空间都有要求的话推荐美信的DS18B20。

    下面我们来看一下这款传感器的具体参数:

    上面这三个表,就可以很直观的看出这款传感器的参数了,这里就不再做过多的文字叙述了。

    了解完了这些基本的,那我们再来看一下我们是如何从传感器取到温湿度的值呢?说到这里,那就不得不提一个概念了,相信搞嵌入式开发的都知道,那就是单总线通信方式,那么什么是单总线通信方式呢?它与其他通信方式又有什么不同呢?下面我们先来看一下百科:

    单总线是美国DALLAS公司推出的外围串行扩展总线技术。与SPII²C串行数据通信方式不同.它采用单根信号线,既传输时钟又传输数据,而且数据传输是双向的,具有节省I/O口线、资源结构简单、成本低廉、便于总线扩展和维护等诸多优点。(百度百科)

    简单来说,就是双方通信只通过一根线解决,不像其他通信方式有时钟线和数据线,这样的好处是极大的节省了I/O资源,当然这种通信方式的速率自然也会有所降低,像前面说的DS18B20也是采用单总线通信方式。

    那么我们再来看一下DHT11通过单总线发送的数据格式,了解了数据格式可以更好的帮助我们理解程序是如何读取温湿度的,因为数据传输在硬件层就是电平高低,转化为计算机语言就是0/1,我们就是通过DHT11发送的这些0/1中找出温湿度的值:

    可以看到一共是有40位数据的,每8位是一组,包含了温湿度和校验值,校验值等于温湿度的和,如果不理解,那么我们通过一个实际例子来看一下:

    这就是一个完整的数据包过来,我们如何解包和验证,那么我们看一下代码:

      1 static uint8_t ICACHE_FLASH_ATTR dht11ReadBit(void)
      2 {
      3     uint8_t retry=0;
      4     
      5     while(DHT11_IN&&retry<100)                                  //wait become Low level
      6     {
      7         retry++;
      8         tempHumDelay(1);
      9     }
     10 
     11     retry=0;
     12     while(!DHT11_IN&&retry<100)                                 //wait become High level
     13     {
     14         retry++;
     15         tempHumDelay(1);
     16     }
     17 
     18     tempHumDelay(40);                                         //wait 40us
     19 
     20     if(DHT11_IN)
     21         return 1;
     22     else
     23         return 0;
     24 }
     25 
     26 static uint8_t ICACHE_FLASH_ATTR hdt11ReadByte(void)
     27 {
     28     uint8_t i;
     29     uint8_t dat=0;
     30     
     31     for (i=0; i<8; i++)
     32     {
     33         dat<<=1;
     34         dat |= dht11ReadBit(); 
     35     }
     36 
     37     return dat;
     38 }
     39 
     40 static uint8_t ICACHE_FLASH_ATTR dht11ReadData(u8 * temperature, u8 * humidity)
     41 {
     42     uint8_t i;
     43     uint8_t buf[5];
     44     
     45     dht11Rst(); 
     46     if(0 == dht11Check()) 
     47     {
     48         for(i=0; i<5; i++)
     49         {
     50             buf[i] = hdt11ReadByte(); 
     51         }
     52         if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
     53         {
     54             *humidity=buf[0];
     55             *temperature=buf[2];
     56         }
     57     }
     58     else
     59     {
     60         return 1;
     61     }
     62 
     63     return 0;
     64 }
     65 
     66 uint8_t ICACHE_FLASH_ATTR dh11Read(uint8_t * temperature, uint8_t * humidity)
     67 {
     68     uint8_t ret = 0; 
     69     uint8_t cur_i = 0;
     70     uint8_t curTem = 0;
     71     uint8_t curHum = 0;
     72     uint16_t temMeans = 0;
     73     uint16_t hum_means = 0;
     74 
     75     ret = dht11ReadData(&curTem, &curHum);
     76 
     77     if(0 == ret) 
     78     {
     79         //Cycle store ten times stronghold
     80         if(MEAN_NUM > temphum_typedef.th_num)
     81         {
     82             temphum_typedef.th_bufs[temphum_typedef.th_num][0] = curTem;
     83             temphum_typedef.th_bufs[temphum_typedef.th_num][1] = curHum;
     84 
     85             temphum_typedef.th_num++;
     86         }
     87         else
     88         {
     89             temphum_typedef.th_num = 0;
     90 
     91             temphum_typedef.th_bufs[temphum_typedef.th_num][0] = curTem;
     92             temphum_typedef.th_bufs[temphum_typedef.th_num][1] = curHum;
     93 
     94             temphum_typedef.th_num++;
     95         }
     96     }
     97     else
     98     {
     99         return 1; 
    100     }
    101     
    102     if(MEAN_NUM <= temphum_typedef.th_num) 
    103     {
    104         temphum_typedef.th_amount = MEAN_NUM;
    105     }
    106 
    107     if(0 == temphum_typedef.th_amount) 
    108     {
    109         //Calculate Before ten the mean
    110         for(cur_i = 0; cur_i < temphum_typedef.th_num; cur_i++)
    111         {
    112             temMeans += temphum_typedef.th_bufs[cur_i][0];
    113             hum_means += temphum_typedef.th_bufs[cur_i][1];
    114         }
    115 
    116         temMeans = temMeans / temphum_typedef.th_num;
    117         hum_means = hum_means / temphum_typedef.th_num; 
    118         
    119         *temperature = temMeans;
    120         *humidity = hum_means;
    121     }
    122     else if(MEAN_NUM == temphum_typedef.th_amount) 
    123     {
    124         //Calculate After ten times the mean
    125         for(cur_i = 0; cur_i < temphum_typedef.th_amount; cur_i++) 
    126         {
    127             temMeans += temphum_typedef.th_bufs[cur_i][0];
    128             hum_means += temphum_typedef.th_bufs[cur_i][1];
    129         }
    130 
    131         temMeans = temMeans / temphum_typedef.th_amount; 
    132         hum_means = hum_means / temphum_typedef.th_amount; 
    133         
    134         *temperature = (uint8_t)temMeans; 
    135         *humidity = (uint8_t)hum_means; 
    136     }
    137 
    138     return 0;
    139 }

    这就是我们读温湿度的主要代码,大家可以看一下,我们是不是对40位的bit位的数据做了处理呢?后面我们会结合OLED显示屏来实际测试一下,这里就先不做测试了。

    说完了DHT11,我们再来了解一下SSD1306,其实这是一款OLED屏幕的控制芯片,目前在淘宝等常见的0.96吋小OLED显示屏幕大多就是使用这款芯片的,当然还有一款功能一样的替代芯片叫SHT1106,不过两者指令兼容,所以会一款,另一款也就会了。这款主控芯片是香港晶门科技公司的,目前在一般小制作或者小创意上用这款主控的显示屏幕还是比较多的,我也一直在使用,这款芯片最大只能控制128x64个像素点,所以有时候我们常说的OLED12864,多也是使用这块主控的屏幕,当然这家公司也生产很多可以控制更多像素点的主控芯片,有兴趣的可以去官网了解一下:

    晶门科技有限公司​www.solomon-systech.com.cn

    同样的,我们先来了解一下,遗憾的是没有找到官方的中文数据手册,又怕某些翻译的不太准确,所以这里就直接贴英文数据手册的截图了:

    其中我们做开发需要关注的就是上面提到的两种通信方式了,可以看到是支持IIC和SPI通信方式的,还支持亮度调节,我这里其实最近重新撸了一下驱动,之前也是一直拿来别人写好的直接用,最近比较想自己动手撸一下,于是也借鉴别人写的,自己看着数据手册重新写了一下,当然过程没那么顺利,我这里是使用IIC通信的,但是由于ESP8266没有硬件IIC,这刷新效果也是有点感人,其实最重要的也是采用了全局刷新方式,没有写局部刷新的驱动,就导致每次修改某一个地方,都会把所有的像素点重新写一遍~自然这FPS就降下来了,后面再考虑优化吧,但是通过整个过程也是对工作方式有了更深的了解,呃呃呃,又讲远了。

    我们再来看一下主要特性:

    我们再来看一下尺寸,可以说是非常薄了,我们是不可能用手焊接的,一般买也是买别人把芯片跟显示屏封装好的模组的:

    可以看到厚度只有0.3mm,这里给大家看一下跟屏幕封装好的模组,这也是前不久做一款STM32 Mini开发板的显示扩展板剩下的:

    按理说接下来我们应该讲一下如何去驱动这款芯片了,但是相比于温湿度传感器来说,就有点复杂了,而且也比较难讲清楚,不过这里推荐大家看一下杜洋老师对这款芯片的视频讲解,戳看片观看:

    优酷视频​v.youku.com

    分了好几集,上面卡片是第一集,大家可以看一下,个人认为讲的还是比较不错的。

    下面我们来看一下我这撸的驱动代码的,目前支持IIC通信和中英文显示,由于手头没有SPI接口的屏幕,也没法测试,所以有机会再更新SPI通信方式的。

      1 /*
      2  * MIT License
      3  *
      4  * Copyright (c) 2018 imliubo
      5  *
      6  * Github  https://github.com/imliubo
      7  * Website https://www.makingfun.xyz
      8  * Zhihu   https://www.zhihu.com/people/MAKINGFUNXYZ
      9  *
     10  * Permission is hereby granted, free of charge, to any person obtaining a copy
     11  * of this software and associated documentation files (the "Software"), to deal
     12  * in the Software without restriction, including without limitation the rights
     13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14  * copies of the Software, and to permit persons to whom the Software is
     15  * furnished to do so, subject to the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be included in all
     18  * copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     26  * SOFTWARE.
     27  */
     28 #include "modules/ssd1306.h"
     29 
     30 #if defined(SSD1306_USE_I2C)
     31 int ICACHE_FLASH_ATTR
     32 HAL_I2C_Mem_Write( uint16_t DevAddress, uint16_t MemAddress, uint8_t pData, uint16_t Size )
     33 {
     34     i2c_master_start();
     35     i2c_master_writeByte( DevAddress );
     36     if ( !i2c_master_checkAck() )
     37     {
     38         i2c_master_stop();
     39         return(0);
     40     }
     41 
     42     i2c_master_writeByte( MemAddress );
     43     if ( !i2c_master_checkAck() )
     44     {
     45         i2c_master_stop();
     46         return(0);
     47     }
     48 
     49     i2c_master_writeByte( pData );
     50     if ( !i2c_master_checkAck() )
     51     {
     52         i2c_master_stop();
     53         return(0);
     54     }
     55 
     56     i2c_master_stop();
     57     return(1);
     58 }
     59 
     60 
     61 void ssd1306_Reset( void )
     62 {
     63     /* for I2C - do nothing */
     64 }
     65 
     66 
     67 /* Send a byte to the command register */
     68 void ssd1306_WriteCommand( uint8_t byte )
     69 {
     70     HAL_I2C_Mem_Write( SSD1306_I2C_ADDR, 0x00, byte, 1 );
     71 }
     72 
     73 
     74 /* Send data */
     75 void ssd1306_WriteData( uint8_t buffer, size_t buff_size )
     76 {
     77     HAL_I2C_Mem_Write( SSD1306_I2C_ADDR, 0x40, buffer, buff_size );
     78 }
     79 
     80 #elif defined(SSD1306_USE_SPI)
     81 
     82 #else
     83 #error "You should define SSD1306_USE_SPI or SSD1306_USE_I2C macro"
     84 #endif
     85 
     86 
     87 /* Screenbuffer */
     88 static uint8_t SSD1306_Buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];
     89 
     90 /* Screen object */
     91 static SSD1306_t SSD1306;
     92 
     93 /* Initialize the oled screen */
     94 void ssd1306_Init( void )
     95 {
     96     /* Reset OLED */
     97     ssd1306_Reset();
     98 
     99     /* Wait for the screen to boot */
    100     os_delay_us( 60000 );
    101     os_delay_us( 40000 );
    102 
    103 /*     // Init OLED */
    104     ssd1306_WriteCommand( 0xAE );   /* display off */
    105 
    106     ssd1306_WriteCommand( 0x20 );   /* Set Memory Addressing Mode */
    107     ssd1306_WriteCommand( 0x10 );   /*
    108                                      * 00,Horizontal Addressing Mode; 01,Vertical Addressing Mode;
    109                                      * 10,Page Addressing Mode (RESET); 11,Invalid
    110                                      */
    111 
    112     ssd1306_WriteCommand( 0xB0 );   /* Set Page Start Address for Page Addressing Mode,0-7 */
    113 
    114 #ifdef SSD1306_MIRROR_VERT
    115     ssd1306_WriteCommand( 0xC0 );   /* Mirror vertically */
    116 #else
    117     ssd1306_WriteCommand( 0xC8 );   /* Set COM Output Scan Direction */
    118 #endif
    119 
    120     ssd1306_WriteCommand( 0x00 );   /* ---set low column address */
    121     ssd1306_WriteCommand( 0x10 );   /* ---set high column address */
    122 
    123     ssd1306_WriteCommand( 0x40 );   /* --set start line address - CHECK */
    124 
    125     ssd1306_WriteCommand( 0x81 );   /* --set contrast control register - CHECK */
    126     ssd1306_WriteCommand( 0xFF );
    127 
    128 #ifdef SSD1306_MIRROR_HORIZ
    129     ssd1306_WriteCommand( 0xA0 );   /* Mirror horizontally */
    130 #else
    131     ssd1306_WriteCommand( 0xA1 );    /*--set segment re-map 0 to 127 - CHECK */
    132 #endif
    133 
    134 #ifdef SSD1306_INVERSE_COLOR
    135     ssd1306_WriteCommand( 0xA7 );   /* --set inverse color */
    136 #else
    137     ssd1306_WriteCommand( 0xA6 );   /* --set normal color */
    138 #endif
    139 
    140     ssd1306_WriteCommand( 0xA8 );   /* --set multiplex ratio(1 to 64) - CHECK */
    141     ssd1306_WriteCommand( 0x3F );   /*  */
    142 
    143     ssd1306_WriteCommand( 0xA4 );   /* 0xa4,Output follows RAM content;0xa5,Output ignores RAM content */
    144 
    145     ssd1306_WriteCommand( 0xD3 );   /* -set display offset - CHECK */
    146     ssd1306_WriteCommand( 0x00 );   /* -not offset */
    147 
    148     ssd1306_WriteCommand( 0xD5 );   /* --set display clock divide ratio/oscillator frequency */
    149     ssd1306_WriteCommand( 0xF0 );   /* --set divide ratio */
    150 
    151     ssd1306_WriteCommand( 0xD9 );   /* --set pre-charge period */
    152     ssd1306_WriteCommand( 0x22 );   /*  */
    153 
    154     ssd1306_WriteCommand( 0xDA );   /* --set com pins hardware configuration - CHECK */
    155     ssd1306_WriteCommand( 0x12 );
    156 
    157     ssd1306_WriteCommand( 0xDB );   /* --set vcomh */
    158     ssd1306_WriteCommand( 0x20 );   /* 0x20,0.77xVcc */
    159 
    160     ssd1306_WriteCommand( 0x8D );   /* --set DC-DC enable */
    161     ssd1306_WriteCommand( 0x14 );   /*  */
    162     ssd1306_WriteCommand( 0xAF );   /* --turn on SSD1306 panel */
    163 
    164 
    165     /* Clear screen */
    166     ssd1306_Fill( Black );
    167 
    168     /* Flush buffer to screen */
    169     ssd1306_UpdateScreen();
    170 
    171     /* Set default values for screen object */
    172     SSD1306.CurrentX    = 0;
    173     SSD1306.CurrentY    = 0;
    174 
    175     SSD1306.Initialized = 1;
    176 }
    177 
    178 
    179 /* Fill the whole screen with the given color */
    180 void ssd1306_Fill( SSD1306_COLOR color )
    181 {
    182     /* Set memory */
    183     uint32_t i;
    184 
    185     for ( i = 0; i < sizeof(SSD1306_Buffer); i++ )
    186     {
    187         SSD1306_Buffer[i] = (color == Black) ? 0x00 : 0xFF;
    188     }
    189 }
    190 
    191 
    192 /* Write the screenbuffer with changed to the screen */
    193 void ssd1306_UpdateScreen( void )
    194 {
    195     uint8_t i, j;
    196     for ( i = 0; i < 8; i++ )
    197     {
    198         ssd1306_WriteCommand( 0xB0 + i );
    199         ssd1306_WriteCommand( 0x00 );
    200         ssd1306_WriteCommand( 0x10 );
    201         for ( int j = 0; j < 128; j++ )
    202         {
    203             /* code */
    204             ssd1306_WriteData( SSD1306_Buffer[j + SSD1306_WIDTH * i], SSD1306_WIDTH );
    205         }
    206     }
    207 }
    208 
    209 
    210 /*
    211  *    Draw one pixel in the screenbuffer
    212  *    X => X Coordinate
    213  *    Y => Y Coordinate
    214  *    color => Pixel color
    215  */
    216 void ssd1306_DrawPixel( uint8_t x, uint8_t y, SSD1306_COLOR color )
    217 {
    218     if ( x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT )
    219     {
    220         /* Don't write outside the buffer */
    221         return;
    222     }
    223 
    224     /* Check if pixel should be inverted */
    225     if ( SSD1306.Inverted )
    226     {
    227         color = (SSD1306_COLOR) !color;
    228     }
    229 
    230     /* Draw in the right color */
    231     if ( color == White )
    232     {
    233         SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] |= 1 << (y % 8);
    234     } else {
    235         SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8) );
    236     }
    237 }
    238 
    239 
    240 /*
    241  * Draw 1 char to the screen buffer
    242  * ch         => char om weg te schrijven
    243  * Font     => Font waarmee we gaan schrijven
    244  * color     => Black or White
    245  */
    246 char ssd1306_WriteChar( char ch, FontDef Font, SSD1306_COLOR color )
    247 {
    248     uint32_t i, b, j;
    249 
    250     /* Check remaining space on current line */
    251     if ( SSD1306_WIDTH <= (SSD1306.CurrentX + Font.FontWidth) ||
    252          SSD1306_HEIGHT <= (SSD1306.CurrentY + Font.FontHeight) )
    253     {
    254         /* Not enough space on current line */
    255         return(0);
    256     }
    257 
    258     /* Use the font to write */
    259     for ( i = 0; i < Font.FontHeight; i++ )
    260     {
    261         os_printf("Font: %d
    ",ch);
    262         b = Font.data[(ch - 32) * Font.FontHeight + i];
    263         for ( j = 0; j < Font.FontWidth; j++ )
    264         {
    265             if ( (b << j) & 0x8000 )
    266             {
    267                 ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) color );
    268             } else {
    269                 ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) !color );
    270             }
    271         }
    272     }
    273 
    274     /* The current space is now taken */
    275     SSD1306.CurrentX += Font.FontWidth;
    276 
    277     /* Return written char for validation */
    278     return(ch);
    279 }
    280 
    281 /*
    282  * Draw 1 Chinese char to the screen buffer
    283  * ch         => char 
    284  * color     => Black or White
    285  */
    286 char ssd1306_WriteZhChar( signed char ch[], SSD1306_COLOR color ){
    287 
    288 
    289     uint32_t  b, j, k, data[32];
    290 
    291     /* Check remaining space on current line */
    292     if ( SSD1306_WIDTH <= (SSD1306.CurrentX + 16) ||
    293          SSD1306_HEIGHT <= (SSD1306.CurrentY + 16) )
    294     {
    295         /* Not enough space on current line */
    296         return(0);
    297     }
    298 
    299     for (int i = 0; i < 20; ++i)
    300     {
    301         if ((ZhFont16x16[i].Index[0] == ch[0]) && (ZhFont16x16[i].Index[1] == ch[1]) && (ZhFont16x16[i].Index[2] == ch[2]) )
    302         {
    303             for (int z = 0; z < ZH_CN_HEIGHT_WIDTH; z++)
    304             {
    305                 data[z] = ZhFont16x16[i].Msk[z];
    306 
    307             }
    308         }
    309     }
    310 
    311     for ( int i = 0; i < ZH_CN_HEIGHT_WIDTH; i++ )
    312     {
    313 
    314         b = data[i];
    315         for ( j = 0; j < ZH_CN_HEIGHT_WIDTH; j++ )
    316         {
    317             //os_printf("Font: %d
    ",Font.FontWidth);
    318             if ( (b << j) & 0x8000 )
    319             {
    320                 ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) color );
    321             } else {
    322                 ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) !color );
    323             }
    324         }
    325     }
    326 
    327     /* The current space is now taken */
    328     SSD1306.CurrentX += ZH_CN_HEIGHT_WIDTH;
    329 
    330     /* Return written char for validation */
    331      return(*ch);   
    332 }
    333 
    334 
    335 /* Write full string to screenbuffer */
    336 char ssd1306_WriteString( char* str, FontDef Font, SSD1306_COLOR color )
    337 {
    338     /* Write until null-byte */
    339     while ( *str )
    340     {
    341         if ( ssd1306_WriteChar( *str, Font, color ) != *str )
    342         {
    343             /* Char could not be written */
    344             
    345             return(*str);
    346         }
    347 
    348         /* Next char */
    349         str++;
    350     }
    351 
    352     /* Everything ok */
    353     return(*str);
    354 }
    355 
    356 /* Write full Chinese string to screenbuffer */
    357 char ssd1306_WriteZhString( signed char *str, SSD1306_COLOR color ){
    358 
    359     /* Write until null-byte */
    360     while ( *str )
    361     {
    362         ssd1306_WriteZhChar( (signed char *)str, color );
    363         /* Next char */
    364         str = str + 3;
    365 
    366     }
    367     /* Everything ok */
    368     return(*str);
    369 
    370 }
    371 
    372 
    373 /* Position the cursor */
    374 void ssd1306_SetCursor( uint8_t x, uint8_t y )
    375 {
    376     SSD1306.CurrentX    = x;
    377     SSD1306.CurrentY    = y;
    378 }

    为了汉字显示的和谐统一,目前仅支持16*16点阵的宋体,汉字显示效果如下:

    缺点:

    1. 不支持中英文混显,就是写中文和英文都有单独的函数,如果想在一行中显示中英文就可能需要分开写。
    2. 刷新速度慢,其实这里也不全是全局刷新的原因,也是ESP8266没有硬件IIC,只能使用模拟IICd的原因。

    最后我们结合一下DHT11和SSD1306做一个桌面温湿度显示仪,主要代码:

     1 uint8 temp,humd;
     2 os_timer_t DHT11_Read_timer;
     3 
     4 void ICACHE_FLASH_ATTR DHT11_Read(void)
     5 {
     6     char temp_buffer[10],humd_buffer[10];
     7     os_timer_disarm(&DHT11_Read_timer);//取消定时器
     8     dh11Read(&temp,&humd);
     9     os_printf("Temp: %d'C Humd: %d%
    ",temp,humd);
    10     os_sprintf(temp_buffer,":%d'",temp);
    11     os_sprintf(humd_buffer,":%d%",humd);
    12     ssd1306_SetCursor(0, 40);
    13     ssd1306_WriteZhString("温度",White);
    14     ssd1306_SetCursor(30, 44);
    15     ssd1306_WriteString(temp_buffer,Font_7x10,White);
    16     ssd1306_SetCursor(64, 40);
    17     ssd1306_WriteZhString("湿度",White);
    18     ssd1306_SetCursor(94, 44);
    19     ssd1306_WriteString(humd_buffer,Font_7x10,White);
    20     ssd1306_UpdateScreen();
    21     os_timer_arm(&DHT11_Read_timer, 5000, true);//使能定时器
    22 }
    23 
    24 void user_init(void)
    25 {
    26     uart_init(115200, 115200);
    27 
    28     dh11Init();
    29 
    30     i2c_master_gpio_init();
    31 
    32     ssd1306_Init();
    33 
    34     ssd1306_Fill(Black);
    35     ssd1306_SetCursor(8, 0);
    36     ssd1306_WriteZhString("神奇物联网之旅",White);
    37     ssd1306_SetCursor(20, 16);
    38     ssd1306_WriteString("IAMLIUBO",Font_11x18,White);
    39     ssd1306_UpdateScreen();
    40 
    41     os_timer_disarm(&DHT11_Read_timer);//取消定时器
    42     os_timer_setfn(&DHT11_Read_timer, (os_timer_func_t *) DHT11_Read,NULL);//定时回调函数
    43     os_timer_arm(&DHT11_Read_timer, 5000, true);//使能定时器,设置时间为1s
    44 
    45 }

    我们直接看一下效果:

    最后附上我的Github仓库,一些小的Demo没有写相应的文章,但是不断更新,建议大家Star或者watch一下,以便及时获得新的例程~

    imliubo/makingfunxyz-esp8266​github.com

    欢迎大家去我的仓库点个star,有问题或者Bug可以提交issues,我看到后会第一时间回复,如果您对我的代码有改进意见,也欢迎fork后提交PR,我会及时采纳大家的意见。

    夜深了,晚安。

    QQ交流群:592587184

    唯有爱与科技不可辜负。
  • 相关阅读:
    wu
    Win10编译cuda版OpenCV
    Windows编译OpenCV可能下载失败的文件
    20220419Servlet和HTTP请求协议
    20220418Tomcat
    比 Navicat 还要好用、功能更强大的工具!
    Java 8的18个常用日期处理
    Oracle 执行存储过程五种方法(带参数& 不带参数)
    帆软设置浏览内容宽度为屏幕宽度
    帆软参数为空查询全部
  • 原文地址:https://www.cnblogs.com/imliubo/p/10577333.html
Copyright © 2020-2023  润新知