/********************************************************************** * Copyright: (C)2021 LingYun IoT System Studio * Author: GuoWenxue QQ: 281143292 * Description: BearKE1 NB-IoT Board OLED Hardware Abstract Layer source code * * ChangeLog: * Version Date Author Description * V1.0.0 2021.08.10 GuoWenxue Release initial version ***********************************************************************/ #include "hal_oled.h" #include "font_ascii.h" enum { OLED_CMD = 0, OLED_DATA, }; /* *+-------------------------------------------------+ *| GPIO simulate I2C for OLED function API | *+-------------------------------------------------+ */ #define CONFIG_OLED_USE_GPIO_I2C /* use GPIO simulate I2C API */ typedef struct i2c_gpio_s { GPIO_TypeDef *group; uint16_t scl; /* SCL */ uint16_t sda; /* SDA */ } i2c_gpio_t; /* OLED I2C interface connected pins */ static i2c_gpio_t oled_i2c = { .group = GPIOB, .scl = GPIO_PIN_8, /* SCL Pin: PB8 */ .sda = GPIO_PIN_9, /* SDA Pin: PB9 */ }; #define OLED_IIC_GPIO_Init() \ { GPIO_InitTypeDef GPIO_InitStruct = {0}; \ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \ GPIO_InitStruct.Pull = GPIO_PULLUP; \ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \ GPIO_InitStruct.Pin = oled_i2c.sda; \ HAL_GPIO_Init(oled_i2c.group, &GPIO_InitStruct); \ GPIO_InitStruct.Pin = oled_i2c.scl; \ HAL_GPIO_Init(oled_i2c.group, &GPIO_InitStruct); \ } #define OLED_SCL_H() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.scl, GPIO_PIN_SET) #define OLED_SCL_L() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.scl, GPIO_PIN_RESET) #define OLED_SDA_H() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.sda, GPIO_PIN_SET) #define OLED_SDA_L() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.sda, GPIO_PIN_RESET) /* StartCondition(S) */ void IIC_Start(void) { /* StartCondition(S): A high to low transition on the SDA line while SCL is high. _______ SCL: |___ _____ SDA: |_____ */ OLED_SCL_H(); OLED_SDA_H(); OLED_SDA_L(); OLED_SCL_L(); } /* StopCondition(P) */ void IIC_Stop(void) { /* StopCondition(P): A low to high transition on the SDA line while SCL is high. _____ SCL: ___| _____ SDA: _____| */ OLED_SCL_H(); OLED_SDA_L(); OLED_SDA_H(); } void Write_IIC_Byte(uint8_t byte) { uint8_t i; uint8_t dat; dat=byte; /* Data line changes must happened when SCL is low */ OLED_SCL_L(); /* 1Byte=8bit, MSB send: bit[7]-->bit[0] */ for(i=0; i<8; i++) { if( dat&0x80 ) OLED_SDA_H(); else OLED_SDA_L(); OLED_SCL_H(); OLED_SCL_L(); /* prepare for next bit */ dat=dat<<1; } /* clk #9 for ACK but don't care it */ OLED_SCL_H(); OLED_SCL_L(); } static void IIC_Write_Command(uint8_t command) { /* Send I2C start signal */ IIC_Start(); /* Send OLED I2C slave write address, SA0=0, R/W#=0 */ Write_IIC_Byte(OLED_I2CWR_ADDR); /* send command value */ Write_IIC_Byte(0x00); Write_IIC_Byte(command); /* Send I2C stop signal */ IIC_Stop(); } static void IIC_Write_Data(uint8_t data) { /* Send I2C start signal */ IIC_Start(); /* Send OLED I2C slave write address, SA0=0, R/W#=0 */ Write_IIC_Byte(OLED_I2CWR_ADDR); /* send data value */ Write_IIC_Byte(0x40); Write_IIC_Byte(data); /* Send I2C stop signal */ IIC_Stop(); } /* OLED write a byte command data or command */ void OLED_WR_Byte(uint8_t data, uint8_t type) { if( OLED_CMD==type ) { IIC_Write_Command(data); } else { IIC_Write_Data(data); } } /* *+-------------------------------------------------+ *| OLED initial/control function API | *+-------------------------------------------------+ */ /* Turn OLED display onʾ */ void OLED_Display_On(void) { OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC command OLED_WR_Byte(0X14, OLED_CMD); //DCDC ON OLED_WR_Byte(0XAF, OLED_CMD); //DISPLAY ON } /* Turn OLED display off */ void OLED_Display_Off(void) { OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC command OLED_WR_Byte(0X10, OLED_CMD); //DCDC OFF OLED_WR_Byte(0XAE, OLED_CMD); //DISPLAY OFF } /* Clear OLED, it will be black */ void OLED_Clear(void) { uint8_t i, j; /* update display */ for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i, OLED_CMD); // set page address: 0~7 OLED_WR_Byte (0x00, OLED_CMD); // set display address, column address lower bytes;ַ OLED_WR_Byte (0x10, OLED_CMD); // set display address, column address higher bytes; for(j=0; j<128; j++) OLED_WR_Byte(0, OLED_DATA); } OLED_Set_Pos(0, 0); } void OLED_On(void) { uint8_t i, j; /* update display */ for(i=0; i<8; i++) { OLED_WR_Byte (0xb0+i, OLED_CMD); // set page address: 0~7 OLED_WR_Byte (0x00, OLED_CMD); // set display address, row address lower bytes;ַ OLED_WR_Byte (0x10, OLED_CMD); // set display address, row address higher bytes; for(j=0; j<128; j++) OLED_WR_Byte(1, OLED_DATA); } } void OLED_Init(void) { #ifdef CONFIG_OLED_USE_GPIO_I2C OLED_IIC_GPIO_Init(); /* initial GPIO status for I2C pins */ #endif HAL_Delay(200); OLED_WR_Byte(0xAE,OLED_CMD); // Disable OLED_WR_Byte(0x40,OLED_CMD); //---set low column address OLED_WR_Byte(0xB0,OLED_CMD); //---set high column address OLED_WR_Byte(0xC8,OLED_CMD); OLED_WR_Byte(0x81,OLED_CMD); OLED_WR_Byte(0xff,OLED_CMD); OLED_WR_Byte(0xa1,OLED_CMD); OLED_WR_Byte(0xa6,OLED_CMD); OLED_WR_Byte(0xa8,OLED_CMD); OLED_WR_Byte(0x1f,OLED_CMD); OLED_WR_Byte(0xd3,OLED_CMD); OLED_WR_Byte(0x00,OLED_CMD); OLED_WR_Byte(0xd5,OLED_CMD); OLED_WR_Byte(0xf0,OLED_CMD); OLED_WR_Byte(0xd9,OLED_CMD); OLED_WR_Byte(0x22,OLED_CMD); OLED_WR_Byte(0xda,OLED_CMD); OLED_WR_Byte(0x02,OLED_CMD); OLED_WR_Byte(0xdb,OLED_CMD); OLED_WR_Byte(0x49,OLED_CMD); OLED_WR_Byte(0x8d,OLED_CMD); OLED_WR_Byte(0x14,OLED_CMD); OLED_WR_Byte(0xaf,OLED_CMD); OLED_Clear(); } /* *+-------------------------------------------------+ *| OLED display function API | *+-------------------------------------------------+ */ /* set OLED display position */ void OLED_Set_Pos(uint8_t x, uint8_t y) { OLED_WR_Byte(0xb0+y, OLED_CMD); OLED_WR_Byte(((x&0xf0)>>4)|0x10, OLED_CMD); OLED_WR_Byte((x&0x0f), OLED_CMD); } /* show a character on OLED as $Char_Size */ void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t char_Size) { uint8_t c=0,i=0; c=chr-' '; // get offset value if( x>X_WIDTH-1 ) { x=0; y=y+2; } if(char_Size ==16) { OLED_Set_Pos(x,y); for(i=0; i<8; i++) OLED_WR_Byte(F8X16[c*16+i],OLED_DATA); OLED_Set_Pos(x,y+1); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA); } else { OLED_Set_Pos(x,y); for(i=0;i<6;i++) OLED_WR_Byte(F6x8[c][i],OLED_DATA); } } /* show a string on OLED */ void OLED_ShowString(uint8_t x, uint8_t y, char *chr, uint8_t font_size) { uint8_t j=0; while( chr[j]!='\0' ) { OLED_ShowChar(x, y, chr[j], font_size); x+=8; if(x>120) { x=0; y+=2; } j++; } } /* Show Chinese on OLED */ void OLED_ShowChinese(uint8_t (*Hzk)[32], uint8_t x, uint8_t y, uint8_t no) { uint8_t t,adder=0; OLED_Set_Pos(x, y); for(t=0;t<16;t++) { OLED_WR_Byte(Hzk[2*no][t],OLED_DATA); adder+=1; } OLED_Set_Pos(x,y+1); for(t=0;t<16;t++) { OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA); adder+=1; } } /* Show BMP images(128x64) on OLED, x: 0~127 y:0~7 */ void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *BMP) { uint32_t j=0; uint8_t x,y; if( y1%8==0 ) y = y1/8; else y = y1/8+1; for(y=y0; y