STM32F401RET6之u8g2库的oled


跟I2C和OLED杠上了,之前的两篇笔记也是I2C和oled

硬件配置

  • 这个就不多说了,和之前的一样,一个主控,一个oled

软件编程

oled有很多库,,这次使用u8g2库来驱动oled,像这样类似的库有很多,比如Adafruit_SSD1306,Adafruit_SH1106,SSD1306Ascii,OLED_I2C等等

模拟I2C移植说明

  • GPIO模拟I2C移植说明
    最好再下载一份stm32对应是例程:地址,例程用的是SPI,只需要看main函数执行过程就可以了
  1. 包含头文件,创建实例对象,,进行宏定义
/*把下载的库文件中csrc放到U8g2文件夹下,工程中也要进行包含*/
#include "U8g2/u8g2.h"	
u8g2_t u8g2;
/* 定义I2C引脚 */
#define OLED_SCL_Port GPIOB
#define OLED_SDA_Port GPIOB
#define OLED_SCL_Pin GPIO_PIN_6
#define OLED_SDA_Pin GPIO_PIN_7
  1. 初始化oled的时候要调用接口函数,还要配置GPIO端口
    例如:在初始化OLED的时候要调用u8x8_Setup(&u8x8, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_i2c, u8x8_byte_sw_i2c, psoc_gpio_and_delay_cb);
    其中的u8x8_Setup是u8g2的接口,u8x8是创建的一个oled实例对象,u8x8_d_ssd1306_128x64_noname是所使用的驱动函数,这个在官方文件里的csrc中有,需要哪个就用哪个,u8x8_byte_sw_i2c这个是u8g2中u8x8_byte中的函数,psoc_gpio_and_delay_cb这个是GPIO和延时的回调函数。
void OLED_INIT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //GPIO引脚初始化设置
    GPIO_InitStructure.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, \
                        u8g2_gpio_and_delay_stm32);
    u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
    u8g2_SetPowerSave(&u8g2, 0); // wake up display

/******************** 显示一个对角线 ********************/
    u8g2_ClearBuffer(&u8g2);
    u8g2_FirstPage(&u8g2);
    do
    {
        u8g2_DrawLine(&u8g2, 0,0, 128, 64);
        
    } while( u8g2_NextPage(&u8g2) );
    u8g2_SendBuffer(&u8g2);
    u8g2_ClearBuffer(&u8g2);
  1. 需要自己编写一个GPIO口配置和延时的回调函数
/* 延时和gpio定义 */
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, \
                    U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, \
                    U8X8_UNUSED void *arg_ptr)
{
	switch(msg){
		//Initialize SPI peripheral
		case U8X8_MSG_GPIO_AND_DELAY_INIT:
        {
            /* HAL initialization contains all what we need so we can skip this part. */
        }
		break;
		//Function which implements a delay, arg_int contains the amount of ms
		case U8X8_MSG_DELAY_MILLI:
            __NOP();
		break;
		//Function which delays 10us
		case U8X8_MSG_DELAY_10MICRO:
		for (uint16_t n = 0; n < 320; n++)
		{
			__NOP();
		}
		break;
		//Function which delays 100ns
		case U8X8_MSG_DELAY_100NANO:
            __NOP();
		break;
        case U8X8_MSG_DELAY_I2C:// arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        for (uint16_t n = 0; n < 100; n++)
		{
			__NOP();
		}
        break;// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
        case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
            arg_int ? HAL_GPIO_WritePin(OLED_SCL_Port,OLED_SCL_Pin,GPIO_PIN_SET)\
            : HAL_GPIO_WritePin(OLED_SCL_Port,OLED_SCL_Pin,GPIO_PIN_RESET);
        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
            arg_int ? HAL_GPIO_WritePin(OLED_SDA_Port,OLED_SDA_Pin,GPIO_PIN_SET)\
            : HAL_GPIO_WritePin(OLED_SDA_Port,OLED_SDA_Pin,GPIO_PIN_RESET);
		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; //A message was received which is not implemented, return 0 to indicate an error
	}
	return 1; // command processed successfully.
}
  1. 显示LOGO
/* 显示logo */
void draw(u8g2_t *u8g2)
{
    u8g2_SetFontMode(u8g2, 1);	// Transparent
    u8g2_SetFontDirection(u8g2, 0);
    u8g2_SetFont(u8g2, u8g2_font_inb21_mf);
    u8g2_DrawStr(u8g2, 0, 30, "U");
    
    u8g2_SetFontDirection(u8g2, 1);
    u8g2_SetFont(u8g2, u8g2_font_crox3h_tr);
    u8g2_DrawStr(u8g2, 21,8,"9");
        
    u8g2_SetFontDirection(u8g2, 0);
    u8g2_SetFont(u8g2, u8g2_font_inb21_mf);
    u8g2_DrawStr(u8g2, 51,30,"g");
    u8g2_DrawStr(u8g2, 67,30,"\xb2");

    u8g2_SetFont(u8g2, u8g2_font_6x10_tf);
    u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
}
  1. 剩下的就简单多了,只需要在主函数初始化oled之后,就随便调用u8g2库中的所有绘画函数
u8g2_FirstPage(&u8g2);
do
{
    draw(&u8g2);
} while( u8g2_NextPage(&u8g2) );

硬件I2C移植

硬件的移植不需要配置GPIO,但是需要配置I2C,这里用的是I2C1
0. 包含头文件,创建实例

#include "U8g2/u8g2.h"
u8g2_t u8g2;
  1. GPIO和延时函数
    感觉这个可以不写任何内容,但是不能没有
/* 延时和gpio定义 */
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, \
                    U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, \
                    U8X8_UNUSED void *arg_ptr)
{
	switch(msg){
		//Initialize SPI peripheral
		case U8X8_MSG_GPIO_AND_DELAY_INIT:
        {
            /* HAL initialization contains all what we need so we can skip this part. */
        }
		break;
		//Function which implements a delay, arg_int contains the amount of ms
		case U8X8_MSG_DELAY_MILLI:
            __NOP();
		break;
		//Function which delays 10us
		case U8X8_MSG_DELAY_10MICRO:
		for (uint16_t n = 0; n < 320; n++)
		{
			__NOP();
		}
		break;
		//Function which delays 100ns
		case U8X8_MSG_DELAY_100NANO:
            __NOP();
		break;
        case U8X8_MSG_DELAY_I2C:// arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        for (uint16_t n = 0; n < 100; n++)
		{
			__NOP();
		}
        break;// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
		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; //A message was received which is not implemented, return 0 to indicate an error
	}

	return 1; // command processed successfully.
  1. 硬件I2C写入操作
uint8_t u8x8_byte_i2c_hw(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_SET_DC:
      /* ignored for i2c */
    break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        buf_idx = 0;
    break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        HAL_I2C_Master_Transmit(&hi2c1,u8x8_GetI2CAddress(u8x8), buffer, \
                        buf_idx, 10);/*transmit function of HAL library*/
    break;
    default:
    return 0;
  }
  return 1;
}
  1. 画图函数
/* 显示logo */
void draw(u8g2_t *u8g2)
{
    u8g2_SetFontMode(u8g2, 1);	// Transparent
    u8g2_SetFontDirection(u8g2, 0);
    u8g2_SetFont(u8g2, u8g2_font_inb21_mf);
    u8g2_DrawStr(u8g2, 0, 30, "U");
    
    u8g2_SetFontDirection(u8g2, 1);
    u8g2_SetFont(u8g2, u8g2_font_crox3h_tr);
    u8g2_DrawStr(u8g2, 21,8,"9");
        
    u8g2_SetFontDirection(u8g2, 0);
    u8g2_SetFont(u8g2, u8g2_font_inb21_mf);
    u8g2_DrawStr(u8g2, 51,30,"g");
    u8g2_DrawStr(u8g2, 67,30,"\xb2");
  
    u8g2_SetFont(u8g2, u8g2_font_6x10_tf);
    u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
}
  1. 主函数
int main(void)
{
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_I2C1_Init();
	OLED_INIT();
	while (1)
	 {
		u8g2_FirstPage(&u8g2);
		do
		{
		    draw(&u8g2);
		} while( u8g2_NextPage(&u8g2) );
	 }
}

比较

  • 模拟的延时比硬件的长,并且可控,通过延时的回调函数中的U8X8_MSG_DELAY_I2C进行配置
  • 现在u8g2库中的所有函数我都包含进来了,只是去除了一些字库,文件也挺大的,以后想办法精简一下

结语

oled使用库文件可以减少很多步骤,对于初学者有很好的帮助,但是缺少了用寄存器读取的快乐,但是这种快乐也是因人而异吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值