【前言】
OLED是非常常用的显示设备,可以由4线、3线的spi驱动,也可以使用2线的IIC来驱动。百问网提供了spi_OLED的驱动例程,这次使用IIC来驱动,并且使用基于面向对象的编程来实现。
【实现步聚】
1、配置IIC,打开RASC后,在栈中增加rau_master_I2C,并设置channel为0b20即通道2,选择SCL为P112与SDA为P110。
【注】,我原来设置了为通道0或者通道1,但是都与UART或的外接晶振的IO有冲突,所以只能选择这个通道但是他还是与tx、LED有冲突,如果自己的设计的话还需要考虑到IO的冲突问题。
2、生成代码后,我拷贝drv_oled.h/c以及driv_spi.h到工程之中。
3、在原来的OLED工程之中,是使用spi来驱动的,同时原来的RA5他的内存与频率相比RA0要高很多,需要进行很多的更改。首先添加回调函数,回调函数中判断接收状态,并更新:
void sau_i2c_master_callback(i2c_master_callback_args_t * p_args) { switch (p_args->event) { case I2C_MASTER_EVENT_TX_COMPLETE: { gI2C1TxCplt = true; break; } case I2C_MASTER_EVENT_RX_COMPLETE: { gI2C1RxCplt = true; break; } default: { gI2C1TxCplt = gI2C1RxCplt = false; break; } } }
4、接着修改发送等待超时函数,在我们向i2c总线发送数据结事后,我们需要用这个函数来判断是否发送结束的标志位。
static void I2C1WaitTxCplt(void) { uint16_t wTimeOut = 10; while(!gI2C2TxCplt && wTimeOut) { HAL_Delay(1); wTimeOut--; } gI2C2TxCplt = false; }
5、修改向ssd1306写入一个寄存器的功能函数,在这个函数中,我们要组装一个buff用于向i2c总线写入数据的,由于向ssd1306写入寄存器,第一个字节为0x00,所以组装为[0x00,cmd]。
static void OLEDDrvWriteReg(uint8_t ucData) { uint8_t buff[2]= {0x00,0x00}; buff[1] = ucData; fsp_err_t err = R_SAU_I2C_Write(&g_sau_i2c_master_ctrl, buff, 2, true); if (FSP_SUCCESS != err) { printf("%s %d\r\n", __FUNCTION__, __LINE__); return; } I2C1WaitTxCplt(); }
6、组装向ssd1306发送一整个buff的命令:
static void OLEDDrvWriteBuf(uint8_t* rbuf, uint16_t wSize) { fsp_err_t err; // err =R_SAU_I2C_Write(&g_sau_i2c_master_ctrl, 0x40, 1, false); // if(FSP_SUCCESS != err) // printf("Function:%s\tLine:%d\r\n", __FUNCTION__, __LINE__); rbuf[0] = 0x40; err = R_SAU_I2C_Write(&g_sau_i2c_master_ctrl, rbuf, 1024, true); if(FSP_SUCCESS != err) printf("Function:%s\tLine:%d\r\n", __FUNCTION__, __LINE__); I2C1WaitTxCplt(); }
【注】这里原来使用malloc进行了重新的内存申请,但是由于这个MCU的内存有限,我做了申请,好象一直不成功,先写成这样,其实buf中的0位是被清除掉了的,所以会有点问题,在后面我将重新这个驱动,这里先实现基本功能。
7、编写测试函数如下:
void led_blink(void) { UartDevicesRegister(); DisplayDevice *ptDispDev = OLEDGetDevice(); if(ptDispDev == NULL) { printf("Failed to get OLED Display Device!\r\n"); return; } ptDispDev->Init(ptDispDev); uint8_t *pBuf = (uint8_t*)ptDispDev->FBBase; while(1) { for(uint16_t i=0; i<ptDispDev->dwSize; i++) { pBuf[i] = 0x00; } ptDispDev->Flush(ptDispDev); HAL_Delay(1); for(uint16_t i=0; i<ptDispDev->dwSize; i++) { pBuf[i] = 0xFF; } ptDispDev->Flush(ptDispDev); HAL_Delay(1); } }
其中第一段是向整个屏写入了0x00即全屏为黑色,第二段是写入oxFF即全白。这样就实现了清屏-》全亮的效果。
【总结】
在面向对象的编程中,对OLED进行的封装,在使用的过程中,可以实现少量的低层代码的修改即中实现模块化的功能实现。下一步,我将补全字符、图片的功能。
附工程源码: