使用树莓派 结合Python Adafruit驱动OLED屏幕 显示实时视频

 关于OLED屏幕的驱动,在之前我已经写过很多篇博文:

IIC 协议 和 OLED_oled iic-CSDN博客

香橙派配合IIC驱动OLED & 使用SourceInsight解读源码_香橙派5 驱动屏幕-CSDN博客

这两篇博文都是通过模拟或调用IIC协议来使用C语言驱动OLED屏幕,现在在树莓派中我尝试了和香橙派类似的方法,我发现了一些问题:香橙派中使用了wiringPi库提供的Oled测试代码并进行修改,其中包含了“font.h”和“oled.h”这两个头文件,但是我已经忘记了我当时这两个头文件是从哪里来的= =,如果不使用这两个库,在查阅了一些别人的实现后发现,如果纯用C语言结合wiringPi库来驱动OLED本质还是要模拟IIC协议,比较麻烦。

综上,经过一些比较和考量,我决定使用Python Adafruit驱动OLED屏幕

树莓派的IIC开启和OLED屏幕识别

虽说要使用Python来驱动,但是OLED屏幕底层依然是IIC协议,所以对于树莓派需要先手动开启IIC协议:

IIC开启

  • 运行以下代码进入设置界面:
sudo raspi-config
  • 选择“Interface Options”:

  • 选择“I2c”然后打开:

此时,就可以正常使用IIC了,通过“gpio-readall” 可知:

现在,物理引脚3和5对应的就是SDA.1和SCL.1,其中“.1”代表的就是驱动文件是“/dev/i2c-1

此时,就可以按照引脚连接OLED屏幕了!

OLED屏幕识别

屏幕连接完成后,进行设备的识别:

  • 运行以下命令安装i2c-tools
sudo apt-get install -y i2c-tools    //安装IIC工具
  • 运行以下命令识别OLED屏幕
sudo i2cdetect -y 1
//“1”代表“i2c-1”

 

可见,树莓派已经成功识别到了OLED屏幕!

Adafruit_Python_SSD1306 库的下载和使用

根据淘宝的搜索,可以了解到我的OLED屏幕驱动芯片为SSD1306(这也是市面上绝大部分单片机小OLED屏幕的芯片,不过现在最新的好像换代了)。

驱动芯片为SSD1306对应的python库就是“Adafruit_Python_SSD1306"。

以下是安装的代码:

1. pip install Adafruit-GPIO
2. pip install Adafruit-SSD1306
3. git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git

安装完成后,运行例程查看效果: 

cd Adafruit_Python_SSD1306/examples/
python3 shapes.py

将shapes.py中的“disp = Adafruit_SSD1306_128_32(rst=RST)”修改为“disp = Adafruit_SSD1306_128_64(rst=RST)”,可以显示得更清晰,具体根据不同的OLED屏幕尺寸来修改

成功显示!

修改例程显示图片

 首先,将刚刚测试成功的例程“shapes.py”复制到我的代码路径中:

 cp shapes.py /home/pi/mjm_code/oled_camera.py

由于之后我还是想用C语言来调用这个python文件,所以和我之前博文的思路一样,先将不需要的代码删去,再将python程序定义为函数进行测试:

oled_camera.py: 

由于我的最终目的是显示实时的视频流,所以我先将这个python代码修改,显示一张图片,后续C语言进行while循环不断来显示当前拍照图片就可以有视频的效果。

# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
#
# 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.
import time

import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont


def init():
    # Raspberry Pi pin configuration:
    RST = 24
    # Note the following are only used with SPI:
    DC = 23
    SPI_PORT = 0
    SPI_DEVICE = 0

# Beaglebone Black pin configuration:
# RST = 'P9_12'
# Note the following are only used with SPI:
# DC = 'P9_15'
# SPI_PORT = 1
# SPI_DEVICE = 0

# 128x32 display with hardware I2C:
    disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

# 128x64 display with hardware I2C:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

# Note you can change the I2C address by passing an i2c_address parameter like:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, i2c_address=0x3C)

# Alternatively you can specify an explicit I2C bus number, for example
# with the 128x32 display you would use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, i2c_bus=2)

# 128x32 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))

# 128x64 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))

# Alternatively you can specify a software SPI implementation by providing
# digital GPIO pin numbers for all the required display pins.  For example
# on a Raspberry Pi with the 128x32 display you might use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, sclk=18, din=25, cs=22)

# Initialize library.
    disp.begin()

# Clear display.
    disp.clear()
    disp.display()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
#    width = disp.width
#    height = disp.height
#    image = Image.new('1', (width, height))

# Get drawing object to draw on image.
#    draw = ImageDraw.Draw(image)
# Draw a black filled box to clear the image.
#    draw.rectangle((0,0,width,height), outline=0, fill=0)


# Load default font.
#    font = ImageFont.load_default()

def display():
    # Raspberry Pi pin configuration:
    RST = 24
    # Note the following are only used with SPI:
    DC = 23
    SPI_PORT = 0
    SPI_DEVICE = 0

# 128x32 display with hardware I2C:
    disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)


# Initialize library.
    disp.begin()


    #打开本地的照片
    #当前路径测试用,需按照实际情况修改
    img = Image.open('/home/pi/mjm_code/mjm.png')

    # 调整图片大小到 128x64
    img_resized = img.resize((128, 64),Image.LANCZOS)

    image = img_resized.convert('1')

# Display image.
    disp.image(image)
    disp.display()

if __name__ == '__main__': #写一个main调用face_detect函数来测试
    init()
    display()

 显示效果

运行“python3 oled_camera.py”:

可见,虽然画面很粗糙,但是成功显示图片!而且由于使用了现成的python库,不需要在麻烦的使用IIC协议写命令,初始化,取模了。 

OLED显示实时视频流

现在已经能在OLED上显示一张图片了,再次重复刚刚的思路:

“由于我的最终目的是显示实时的视频流,所以我先将这个python代码修改,显示一张图片,后续C语言进行while循环不断来显示当前拍照图片就可以有视频的效果。”

关于如何拍照并保存本地,和如何使用C语言调用Python,可以看我之前的博文:

树莓派接入USB摄像头并使用fswebcam和mjpg-streamer进行测试_树莓派mjpg-streamer-CSDN博客

基于阿里云平台 通过树莓派实现 1:1人脸识别-CSDN博客 

编写C语言调用oled_camera.py

回顾“C语言调用Python的步骤”:

oled_show.c:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <Python.h>
 
#include "oled_show.h"
 
 
void oled_init(void)
{
    Py_Initialize();
    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys, "path");
    PyList_Append(path, PyUnicode_FromString("."));
}
 
void oled_final(void)
{
    Py_Finalize();
}

void oled_show_init(void) //由于没有返回参数,所以可以直接定义void型
{
    PyObject *pModule = PyImport_ImportModule("oled_camera"); //加载python文件
    if (!pModule)
    {
        PyErr_Print();
        printf("Error: failed to load module\n");
        goto FAILED_MODULE; //goto的意思就是如果运行到这里就直接跳转到FAILED_MODULE
    }
    PyObject *pFunc = PyObject_GetAttrString(pModule, "init"); //加载python文件中的对应函数
    if (!pFunc)
    {
        PyErr_Print();
        printf("Error: failed to load function\n");
        goto FAILED_FUNC;
    }
    PyObject *pValue = PyObject_CallObject(pFunc, NULL);
    if (!pValue)
    {
        PyErr_Print();
        printf("Error: function call failed\n");
        goto FAILED_VALUE;
    }

    /* 没有返回值,无需调用
    int result = 0;
    if (!PyArg_Parse(pValue, "i", &result)) //ace_detect函数返回的是已经经过提取和取证过的置信度score,是个int型,用‘i’表示
    {
        PyErr_Print();
        printf("Error: parse failed");
        goto FAILED_RESULT;
    }*/
 
FAILED_RESULT:
    Py_DECREF(pValue);
FAILED_VALUE:
    Py_DECREF(pFunc);
FAILED_FUNC:
    Py_DECREF(pModule);
FAILED_MODULE:
    //无需return
}

void oled_show(void) //由于没有返回参数,所以可以直接定义void型
{
    PyObject *pModule = PyImport_ImportModule("oled_camera"); //加载python文件
    if (!pModule)
    {
        PyErr_Print();
        printf("Error: failed to load module\n");
        goto FAILED_MODULE; //goto的意思就是如果运行到这里就直接跳转到FAILED_MODULE
    }
    PyObject *pFunc = PyObject_GetAttrString(pModule, "display"); //加载python文件中的对应函数
    if (!pFunc)
    {
        PyErr_Print();
        printf("Error: failed to load function\n");
        goto FAILED_FUNC;
    }
    PyObject *pValue = PyObject_CallObject(pFunc, NULL);
    if (!pValue)
    {
        PyErr_Print();
        printf("Error: function call failed\n");
        goto FAILED_VALUE;
    }

    /* 没有返回值,无需调用
    int result = 0;
    if (!PyArg_Parse(pValue, "i", &result)) //ace_detect函数返回的是已经经过提取和取证过的置信度score,是个int型,用‘i’表示
    {
        PyErr_Print();
        printf("Error: parse failed");
        goto FAILED_RESULT;
    }*/
 
FAILED_RESULT:
    Py_DECREF(pValue);
FAILED_VALUE:
    Py_DECREF(pFunc);
FAILED_FUNC:
    Py_DECREF(pModule);
FAILED_MODULE:
    //无需return
}
oled_show.h:
#ifndef __oled__H
#define __oled__H
 
void oled_init(void);
void oled_final(void);
void oled_show_init(void);
void oled_show(void);
 
#endif

编写C程序调用刚刚的C函数实现实时视频流显示

test_oled_camera.c:

注意,由于此处涉及了拍照,拍照保存的路径和照片的名字需要和oled_camera.py中保持一样,所以此处需要按照需求修改python代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

#include "oled_show.h"

int main()
{
	oled_init();
	oled_show_init();

	while(1){
		system("wget http://192.168.2.56:8080/?action=snapshot -O /home/pi/mjm_code/oled_pic.png"); //拍照
		delay(10);//给一点时间让照片拍出来
		if(0 == access("/home/pi/mjm_code/oled_pic.png", F_OK)){ //如果照片成功拍到了
			oled_show();
		}else{
			printf("pic not exist!\n");
		}
		remove("/home/pi/mjm_code/oled_pic.png");
		delay(50); //此处决定帧率,delay时间越短帧率越高
	}

	oled_final();
	return 0;
}

编译运行

  • 输入以下指令编译:
gcc test_oled_camera.c oled_show.c -I /usr/include/python3.11/ -l python3.11 -lwiringPi
  • 输入以下指令运行程序: 
./a.out
  • 输入以下指令结束运行:
ps -ef|grep 程序名称
kill 进程编号

最终效果

视频中我出现在画框中并朝着屏幕挥手:

可见,虽然帧率和分辨率低的可怕,但是的确实现了使用OLED实时显示视频流的功能!

  • 31
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在树莓派OLED屏幕显示keypad输入内容,您需要编写一个Python脚本来执行以下操作: 1. 初始化OLED屏幕并设置字体大小和颜色。 2. 初始化keypad并设置输入键。 3. 监听输入键并在屏幕显示输入内容。 以下是一个简单的示例代码,您可以根据需要进行修改: ```python import Adafruit_SSD1306 # OLED屏幕库 import Adafruit_GPIO as GPIO # GPIO库 import Adafruit_GPIO.SPI as SPI # SPI接口库 import time from pad4pi import rpi_gpio # keypad库 # 设置OLED屏幕参数 RST = None DC = 23 SPI_PORT = 0 SPI_DEVICE = 0 disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000)) disp.begin() disp.clear() disp.display() # 设置字体和颜色 from PIL import Image from PIL import ImageDraw from PIL import ImageFont font = ImageFont.load_default() draw = ImageDraw.Draw(disp.image) draw.fontmode = '1' draw.text((0,0), 'Enter text:', font=font, fill=255) disp.image(disp.image) disp.display() # 设置keypad输入 KEYPAD = [['1','2','3'], ['4','5','6'], ['7','8','9'], ['*','0','#']] ROW_PINS = [4, 14, 15, 17] # BCM numbering COL_PINS = [18, 27, 22] # BCM numbering factory = rpi_gpio.KeypadFactory() keypad = factory.create_keypad(keypad=KEYPAD, row_pins=ROW_PINS, col_pins=COL_PINS) # 监听keypad输入并在屏幕显示输入内容 def print_key(key): print(key) draw.rectangle((0, 10, 127, 31), outline=0, fill=0) # 清空上一次的输入 draw.text((0,10), key, font=font, fill=255) # 在屏幕显示输入 disp.image(disp.image) disp.display() keypad.registerKeyPressHandler(print_key) while True: time.sleep(1) ``` 在运行该脚本后,您可以使用keypad输入数字或字符,该数字或字符将在OLED屏幕显示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值