首先板载的系统在板子上树莓派40pin接口具有两个iic接口并且以及打开了
下面这个表格汇总了主要步骤和要点:
| 步骤 | 关键行动 | 说明/命令示例 |
|---|---|---|
| 1. 确认接口与连接 | 确认OLED使用I2C还是SPI通信,并正确连接硬件 | 参考理解常见接线逻辑;具体引脚需查阅OK3506原理图 |
| 2. 检查与使能接口 | 确认系统识别到I2C或SPI设备 | I2C检查:ls /dev/i2c*;SPI检查:ls /dev/spi*;必要时在系统配置中使能 |
| 3. 获取OLED用户层驱动代码 | 编写或获取基于I2C/SPI的OLED驱动代码 | 代码需基于I2C(如使用/dev/i2c-1)或SPI(如使用/dev/spidev1.0)设备文件操作 |
| 4. 交叉编译 | 在主机上使用交叉编译工具链编译代码 | arm-linux-gnueabihf-gcc -o oled_test oled_test.c -static |
| 5. 部署与测试 | 将编译好的程序传到板子上运行 | 使用scp传输;设置可执行权限chmod +x oled_test;运行./oled_test |
I2C1_SDA, I2C1_SCL)或SPI接口对应的物理引脚。在OK3506的终端中,检查I2C或SPI设备是否已被系统识别:
ls /dev/i2c*,如果能看到类似 /dev/i2c-0 或 /dev/i2c-1 的设备文件,说明I2C驱动已加载。ls /dev/spi*,检查是否存在类似 /dev/spidev1.0 的设备文件。如果找不到对应的设备文件,你可能需要在Buildroot的系统配置中使能I2C或SPI的用户空间设备支持,并重新构建根文件系统。
你需要一个在用户空间通过I2C或SPI控制OLED的程序。由于你的OLED是I2C接口,下面提供一个基于I2C的简单C代码框架(例如保存为 oled_i2c.c),用于点亮OLED并进行基本显示。此代码框架思路亦可见于的ESP8266驱动。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#define OLED_I2C_DEV "/dev/i2c-1" // 根据实际i2c设备文件修改
#define OLED_ADDR 0x3C // OLED的I2C地址,常见为0x3C或0x3D
int i2c_fd;
// 向OLED发送命令
void oled_write_cmd(unsigned char cmd) {
unsigned char buffer[2] = {0x00, cmd}; // I2C模式下,通常第一个字节为0x00表示命令
if (write(i2c_fd, buffer, 2) != 2) {
perror("Failed to write command");
}
}
// 初始化OLED序列
void oled_init() {
// 详细的初始化命令序列需参考SSD1306数据手册或厂家示例
oled_write_cmd(0xAE); // 关闭显示
// ... 这里需要添加更多的初始化命令,例如设置内存地址模式、扫描方向、对比度等
// oled_write_cmd(0x20); oled_write_cmd(0x00); // 设置内存地址模式为水平模式
// ... 更多初始化命令
oled_write_cmd(0xAF); // 打开显示
}
int main() {
// 打开I2C设备
i2c_fd = open(OLED_I2C_DEV, O_RDWR);
if (i2c_fd < 0) {
perror("Failed to open I2C device");
return -1;
}
// 设置I2C从设备地址
if (ioctl(i2c_fd, I2C_SLAVE, OLED_ADDR) < 0) {
perror("Failed to set I2C slave address");
close(i2c_fd);
return -1;
}
// 初始化并点亮OLED
oled_init();
printf("OLED initialized and turned on.\\n");
// ... 这里可以添加具体的显示函数,例如显示字符串、图形等
sleep(5); // 保持显示5秒
close(i2c_fd);
return 0;
}
下面是我自己的oled驱动代码是iic-2的接口
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#define OLED_I2C_ADDR 0x3C // 常见 I2C 地址 (有些是 0x3D)
#define OLED_CMD 0x00 // 控制字节: 命令
#define OLED_DATA 0x40 // 控制字节: 数据
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_PAGES (OLED_HEIGHT / 8)
// 如果你的屏是 SH1106 控制器,常见需要列偏移 2;SSD1306 一般为 0
#ifndef OLED_COL_OFFSET
#define OLED_COL_OFFSET 0
#endif
static int i2c_fd = -1;
// 发送一条命令
static int oled_write_cmd(uint8_t cmd) {
uint8_t buf[2] = { OLED_CMD, cmd };
ssize_t n = write(i2c_fd, buf, 2);
if (n != 2) return -1;
return 0;
}
// 发送一段数据(内部自动加控制字节0x40,分片写入)
static int oled_write_data(const uint8_t* data, size_t len) {
// 一些适配器对 I2C 块写长度有限制,分片到 16 字节以内更稳妥
const size_t chunk = 16;
uint8_t buf[1 + chunk];
buf[0] = OLED_DATA;
size_t sent = 0;
while (sent < len) {
size_t n = (len - sent) > chunk ? chunk : (len - sent);
memcpy(buf + 1, data + sent, n);
ssize_t w = write(i2c_fd, buf, 1 + n);
if (w != (ssize_t)(1 + n)) return -1;
sent += n;
}
return 0;
}
static void oled_set_pos(uint8_t page, uint8_t col) {
col += OLED_COL_OFFSET;
oled_write_cmd(0xB0 | (page & 0x07)); // 页地址
oled_write_cmd(0x00 | (col & 0x0F)); // 列低4位
oled_write_cmd(0x10 | ((col >> 4) & 0x0F)); // 列高4位
}
static int oled_init(void) {
// 参考 SSD1306 128x64 初始化,改为“页寻址模式”
if (oled_write_cmd(0xAE)) return -1; // Display OFF
if (oled_write_cmd(0x20)) return -1; // Set Memory Addressing Mode
if (oled_write_cmd(0x02)) return -1; // Page Addressing Mode
if (oled_write_cmd(0xB0)) return -1; // Page Start Address for Page Addressing Mode
if (oled_write_cmd(0xC8)) return -1; // COM Output Scan Direction: remapped mode
if (oled_write_cmd(0x00)) return -1; // set low column address
if (oled_write_cmd(0x10)) return -1; // set high column address
if (oled_write_cmd(0x40)) return -1; // set start line address
if (oled_write_cmd(0x81)) return -1; // Contrast
if (oled_write_cmd(0x7F)) return -1;
if (oled_write_cmd(0xA1)) return -1; // Segment re-map (A0/A1)
if (oled_write_cmd(0xA6)) return -1; // Normal display (A7 inverse)
if (oled_write_cmd(0xA8)) return -1; // Multiplex ratio
if (oled_write_cmd(0x3F)) return -1; // 1/64 duty
if (oled_write_cmd(0xA4)) return -1; // Display follows RAM
if (oled_write_cmd(0xD3)) return -1; // Display offset
if (oled_write_cmd(0x00)) return -1;
if (oled_write_cmd(0xD5)) return -1; // Display clock divide
if (oled_write_cmd(0x80)) return -1;
if (oled_write_cmd(0xD9)) return -1; // Pre-charge
if (oled_write_cmd(0xF1)) return -1;
if (oled_write_cmd(0xDA)) return -1; // COM pins
if (oled_write_cmd(0x12)) return -1; // For 128x64
if (oled_write_cmd(0xDB)) return -1; // VCOMH
if (oled_write_cmd(0x40)) return -1;
if (oled_write_cmd(0x8D)) return -1; // Charge pump
if (oled_write_cmd(0x14)) return -1; // Enable
if (oled_write_cmd(0xAF)) return -1; // Display ON
usleep(1000 * 100);
return 0;
}
// 清屏
static void oled_clear(void) {
uint8_t zeros[OLED_WIDTH];
memset(zeros, 0x00, sizeof(zeros));
for (uint8_t p = 0; p < OLED_PAGES; ++p) {
oled_set_pos(p, 0);
oled_write_data(zeros, OLED_WIDTH);
}
}
// 简易 5x7 字库(仅覆盖本例中用到的字符;其余显示为空白)
// 每个字符 5 列(第6列留作1像素空列)
static void glyph5x7(char c, uint8_t out5[5]) {
// 预设为空白
memset(out5, 0x00, 5);
switch (c) {
case ' ': out5[0]=0x00; out5[1]=0x00; out5[2]=0x00; out5[3]=0x00; out5[4]=0x00; break;
// Digits '0'-'9'
case '0': out5[0]=0x3E; out5[1]=0x51; out5[2]=0x49; out5[3]=0x45; out5[4]=0x3E; break;
case '1': out5[0]=0x00; out5[1]=0x42; out5[2]=0x7F; out5[3]=0x40; out5[4]=0x00; break;
case '2': out5[0]=0x42; out5[1]=0x61; out5[2]=0x51; out5[3]=0x49; out5[4]=0x46; break;
case '3': out5[0]=0x21; out5[1]=0x41; out5[2]=0x45; out5[3]=0x4B; out5[4]=0x31; break;
case '4': out5[0]=0x18; out5[1]=0x14; out5[2]=0x12; out5[3]=0x7F; out5[4]=0x10; break;
case '5': out5[0]=0x27; out5[1]=0x45; out5[2]=0x45; out5[3]=0x45; out5[4]=0x39; break;
case '6': out5[0]=0x3C; out5[1]=0x4A; out5[2]=0x49; out5[3]=0x49; out5[4]=0x30; break;
case '7': out5[0]=0x01; out5[1]=0x71; out5[2]=0x09; out5[3]=0x05; out5[4]=0x03; break;
case '8': out5[0]=0x36; out5[1]=0x49; out5[2]=0x49; out5[3]=0x49; out5[4]=0x36; break;
case '9': out5[0]=0x06; out5[1]=0x49; out5[2]=0x49; out5[3]=0x29; out5[4]=0x1E; break;
// Uppercase 'A'-'Z'
case 'A': out5[0]=0x7E; out5[1]=0x11; out5[2]=0x11; out5[3]=0x11; out5[4]=0x7E; break;
case 'B': out5[0]=0x7F; out5[1]=0x49; out5[2]=0x49; out5[3]=0x49; out5[4]=0x36; break;
case 'C': out5[0]=0x3E; out5[1]=0x41; out5[2]=0x41; out5[3]=0x41; out5[4]=0x22; break;
case 'D': out5[0]=0x7F; out5[1]=0x41; out5[2]=0x41; out5[3]=0x22; out5[4]=0x1C; break;
case 'E': out5[0]=0x7F; out5[1]=0x49; out5[2]=0x49; out5[3]=0x49; out5[4]=0x41; break;
case 'F': out5[0]=0x7F; out5[1]=0x09; out5[2]=0x09; out5[3]=0x09; out5[4]=0x01; break;
case 'G': out5[0]=0x3E; out5[1]=0x41; out5[2]=0x49; out5[3]=0x49; out5[4]=0x3A; break;
case 'H': out5[0]=0x7F; out5[1]=0x08; out5[2]=0x08; out5[3]=0x08; out5[4]=0x7F; break;
case 'I': out5[0]=0x00; out5[1]=0x41; out5[2]=0x7F; out5[3]=0x41; out5[4]=0x00; break;
case 'J': out5[0]=0x20; out5[1]=0x40; out5[2]=0x41; out5[3]=0x3F; out5[4]=0x01; break;
case 'K': out5[0]=0x7F; out5[1]=0x08; out5[2]=0x14; out5[3]=0x22; out5[4]=0x41; break;
case 'L': out5[0]=0x7F; out5[1]=0x40; out5[2]=0x40; out5[3]=0x40; out5[4]=0x40; break;
case 'M': out5[0]=0x7F; out5[1]=0x02; out5[2]=0x0C; out5[3]=0x02; out5[4]=0x7F; break;
case 'N': out5[0]=0x7F; out5[1]=0x04; out5[2]=0x08; out5[3]=0x10; out5[4]=0x7F; break;
case 'O': out5[0]=0x3E; out5[1]=0x41; out5[2]=0x41; out5[3]=0x41; out5[4]=0x3E; break;
case 'P': out5[0]=0x7F; out5[1]=0x09; out5[2]=0x09; out5[3]=0x09; out5[4]=0x06; break;
case 'Q': out5[0]=0x3E; out5[1]=0x41; out5[2]=0x51; out5[3]=0x21; out5[4]=0x5E; break;
case 'R': out5[0]=0x7F; out5[1]=0x09; out5[2]=0x19; out5[3]=0x29; out5[4]=0x46; break;
case 'S': out5[0]=0x46; out5[1]=0x49; out5[2]=0x49; out5[3]=0x49; out5[4]=0x31; break;
case 'T': out5[0]=0x01; out5[1]=0x01; out5[2]=0x7F; out5[3]=0x01; out5[4]=0x01; break;
case 'U': out5[0]=0x3F; out5[1]=0x40; out5[2]=0x40; out5[3]=0x40; out5[4]=0x3F; break;
case 'V': out5[0]=0x1F; out5[1]=0x20; out5[2]=0x40; out5[3]=0x20; out5[4]=0x1F; break;
case 'W': out5[0]=0x7F; out5[1]=0x20; out5[2]=0x18; out5[3]=0x20; out5[4]=0x7F; break;
case 'X': out5[0]=0x63; out5[1]=0x14; out5[2]=0x08; out5[3]=0x14; out5[4]=0x63; break;
case 'Y': out5[0]=0x03; out5[1]=0x04; out5[2]=0x78; out5[3]=0x04; out5[4]=0x03; break;
case 'Z': out5[0]=0x61; out5[1]=0x51; out5[2]=0x49; out5[3]=0x45; out5[4]=0x43; break;
// Lowercase (覆盖本例需要)
case 'a': out5[0]=0x20; out5[1]=0x54; out5[2]=0x54; out5[3]=0x54; out5[4]=0x78; break;
case 'd': out5[0]=0x38; out5[1]=0x44; out5[2]=0x44; out5[3]=0x48; out5[4]=0x7F; break;
case 'e': out5[0]=0x38; out5[1]=0x54; out5[2]=0x54; out5[3]=0x54; out5[4]=0x18; break;
case 'l': out5[0]=0x00; out5[1]=0x41; out5[2]=0x7F; out5[3]=0x40; out5[4]=0x00; break;
case 'o': out5[0]=0x38; out5[1]=0x44; out5[2]=0x44; out5[3]=0x44; out5[4]=0x38; break;
case 's': out5[0]=0x48; out5[1]=0x54; out5[2]=0x54; out5[3]=0x54; out5[4]=0x20; break;
case 't': out5[0]=0x04; out5[1]=0x3F; out5[2]=0x44; out5[3]=0x40; out5[4]=0x20; break;
default: break; // 其它字符暂不显示
}
}
// 显示一个字符(6列:5列字模 + 1列空白)
static void oled_draw_char(uint8_t page, uint8_t col, char c) {
if (page >= OLED_PAGES || col >= OLED_WIDTH) return;
uint8_t g[5]; glyph5x7(c, g);
// 如超出右边界则截断
int remain = OLED_WIDTH - col;
uint8_t buf[6] = { g[0], g[1], g[2], g[3], g[4], 0x00 };
int to_write = remain >= 6 ? 6 : remain;
oled_set_pos(page, col);
oled_write_data(buf, to_write);
}
// 在指定页与列显示字符串(超宽会自动换到下一页)
static void oled_show_text(uint8_t page, uint8_t col, const char* text) {
uint8_t p = page;
uint8_t x = col;
for (const char* s = text; *s; ++s) {
if (x + 6 > OLED_WIDTH) { // 换到下一页
x = 0;
p++;
if (p >= OLED_PAGES) break;
}
oled_draw_char(p, x, *s);
x += 6; // 每字 6 列(含1列间隔)
}
}
int main(int argc, char** argv) {
const char* dev = (argc >= 2) ? argv[1] : "/dev/i2c-2"; // 可传 /dev/i2c-2
int addr = (argc >= 3) ? strtol(argv[2], NULL, 0) : OLED_I2C_ADDR;
i2c_fd = open(dev, O_RDWR);
if (i2c_fd < 0) {
fprintf(stderr, "无法打开I2C设备 %s: %s\\n", dev, strerror(errno));
return 1;
}
if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0) {
fprintf(stderr, "无法设置I2C地址 0x%02X: %s\\n", addr, strerror(errno));
close(i2c_fd);
return 1;
}
if (oled_init() < 0) {
fprintf(stderr, "OLED 初始化失败\\n");
close(i2c_fd);
return 1;
}
oled_clear();
usleep(1000 * 50);
// 显示测试内容(隔一页便于行距:0,2,4)
oled_show_text(0, 0, "Hello");
oled_show_text(2, 0, "OK3506");
oled_show_text(4, 0, "OLED Test");
oled_show_text(6, 0, "xiaozhou");
close(i2c_fd);
return 0;
}
注意 :以上代码中的 oled_init 函数内的初始化命令序列并不完整。你需要根据OLED驱动芯片(通常是SSD1306)的数据手册或厂家提供的初始化代码,补充完整的初始化命令序列,屏幕才能正常显示内容。可以参考中关于SSD1306初始化命令的说明。
由于OK3506板载Buildroot系统没有GCC,你需要在你的主机(例如x86电脑)上使用交叉编译工具链来编译这个程序。
gcc-arm-linux-gnueabihf。
sudo apt-get install gcc-arm-linux-gnueabihf-static 选项进行静态链接 ,这样可以避免板子上缺少动态库的问题。arm-linux-gnueabihf-gcc -o oled_i2c oled_i2c.c -static
这将生成一个名为 oled_i2c 的可执行文件。
`
cd /root
chmod +x oled_i2c
./oled_i2c
最后的运行效果:
spidev)已正确启用,且用户有访问权限(如 /dev/i2c-1 或 /dev/spidev1.0)。i2cdetect -y 1(假设总线是 i2c-1),查看OLED设备的地址。更多回帖