物联网开发笔记(48)- 使用Micropython开发ESP32开发板之控制OLED ssd1306屏幕

news2025/7/18 5:48:01

一、目的

        这一节我们学习如何使用我们的ESP32开发板来控制OLED ssd1306屏幕,此处使用的是I2C协议,大家可自行百度学习一下I2C。

二、环境

        ESP32 + OLED ssd1306屏幕 + Thonny IDE(或者WOKWI在线仿真) + 几根杜邦线

本次使用在线仿真,笔者太了,写了那么多,也没人打赏,买不起设备了!!!

 接线方法:

 WOKWI在线仿真地址,国外网站,速度较慢:

Wokwi - Online Arduino and ESP32 Simulator

关于这个屏幕的具体介绍参考如下地址:

board-ssd1306 Reference | Wokwi Docs

三、代码

屏幕驱动芯片:

#MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_NORM_INV        = const(0xa6)
SET_DISP            = const(0xae)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)


class SSD1306:
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        # Note the subclass must initialize self.framebuf to a framebuffer.
        # This is necessary because the underlying data buffer is different
        # between I2C and SPI implementations (I2C needs an extra byte).
        self.poweron()
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00, # off
            # address setting
            SET_MEM_ADDR, 0x00, # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
            SET_MUX_RATIO, self.height - 1,
            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
            SET_DISP_OFFSET, 0x00,
            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV, 0x80,
            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
            # display
            SET_CONTRAST, 0xff, # maximum
            SET_ENTIRE_ON, # output follows RAM contents
            SET_NORM_INV, # not inverted
            # charge pump
            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01): # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_framebuf()

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)


class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        # Add an extra byte to the data buffer to hold an I2C data/command byte
        # to use hardware-compatible I2C transactions.  A memoryview of the
        # buffer is used to mask this byte from the framebuffer operations
        # (without a major memory hit as memoryview doesn't copy to a separate
        # buffer).
        self.buffer = bytearray(((height // 8) * width) + 1)
        self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
        self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80 # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_framebuf(self):
        # Blast out the frame buffer using a single I2C transaction to support
        # hardware I2C interfaces.
        self.i2c.writeto(self.addr, self.buffer)

    def poweron(self):
        pass


class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        self.buffer = bytearray((height // 8) * width)
        self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()

    def write_framebuf(self):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.high()
        self.cs.low()
        self.spi.write(self.buffer)
        self.cs.high()

    def poweron(self):
        self.res.high()
        time.sleep_ms(1)
        self.res.low()
        time.sleep_ms(10)
        self.res.high()

示例代码1

from machine import Pin, SoftI2C  # 导入Pin和软I2C模块
from time import sleep  # 导入时间模块
import ssd1306  # 导入屏幕驱动模块


# 创建i2c对象
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))  # 时钟接Pin22,数据接Pin21

# 宽度高度,屏幕宽高为128*64 像素
oled_width = 128  
oled_height = 64

# 创建oled屏幕对象
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)  # 设置宽度,高度和I2C通信

# 在指定位置处显示文字
oled.text('Shanghai!', 0, 0)  # 在屏幕的左上角开始显示
oled.text('Beijing welcome!', 0, 15) 
oled.text('Guangzhou beautiful!', 0, 25)
        
oled.show()  # 显示文字

示例代码2

from machine import Pin, I2C  # 导入PIN和I2C
from ssd1306 import SSD1306_I2C  # 导入屏幕驱动

#OLED=....
i2c = I2C(scl=Pin(22), sda=Pin(21))  # 创建I2C对象
OLED= SSD1306_I2C(128, 64, i2c)  # 创建OLED对象

#fonts=....字使用字典,字典的key来放字的编码的十六进制,键来放字模
fonts= {
    0xE5A5BD:
    [0x00,0x04,0x08,0x10,0x20,0xFF,0x11,0x12,0x14,0x18,0x24,0x42,0x00,0x00,0x00,0x00,
    0x00,0x00,0xF8,0x10,0x20,0xF8,0x40,0x20,0x10,0x08,0x28,0x10,0x00,0x00,0x00,0x00],  # 好
    
    0xE4BABA:
    [0x00,0x01,0x01,0x01,0x01,0x02,0x04,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00],  # 人
    
    0xE5A49A:
    [0x00,0x02,0x04,0x0F,0x18,0x25,0x02,0x0D,0x12,0x04,0x00,0x01,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x80,0xA0,0x40,0xF8,0x08,0xD0,0x20,0x40,0x80,0x00,0x00,0x00,0x00],  # 多
}


# 顶替中文函数部分
def chinese(ch_str, x_axis, y_axis):  # 需要显示的中文,x轴的开始位置,y轴的开始位置
   offset_ = 0  # 偏移量设为0,也可以设为其他值,俺需要修正
   for k in ch_str:   # for循环去除每个字
       code = 0x00  # 将中文转成16进制编码 
       data_code = k.encode("utf-8")  # 编码为utf-8格式
       code |= data_code[0] << 16
       code |= data_code[1] << 8
       code |= data_code[2]
       byte_data = fonts[code]
       for y in range(0, 16):
           a_ = bin(byte_data[y]).replace('0b', '')
           while len(a_) < 8:
               a_ = '0'+ a_
           b_ = bin(byte_data[y+16]).replace('0b', '')
           while len(b_) < 8:
               b_ = '0'+ b_
           for x in range(0, 8):
               OLED.pixel(x_axis + offset_ + x,     y+y_axis, int(a_[x]))   
               OLED.pixel(x_axis + offset_ + x + 8, y+y_axis, int(b_[x]))   
       offset_ += 16

chinese('好人多', 35, 4)  # 需要显示的中文
OLED.show()  # 显示
OLED.text('welcome to china', 0, 32)  # 需要显示的英文
OLED.show()  # 显示

四、演示效果

示例代码1的效果:

示例代码2的效果:

 也可以点开如下地址,在线查看效果:

Wokwi Arduino and ESP32 Simulatoricon-default.png?t=M85Bhttps://wokwi.com/projects/348669376140935763

五、设计字库

        我们显示中文,需要对中文进行设计,然后再让屏幕显示出来。请看如下操作:

1,我们通过如下网址,可以得到中文和UTF-8之间的相互转换。

查看字符编码(UTF-8)

 2,通过如下工具,制作汉子对应的形状。

         工具大家可以在文末的链接内下载找到。如果你是英文版本系统,或者你打开这个工具后显示乱码。需要对你的系统进行设置。下面以Win10为例讲解如何设置。

        1,打开控制面板,找到 时钟和地区,按如下操作即可

 

 

 2,我们打开工具PCtoLCD2002,按如下步骤进行操作

 

 

 

 

 

 然后我们复制上图红框中的数据,粘贴到代码中对应的汉字的即可。

 

六、购买

某宝链接如下:
https://item.taobao.com/item.htm?spm=a230r.1.14.32.788158fdpYtkII&id=573950296900&ns=1&abbucket=8#detail

 

产品规格:0.96寸OLED裸屏-30P-1306技术资料

对应技术资料下载地址:https://pan.baidu.com/s/1_P7dey5xLMGfZ70UylNm7w

提取码:xnn1

产品规格:0.96寸OLED带板带字库-1306技术资料

对应技术资料下载地址:https://pan.baidu.com/s/12aTj4TzXrw3ynlDJcmKewA

提取码:1bqm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/17492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue 项目在加载完成之前,显示预置加载动画

vue 项目在加载完成之前&#xff0c;显示预置加载动画 自己有一个日记项目&#xff0c;由于服务器带宽很小1MB&#xff0c;在加载之前页面中显示是空白的&#xff0c;就想给它加个前置的动画&#xff0c;这个用户体验更好。 一、实现 1. 定义项目入口 如果你是 pwa 应用&am…

[附源码]计算机毕业设计JAVA化妆品销售管理系统

[附源码]计算机毕业设计JAVA化妆品销售管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM myba…

SQL语句的约束 总结

目录 基本概念 主键约束 概念 操作 自增长约束 概念 操作 非空约束 概念 操作 唯一约束 概念 操作 默认约束 概念 操作 零填充约束 概念 约束总结 基本概念 主键约束 概念 主键约束相当于 唯一约束 非空约束 的组合&#xff0c;主键约束列不允许重复&am…

http网站升级为https网站,证书、http-flv视频显示处理

一、使用OpenSSL生成自签名证书 升级https网站需要自签名证书&#xff0c;证书在视频服务器Nginx中也需要&#xff0c;使用OpenSSL生成。 1.下载安装OpenSSL 2.以管理员身份运行cmd进入OpenSSL的安装目录查看安装版本 3.生成自签名证书。 生成私钥&#xff1a;openssl genr…

【 STM32Fxx串口问题-发送时间-发送字节拉长-每一位与下一位也拉长->>记录问题以及解决方式-复盘】

【 STM32Fxx串口问题-发送时间-发送字节拉长-每一位与下一位也拉长-&#xff1e;&#xff1e;记录问题以及解决方式】前言环境问题描述&#xff08;1&#xff09;测试uart5时&#xff1a;&#xff08;2&#xff09;测试uart1时&#xff1a;原因点解决方式细节点总结前言 在做项…

1388. 3n 块披萨

文章目录1. 背2. 题目3. 答案1. 背 首先&#xff0c;考虑没有环的情况。如果没有环这道题可以转变为和打家劫舍II一毛一样。但是明明这道题是三块披萨一拿啊&#xff0c;打家劫舍是相邻不能拿&#xff0c;还是不一样啊。 这块证明挺难的&#xff0c;但是我可以用个简单的例子…

MicroPython-On-ESP8266——8x8LED点阵模块(1)驱动原理

MicroPython-On-ESP8266——8x8LED点阵模块&#xff08;1&#xff09;驱动原理 1. 8x8LED点阵模块介绍 1.1. 显示模块的升级 之前已经试过点亮8段数码管&#xff0c;并能够使用两片HC595芯片来驱动数码管。今天我又找来了一个8x8点阵LED屏&#xff0c;下面分析一下这个屏幕并…

【用户画像】Redis的简介和安装

文章目录一 Redis简介1 应用场景&#xff08;1&#xff09;业务系统&#xff1a;配合关系型数据库做高速缓存&#xff08;2&#xff09;大数据场景&#xff1a;缓存数据&#xff08;3&#xff09;大数据场景&#xff1a;临时数据&#xff08;4&#xff09;大数据场景&#xff1…

【计算机毕业设计】医院管理系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 一&#xff0e;摘要 目前各医疗机构中&#xff0c;绝大部分中小型医疗机构内部没有实现任何信息化管理&#xff0c;医院临床信息&#xff0c;业务流程的数据依然采取纸质记录&#xff0c;造成数据容易丢失&#xff…

CCSP通过经验 | 讲义覆盖的知识点更全面(含题型分析)

我一直就职于国内网络安全乙方&#xff0c;自2014年接触云安全后&#xff0c;一直希望能获取一个比较官方的云安全从业水平的资格证书。 在横向比较了如腾讯云、华为云、阿里云以及国外如亚马逊云认证后&#xff0c;在没有明确就职意向的情况下&#xff0c;选择了ISC2的认证资…

如何用等价类划分法设计测试用例, 来测试程序的日期检查功能?

某学籍排查系统要求学生输入入学日期&#xff0c;日期限制在2008年9月至2012年7月&#xff0c;即系统只能对该段期间内的学籍进行处理&#xff0c;如日期不在此范围内&#xff0c;则显示输入错误信息。系统日期规定由年、月的6位数字 字符组成&#xff0c;前四位代表年&#xf…

多环境 运维

启动dev 同时包含 下面的 MVC DB 做配置时 如果 遇到相同参数 后加载的 覆盖前加载的 先加载 include 的 active 的是最后加载的 如果需要该 dev 需要该很多 include 换成 group 如果 active 是 dev 则加载dev组 如果 active 是pro 则加载pro组 在pom文件中 设置多环境 &l…

[UE][UE5]像素流送,像素流去掉黑边和按钮

[UE]这里写目录标题1.写在前面01.作者碎碎念02.结果演示截图视频教程2.需要准备的软件3.步骤01.准备一个打包好的项目02.启动服务器03.连接!去掉黑边和按钮结尾1.写在前面 01.作者碎碎念 2022.11.19初次更新 俺是不是很粗长&#xff01;老仔细了&#xff0c;全是截图&#xf…

目标检测算法——YOLOv5/YOLOv7改进|结合涨点Trick之ASFF_Detect(自适应空间特征融合)

>>>深度学习Tricks,第一时间送达<<< 🚀🚀🚀NEW!!!魔改YOLOv5/YOLOv7目标检测算法来啦 ~ 💡💡魔法搭配计算机视觉领域各类创新新颖且行之有效的网络结构,平均精度均值mAP涨点明显,实验效果也俱佳。有需要的小伙伴可以在CSDN后台留言+点赞收藏…

Linux环境搭配

Linux环境搭配 文章目录Linux环境搭配1.Linux背景介绍1.1 系统发展史1.2 开源与官方网址1.3 企业Linux应用现状1.4 Linux发行版本2.Linux环境搭配2.1 Linux环境搭配方式2.2 服务器购买2.3 云服务器配置3.Linux远程登陆3.1 Linux桌面3.2 远程登陆工具3.3 Xshell登陆服务器(单用户…

开放式无线运动耳机怎么挑选,适合在运动佩戴的几款耳机推荐

作为一个运动爱好者而言&#xff0c;耳机是可以堪称灵魂伴侣&#xff0c;好比如在健身房运动的时候可以一边戴着耳机&#xff0c;一边在跑步机上刷着剧&#xff0c;不仅能将两小时的需求量直接浓缩为一小时的使用量&#xff0c;想想都觉得自己赚到了&#xff0c;但是在耳机选购…

Windows11 Android开发相关记录(持续更新...)

Windows11 Android开发相关记录&#xff08;持续更新…&#xff09; 本章节主要记录安装好Windos系统后开发环境搭建及其心得。 以及开发常用软件和相关配置。 以下属于个人做法&#xff0c;仅供参考&#xff1a; 文章目录Windows11 Android开发相关记录&#xff08;持续更新…

【计算机网络】Tomcat和Servlet基础知识汇总

目录 1.Tomcat&#xff1a; 2.Servlet&#xff1a; 1.Tomcat&#xff1a; Tomcat是一个HTTP的服务器&#xff0c;本质上就是一个TCP服务器&#xff0c;只不过加上了一些按照HTTP协议格式进行解析/构造这样的代码。学习Tomcat的目的就是能够熟练掌握Tomcat api&#xff0c;基…

公司的这种打包启动方式,我简直惊呆了

前言 大家都知道&#xff0c;SpringBoot应用最终会打出一个Fat Jar, 里面包含了用到的全部依赖&#xff0c;启动也非常简单&#xff0c;java -jar xxx.jar即可。 但是我们公司打出的最终包&#xff0c;将依赖包挪到了外部&#xff0c;然后启动的时候通过loader.path指定依赖包…

第1章 数据库及其表的自动生成与前言

001 RootEntityTkey<Tkey>、BlogArticle RootEntityTkey<Tkey>&#xff1a;该实体类以泛型形式&#xff0c;定义了当前程序中所有实体的自增型主键。 BlogArticle&#xff1a;继承了RootEntityTkey<Tkey>&#xff0c;通过该实体类及其属性成员&#xff0c;用…