I2C通信实例 - OLED显示 02

前文回顾:


本文介绍基于HAL库编写OLED显示驱动的基本方法。如前文所述,先在Hardware文件夹中新建一个OLED文件夹,然后在其中新建一个oled.h和一个oled.c文件。

定义别名

为了提高程序的可读性和通用性,先在oled.h中为常量和常用指令定义别名。SSD1306的指令有几十条,在手册上都可以查到。不必求全,按需定义即可。先定义几个常量:

#define Max_Col128U#define Max_Row32U#define Max_Page  4U

这3个常量主要是为了适应不同分辨率的屏幕。这里是128×32的屏,共4页。比如换了128×64的,Max_Row和Max_Page相应调整为64U和8U(每页8行)即可。指令定义如下:

typedef enum {SET_CONTRAST= 0x81, //#2bytes command#SCROLL_STOP= 0x2E, //Stop scrollingSCROLL_START= 0x2F, //Start scrollingSET_SCROLL_AREA= 0xA3, //Set vertical scroll area,SET_ADDR_MODE= 0x20, //Set memory addressing mode. SET_COL_ADDR= 0x21, //Setup column start and end addressSET_PAG_ADDR= 0x22, //Setup page start and end addressADDR_Y_START= 0xB0, //0xB0+i, set PAGE start address in GDDRAMADDR_X_LOWER= 0x00, //0x00, set column start address lower 4bitADDR_X_HIGHER= 0x10, //0x10, set column start address higher 4bitSET_MUX= 0xA8, //Set MUXdSET_OSC_FRE= 0xD5, //Set DCLK divide ratio / oscillator frequency FOCSSET_PRE_CHARGE= 0xD9, //Set pre-charge period A[3:0]:phase 1; A[7:4]:phase 2SET_VCOMH_LEVEL= 0xDB, //Set V_COMH deselect levelSET_CHARGE_PUMP= 0X8D, //Charge pump setting CHARGE_PUMP_ON= 0x14, //Enable charge pump during display on. (ENABLE BEFORE ON)CHARGE_PUMP_OFF= 0x10, //Disable charge pump. (RESET)} OLED_CMD;//Display modetypedef enum {DISPLAY_NORMAL = 0xA6, //1 in RAM ->ONDISPLAY_INVERSE = 0xA7, //1 in RAM ->OFFDISPLAY_SLEEP = 0xAE, //Display OFF, sleep mode. (RESET)DISPALY_WAKEUP = 0xAF, //Display ON, normal mode.DISPLAY_ENTIRE_RAM = 0xA4, //Entire Display ON. Output follows RAM content. (RESET)DISPLAY_ENTIRE_ON = 0xA5, //Entire Display ON. Output ignores RAM content.} DISPLAY_MODE;

以枚举类的形式为常用指令定义了别名。名字按自己喜好随便取,达意即可。显示模式相关的指令单独定义到了一个类中,主要是为了函数传参方便。

头文件中还要有必要的#Include和公共函数的声明。都是常识,略过不表。

指令或数据的发送

OLED是自带驱动模块的,驱动程序只需发送控制指令和把拟显示的内容写入到显存中的合适位置即可。可分为三种基本操作:指令写入、数据写入、定位数据写入位置。

由于这里所用的OLED是I2C接口,写入操作需要调用I2C API中的HAL_I2C_Mem_Write,而不是像前文控制SHT35传感器时那样用HAL_I2C_Master_Transmit。前者是向内存中写入数据,后者是向从机发送数据。HAL_I2C_Mem_Write函数可以一次写入任意数量的数据,因此我们只需把要发送的指令数据放到一个数组中,然后调用HAL_I2C_Mem_Write一次性发送出去即可。这样操作可以避免HAL库的冗余校验造成额外开销。

先来定义两个写入函数:

// I2C Address of OLED#defineADDR_WRITE0x78//0111 1000#defineADDR_READ0x79  //0111 1001#defineADDR_CMD0x00#defineADDR_DAT0x40/*----------------------------------------------------------------------------* * @briefWrite an amount of bytes to a specific memory address * @param DAT/CMD Data/command need to be write * @paramNUM  number of bytes *----------------------------------------------------------------------------*/void OLED_Write_DAT(u8 *dat, u16 num) {HAL_StatusTypeDef status;status = HAL_I2C_Mem_Write( &hi2c1, ADDR_WRITE, ADDR_DAT,I2C_MEMADD_SIZE_8BIT, dat, num, 100);if (status!=HAL_OK)Error_Handler();}void OLED_Write_CMD(u8 *cmd, u16 num) {HAL_StatusTypeDef status;status = HAL_I2C_Mem_Write( &hi2c1, ADDR_WRITE, ADDR_CMD,I2C_MEMADD_SIZE_8BIT, cmd, num, 100);if (status!=HAL_OK)Error_Handler();}

OLED的控制器是根据地址来区分读、写指令,以及判断收到的信息是指令还是数据的。因此,一开始先定义了这4个地址。OLED_Write_DAT函数写数据,OLED_Write_CMD写指令。注意第2个地址(第3个参数)的区别。

定位函数如下:

void OLED_Set_Pos(u8 x, u8 y) {//Locate the SEG at (Col X, Page Y)u8 cmdlist[] = {    (x&0x0f),//Lower 4 bits    ((x&0xf0)>>4U)|0X10, //Higher 4 bitsADDR_Y_START+y //Page};OLED_Write_CMD(cmdlist, sizeof(cmdlist));}

这个函数把数据写入位置定位到(Col x,Page y)。注意看这个函数,很有代表性。把拟发送的指令:列地址的LSB、MSB和页地址放到一个数组中,然后调用OLED_Write_CMD一次性发送。再次提醒:HAL库要尽量避免多数参考例程那种逐条发送。

做完这些准备工作,接下来就可以按需添加功能函数了。


后文链接:

  • I2C通信实例 - OLED显示 03
实例   通信   I2C
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章