orangepi-zero2实时显示USB摄像头图像
本文使用环境: 电脑:Ubuntu 18.04.5 LTS 开发板:orangepi-zero2 交叉编译器:aarch64-none-linux-gnu- 显示屏:openmv 1.8英寸SPI显示屏 显示屏资料:https://openmv.io/products/lcd-shield (128RMB,为什么会这么贵,搞不清楚)
一、显示接口连接
1、显示屏接口: 2、开发板显示屏接口: 3、屏幕和开发板连接:
ZERO2 | LCD |
---|
CS | SPI Chip Select | RESET | LCD Reset | D/C | SPI Command | SDI(MOSI) | SPI Data in – to LCD | SCK | SPI Clock | LED | Backlight Control | SDO(MISO) | 不接 |
4、扩展 ??官方给出的开发板并没有外接显示电路,同时没有散热。不接散热,是不行的,在实际运行中温度太高了。所以就花了点时间设计了一版扩展板,有需要的可以自取,可以直接打样,使用的是立创EDA(可以免费打样的,需要的可以直接嘉立创一条龙)。支持国产,大家一起加油。 链接: https://oshwhub.com/xiansenzhao/orangepi_copy
二、加载驱动设置
1、内核设置 ??查找LCD所对应的驱动型号,本文使用的LCD驱动为:fb_st7735r(RGB585),内核中有该驱动所以可以直接使用驱动,不需要再单独编译驱动。 下图为编译内核时,驱动的位置。(默认是M,简而言之需要手动加载模块)
Device Drivers --->
Graphics support --->
<*> Support for small TFT LCD display modules --->
...
<M> FB driver for the ILI9340 LCD Controller
<M> FB driver for the ST7735R LCD Controller
...
<M> Module to for adding FBTFT devices
2、加载驱动 ??现在我们不直接加载,先看一下驱动文件在哪里,驱动名字是什么。在内核文件中找到对应的代码,文件路径如下:
kernel/orange-pi-4.9-sun50iw9/drivers/staging/fbtft/fbtft_devices.c
??部分代码如下:可以自己Ctrll+F查找关键字:fb_st7735r。对应的应该会有两个函数,这里只列出其中一个。
static struct fbtft_device_display displays[] = {
.name = "adafruit18",
.spi = &(struct spi_board_info) {
.modalias = "fb_st7735r",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.gpios = (const struct fbtft_gpio []) {
{ "reset", 25 },
{ "dc", 24 },
{ "led", 18 },
{},
},
.gamma = ADAFRUIT18_GAMMA,
}
}
},
??可以很明显的看出:fb_st7735r为本文所用LCD的驱动,那就意味着可以直接使用。尝试着手动加载驱动试一下: ??直接登录系统。输如如下代码:
modprobe fbtft_device custom name=adafruit18 busnum=1 cs=1 gpios=reset:73,dc:70,led:69 rotate=90
busnum:表示使用SPI1,硬件接线使用的就是SPI1。 后面的就是字面意思了,GPIO的引脚对应其功能。
注意:官方的教程中的加载驱动模块代码,是不能直接使用的,会出现显示模糊的情况,经过我多方排除,我发现是时钟频率不对,使用驱动中默认的就好了,不需要修改。
??输入以下代码后,就应该可以在/dev/下看到对应的设备了:(系统默认带有fb0),所以加载后本文所用LCD就是:fb1。 ??只要出现fb1,说明LCD加载成功了。接下来让系统启动自动加载驱动。
a、新建文件 /etc/modules-load.d/fbtft.con 配置文件,文件内容如下:
fbtft_device
b、新建 /etc/modprobe.d/fbtft.conf 配置文件,文件内容如下所示:
options fbtft_device custom name=adafruit18 busnum=1 cs=1 gpios=reset:73,dc:70,led:69 rotate=90
重启开发板就能实现LCD的自动加载。 3、显示测试 ??测试LCD是否可以显示,由于本文所有的LCD和官方给的LCD并不匹配,所以显示会出现分辨率的问题,但是不影响使用。 输入使用如下代码:
apt -y install fbi
fbi -vt 1 -noverbose -d /dev/fb1 /boot/boot.bmp
显示如下: 如果出现上图的情况说明已经成功了。
三、 USB摄像头数据实时显示
??说明:本文目前使用的是最简单的一种视频读取方式:OPENCV读取,也就意味着必须要安装相对应的opencv库,否则不能运行。 写文章还是不容易的,一个知识点牵涉着另外的知识点,opencv的交叉编译又可以单独写一篇文章了。除了opencv还有另外的一种是读取方式,就是直接open设备,这种方式倒是不需要其他库就是麻烦一点点,采集的数据是YUV,需要转化成RGB565,还需要resize成显示屏的尺寸,因为显示屏是128X160的。。而采集的视频是640X480的,这一下又是两篇文章了。。。。。。。不说了我们继续本章的话题,后面有时间再写吧。
1、安装OPENCV的库,懒得交叉编译了,因为很麻烦,我们直接采用现成的库。。。。 感谢qiuiqiu大佬的贡献。 https://github.com/dog-qiuqiu/libopencv 从上诉链接下载opencv的交叉库,下载完后打开如下所示: 注意教程使用的是aarch64,所以只使用aarch64-linux-gnu文件夹下的库。 将文件夹改名为:(不改也可以其实。。为了方便识别) aarch64-linux-gnu-opencv4.5
2、编程 a、程序如下: ??需要注意的就是LCD是RGB565的,而采集出来的视频RGB888。需要转化一下。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#define CV_AA 8
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#define RGB2RGB565(R,G,B) ((((R)>>3)<<11)|(((G)>>2)<<5)|((B)>>3))&0XFFFF
static void display_pic(void *base,unsigned int width, unsigned int height, unsigned int stride, Mat frame)
{
unsigned int xcoi, ycoi;
unsigned short rgb565_color = 0;
unsigned short R, G, B;
unsigned int iPixelAddr = 0;
Mat pic_resize;
unsigned short *screen_base = (unsigned short *)base;
resize(frame,pic_resize,Size(160,128),INTER_LANCZOS4);
unsigned int num=0;
for(ycoi = 0; ycoi < height; ycoi++)
{
for(xcoi = 0; xcoi < width; xcoi += 1)
{
int i = xcoi+ycoi*width;
B = pic_resize.data[3*i];
G = pic_resize.data[3*i+1];
R = pic_resize.data[3*i+2];
rgb565_color = RGB2RGB565(R,G,B);
screen_base[i] = rgb565_color;
}
iPixelAddr += width*2;
}
}
int testCam() {
cv::Mat frame;
cv::VideoCapture cap(0);
struct fb_var_screeninfo fb_var = {0};
struct fb_fix_screeninfo fb_fix = {0};
unsigned int screensize;
int fd;
static void *base = NULL;
fd = open("/dev/fb1", O_RDWR);
if (fd < 0) {
printf("Error: Failed to open /dev/fb0 device.\n");
return fd;
}
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
screensize = fb_var.yres* fb_fix.line_length;
printf("lie: %d hang: %d %d %d\n",fb_var.yres,fb_var.xres,fb_fix.line_length,fb_var.bits_per_pixel);
base = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == base) {
close(fd);
perror("mmap error");
return -1;
}
memset(base, 0x00, screensize);
while (true) {
cap >> frame;
if (frame.empty()) break;
display_pic( base,fb_var.xres, fb_var.yres, fb_fix.line_length,frame);
}
cap.release();
memset(base, 0x00, screensize);
munmap(base, screensize);
close(fd);
return 0;
}
int main() {
testCam();
return 0;
}
b、编写makefil文件: ??库的路径和交叉编译器的路径需要根据实际情况修改。
TARGET=lcd-main
EXEC= obj-m
LIBARY= -lopencv_world -llibprotobuf -llibjpeg-turbo -llibwebp -llibpng -llibtiff -llibopenjp2 -lzlib -littnotify -ltegra_hal -lquirc -lade -ldl -lm -lpthread -lrt
LDFLAGS= -L /home/zxx/orange_project/libopencv-main/aarch64-linux-gnu/lib/ $(LIBARY)
COMMON+= -I /home/zxx/orange_project/libopencv-main/aarch64-linux-gnu/include/
CC :=aarch64-none-linux-gnu-g++
SRC = ldc_opencv.cpp
OBJS = $(SRC:%.c=%.o)
all:$(OBJS)
$(CC) -o $(TARGET) $(SRC) $(COMMON) $(LDFLAGS) -fopenmp
clean :
rm -rf *.o
rm -rf lcd-main
c、直接make 会生成lcd-main可执行文件。将文件scp到开发板。
scp lcd-main root@192.168.1.213:/zxx/lcd_show
d、运行程序 ??如图:
root@orangepizero2:/zxx/lcd_show# ./lcd-main
lie: 128 hang: 160 320 16
实际效果: ??到此本文全部结束。后期还会出使用open进行usb数据采集的教程,感兴趣的可以继续关注一下。
|