没有创建空白工程的读者建议先阅读这个:连接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,解除那个数组的注释(有点长,须要耐心)。