沒有創建空白工程的讀者建議先閱讀這個:連接git
同時,本文對於工程模板的完善將針對科協的Birch開發板進行(版本V2.1)。github
上一篇文章中咱們建了一個空白工程,不過這個工程還不太好用,增添一些可以提供一些現成函數供調用的代碼進去的話,能夠省去許多造輪子的功夫,今天咱們就來作這件事。segmentfault
BSP是板級支持包的意思,這裏呢,由於相關編寫工做尚未所有結束,因此提供的BSP暫時只實現了延時函數、串口接收和板載LED的驅動,而後,硬件驅動上提供獨立按鍵、矩陣鍵盤的讀取程序和一個IIC驅動程序。數組
步驟以下:函數
步驟以下:測試
在添加了BSP之後,延時和點亮LED等操做都有現成函數能夠調用了,故main函數能夠修改以下:字體
#include "bsp.h" int main() { Bsp_Init(); while(1) { Board_LED_ON(); Bsp_Delay_ms(200); Board_LED_OFF(); Bsp_Delay_ms(200); } return 0;//程序不會運行到這裏 }
到這裏的話,工程模板已經比較完善了,由於新增的部分主要是與Birch開發板配套的,因此工程模板能夠改相似「F103_Template_Birch」這樣的名字,過程當中有問題的話請參考示例工程:連接)優化
u8g2lib是一個適合單色屏使用的開源屏幕驅動庫,能提供大量的圖形繪製函數、豐富的字庫、多種屏幕控制芯片的驅動程序,並且,移植很是簡單,在一番測試以後(其實還測試了ugui、SimpleGUI、lkdGUI等等),決定爲Birch開發板配套的工程模板移植此庫提供GUI支持。ui
步驟以下:this
這裏須要說明一下,csrc目錄下的一些像u8x8_d_器件名.c這樣的文件用於存儲屏幕控制芯片的驅動程序,只要添加本身屏幕對應的便可,其餘相似格式的可不用添加,針對咱們使用的OLED模塊,添加u8x8_d_ssd1306_128x64_noname.c便可
在不少狀況下,移植GUI至少須要向GUI組件提供硬件初始化程序和畫點的程序,不過,u8g2lib在這塊基本是傻瓜化的,畢竟,驅動已經有不少前輩作好了,移植者須要作的事情能夠說至關簡單,主要就是按照模板實現一個函數和註釋掉一些不用的部分以減小空間佔用。
u8g2的開發者爲移植者提供了一個函數模板,移植者應參照此模板實現一個函數供u8g2lib調用以實現延時等等,模板以下:
uint8_t u8x8_gpio_and_delay_template(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { switch(msg) { case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8 break; // can be used to setup pins case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second break; case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds break; case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds break; case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second break; case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us case U8X8_MSG_GPIO_D0: // D0 or SPI clock pin: Output level in arg_int //case U8X8_MSG_GPIO_SPI_CLOCK: break; case U8X8_MSG_GPIO_D1: // D1 or SPI data pin: Output level in arg_int //case U8X8_MSG_GPIO_SPI_DATA: break; case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int break; case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int break; case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int break; case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int break; case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int break; case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int break; case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int break; case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int break; case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int break; case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int break; case U8X8_MSG_GPIO_CS1: // CS1 (chip select) pin: Output level in arg_int break; case U8X8_MSG_GPIO_CS2: // CS2 (chip select) pin: Output level in arg_int break; case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin break; // arg_int=1: Input dir with pullup high for I2C clock pin case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin break; // arg_int=1: Input dir with pullup high for I2C data pin case 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 value break; } return 1; }
諾,看看代碼就知道,傳入一個消息,而後由這個函數對消息進行判斷,並實現相應操做。
這裏咱們的實現以下:
uint8_t STM32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { 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 seconds for (uint16_t n = 0; n < 320; n++) { __NOP(); } break; case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second Bsp_Delay_ms(1); break; case U8X8_MSG_DELAY_I2C: __NOP();__NOP();__NOP(); break; case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin if(arg_int == 1) // arg_int=1: Input dir with pullup high for I2C clock pin GPIO_WriteBit(GPIOB,GPIO_Pin_8,1); else if(arg_int == 0) GPIO_WriteBit(GPIOB,GPIO_Pin_8,0); break; case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin if(arg_int == 1) // arg_int=1: Input dir with pullup high for I2C data pin GPIO_WriteBit(GPIOB,GPIO_Pin_9,1); else if(arg_int == 0) GPIO_WriteBit(GPIOB,GPIO_Pin_9,0); break; case 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 value break; } return 1; }
在某一特定應用下,並非全部case都是必須的,上面的函數通過了必定的精簡。
另外,注意所使用的引腳須要預先初始化。
而後,初始化的套路差很少是下面這樣:
// a structure which will contain all the data for one display u8g2_t u8g2; // init u8g2 structure u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, STM32_gpio_and_delay); // send init sequence to the display, display is in sleep mode after this u8g2_InitDisplay(&u8g2); //wake up display u8g2_SetPowerSave(&u8g2, 0);
就是,初始化一個結構體用於各項參數的存儲和幀緩衝,而後初始化函數初始化該結構體,以後經過咱們以前編寫的函數進行初始化操做,默認是關閉的,因此最後須要打開顯示,固然,到這裏屏幕上尚未內容,具體的顯示內容咱們以後來編寫。
編譯工程,你會發現報了一大堆的錯,其中第一條內容以下:
.\Objects\F103_Template.axf: Error: L6406E: No space in execution regions with .ANY selector matching u8g2_fonts.o(.constdata).
OK,看No Space倆字大概就能知道是空間不夠用了,這個提示是由於u8g2_fonts.c這個文件夾利用用了一大堆超大的數組來存放字體數據,雖然你大部分都沒使用,可是編譯器仍是給它們分配了空間,而後C8T6可憐的64KB的ROM就不夠用了,其實開O3優化的話能夠解決這個問題,可是另外一個文件裏定義的一堆所有變量仍是須要手動處理,因此推薦按下面的步驟操做:
下一步,依據報錯提示,取消掉兩個上一步兩個文件中部份內容的註釋。
.\Objects\F103_Template.axf: Error: L6218E: Undefined symbol u8g2_m_16_8_f (referred from u8g2_d_setup.o).
好比看到這一條的話,在u8g2_d_memory.c裏面搜一下「u8g2_m_16_8_f」,解除相關部分的註釋,以下圖:
.\Objects\F103_Template.axf: Error: L6218E: Undefined symbol u8g2_font_inb24_mf (referred from gui_port.o).
而後,這樣的報錯的話,去u8g2_fonts.c裏面搜u8g2_font_inb24_mf,解除那個數組的註釋(有點長,須要耐心)。