OrangePi ZERO 2 外设应用程序开发之基于 wiringOP 库的 OLED 二次开发

上篇文章(《OrangePi ZERO 2 外设应用程序开发之 I²C 配置及驱动 OLED 屏幕》)我们用 wiringOP 库的 demo 代码,成功地驱动了 OLED 屏幕,本篇就基于 wiringOP 库所提供的 API 进行二次开发,便于实现更多的显示效果。

一、基于oled_putstr函数的文本显示

先模仿 demo 代码写一段程序,显示内容部分在oledShow函数里完成。

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <wiringPi.h>

#include "oled.h"
#include "font.h"

void oledShow(struct display_info *disp)
{

}

int main(int argc, char **argv)
{
	int err;
	char channal[32];
	struct display_info disp;

	if (argc < 2) {
		printf("\nUsage:\n%s <I2C bus device node >\n", argv[0]);
		return -1;
	}

	memset(&disp, 0, sizeof(disp));
	sprintf(channal, "%s", argv[1]);
	disp.address = OLED_I2C_ADDR;
	disp.font = font2;

	err = oled_open(&disp, channal);

	if (err < 0) {
		printf("\nERROR: %i, Failed(oled_open)\n\n", err);
	} else {
		err = oled_init(&disp);
		if (err < 0) {
			printf("\nERROR: %i, Failed(oled_init)\n\n", err);
		} else {
			printf("---------start--------\n");
			oled_clear(&disp);
			oledShow(&disp);
			delay(3000);
			oled_clear(&disp);
			printf("----------end---------\n");
		}
	}

	return 0;
}

显示的字体,我个人比较喜欢font2,这个字体每行可以显示 21 个字符,字体间隔没那么紧凑,看着页舒服。font1font3每行都可以显示 25 个字符,都是比较紧凑。另外就是font3的字体太小,也不方便阅读。

oled_putstr函数是按页寻址模式填充 OLED 的,不过只能填充一页,第三个参数是需要显示在 OLED 上的字符串首地址,如果字符串个数超出每页可显示的字符个数,只会显示最前面部分,超出部分不显示。

在这里插入图片描述

如下代码,是在第三页的位置显示buf数组的内容。

void oledShow(struct display_info *disp)
{
	uint8_t buf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	
	oled_putstr(disp, 3, buf);

	oled_send_buffer(disp);
}

实际效果如下(font2字体最多每页显示 21 个字符):

在这里插入图片描述

如果每页显示相同的字符,代码如下:

void oledShow(struct display_info *disp)
{
	uint8_t buf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	
	for (int i = 0; i < 8; i++)
		oled_putstr(disp, i, buf);

	oled_send_buffer(disp);
}

效果如下:

在这里插入图片描述

当然,如果显示一段英文短句,也是可以的,只要对数组进行偏移即可。

void oledShow(struct display_info *disp)
{
	uint8_t buf[] = "  Life is like a rainbow, "\
					"each color represents a different experience, "\
					"and together they make up the beautiful sky.";
	
	for (int i = 0; i < 6; i++)
		oled_putstr(disp, i + 1, buf + i * 21);

	oled_send_buffer(disp);
}

效果如下:

在这里插入图片描述

二、基于oled_putpixel函数的图形显示

oled_putpixel函数可以在 OLED 任意位置点亮或熄灭一个点,可以利用这个特点,在 OLED 上绘制一些图案。类似这种通过点亮某些点的方式来绘制图案的方法,通常都会用 Bresenham 算法来实现,下面是一些通过 Bresenham 算法实现的图形绘制函数。

1. 绘制直线

使用相同的显示函数 oled_putpixel 来绘制直线,可以借助直线的数学定义和简单的直线算法(Bresenham 算法)来实现。下面是一个示例代码,用于在 128 × 64 的 OLED 上绘制一条直线:

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <wiringPi.h>
#include <math.h>
#include "oled.h"
#include "font.h"

void drawLine(struct display_info *disp, int x0, int y0, int x1, int y1)
{
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int sx = (x0 < x1) ? 1 : -1;
    int sy = (y0 < y1) ? 1 : -1;
    int err = dx - dy;

    while (x0 != x1 || y0 != y1) {
        oled_putpixel(disp, x0, y0, 1);
	oled_send_buffer(disp);
        int e2 = 2 * err;
        if (e2 > -dy) {
            err -= dy;
            x0 += sx;
        }
        if (e2 < dx) {
            err += dx;
            y0 += sy;
        }
    }
}

int main(int argc, char **argv)
{
	int err;
	char channal[32];
	struct display_info disp;

	if (argc < 2) {
		printf("\nUsage:\n%s <I2C bus device node >\n", argv[0]);
		return -1;
	}

	memset(&disp, 0, sizeof(disp));
	sprintf(channal, "%s", argv[1]);
	disp.address = OLED_I2C_ADDR;
	disp.font = font2;

	err = oled_open(&disp, channal);

	if (err < 0) {
		printf("\nERROR: %i, Failed(oled_open)\n\n", err);
	} else {
		err = oled_init(&disp);
		if (err < 0) {
			printf("\nERROR: %i, Failed(oled_init)\n\n", err);
		} else {
			printf("---------start--------\n");
			oled_clear(&disp);
			drawLine(&disp, 0, 50, 100, 0);
			delay(3000);
			oled_clear(&disp);
			printf("----------end---------\n");
		}
	}

	return 0;
}

这里封装了一个绘制直线的函数drawLine,后面四个参数分别是直线起点的坐标和终点坐标,效果如下:

在这里插入图片描述

2. 绘制圆形

同样可以借助圆的数学定义和 Bresenham 算法来实现在 OLED 上面画圆,下面是一个简单的示例代码:

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <wiringPi.h>
//#include <math.h>
#include "oled.h"
#include "font.h"

void drawCircle(struct display_info *disp, int xc, int yc, int radius)
{
    int x = radius;
    int y = 0;
    int err = 0;

    while (x >= y) {
        oled_putpixel(disp, xc + x, yc + y, 1);
        oled_putpixel(disp, xc + y, yc + x, 1);
        oled_putpixel(disp, xc - y, yc + x, 1);
        oled_putpixel(disp, xc - x, yc + y, 1);
        oled_putpixel(disp, xc - x, yc - y, 1);
        oled_putpixel(disp, xc - y, yc - x, 1);
        oled_putpixel(disp, xc + y, yc - x, 1);
        oled_putpixel(disp, xc + x, yc - y, 1);
	oled_send_buffer(disp);

        if (err <= 0) {
            y += 1;
            err += 2*y + 1;
        }
        if (err > 0) {
            x -= 1;
            err -= 2*x + 1;
        }
    }
}

int main(int argc, char **argv)
{
	int err;
	char channal[32];
	struct display_info disp;

	if (argc < 2) {
		printf("\nUsage:\n%s <I2C bus device node >\n", argv[0]);
		return -1;
	}

	memset(&disp, 0, sizeof(disp));
	sprintf(channal, "%s", argv[1]);
	disp.address = OLED_I2C_ADDR;
	disp.font = font2;

	err = oled_open(&disp, channal);

	if (err < 0) {
		printf("\nERROR: %i, Failed(oled_open)\n\n", err);
	} else {
		err = oled_init(&disp);
		if (err < 0) {
			printf("\nERROR: %i, Failed(oled_init)\n\n", err);
		} else {
			printf("---------start--------\n");
			oled_clear(&disp);
			drawCircle(&disp, 64, 32, 30);
			delay(3000);
			oled_clear(&disp);
			printf("----------end---------\n");
		}
	}

	return 0;
}

主函数中调用了绘制圆形的函数,圆心是(64, 32),半径为 30,效果如下:

在这里插入图片描述

想玩花一些,可以画一个奥运五环,代码如下:

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <wiringPi.h>
//#include <math.h>
#include "oled.h"
#include "font.h"

void drawCircle(struct display_info *disp, int xc, int yc, int radius)
{
    int x = radius;
    int y = 0;
    int err = 0;

    while (x >= y) {
        oled_putpixel(disp, xc + x, yc + y, 1);
        oled_putpixel(disp, xc + y, yc + x, 1);
        oled_putpixel(disp, xc - y, yc + x, 1);
        oled_putpixel(disp, xc - x, yc + y, 1);
        oled_putpixel(disp, xc - x, yc - y, 1);
        oled_putpixel(disp, xc - y, yc - x, 1);
        oled_putpixel(disp, xc + y, yc - x, 1);
        oled_putpixel(disp, xc + x, yc - y, 1);
        oled_send_buffer(disp);

        if (err <= 0) {
            y += 1;
            err += 2*y + 1;
        }
        if (err > 0) {
            x -= 1;
            err -= 2*x + 1;
        }
    }
}

int main(int argc, char **argv)
{
        int err;
        char channal[32];
        struct display_info disp;

        if (argc < 2) {
                printf("\nUsage:\n%s <I2C bus device node >\n", argv[0]);
                return -1;
        }

        memset(&disp, 0, sizeof(disp));
        sprintf(channal, "%s", argv[1]);
        disp.address = OLED_I2C_ADDR;
        disp.font = font2;

        err = oled_open(&disp, channal);

        if (err < 0) {
                printf("\nERROR: %i, Failed(oled_open)\n\n", err);
        } else {
                err = oled_init(&disp);
                if (err < 0) {
                        printf("\nERROR: %i, Failed(oled_init)\n\n", err);
                } else {
                        printf("---------start--------\n");
                        oled_clear(&disp);
                        drawCircle(&disp, 64, 25, 18);
                        drawCircle(&disp, 24, 25, 18);
                        drawCircle(&disp, 64+40, 25, 18);
                        drawCircle(&disp, 64+20, 40, 18);
                        drawCircle(&disp, 64-20, 40, 18);
                        delay(3000);
                        oled_clear(&disp);
                        printf("----------end---------\n");
                }
        }

        return 0;
}

效果如下:

在这里插入图片描述

3. 显示图片(全屏)

这里特别强调一下,此处所提的图片分辨率必须为 128 × 64 像素的位图,通过取模软件获得图片对应的字符类型一维数组。我用的取模软件是“字模提取 V2.1”,取模方式为 C51 纵向取模。

在这里插入图片描述

具体实现显示图片的代码如下:

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <wiringPi.h>

#include "oled.h"
#include "font.h"

const char bmp_data[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xFC,0xFC,0xFC,0xFC,0xFC,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,
0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0xFC,0xFC,0xF8,0xF0,0xE0,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x8F,0x8F,0x8F,0x8F,0x87,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xFF,0xFF,0xFF,0xFF,0x7F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0x0F,0x0F,0x0F,0x0F,0x8F,0xCF,0xCF,0xCF,0xCF,0xCF,0xC7,0xC7,0xC7,0xC3,0xC1,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
0xE0,0xE0,0xE6,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0xE6,0xFE,0x7C,
0x38,0x00,0x00,0xF8,0xFC,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x42,0x00,0x00,0xFE,
0xFE,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0xFE,0x7E,0x3C,0x00,0x00,0x00,0xFC,0xFE,0xEE,
0xE6,0xE6,0xE6,0xE6,0xE6,0xE6,0x42,0x00,0x00,0xF8,0xFC,0xFE,0xC6,0xC6,0xC6,0xC6,
0xC6,0xC6,0x42,0x00,0x00,0xF8,0xFC,0xFE,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x00,
0x02,0x06,0x06,0x06,0xFE,0xFE,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0x0F,0x1F,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x08,0x00,0x00,0x1F,
0x1F,0x1F,0x00,0x00,0x00,0x00,0x01,0x0F,0x1F,0x1E,0x00,0x00,0x00,0x1F,0x1F,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x1F,0x1C,0x1C,0x1C,0x1C,
0x1C,0x1C,0x08,0x00,0x00,0x03,0x07,0x0F,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x18,0x00,
0x00,0x00,0x00,0x00,0x1F,0x1F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x0A,0x06,0x00,0x00,0x00,0x00,0x00,0x1E,0x0A,
0x0A,0x14,0x00,0x00,0x00,0x00,0x00,0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00,0x00,
0x0C,0x12,0x12,0x18,0x00,0x00,0x00,0x00,0x00,0x1E,0x0A,0x0A,0x14,0x00,0x00,0x00,
0x00,0x00,0x1C,0x0A,0x0A,0x1C,0x00,0x00,0x00,0x00,0x00,0x1E,0x04,0x18,0x04,0x1E,
0x00,0x00,0x00,0x00,0x00,0x1E,0x04,0x08,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,
0x16,0x12,0x00,0x00,0x00,0x00,0x00,0x1E,0x0A,0x0A,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

void displayBmp(struct display_info *disp, const char *bmp)
{
    uint8_t x, y;
	uint16_t index = 0;
	uint8_t pixel_value;
    for (y = 0; y < 64; y += 8) {
        for (x = 0; x < 128; x++) {
			for (int i = 0; i < 8; i++) {
				pixel_value = (bmp[index] >> i) & 0x01;
				oled_putpixel(disp, x, y + i, pixel_value);
			}
			index++;
			//oled_send_buffer(disp);
        }
		//oled_send_buffer(disp);
    }
	oled_send_buffer(disp);
}

int main(int argc, char **argv)
{
        int err;
        char channal[32];
        struct display_info disp;

        if (argc < 2) {
                printf("\nUsage:\n%s <I2C bus device node >\n", argv[0]);
                return -1;
        }

        memset(&disp, 0, sizeof(disp));
        sprintf(channal, "%s", argv[1]);
        disp.address = OLED_I2C_ADDR;
        disp.font = font2;

        err = oled_open(&disp, channal);

        if (err < 0) {
                printf("\nERROR: %i, Failed(oled_open)\n\n", err);
        } else {
                err = oled_init(&disp);
                if (err < 0) {
                        printf("\nERROR: %i, Failed(oled_init)\n\n", err);
                } else {
                        printf("---------start--------\n");
                        oled_clear(&disp);
                        displayBmp(&disp, bmp_data);
                        delay(5000);
                        oled_clear(&disp);
                        printf("----------end---------\n");
                }
        }

        return 0;
}

显示效果如下:

在这里插入图片描述
如果有多图片循环切换,可以到达一些动画效果,就是刷新率比较感人。

1000032190

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Grayson_Zheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值