文章目錄
- 一、簡介
- (1)U8g2
- (2)U8x8
- 二、配置要求
- 三、移植步驟
- (1)文件準備和添加
- (2)實現回調接口(I2C的讀寫函數)
- ①軟件I2C
- ②硬件I2C
- (3)功能裁剪
- ① u8g2_d_setup.c
- ② u8g2_d_memory.c
- ③ 關于字庫
在低端芯片上使用U8G2
一、簡介
U8g2:單色顯示庫,版本2
U8g2是一個用于嵌入式設備的單色圖形庫。U8g2支持單色oled和lcd,其中包括以下控制器:Ssd1305、ssd1306、ssd1309、ssd1312、ssd1316、ssd1318、ssd1320、ssd1322、ssd1325、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1106、sh1107、sh1108、ssd1607、hx1230、uc1601、uc1604、uc1608、pcd8544、pcf8812、hx1230、uc1601、uc1611、uc1617、uc1638、uc1701、st7511、st7528、st7565、st7567、st7586、st7588、st75160、st75256、st75320、nt7534、st7920、ist3020、ist3088、ist7920、ld7032、ks0108、ks0713、hd44102、t7932、sed1520、sbn1661、il3820、max7219、gp1287、gp1247、GU800(查看完整列表)。
Arduino庫U8g2可以從Arduino IDE的庫管理器中安裝。U8g2還包括U8x8庫:
(1)U8g2
-
包括所有圖形程序(線/框/圓繪制)。
-
支持多種字體。(幾乎)對字體高度沒有限制。
-
在微控制器中需要一些內存來呈現顯示。
(2)U8x8
-
僅文本輸出(字符)設備。
-
只允許適合8x8像素網格的字體。
-
直接寫入顯示。在微控制器中不需要緩沖區。
二、配置要求
最少要求:
ROM:122+354+12+56+304+723+312+72+134+280+12+28+502+412+288+101+192+10+72=3986byte
RAM:0x80+0x01=0x81=129byte
RAM范圍[128,1024],越大刷新越快。
Demo工程整體大小:NOS+IIC+GPIO+U8G2
- Total RO Size (Code + RO Data) 9472 ( 9.25kB)
- Total RW Size (RW Data + ZI Data) 880 ( 0.86kB)
- Total ROM Size (Code + RO Data + RW Data) 9492 ( 9.27kB)
三、移植步驟
(1)文件準備和添加
- 下載文件(Gitee)
- 解壓csrc到工程根目錄
- keil添加目錄文件
注意:帶_d_是用戶自定義文件,可以移動到工程中修改。
- keil添加頭文件 [csrc的目錄]
- 添加驅動文件
u8g2里面支持多種驅動芯片,以u8x8_d_xxx.c命名的就是驅動文件,本文使用的是0.96吋oled,芯片是ssd1306,因此只需將u8x8_d_ssd1312_128x64_noname.c這個驅動文件添加到工程中:
(2)實現回調接口(I2C的讀寫函數)
void u8g2_Setup_ssd1306_i2c_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
byte_cb:是通信相關的函數,比如i2c寫數據,
gpio_and_delay_cb:是延時相關的函數。
①軟件I2C
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, gpio_and_delay); // init u8g2 structure
- u8x8_byte_sw_i2c官方已經實現 <–u8x8_byte.c
- 我們需要實現gpio_and_delay函數
uint8_t gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {//printf("%s:msg = %d,arg_int = %d\r\n",__FUNCTION__,msg,arg_int);switch(msg) {case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds__NOP();break;case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro secondsfor (uint16_t n = 0; n < 320; n++) {__NOP();} break;case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli secondHAL_Delay(1);break;case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz//delay 5usdelay_us(5); // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25uscase U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pinif(arg_int == 1) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);} else if(arg_int == 0) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); } break; // arg_int=1: Input dir with pullup high for I2C clock pincase U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin// printf("U8X8_MSG_GPIO_I2C_DATA:%d\r\n",arg_int);if(arg_int == 1) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);} else if(arg_int == 0) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); } break; // arg_int=1: Input dir with pullup high for I2C data pincase U8X8_MSG_GPIO_MENU_SELECT:u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);break;case U8X8_MSG_GPIO_MENU_NEXT:u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);break;case U8X8_MSG_GPIO_MENU_PREV:u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);break;case U8X8_MSG_GPIO_MENU_HOME:u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);break;default:u8x8_SetGPIOResult(u8x8, 1); // default return valuebreak;}return 1;
}
②硬件I2C
跟軟件實現方式類似
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, gpio_and_delay); // init u8g2 structure
#define I2C_SPEED_RATE 100 //uint khz
I2C_HandleTypeDef i2c_test = {0};
FlagStatus i2c_int = RESET;main:
{__HAL_RCC_I2C_CLK_ENABLE();gpioi2c.Pin = GPIO_PIN_5;gpioi2c.Mode = GPIO_MODE_AF; // GPIO端口復用功能 gpioi2c.Alternate = GPIO_AF4_I2C_SDA;gpioi2c.OpenDrain = GPIO_OPENDRAIN; // 開漏輸出gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE; // 禁止輸入去抖動gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH; // 電壓轉換速率gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH; // 驅動強度gpioi2c.Pull = GPIO_PULLUP; // 上拉HAL_GPIO_Init(GPIOB, &gpioi2c);gpioi2c.Pin = GPIO_PIN_4;gpioi2c.Mode = GPIO_MODE_AF;gpioi2c.Alternate = GPIO_AF4_I2C_SCL;gpioi2c.OpenDrain = GPIO_OPENDRAIN; gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH;gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH;gpioi2c.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &gpioi2c);i2c_test.Instance = I2C;i2c_test.Init.master = I2C_MASTER_MODE_ENABLE; // 主機模式使能i2c_test.Init.slave = I2C_SLAVE_MODE_DISABLE; // 從機模式禁止i2c_test.Mode = HAL_I2C_MODE_MASTER; // 主機模式i2c_test.Init.broadack = I2C_BROAD_ACK_DISABLE; // 廣播地址應答禁止i2c_test.Init.speedclock = I2C_SPEED_RATE; // I2C傳輸速率 i2c_test.State = HAL_I2C_STATE_RESET; //HAL_I2C_Init(&i2c_test);
}uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {static uint8_t buffer[32]; /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */static uint8_t buf_idx;uint8_t *data;switch(msg){case U8X8_MSG_BYTE_SEND:data = (uint8_t *)arg_ptr; while( arg_int > 0 ){buffer[buf_idx++] = *data;data++;arg_int--;} break;case U8X8_MSG_BYTE_INIT:/* add your custom code to init i2c subsystem */break;case U8X8_MSG_BYTE_START_TRANSFER:buf_idx = 0;break;case U8X8_MSG_BYTE_END_TRANSFER:HAL_I2C_Master_Transmit(&i2c_test, buffer[0], &buffer[1], buf_idx - 1);break;default:return 0;}return 1;
}uint8_t gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{switch(msg){case U8X8_MSG_GPIO_AND_DELAY_INIT:break;case U8X8_MSG_DELAY_MILLI:HAL_Delay(arg_int);break;case U8X8_MSG_GPIO_I2C_CLOCK: break; case U8X8_MSG_GPIO_I2C_DATA: break;default: return 0;}return 1; // command processed successfully.
}
到此,移植完畢,但是編譯失敗,空間不足!
(3)功能裁剪
① u8g2_d_setup.c
- 注釋全部函數
- 找到u8g2_Setup_ssd1306_i2c_128x64_noname_1函數,解除注釋。
注:用緩存128舉例。有條件的可以使用256,1024.
u8g2_Setup_ssd1306_i2c_128x64_noname_1() --緩存128byte
u8g2_Setup_ssd1306_i2c_128x64_noname_2() --緩存256byte
u8g2_Setup_ssd1306_i2c_128x64_noname_f() --緩存1024byte
② u8g2_d_memory.c
- 注釋全部函數
- 找到u8g2_m_16_8_1函數,解除注釋。
注:用緩存128舉例。有條件的可以使用256,1024.
u8g2_Setup_ssd1306_i2c_128x64_noname_1() --緩存128byte
u8g2_Setup_ssd1306_i2c_128x64_noname_2() --緩存256byte
u8g2_Setup_ssd1306_i2c_128x64_noname_f() --緩存1024byte
u8g2_Setup_ssd1306_128x64_noname_1、
u8g2_Setup_ssd1306_128x64_noname_2、
u8g2_Setup_ssd1306_128x64_noname_f,
這些都是spi接口的;
u8g2_Setup_ssd1306_i2c_128x64_noname_1、
u8g2_Setup_ssd1306_i2c_128x64_noname_2、
u8g2_Setup_ssd1306_i2c_128x64_noname_f,
這些都是i2c接口的;
后綴1、2、f代表緩沖區大小的不同:
1代表128字節,
2代表256字節,
f代表1024字節;
根據單片機空間的大小選擇合適的接口,緩沖區小的,刷新lcd/oled的時候就比較耗時,反之。
③ 關于字庫
“u8g2_fonts.c”文件中定義了各種字庫,這些字庫比較占用空間,根據使用情況屏蔽掉沒有使用的。
demo工程gitee