dirty 发表于 2024-7-19 22:22

【全能小网关|CH32V208】--8.图形库u8g2的oled显示

<div class='showpostmsg'> 本帖最后由 dirty 于 2024-7-19 22:34 编辑

<p>&nbsp; &nbsp; &nbsp; 本篇讲述使用u8g2图形库驱动oled显示,使用改图形库优势功能强大,具有字体库,包含中文GB2312,显示汉字非常方便全面,不用取模工具去取汉字点阵,此外也有很多可界面设计的API函数,非常推荐实际工程项目中使用。</p>

<p>&nbsp;</p>

<p><strong><span style="color:#0000ff;">一.准备工作</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 本次使用ssd1306驱动OLED屏,像素分辨率128*32,I2C接口。<a href="https://github.com/olikraus/u8g2" target="_blank"><span style="color:#0000ff;"><strong>u8g2</strong></span></a>是单色显示库的第二个版本,其是开源的。u8g2支持lcd和oled,支持众多驱动芯片,包含了SSD1306,具体支持驱动情况可以资源库查看到。</p>

<p>硬件连接如下:</p>

<p>开发板&nbsp; &nbsp; &nbsp;OLED</p>

<p>PB9&nbsp; &nbsp; &nbsp; SDA</p>

<p>PB8&nbsp; &nbsp; &nbsp; SCL&nbsp; &nbsp;</p>

<p>3V3&nbsp; &nbsp; &nbsp; &nbsp;VCC</p>

<p>GND&nbsp; &nbsp; &nbsp;GND</p>

<p>&nbsp;</p>

<p><strong><span style="color:#0000ff;">二.代码准备</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 本工程移植支持ssd1306 128*64/128*32分辨率,通过如下宏选择使用。移植中注意根据需要裁剪,不需要的尽量删掉,避免占用资源。</p>

<pre>
<code>#define SSD1306_128x641
#define SSD1306_128x322

#define SSD1306_DEVICESSD1306_128x32//SSD1306_128x64//</code></pre>

<p>1.u8g2资源克隆下来后,使用scrc文件里资源</p>

<p>2.删除u8x8_d_xxx.c非相关驱动源文件.这里选择 ssd1306 128x64/128x32(选其中一个)</p>

<p>3.u8g2_d_setup.c源文件选择使用的驱动芯片初始化函数,删除其他。这里保留选择u8g2_Setup_ssd1306_i2c_128x64_noname_f/u8g2_Setup_ssd1306_i2c_128x32_univision_f</p>

<p>4.修改&ldquo;u8g2_d_memory.c&rdquo;文件,这个文件里面其实就是&ldquo;u8g2_d_setup.c&rdquo;文件对应的缓冲区,同上面一样,屏蔽掉没用到的,留下用到的</p>

<p>5.关于字库.u8g2_fonts.c&rdquo;文件中定义了各种字库,这些字库比较占用空间,根据使用情况屏蔽掉没有使用的。使用到GB2312字体库,需要使能宏U8G2_USE_LARGE_FONTS。具体做法如下:</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图1:使能GB2312字体库</div>

<p>6.两个回调函数<br />
void u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);参数byte_cb和gpio_and_delay_cb是需要编写的两个回调函数。byte_cb:是通信相关的函数,比如i2c写数据,gpio_and_delay_cb:是延时相关的函数。通信函数分为硬件接口和软件模拟方式,软件模拟方式官方基本写好了,只需要简单的指定io口即可。这里使用硬件方式。实现如下:</p>

<pre>
<code>uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
      static uint8_t buffer; /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
      static uint8_t buf_idx;
      uint8_t *data;

      switch (msg)
      {
      case U8X8_MSG_BYTE_SEND:
            data = (uint8_t *)arg_ptr;
            while (arg_int &gt; 0)
            {
                  buffer = *data;
                  data++;
                  arg_int--;
            }
            break;

      case U8X8_MSG_BYTE_INIT:
            /* add your custom code to init i2c subsystem */
            break;

      case U8X8_MSG_BYTE_START_TRANSFER:
            buf_idx = 0;
            break;

      case U8X8_MSG_BYTE_END_TRANSFER:
            HW_I2cWrite(buffer, buf_idx);   //硬件I2C写字节
            break;

      default:
            return 0;
      }
      return 1;
}

uint8_t u8g2_gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
      switch (msg)
      {
      case U8X8_MSG_GPIO_AND_DELAY_INIT:
            OLED_I2C_Init();    //初始化
            break;

      case U8X8_MSG_DELAY_MILLI:
            Delay_Ms(arg_int);//延时
            break;

      case U8X8_MSG_GPIO_I2C_CLOCK:
            break;

      case U8X8_MSG_GPIO_I2C_DATA:
            break;

      default:
            return 0;
      }
      return 1; // command processed successfully.
}</code></pre>

<p>7.u8g2初始化</p>

<pre>
<code>void u8g2_Init(u8g2_t *u8g2)
{
   #if(SSD1306_DEVICE==SSD1306_128x64)
          u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8g2_gpio_and_delay); // 初始化 u8g2,硬件I2C
      #elif(SSD1306_DEVICE==SSD1306_128x32)
          u8g2_Setup_ssd1306_i2c_128x32_univision_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8g2_gpio_and_delay);
          #endif
          u8g2_InitDisplay(u8g2);                 //根据所选芯片初始化,完成后显示器处于关闭状态                                                                      // 根据所选的芯片进行初始化工作,初始化完成后,显示器处于关闭状态
      u8g2_SetPowerSave(u8g2, 0);         //唤醒显示器                                                               
      u8g2_SetContrast(u8g2, 88);        //设置对比度                                                               
      u8g2_ClearBuffer(u8g2);            //清除显示缓存                                                               
}</code></pre>

<p>8.设计界面</p>

<p>(1)画对角线</p>

<pre>
<code>   #if(SSD1306_DEVICE==SSD1306_128x64)
        u8g2_DrawLine(&amp;u8g2, 0, 0, 127, 63); // 画一条线,起始坐标(0,0),终点坐标(127,63)
        u8g2_SendBuffer(&amp;u8g2);            // 发送缓冲区数据
        u8g2_DrawLine(&amp;u8g2, 127, 0, 0, 63);
        u8g2_SendBuffer(&amp;u8g2);
    #elif(SSD1306_DEVICE==SSD1306_128x32)
        u8g2_DrawLine(&amp;u8g2, 0, 0, 127, 31); // 画一条线,起始坐标(0,0),终点坐标(127,63)
    u8g2_SendBuffer(&amp;u8g2);            // 发送缓冲区数据
    u8g2_DrawLine(&amp;u8g2, 127, 0, 0, 31);
    u8g2_SendBuffer(&amp;u8g2);
    #endif</code></pre>

<p>(2)画U8g2的Logo大体的,横着放,竖着放等。</p>

<pre>
<code>void draw(u8g2_t *u8g2)
{
        #if(SSD1306_DEVICE==SSD1306_128x64)
        u8g2_SetFontMode(u8g2, 1);            /*字体模式选择*/
        u8g2_SetFontDirection(u8g2, 0);         /*字体方向选择*/
        u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/
        u8g2_DrawStr(u8g2, 0, 20, "U");

        u8g2_SetFontDirection(u8g2, 1);
        u8g2_SetFont(u8g2, u8g2_font_inb30_mn);
        u8g2_DrawStr(u8g2, 21, 8, "8");

        u8g2_SetFontDirection(u8g2, 0);
        u8g2_SetFont(u8g2, u8g2_font_inb24_mf);
        u8g2_DrawStr(u8g2, 51, 30, "g");
        u8g2_DrawStr(u8g2, 67, 30, "\xb2");

        u8g2_DrawHLine(u8g2, 2, 35, 47);
        u8g2_DrawHLine(u8g2, 3, 36, 47);
        u8g2_DrawVLine(u8g2, 45, 32, 12);
        u8g2_DrawVLine(u8g2, 46, 33, 12);

        u8g2_SetFont(u8g2, u8g2_font_4x6_tr);
        u8g2_DrawStr(u8g2, 1, 54, "github.com/olikraus/u8g2");

        #elif(SSD1306_DEVICE==SSD1306_128x32)

        u8g2_SetFontMode(u8g2, 1);            /*字体模式选择*/
        u8g2_SetFontDirection(u8g2, 0);         /*字体方向选择*/
        u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/
        u8g2_DrawStr(u8g2, 0, 24, "U");

        u8g2_SetFontDirection(u8g2, 1);
        u8g2_SetFont(u8g2, u8g2_font_inb30_mn);
        u8g2_DrawStr(u8g2, 24, 8, "8");

        u8g2_SetFontDirection(u8g2, 0);
        u8g2_SetFont(u8g2, u8g2_font_inb24_mf);
        u8g2_DrawStr(u8g2, 64, 24, "g");
        u8g2_DrawStr(u8g2, 96, 32, "\xb2");

        #endif

}</code></pre>

<p>(3)显示中英文。这里显示我们EEWorld和沁恒相关的。</p>

<pre>
<code>        #if(SSD1306_DEVICE==SSD1306_128x64)
        u8g2_ClearBuffer(&amp;u8g2);
        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB14_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 0, 15, "Hello World!");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy16_t_chinese2);
        u8g2_DrawUTF8(&amp;u8g2, 0, 30, "H你好世界");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy12_t_chinese2);
        u8g2_DrawUTF8(&amp;u8g2, 0, 43, "H你好世界");
       
        u8g2_SetFont(&amp;u8g2, u8g2_font_fur11_tr);
        u8g2_DrawUTF8(&amp;u8g2, 0, 59, "blog.zeruns.tech");
        #elif(SSD1306_DEVICE==SSD1306_128x32)
        u8g2_ClearBuffer(&amp;u8g2);
        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB14_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 0, 14, "EEWorld");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy13_t_gb2312);
        u8g2_DrawUTF8(&amp;u8g2, 0, 30, "沁恒");

        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB08_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 26, 30, "CH32V208");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy13_t_gb2312);
        u8g2_DrawUTF8(&amp;u8g2, 80, 30, "开发板");

        #endif</code></pre>

<p>(4)循环显示渐变同心圆。</p>

<pre>
<code>        while(1)
        {
          Delay_Ms(100);
                u8g2_ClearBuffer(&amp;u8g2);//清除缓冲区数据
                #if(SSD1306_DEVICE==SSD1306_128x64)
                if (++t &gt;= 32)
                        t = 1;
                u8g2_DrawCircle(&amp;u8g2, 64, 32, t, U8G2_DRAW_ALL);   //画圆
                u8g2_DrawCircle(&amp;u8g2, 32, 32, t, U8G2_DRAW_ALL);
                u8g2_DrawCircle(&amp;u8g2, 96, 32, t, U8G2_DRAW_ALL);
                u8g2_SendBuffer(&amp;u8g2); // 发送缓冲区数据
                #elif(SSD1306_DEVICE==SSD1306_128x32)
                if (++t &gt;= 16)
                        t = 1;
                u8g2_DrawCircle(&amp;u8g2, 64, 16, t, U8G2_DRAW_ALL);   //画圆
                u8g2_DrawCircle(&amp;u8g2, 32, 16, t, U8G2_DRAW_ALL);
                u8g2_DrawCircle(&amp;u8g2, 96, 16, t, U8G2_DRAW_ALL);
                u8g2_SendBuffer(&amp;u8g2); // 发送缓冲区数据

                #endif

        }</code></pre>

<p>9.主函数如下。这里工程u8g2源文件添加等就不具体讲了。</p>

<pre>
<code>int main(void)
{
        uint8_t t = 0;

    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);
    printf( "SystemClk:%d\r\n", SystemCoreClock );
    printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

        OLED_I2C_Init();

    u8g2_Init(&amp;u8g2);   //初始化U8g2
        Delay_Ms(100);

    #if(SSD1306_DEVICE==SSD1306_128x64)
        u8g2_DrawLine(&amp;u8g2, 0, 0, 127, 63); // 画一条线,起始坐标(0,0),终点坐标(127,63)
        u8g2_SendBuffer(&amp;u8g2);            // 发送缓冲区数据
        u8g2_DrawLine(&amp;u8g2, 127, 0, 0, 63);
        u8g2_SendBuffer(&amp;u8g2);
    #elif(SSD1306_DEVICE==SSD1306_128x32)
        u8g2_DrawLine(&amp;u8g2, 0, 0, 127, 31); // 画一条线,起始坐标(0,0),终点坐标(127,63)
    u8g2_SendBuffer(&amp;u8g2);            // 发送缓冲区数据
    u8g2_DrawLine(&amp;u8g2, 127, 0, 0, 31);
    u8g2_SendBuffer(&amp;u8g2);
    #endif

        Delay_Ms(300);

        u8g2_ClearBuffer(&amp;u8g2);//清除缓冲区数据
        draw(&amp;u8g2);
        u8g2_SendBuffer(&amp;u8g2);
        Delay_Ms(1000);
       
        #if(SSD1306_DEVICE==SSD1306_128x64)
        u8g2_ClearBuffer(&amp;u8g2);
        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB14_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 0, 15, "Hello World!");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy16_t_chinese2);
        u8g2_DrawUTF8(&amp;u8g2, 0, 30, "H你好世界");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy12_t_chinese2);
        u8g2_DrawUTF8(&amp;u8g2, 0, 43, "H你好世界");
       
       
        #elif(SSD1306_DEVICE==SSD1306_128x32)
        u8g2_ClearBuffer(&amp;u8g2);
        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB14_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 0, 14, "EEWorld");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy13_t_gb2312);
        u8g2_DrawUTF8(&amp;u8g2, 0, 30, "沁恒");

        u8g2_SetFont(&amp;u8g2, u8g2_font_ncenB08_tr);    //选择字库
        u8g2_DrawStr(&amp;u8g2, 26, 30, "CH32V208");

        u8g2_SetFont(&amp;u8g2, u8g2_font_wqy13_t_gb2312);
        u8g2_DrawUTF8(&amp;u8g2, 80, 30, "开发板");

        #endif

        u8g2_SendBuffer(&amp;u8g2);

        Delay_Ms(1300);

        while(1)
        {
          Delay_Ms(100);
                u8g2_ClearBuffer(&amp;u8g2);//清除缓冲区数据
                #if(SSD1306_DEVICE==SSD1306_128x64)
                if (++t &gt;= 32)
                        t = 1;
                u8g2_DrawCircle(&amp;u8g2, 64, 32, t, U8G2_DRAW_ALL);   //画圆
                u8g2_DrawCircle(&amp;u8g2, 32, 32, t, U8G2_DRAW_ALL);
                u8g2_DrawCircle(&amp;u8g2, 96, 32, t, U8G2_DRAW_ALL);
                u8g2_SendBuffer(&amp;u8g2); // 发送缓冲区数据
                #elif(SSD1306_DEVICE==SSD1306_128x32)
                if (++t &gt;= 16)
                        t = 1;
                u8g2_DrawCircle(&amp;u8g2, 64, 16, t, U8G2_DRAW_ALL);   //画圆
                u8g2_DrawCircle(&amp;u8g2, 32, 16, t, U8G2_DRAW_ALL);
                u8g2_DrawCircle(&amp;u8g2, 96, 16, t, U8G2_DRAW_ALL);
                u8g2_SendBuffer(&amp;u8g2); // 发送缓冲区数据

                #endif

        }
}</code></pre>

<p>&nbsp;</p>

<p><strong><span style="color:#0000ff;">三.测验</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 编译烧录后,可以看到惊艳的显示效果如下,使用u8g2做关于oled的显示设计,真的很丰富灵活。</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">
<div style="text-align: center;"></div>

<div style="text-align: center;">
<div style="text-align: center;"></div>

<p>&nbsp;</p>
</div>

<p>&nbsp;</p>
</div>

<p>&nbsp; &nbsp; &nbsp; 效果视频如下:</p>

<p>80bfe27277321948c2327edbadf25f48<br />
&nbsp;</p>

<p>&nbsp; &nbsp; &nbsp; 源代码该文下置顶帖,敬请关注。</p>

<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>

dirty 发表于 2024-7-23 23:22

<p><strong><span style="color:#e74c3c;">图形库u8g2的oled工程</span></strong></p>

<p>&nbsp;</p>

lugl4313820 发表于 2024-7-20 11:50

<p>&nbsp;本篇讲述使用u8g2图形库驱动oled显示,使用改图形库优势功能强大,具有字体库,包含中文GB2312,显示汉字非常方便全面,不用取模工具去取汉字点阵,此外也有很多可界面设计的API函数,非常推荐实际工程项目中使用。</p>

<p>flash够用吗?</p>

dirty 发表于 2024-7-20 16:55

lugl4313820 发表于 2024-7-20 11:50
&nbsp;本篇讲述使用u8g2图形库驱动oled显示,使用改图形库优势功能强大,具有字体库,包含中文GB2312,显示 ...

<p>够用,注意芯片用法,配置可到480K. U8g2使用中文库GB2312,资源消耗在300K左右。</p>
页: [1]
查看完整版本: 【全能小网关|CH32V208】--8.图形库u8g2的oled显示