[外設(shè)篇]ESP8266-SDK教程(十)之DHT11坎怪、OLED1306

Hi岖沛,大家好暑始,寫這篇文章的時(shí)候“IAMLIUBO的神奇物聯(lián)網(wǎng)之旅”專欄關(guān)注人數(shù)已經(jīng)有186人了,首先很感謝大家的關(guān)注和相信婴削,開始寫第一篇的文章的時(shí)候也沒想過會(huì)有這么多人感興趣廊镜,看到關(guān)注的人數(shù)越來越多,當(dāng)然對(duì)文章的質(zhì)量也要有更高的要求唉俗,力求每篇文章沒有錯(cuò)別字和錯(cuò)誤的敘述嗤朴,也希望大家可以幫我一起勘誤配椭。寫這些文章的目的就是希望可以幫助更多人,當(dāng)然也收獲了很多知友播赁,也有很多知友加我微信咨詢一些問題颂郎,希望我的每一個(gè)回答都對(duì)你有所幫助,這篇文章是外設(shè)篇的第一篇容为,也是知友小牛最近在微信咨詢我的一點(diǎn)問題乓序,這里就記錄成文章跟大家分享一下。

閑話少說坎背,咱們開始來說正事替劈,相信大家在做一些實(shí)際項(xiàng)目或者小發(fā)明創(chuàng)造的時(shí)候,多多少少都會(huì)用過溫濕度傳感器得滤,或者說會(huì)采集溫濕度數(shù)據(jù)加以展示和判斷處理陨献,那么我們這里說的DHT11就是一款非常不錯(cuò)的溫濕度傳感器,是廣州奧松電子生產(chǎn)的一款溫濕度傳感器懂更,在開發(fā)當(dāng)中我是用的比較多的眨业,上一張圖給大家看一下。

image

當(dāng)然沮协,這款傳感器尺寸不是很小龄捡,做一些對(duì)尺寸要求比較嚴(yán)格的產(chǎn)品還是不怎么推薦的,一般做比較小的產(chǎn)品慷暂,還是比較推薦盛思瑞的SHT系列聘殖,當(dāng)然價(jià)格就不是那么美麗了,但是精度相對(duì)來說還是比較不錯(cuò)的行瑞,當(dāng)然對(duì)大小和空間都有要求的話推薦美信的DS18B20奸腺。

image

下面我們來看一下這款傳感器的具體參數(shù):

image
image
image

上面這三個(gè)表,就可以很直觀的看出這款傳感器的參數(shù)了血久,這里就不再做過多的文字?jǐn)⑹隽恕?/p>

了解完了這些基本的突照,那我們?cè)賮砜匆幌挛覀兪侨绾螐膫鞲衅魅〉綔貪穸鹊闹的兀空f到這里氧吐,那就不得不提一個(gè)概念了讹蘑,相信搞嵌入式開發(fā)的都知道,那就是單總線通信方式副砍,那么什么是單總線通信方式呢衔肢?它與其他通信方式又有什么不同呢?下面我們先來看一下百科:

單總線是美國(guó)DALLAS公司推出的外圍串行擴(kuò)展總線技術(shù)豁翎。與SPI角骤、I2C串行數(shù)據(jù)通信方式不同.它采用單根信號(hào)線,既傳輸時(shí)鐘又傳輸數(shù)據(jù),而且數(shù)據(jù)傳輸是雙向的邦尊,具有節(jié)省I/O口線背桐、資源結(jié)構(gòu)簡(jiǎn)單、成本低廉蝉揍、便于總線擴(kuò)展和維護(hù)等諸多優(yōu)點(diǎn)链峭。(百度百科)

簡(jiǎn)單來說,就是雙方通信只通過一根線解決又沾,不像其他通信方式有時(shí)鐘線和數(shù)據(jù)線弊仪,這樣的好處是極大的節(jié)省了I/O資源,當(dāng)然這種通信方式的速率自然也會(huì)有所降低杖刷,像前面說的DS18B20也是采用單總線通信方式励饵。

那么我們?cè)賮砜匆幌翫HT11通過單總線發(fā)送的數(shù)據(jù)格式,了解了數(shù)據(jù)格式可以更好的幫助我們理解程序是如何讀取溫濕度的滑燃,因?yàn)閿?shù)據(jù)傳輸在硬件層就是電平高低役听,轉(zhuǎn)化為計(jì)算機(jī)語(yǔ)言就是0/1,我們就是通過DHT11發(fā)送的這些0/1中找出溫濕度的值:

image

可以看到一共是有40位數(shù)據(jù)的表窘,每8位是一組典予,包含了溫濕度和校驗(yàn)值,校驗(yàn)值等于溫濕度的和乐严,如果不理解瘤袖,那么我們通過一個(gè)實(shí)際例子來看一下:

image

這就是一個(gè)完整的數(shù)據(jù)包過來,我們?nèi)绾谓獍万?yàn)證麦备,那么我們看一下代碼:

static uint8_t ICACHE_FLASH_ATTR dht11ReadBit(void)
{
    uint8_t retry=0;

    while(DHT11_IN&&retry<100)                                  //wait become Low level
    {
        retry++;
        tempHumDelay(1);
    }

    retry=0;
    while(!DHT11_IN&&retry<100)                                 //wait become High level
    {
        retry++;
        tempHumDelay(1);
    }

    tempHumDelay(40);                                         //wait 40us

    if(DHT11_IN)
        return 1;
    else
        return 0;
}

static uint8_t ICACHE_FLASH_ATTR hdt11ReadByte(void)
{
    uint8_t i;
    uint8_t dat=0;

    for (i=0; i<8; i++)
    {
        dat<<=1;
        dat |= dht11ReadBit(); 
    }

    return dat;
}

static uint8_t ICACHE_FLASH_ATTR dht11ReadData(u8 * temperature, u8 * humidity)
{
    uint8_t i;
    uint8_t buf[5];

    dht11Rst(); 
    if(0 == dht11Check()) 
    {
        for(i=0; i<5; i++)
        {
            buf[i] = hdt11ReadByte(); 
        }
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
        {
            *humidity=buf[0];
            *temperature=buf[2];
        }
    }
    else
    {
        return 1;
    }

    return 0;
}

uint8_t ICACHE_FLASH_ATTR dh11Read(uint8_t * temperature, uint8_t * humidity)
{
    uint8_t ret = 0; 
    uint8_t cur_i = 0;
    uint8_t curTem = 0;
    uint8_t curHum = 0;
    uint16_t temMeans = 0;
    uint16_t hum_means = 0;

    ret = dht11ReadData(&curTem, &curHum);

    if(0 == ret) 
    {
        //Cycle store ten times stronghold
        if(MEAN_NUM > temphum_typedef.th_num)
        {
            temphum_typedef.th_bufs[temphum_typedef.th_num][0] = curTem;
            temphum_typedef.th_bufs[temphum_typedef.th_num][1] = curHum;

            temphum_typedef.th_num++;
        }
        else
        {
            temphum_typedef.th_num = 0;

            temphum_typedef.th_bufs[temphum_typedef.th_num][0] = curTem;
            temphum_typedef.th_bufs[temphum_typedef.th_num][1] = curHum;

            temphum_typedef.th_num++;
        }
    }
    else
    {
        return 1; 
    }

    if(MEAN_NUM <= temphum_typedef.th_num) 
    {
        temphum_typedef.th_amount = MEAN_NUM;
    }

    if(0 == temphum_typedef.th_amount) 
    {
        //Calculate Before ten the mean
        for(cur_i = 0; cur_i < temphum_typedef.th_num; cur_i++)
        {
            temMeans += temphum_typedef.th_bufs[cur_i][0];
            hum_means += temphum_typedef.th_bufs[cur_i][1];
        }

        temMeans = temMeans / temphum_typedef.th_num;
        hum_means = hum_means / temphum_typedef.th_num; 

        *temperature = temMeans;
        *humidity = hum_means;
    }
    else if(MEAN_NUM == temphum_typedef.th_amount) 
    {
        //Calculate After ten times the mean
        for(cur_i = 0; cur_i < temphum_typedef.th_amount; cur_i++) 
        {
            temMeans += temphum_typedef.th_bufs[cur_i][0];
            hum_means += temphum_typedef.th_bufs[cur_i][1];
        }

        temMeans = temMeans / temphum_typedef.th_amount; 
        hum_means = hum_means / temphum_typedef.th_amount; 

        *temperature = (uint8_t)temMeans; 
        *humidity = (uint8_t)hum_means; 
    }

    return 0;
}

這就是我們讀溫濕度的主要代碼孽椰,大家可以看一下昭娩,我們是不是對(duì)40位的bit位的數(shù)據(jù)做了處理呢凛篙?后面我們會(huì)結(jié)合OLED顯示屏來實(shí)際測(cè)試一下,這里就先不做測(cè)試了栏渺。

說完了DHT11呛梆,我們?cè)賮砹私庖幌耂SD1306,其實(shí)這是一款OLED屏幕的控制芯片磕诊,目前在淘寶等常見的0.96吋小OLED顯示屏幕大多就是使用這款芯片的填物,當(dāng)然還有一款功能一樣的替代芯片叫SHT1106,不過兩者指令兼容霎终,所以會(huì)一款滞磺,另一款也就會(huì)了。這款主控芯片是香港晶門科技公司的莱褒,目前在一般小制作或者小創(chuàng)意上用這款主控的顯示屏幕還是比較多的击困,我也一直在使用,這款芯片最大只能控制128x64個(gè)像素點(diǎn)广凸,所以有時(shí)候我們常說的OLED12864阅茶,多也是使用這塊主控的屏幕蛛枚,當(dāng)然這家公司也生產(chǎn)很多可以控制更多像素點(diǎn)的主控芯片,有興趣的可以去官網(wǎng)了解一下:

晶門科技有限公司?www.solomon-systech.com.cn

同樣的脸哀,我們先來了解一下蹦浦,遺憾的是沒有找到官方的中文數(shù)據(jù)手冊(cè),又怕某些翻譯的不太準(zhǔn)確撞蜂,所以這里就直接貼英文數(shù)據(jù)手冊(cè)的截圖了:

image

其中我們做開發(fā)需要關(guān)注的就是上面提到的兩種通信方式了盲镶,可以看到是支持IIC和SPI通信方式的,還支持亮度調(diào)節(jié)蝌诡,我這里其實(shí)最近重新擼了一下驅(qū)動(dòng)徒河,之前也是一直拿來別人寫好的直接用,最近比較想自己動(dòng)手?jǐn)]一下送漠,于是也借鑒別人寫的顽照,自己看著數(shù)據(jù)手冊(cè)重新寫了一下,當(dāng)然過程沒那么順利闽寡,我這里是使用IIC通信的代兵,但是由于ESP8266沒有硬件IIC,這刷新效果也是有點(diǎn)感人爷狈,其實(shí)最重要的也是采用了全局刷新方式植影,沒有寫局部刷新的驅(qū)動(dòng),就導(dǎo)致每次修改某一個(gè)地方涎永,都會(huì)把所有的像素點(diǎn)重新寫一遍~自然這FPS就降下來了思币,后面再考慮優(yōu)化吧,但是通過整個(gè)過程也是對(duì)工作方式有了更深的了解羡微,呃呃呃谷饿,又講遠(yuǎn)了。

我們?cè)賮砜匆幌轮饕匦裕?/p>

image

我們?cè)賮砜匆幌鲁叽缏杈螅梢哉f是非常薄了博投,我們是不可能用手焊接的,一般買也是買別人把芯片跟顯示屏封裝好的模組的:

image

可以看到厚度只有0.3mm盯蝴,這里給大家看一下跟屏幕封裝好的模組毅哗,這也是前不久做一款STM32 Mini開發(fā)板的顯示擴(kuò)展板剩下的:

image
image

按理說接下來我們應(yīng)該講一下如何去驅(qū)動(dòng)這款芯片了,但是相比于溫濕度傳感器來說捧挺,就有點(diǎn)復(fù)雜了虑绵,而且也比較難講清楚,不過這里推薦大家看一下杜洋老師對(duì)這款芯片的視頻講解闽烙,戳看片觀看:

優(yōu)酷視頻?v.youku.com

分了好幾集翅睛,上面卡片是第一集,大家可以看一下,個(gè)人認(rèn)為講的還是比較不錯(cuò)的宏所。

下面我們來看一下我這擼的驅(qū)動(dòng)代碼的酥艳,目前支持IIC通信和中英文顯示,由于手頭沒有SPI接口的屏幕爬骤,也沒法測(cè)試充石,所以有機(jī)會(huì)再更新SPI通信方式的。

/*
 * MIT License
 *
 * Copyright (c) 2018 imliubo
 *
 * Github  https://github.com/imliubo
 * Website https://www.makingfun.xyz
 * Zhihu   https://www.zhihu.com/people/MAKINGFUNXYZ
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "modules/ssd1306.h"

#if defined(SSD1306_USE_I2C)
int ICACHE_FLASH_ATTR
HAL_I2C_Mem_Write( uint16_t DevAddress, uint16_t MemAddress, uint8_t pData, uint16_t Size )
{
    i2c_master_start();
    i2c_master_writeByte( DevAddress );
    if ( !i2c_master_checkAck() )
    {
        i2c_master_stop();
        return(0);
    }

    i2c_master_writeByte( MemAddress );
    if ( !i2c_master_checkAck() )
    {
        i2c_master_stop();
        return(0);
    }

    i2c_master_writeByte( pData );
    if ( !i2c_master_checkAck() )
    {
        i2c_master_stop();
        return(0);
    }

    i2c_master_stop();
    return(1);
}

void ssd1306_Reset( void )
{
    /* for I2C - do nothing */
}

/* Send a byte to the command register */
void ssd1306_WriteCommand( uint8_t byte )
{
    HAL_I2C_Mem_Write( SSD1306_I2C_ADDR, 0x00, byte, 1 );
}

/* Send data */
void ssd1306_WriteData( uint8_t buffer, size_t buff_size )
{
    HAL_I2C_Mem_Write( SSD1306_I2C_ADDR, 0x40, buffer, buff_size );
}

#elif defined(SSD1306_USE_SPI)

#else
#error "You should define SSD1306_USE_SPI or SSD1306_USE_I2C macro"
#endif

/* Screenbuffer */
static uint8_t SSD1306_Buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];

/* Screen object */
static SSD1306_t SSD1306;

/* Initialize the oled screen */
void ssd1306_Init( void )
{
    /* Reset OLED */
    ssd1306_Reset();

    /* Wait for the screen to boot */
    os_delay_us( 60000 );
    os_delay_us( 40000 );

/*     // Init OLED */
    ssd1306_WriteCommand( 0xAE );   /* display off */

    ssd1306_WriteCommand( 0x20 );   /* Set Memory Addressing Mode */
    ssd1306_WriteCommand( 0x10 );   /*
                                     * 00,Horizontal Addressing Mode; 01,Vertical Addressing Mode;
                                     * 10,Page Addressing Mode (RESET); 11,Invalid
                                     */

    ssd1306_WriteCommand( 0xB0 );   /* Set Page Start Address for Page Addressing Mode,0-7 */

#ifdef SSD1306_MIRROR_VERT
    ssd1306_WriteCommand( 0xC0 );   /* Mirror vertically */
#else
    ssd1306_WriteCommand( 0xC8 );   /* Set COM Output Scan Direction */
#endif

    ssd1306_WriteCommand( 0x00 );   /* ---set low column address */
    ssd1306_WriteCommand( 0x10 );   /* ---set high column address */

    ssd1306_WriteCommand( 0x40 );   /* --set start line address - CHECK */

    ssd1306_WriteCommand( 0x81 );   /* --set contrast control register - CHECK */
    ssd1306_WriteCommand( 0xFF );

#ifdef SSD1306_MIRROR_HORIZ
    ssd1306_WriteCommand( 0xA0 );   /* Mirror horizontally */
#else
    ssd1306_WriteCommand( 0xA1 );    /*--set segment re-map 0 to 127 - CHECK */
#endif

#ifdef SSD1306_INVERSE_COLOR
    ssd1306_WriteCommand( 0xA7 );   /* --set inverse color */
#else
    ssd1306_WriteCommand( 0xA6 );   /* --set normal color */
#endif

    ssd1306_WriteCommand( 0xA8 );   /* --set multiplex ratio(1 to 64) - CHECK */
    ssd1306_WriteCommand( 0x3F );   /*  */

    ssd1306_WriteCommand( 0xA4 );   /* 0xa4,Output follows RAM content;0xa5,Output ignores RAM content */

    ssd1306_WriteCommand( 0xD3 );   /* -set display offset - CHECK */
    ssd1306_WriteCommand( 0x00 );   /* -not offset */

    ssd1306_WriteCommand( 0xD5 );   /* --set display clock divide ratio/oscillator frequency */
    ssd1306_WriteCommand( 0xF0 );   /* --set divide ratio */

    ssd1306_WriteCommand( 0xD9 );   /* --set pre-charge period */
    ssd1306_WriteCommand( 0x22 );   /*  */

    ssd1306_WriteCommand( 0xDA );   /* --set com pins hardware configuration - CHECK */
    ssd1306_WriteCommand( 0x12 );

    ssd1306_WriteCommand( 0xDB );   /* --set vcomh */
    ssd1306_WriteCommand( 0x20 );   /* 0x20,0.77xVcc */

    ssd1306_WriteCommand( 0x8D );   /* --set DC-DC enable */
    ssd1306_WriteCommand( 0x14 );   /*  */
    ssd1306_WriteCommand( 0xAF );   /* --turn on SSD1306 panel */

    /* Clear screen */
    ssd1306_Fill( Black );

    /* Flush buffer to screen */
    ssd1306_UpdateScreen();

    /* Set default values for screen object */
    SSD1306.CurrentX    = 0;
    SSD1306.CurrentY    = 0;

    SSD1306.Initialized = 1;
}

/* Fill the whole screen with the given color */
void ssd1306_Fill( SSD1306_COLOR color )
{
    /* Set memory */
    uint32_t i;

    for ( i = 0; i < sizeof(SSD1306_Buffer); i++ )
    {
        SSD1306_Buffer[i] = (color == Black) ? 0x00 : 0xFF;
    }
}

/* Write the screenbuffer with changed to the screen */
void ssd1306_UpdateScreen( void )
{
    uint8_t i, j;
    for ( i = 0; i < 8; i++ )
    {
        ssd1306_WriteCommand( 0xB0 + i );
        ssd1306_WriteCommand( 0x00 );
        ssd1306_WriteCommand( 0x10 );
        for ( int j = 0; j < 128; j++ )
        {
            /* code */
            ssd1306_WriteData( SSD1306_Buffer[j + SSD1306_WIDTH * i], SSD1306_WIDTH );
        }
    }
}

/*
 *    Draw one pixel in the screenbuffer
 *    X => X Coordinate
 *    Y => Y Coordinate
 *    color => Pixel color
 */
void ssd1306_DrawPixel( uint8_t x, uint8_t y, SSD1306_COLOR color )
{
    if ( x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT )
    {
        /* Don't write outside the buffer */
        return;
    }

    /* Check if pixel should be inverted */
    if ( SSD1306.Inverted )
    {
        color = (SSD1306_COLOR) !color;
    }

    /* Draw in the right color */
    if ( color == White )
    {
        SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] |= 1 << (y % 8);
    } else {
        SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8) );
    }
}

/*
 * Draw 1 char to the screen buffer
 * ch         => char om weg te schrijven
 * Font     => Font waarmee we gaan schrijven
 * color     => Black or White
 */
char ssd1306_WriteChar( char ch, FontDef Font, SSD1306_COLOR color )
{
    uint32_t i, b, j;

    /* Check remaining space on current line */
    if ( SSD1306_WIDTH <= (SSD1306.CurrentX + Font.FontWidth) ||
         SSD1306_HEIGHT <= (SSD1306.CurrentY + Font.FontHeight) )
    {
        /* Not enough space on current line */
        return(0);
    }

    /* Use the font to write */
    for ( i = 0; i < Font.FontHeight; i++ )
    {
        os_printf("Font: %d\n",ch);
        b = Font.data[(ch - 32) * Font.FontHeight + i];
        for ( j = 0; j < Font.FontWidth; j++ )
        {
            if ( (b << j) & 0x8000 )
            {
                ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) color );
            } else {
                ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) !color );
            }
        }
    }

    /* The current space is now taken */
    SSD1306.CurrentX += Font.FontWidth;

    /* Return written char for validation */
    return(ch);
}

/*
 * Draw 1 Chinese char to the screen buffer
 * ch         => char 
 * color     => Black or White
 */
char ssd1306_WriteZhChar( signed char ch[], SSD1306_COLOR color ){

    uint32_t  b, j, k, data[32];

    /* Check remaining space on current line */
    if ( SSD1306_WIDTH <= (SSD1306.CurrentX + 16) ||
         SSD1306_HEIGHT <= (SSD1306.CurrentY + 16) )
    {
        /* Not enough space on current line */
        return(0);
    }

    for (int i = 0; i < 20; ++i)
    {
        if ((ZhFont16x16[i].Index[0] == ch[0]) && (ZhFont16x16[i].Index[1] == ch[1]) && (ZhFont16x16[i].Index[2] == ch[2]) )
        {
            for (int z = 0; z < ZH_CN_HEIGHT_WIDTH; z++)
            {
                data[z] = ZhFont16x16[i].Msk[z];

            }
        }
    }

    for ( int i = 0; i < ZH_CN_HEIGHT_WIDTH; i++ )
    {

        b = data[i];
        for ( j = 0; j < ZH_CN_HEIGHT_WIDTH; j++ )
        {
            //os_printf("Font: %d\n",Font.FontWidth);
            if ( (b << j) & 0x8000 )
            {
                ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) color );
            } else {
                ssd1306_DrawPixel( SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) !color );
            }
        }
    }

    /* The current space is now taken */
    SSD1306.CurrentX += ZH_CN_HEIGHT_WIDTH;

    /* Return written char for validation */
     return(*ch);   
}

/* Write full string to screenbuffer */
char ssd1306_WriteString( char* str, FontDef Font, SSD1306_COLOR color )
{
    /* Write until null-byte */
    while ( *str )
    {
        if ( ssd1306_WriteChar( *str, Font, color ) != *str )
        {
            /* Char could not be written */

            return(*str);
        }

        /* Next char */
        str++;
    }

    /* Everything ok */
    return(*str);
}

/* Write full Chinese string to screenbuffer */
char ssd1306_WriteZhString( signed char *str, SSD1306_COLOR color ){

    /* Write until null-byte */
    while ( *str )
    {
        ssd1306_WriteZhChar( (signed char *)str, color );
        /* Next char */
        str = str + 3;

    }
    /* Everything ok */
    return(*str);

}

/* Position the cursor */
void ssd1306_SetCursor( uint8_t x, uint8_t y )
{
    SSD1306.CurrentX    = x;
    SSD1306.CurrentY    = y;
}

為了漢字顯示的和諧統(tǒng)一霞玄,目前僅支持16*16點(diǎn)陣的宋體骤铃,漢字顯示效果如下:

image

缺點(diǎn):

  1. 不支持中英文混顯,就是寫中文和英文都有單獨(dú)的函數(shù)坷剧,如果想在一行中顯示中英文就可能需要分開寫惰爬。
  2. 刷新速度慢,其實(shí)這里也不全是全局刷新的原因惫企,也是ESP8266沒有硬件IIC撕瞧,只能使用模擬IICd的原因。

最后我們結(jié)合一下DHT11和SSD1306做一個(gè)桌面溫濕度顯示儀狞尔,主要代碼:

uint8 temp,humd;
os_timer_t DHT11_Read_timer;

void ICACHE_FLASH_ATTR DHT11_Read(void)
{
    char temp_buffer[10],humd_buffer[10];
    os_timer_disarm(&DHT11_Read_timer);//取消定時(shí)器
    dh11Read(&temp,&humd);
    os_printf("Temp: %d'C Humd: %d%\n",temp,humd);
    os_sprintf(temp_buffer,":%d'",temp);
    os_sprintf(humd_buffer,":%d%",humd);
    ssd1306_SetCursor(0, 40);
    ssd1306_WriteZhString("溫度",White);
    ssd1306_SetCursor(30, 44);
    ssd1306_WriteString(temp_buffer,Font_7x10,White);
    ssd1306_SetCursor(64, 40);
    ssd1306_WriteZhString("濕度",White);
    ssd1306_SetCursor(94, 44);
    ssd1306_WriteString(humd_buffer,Font_7x10,White);
    ssd1306_UpdateScreen();
    os_timer_arm(&DHT11_Read_timer, 5000, true);//使能定時(shí)器
}

void user_init(void)
{
    uart_init(115200, 115200);

    dh11Init();

    i2c_master_gpio_init();

    ssd1306_Init();

    ssd1306_Fill(Black);
    ssd1306_SetCursor(8, 0);
    ssd1306_WriteZhString("神奇物聯(lián)網(wǎng)之旅",White);
    ssd1306_SetCursor(20, 16);
    ssd1306_WriteString("IAMLIUBO",Font_11x18,White);
    ssd1306_UpdateScreen();

    os_timer_disarm(&DHT11_Read_timer);//取消定時(shí)器
    os_timer_setfn(&DHT11_Read_timer, (os_timer_func_t *) DHT11_Read,NULL);//定時(shí)回調(diào)函數(shù)
    os_timer_arm(&DHT11_Read_timer, 5000, true);//使能定時(shí)器丛版,設(shè)置時(shí)間為1s

}

我們直接看一下效果:

image

最后附上我的Github倉(cāng)庫(kù),一些小的Demo沒有寫相應(yīng)的文章偏序,但是不斷更新页畦,建議大家Star或者watch一下,以便及時(shí)獲得新的例程~

imliubo/makingfunxyz-esp8266?github.com

歡迎大家去我的倉(cāng)庫(kù)點(diǎn)個(gè)star研儒,有問題或者Bug可以提交issues豫缨,我看到后會(huì)第一時(shí)間回復(fù),如果您對(duì)我的代碼有改進(jìn)意見端朵,也歡迎fork后提交PR好芭,我會(huì)及時(shí)采納大家的意見。

夜深了逸月,晚安栓撞。
QQ交流群:592587184

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遍膜,一起剝皮案震驚了整個(gè)濱河市碗硬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓢颅,老刑警劉巖恩尾,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異挽懦,居然都是意外死亡翰意,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冀偶,“玉大人醒第,你說我怎么就攤上這事〗” “怎么了稠曼?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)客年。 經(jīng)常有香客問我霞幅,道長(zhǎng),這世上最難降的妖魔是什么量瓜? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任司恳,我火速辦了婚禮,結(jié)果婚禮上绍傲,老公的妹妹穿的比我還像新娘扔傅。我一直安慰自己,他們只是感情好烫饼,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布铅鲤。 她就那樣靜靜地躺著,像睡著了一般枫弟。 火紅的嫁衣襯著肌膚如雪邢享。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天淡诗,我揣著相機(jī)與錄音骇塘,去河邊找鬼。 笑死韩容,一個(gè)胖子當(dāng)著我的面吹牛款违,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播群凶,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼插爹,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了请梢?” 一聲冷哼從身側(cè)響起赠尾,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毅弧,沒想到半個(gè)月后气嫁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡够坐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年寸宵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了崖面。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梯影,死狀恐怖巫员,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甲棍,我是刑警寧澤疏遏,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站救军,受9級(jí)特大地震影響财异,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唱遭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一戳寸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拷泽,春花似錦疫鹊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至脂矫,卻和暖如春枣耀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背庭再。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工捞奕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拄轻。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓颅围,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親恨搓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子院促,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容