文章目录

  • ​​1. 查看GPIO定义 wiringpi库​​
  • ​​2. 确保硬件无问题 (i2c-tools)​​
  • ​​3. 安装oled驱动python包​​
  • ​​3.1 用例测试​​
  • ​​3.2 测试用例2​​
  • ​​4. oled显示时间, 天气, 温度​​
  • ​​5. 应用1 oled滚动显示文字​​


下面如果遇到一些问题, 请见这篇介绍

​​令人惊艳的NanoPC-T4(RK3399)作为工作站的初始配置和相关应用​

很久以前在本科阶段做单片机玩的时候, 余下的​​0.96 oled​​​还有一个, 正好最近看稚晖君的小电视, 灵机一动, 就想利用这个​​oled​​​做一个能够显示当前时间, 天气和cpu温度的显示屏; 同时需要注意的是, ​​NanoPC-T4(RK3399)​​​ 这个板子已经打开了​​I2C​​​的硬件驱动, 也就是说只要根据引脚图接上​​I2C​​​, 这个板子就能在总线上识别到对应的设备, 就跟​​USB​​一个原理; 所以硬件方面就这样解决了!!!

这里缺个展示图

NanoPC-T4(RK3399) game1 oled(I2C)显示时间天气温度_python

说实话, Linux开发下, 一切都那么简单, 尤其是python, 一切你能想到的任务, 都已经有人在​​GitHub​​​做好了包等你​​clone​​​和使用了, 今天这个玩意就是这样子的, 直接去GitHub搜一波​​python oled驱动​​ 就搜出来一个, 然后在深入了解一下, luma包就是调用oled各种型号驱动的python包, 所以软件方面也解决了!!!

NanoPC-T4(RK3399) game1 oled(I2C)显示时间天气温度_python_02

1. 查看GPIO定义 wiringpi库

wiringpi库就是一个操作硬件GPIO驱动库, 安装完之后就可以对外设引脚高低电平, 以及不同的通信协议进行配置, 比如I2C, SPI等

mkdir -p /home/02_hardware && cd /home/02_hardware

# 移除旧版本
wget http://112.124.9.243:8888/wiringpi/friendlyelec-rk3399/remove_oldversion_wiringPi.sh
chmod 755 remove_oldversion_wiringPi.sh
sudo ./remove_oldversion_wiringPi.sh

# 安装新版本
wget http://112.124.9.243:8888/wiringpi/friendlyelec-rk3399/wiringpi-v2.44-friendlyelec-rk3399.deb
sudo dpkg -i wiringpi-v2.44-friendlyelec-rk3399.deb
(base) pi@NanoPC-T4:~$ gpio readall
+------+-----+----------+------+ Model NanoPC-T4 +------+----------+-----+------+
| GPIO | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | GPIO |
+------+-----+----------+------+---+----++----+---+------+----------+-----+------+
| | | 3.3V | | | 1 || 2 | | | 5V | | |
| | | I2C2_SDA | | | 3 || 4 | | | 5V | | |
| | | I2C2_SCL | | | 5 || 6 | | | GND(0V) | | |
| 32 | 7 | GPIO1_A0 | IN | 0 | 7 || 8 | | | I2C3_SCL | | |
| | | GND(0V) | | | 9 || 10 | | | I2C3_SDA | | |
| 33 | 0 | GPIO1_A1 | IN | 0 | 11 || 12 | 1 | IN | GPIO1_C2 | 1 | 50 |
| 35 | 2 | GPIO1_A3 | IN | 0 | 13 || 14 | | | GND(0V) | | |
| 36 | 3 | GPIO1_A4 | IN | 0 | 15 || 16 | 0 | IN | GPIO1_C6 | 4 | 54 |
| | | 3.3V | | | 17 || 18 | 0 | IN | GPIO1_C7 | 5 | 55 |
| 40 | 12 | GPIO1_B0 | ALT | | 19 || 20 | | | GND(0V) | | |
| 39 | 13 | GPIO1_A7 | ALT | | 21 || 22 | 0 | IN | GPIO1_D0 | 6 | 56 |
| 41 | 14 | GPIO1_B1 | ALT | | 23 || 24 | | ALT | GPIO1_B2 | 10 | 42 |
| | | GND(0V) | | | 25 || 26 | | ALT | GPIO4_C5 | 11 | 140 |
| | | I2C2_SDA | | | 27 || 28 | | | I2C2_SCL | | |
| 132 | 21 | GPIO4_A4 | IN | 0 | 29 || 30 | | | GND(0V) | | |
| 133 | 22 | GPIO4_A5 | IN | 0 | 31 || 32 | | | I2S_CLK | | |
| 131 | 23 | GPIO4_A3 | IN | 0 | 33 || 34 | | | GND(0V) | | |
| 134 | 24 | GPIO4_A6 | IN | 0 | 35 || 36 | 0 | IN | GPIO4_A7 | 27 | 135 |
| 124 | 25 | GPIO3_D4 | ALT | | 37 || 38 | | ALT | GPIO3_D5 | 28 | 125 |
| | | GND(0V) | | | 39 || 40 | | ALT | GPIO3_D6 | 29 | 126 |
+------+-----+----------+------+---+----++----+---+------+----------+-----+------+

到这里我们知道 引脚​​3,5​​​是对应的​​I2C2_SDA/SCL​​​ 所以将oled的四个引脚 ​​vcc/gnd,sda,scl​​ 插上就行了

2. 确保硬件无问题 (i2c-tools)

在使用下面命令之前需要注意的点有两个:

  1. i2c设备在进行命令(0x00)和数据(0x04)读写时是有区分的
  2. 这个板子第一个​​I2C​​​接口是使用的​​I2C-2号总线​
  3. 这个板子的​​I2C​​​ 硬件芯片是 ​​rk3x-i2c​​, 而不是常见的xxx
# 安装识别i2c的工具
sudo apt-get install i2c-tools
(base) pi@NanoPC-T4:~$ apt-cache policy i2c-tools
i2c-tools:
Installed: 4.0-2
Candidate: 4.0-2
Version table:
*** 4.0-2 500
500 http://mirrors.ustc.edu.cn/ubuntu-ports bionic/universe arm64 Packages
100 /var/lib/dpkg/status

# 打印所有i2c总线, 发现这里用的芯片是rk3x-i2c, 而不是树莓派的bcm2835
(base) pi@NanoPC-T4:~$ sudo i2cdetect -l
i2c-0 i2c rk3x-i2c I2C adapter
i2c-1 i2c rk3x-i2c I2C adapter
i2c-2 i2c rk3x-i2c I2C adapter
i2c-4 i2c rk3x-i2c I2C adapter
i2c-7 i2c rk3x-i2c I2C adapter
i2c-9 i2c DP-AUX I2C adapter
i2c-10 i2c DP-AUX I2C adapter

# 检测I2C总线
(py3.7) pi@NanoPC-T4:zjq$ sudo i2cdetect -F 2
Functionalities implemented by /dev/i2c-2:
I2C yes
SMBus Quick Command yes
SMBus Send Byte yes
SMBus Receive Byte yes
SMBus Write Byte yes
SMBus Read Byte yes
SMBus Write Word yes
SMBus Read Word yes
SMBus Process Call yes
SMBus Block Write yes
SMBus Block Read no
SMBus Block Process Call no
SMBus PEC yes
I2C Block Write yes
I2C Block Read yes


# 将oled插入到1356引脚, 查询占用的iic地址, 注意通过上图可知, 1345引脚对应的是i2c-2总线
# 所以这里查询i2c-2总线
pi@NanoPC-T4:~$ sudo i2cdetect -y -r -a 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 这里就一个I2C地址 0xUU

# 检查i2c是否有驱动
cat /sys/bus/i2c/devices/i2c-1/name


# 寄存器数据导出。总线上i2c设备的数据是要存储在寄存器上。
(base) pi@NanoPC-T4:~$ sudo i2cdump -y 2 0x3c
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
10: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
20: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
30: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
40: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
50: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
60: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
70: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
80: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
90: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
a0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
b0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
c0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
d0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
e0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC
f0: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 CCCCCCCCCCCCCCCC


# 寄存器数据写入,即向寄存器中某一位地址上插入数据:
sudo i2cset -y 2 0x3c 0x20 0x55

# 读取I2C总线上设备0x3c的0x80寄存器地址的数据
sudo i2cget -y 2 0x3c 0x20

3. 安装oled驱动python包

git clone  https://github.com.cnpmjs.org/rm-hull/luma.examples
cd luma.examples && pip install -e .

3.1 用例测试

cd /home/02_hardware/luma.examples/examples
python 3d_box.py --help

I2C:
--i2c-port I2C_PORT I2C bus number (default: 1)
--i2c-address I2C_ADDRESS
I2C display address (default: 0x3C)
# 因此可以使用下面的命令直接运行demo
python 3d_box.py --i2c-port=2 --i2c-address=0x3c

3.2 测试用例2



#!/usr/bin/python3
# -*- coding: utf-8 -*-
from luma.core.interface.serial import i2c
from luma.core.render import canvas
# SSD1306, SSD1309, SSD1322, SSD1325, SSD1327, SSD1331,SSD1351, SSD1362 and SH1106 devices.
from luma.oled.device import ssd1306, ssd1309, ssd1322, ssd1325, ssd1327, ssd1331, ssd1351, ssd1362, sh1106
from time import sleep

from PIL import ImageDraw, ImageFont

"""
OLED luma 驱动库测试程序
功能:显示 hello world 和矩形外框持续10秒
"""
__version__ = 1.0
# 初始化端口
serial = i2c(port=2, address=0x3C)
# # 初始化设备,这里改ssd1306, ssd1325, ssd1331, sh1106
device = ssd1306(serial)
# 调用显示函数
with canvas(device) as draw:
font = ImageFont.load_default()
# 这里的font2字体可以修改成中文字体, 比如从win10的路径windows/fonts/的楷体, 放到这里后, 就可以啦
font2 = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 20)
draw.rectangle(device.bounding_box, outline="white", fill="black")
draw.text((10, 25), "hello world", font=font2, fill=255)
# 延时显示10s
while True:
pass


注意: 这里用到的字体可以去`c:/windows/fonts/楷书等.ttf` 上传到板子上, 然后根据绝对路径进行使用即可

4. oled显示时间, 天气, 温度

注意: oled如果显示中文字体需要从win里面拷贝一个中文字体的ttf文件放到板子里面

其实很简单, 直接使用系统时间, 通过天气API查询天气, 在通过读取CPU温度文件获取温度, 最后显示在oled上面

# 设置oled显示
# 城市: 祝福
# 日期 时间 星期
# 今天天气
# 明天天气
# 每十秒更新一次
from luma.core.interface.serial import i2c
from luma.core.render import canvas
# SSD1306, SSD1309, SSD1322, SSD1325, SSD1327, SSD1331,SSD1351, SSD1362 and SH1106 devices.
from luma.oled.device import ssd1306, ssd1309, ssd1322, ssd1325, ssd1327, ssd1331, ssd1351, ssd1362, sh1106
from PIL import ImageDraw, ImageFont
import urllib.request
import gzip
import json
import datetime
import time


__version__ = 1.0
# 初始化端口
serial = i2c(port=2, address=0x3C)
# # 初始化设备,这里改ssd1306, ssd1325, ssd1331, sh1106
device = ssd1306(serial)

def get_weather_data() :
url1 = 'http://wthrcdn.etouch.cn/weather_mini?city='+urllib.parse.quote("西安")
url2 = 'http://wthrcdn.etouch.cn/weather_mini?citykey=101010100'
weather_data = urllib.request.urlopen(url1).read()
weather_data = gzip.decompress(weather_data).decode('utf-8')
weather_dict = json.loads(weather_data) # 将json数据转成字典格式
forecast = weather_dict.get('data').get('forecast')
today_weather = "今: " + forecast[0].get('type') + " " + weather_dict.get('data').get('wendu')+'℃ ' + \
"(" +forecast[0].get('low')[3:-1] + "~" + forecast[0].get('high')[3:-1] +")"
# print(today_weather)
tomorrow_weather = "明: " + forecast[1].get('type') + " " +\
forecast[1].get('low')[3:] + "~" + forecast[1].get('high')[3:]
# print(tomorrow_weather)

return today_weather, tomorrow_weather

font1 = ImageFont.load_default() # 默认字体
font2 = ImageFont.truetype('/home/pi/zjq/04_hardware/oled/ttf_font/STKAITI.TTF', 16) # 中文字体


def display():
today_weather, tomorrow_weather = get_weather_data()
now_time = datetime.datetime.now().strftime("%m-%d %A %H:%M ")# now.strftime("%Y-%m-%d %H:%M:%S")
# print(now_time)
with open("/sys/devices/virtual/thermal/thermal_zone0/temp", "r") as f:
temperature = str(int(int(f.read())/1000))
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline="white", fill="black")
draw.text((0, 0), today_weather, font=font2, fill=255)
draw.text((0, 16), tomorrow_weather, font=font2, fill=255)
draw.text((5, 38), "CPU:" + temperature+"°", font=font1, fill=255)
draw.text((5, 50), now_time, font=font1, fill=255)
time.sleep(10)

while True:
display()
# display()

5. 应用1 oled滚动显示文字

text = "将进酒 李白 君不见黄河之水天上来,奔流到海不复回。\
君不见高堂明镜悲白发,朝如青丝暮成雪。 人生得意须尽欢,\
莫使金樽空对月。天生我材必有用,千金散尽还复来。"


from time import sleep
from luma.core.virtual import viewport
from PIL import ImageDraw, ImageFont
virtual = viewport(device, width=2048, height=720)
font2 = ImageFont.truetype('/home/pi/zjq/04_hardware/oled/STKAITI.TTF', 16) # 中文字体


# 水平滚动
def horizontal_scroll():
with canvas(virtual) as draw:
draw.text((0,0), text=text, fill="white", font=font2)
sleep(1)
y = 0
for x in range(len(text)*16):
virtual.set_position((x, y))
sleep(0.05)

def main():
print("当前版本:", __version__)
horizontal_scroll()
# vertical_scroll()

main()