【前言】
此前使用STM32或者python等驱动过OLED屏,但是在Zephyr上还没有实现过,本篇将跟大家分享如何在Zephry中使用I2C,并实现驱动OLED屏。
【启用驱动程序】
1.通过将以下行添加到应用程序配置文件prj.conf中来启用I2C驱动程序。
CONFIG_I2C=y #启动I2C CONFIG_TFM_SECURE_UART=n //在534x 因为与I2C设备地址有冲突,所以需要禁用。 CONFIG_TFM_LOG_LEVEL_SILENCE=y
2、在源代码文件中包含I2C API的头文件
#include <zephyr/drivers/i2c.h>
3、展开配置文件->Devicetree并创建一个覆盖文件。

其内容如下:
&i2c1 {
    status = "okay";
    pinctrl-0 = <&i2c1_default>;
    pinctrl-1 = <&i2c1_sleep>;
    pinctrl-names = "default", "sleep";
    ssd1306: ssd1306@3c {
        compatible = "i2c-device";
        status = "okay";
        reg = <0x3c>;
    };
    clock-frequency = <I2C_BITRATE_FAST>;
};
&pinctrl {
    /omit-if-no-ref/ i2c1_default: i2c1_default {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 1, 14)>,
                    <NRF_PSEL(TWIM_SDA, 1, 15)>;
        };
    };
    /omit-if-no-ref/ i2c1_sleep: i2c1_sleep {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 1, 14)>,
                    <NRF_PSEL(TWIM_SDA, 1, 15)>;
            low-power-enable;
        };
    };
};做好这些准备后,我移植了一个OLED的驱动到工程中,对相应的收发函数进行修改就行了。

4、在oled.c中添加定义节点标识符
#define I2C1_NODE DT_NODELABEL(ssd1306)
5、检索API特定的设备结构。
宏调用I2C_DT_SPEC_GET()返回结构i2c_dt_spec,其中包含I2C总线的设备指针以及目标地址。
static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C1_NODE);
6、使用device_is_ready()验证设备是否可以使用。在oled.c中添加一个函数,用于OLED初始化时调用:
int oled_dev_init(void)
{
    if (!device_is_ready(dev_i2c.bus))
    {
        printk("Device %s is not ready\n", dev_i2c.bus->name);
        return -1;
    }
    return 0;
}此函数在OLED初始时先调用。
7、修改发送函数,由于SSD1306只需要发送数据,所以只需要修改发送函数就行了:
void OLED_WR_Byte(unsigned char dat,unsigned char cmd) {
    unsigned char i2c_tx_buff[2];
    if(cmd) {
        i2c_tx_buff[0] = 0x40;
    } else {
        i2c_tx_buff[0] = 0x00;
    }
    i2c_tx_buff[1] = dat;
    i2c_write_dt(&dev_i2c, i2c_tx_buff, 2);
}8、修改整屏刷新的函数:
void OLED_Display(void) {
    OLED_WR_Byte(0x21, 0); // 设置列地址
    OLED_WR_Byte(0x00, 0); // 起始列地址
    OLED_WR_Byte(SSD1306_WIDTH - 1, 0); // 结束列地址
    OLED_WR_Byte(0x22, 0); // 设置页地址
    OLED_WR_Byte(0x00, 0); // 起始页地址
    OLED_WR_Byte(OLED_PAGE_SIZE - 1, 0); // 结束页地址
    Flash_OLED_Buffer[0] = 0x40;
//  uint8_t i2c_tx_buff[SSD1306_WIDTH * OLED_PAGE_SIZE +1];
//  i2c_tx_buff[0] = 0x40;
//  memcpy(&i2c_tx_buff[1], OLED_buffer, SSD1306_WIDTH * OLED_PAGE_SIZE);
    // i2c_master_write(SSD1306_ADDR, Flash_OLED_Buffer, SSD1306_WIDTH * OLED_PAGE_SIZE +1);
    i2c_write_dt(&dev_i2c, Flash_OLED_Buffer, SSD1306_WIDTH * OLED_PAGE_SIZE + 1);
}到此OLED的驱动就移植好了,源码见我的附件。
【测试】
在main.c中添加对oled的头文件的引用,并添加打印函数:
int main(void)
{
	int ret;
	bool led_state = true;
	printk("start !\n");
	if (!gpio_is_ready_dt(&led)) {
		return 0;
	}
	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return 0;
	}
	OLED_Init();
	OLED_Clear(0);
	GUI_ShowString(0, 0, "hello world", 16, 1);
	OLED_Display();
	while (1)
	{
		ret = gpio_pin_toggle_dt(&led);
		if (ret < 0) {
			return 0;
		}
		led_state = !led_state;
		// printf("LED state: %s\n", led_state ? "ON" : "OFF");
		k_msleep(SLEEP_TIME_MS);
	}
	return 0;
}接上OLED屏后,就可以看到打印出来对应的效果:

附工程源码:

 
					
				
 
			
			
			
						
			 
					
				
 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

