/** * @file ssd1306_oled.c * @author xushenghao * @brief SSD1306 OLED display driver * @version 0.1 * @note PB13-SCK PB12-SDA */ #include "ssd1306_oled.h" #include "ssd1306_oled.h" static i2c_t *ssd1306_oled; static uint8_t buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8]; // 定义屏幕缓冲区 static void ssd1306_write_command(uint8_t command) { uint8_t data[2]; data[0] = SSD1306_CMD_SET_LOW_COLUMN; // Co = 0, D/C# = 0 data[1] = command; ssd1306_oled->interface.start(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, SSD1306_I2C_ADDRESS); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, data[0]); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, data[1]); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.stop(ssd1306_oled); } static void ssd1306_write_data(uint8_t data) { uint8_t buffer[2]; buffer[0] = SSD1306_CMD_SET_START_LINE; // Co = 0, D/C# = 1 buffer[1] = data; ssd1306_oled->interface.start(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, SSD1306_I2C_ADDRESS); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, buffer[0]); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.write_byte(ssd1306_oled, buffer[1]); ssd1306_oled->interface.wait_ack(ssd1306_oled); ssd1306_oled->interface.stop(ssd1306_oled); } static void ssd1306_test(void) { } void ssd1306_init(void) { i2c_gpio_group_t gpios; gpios.scl = gpio_create(SSD1306_SCK_PORT, SSD1306_SCK_PIN); gpios.sda = gpio_create(SSD1306_SDA_PORT, SSD1306_SDA_PIN); ssd1306_oled = i2c_create(gpios, 0); ssd1306_write_command(SSD1306_CMD_DISPLAY_OFF); ssd1306_write_command(SSD1306_CMD_SET_DISPLAY_CLOCK_DIV); ssd1306_write_command(0x80); ssd1306_write_command(SSD1306_CMD_SET_MULTIPLEX); ssd1306_write_command(SSD1306_HEIGHT - 1); ssd1306_write_command(SSD1306_CMD_SET_DISPLAY_OFFSET); ssd1306_write_command(0x00); ssd1306_write_command(SSD1306_CMD_SET_START_LINE | 0x00); ssd1306_write_command(SSD1306_CMD_CHARGE_PUMP); ssd1306_write_command(0x14); ssd1306_write_command(SSD1306_CMD_MEMORY_MODE); ssd1306_write_command(0x00); ssd1306_write_command(SSD1306_CMD_SEG_REMAP | 0x01); ssd1306_write_command(SSD1306_CMD_COM_SCAN_DEC); ssd1306_write_command(SSD1306_CMD_SET_COM_PINS); ssd1306_write_command(0x12); ssd1306_write_command(SSD1306_CMD_SET_CONTRAST); ssd1306_write_command(0xCF); ssd1306_write_command(SSD1306_CMD_SET_PRECHARGE); ssd1306_write_command(0xF1); ssd1306_write_command(SSD1306_CMD_SET_VCOM_DETECT); ssd1306_write_command(0x40); ssd1306_write_command(SSD1306_CMD_DISPLAY_ALL_ON_RESUME); ssd1306_write_command(SSD1306_CMD_NORMAL_DISPLAY); ssd1306_write_command(SSD1306_CMD_DISPLAY_ON); ssd1306_test(); } void ssd1306_display_on(void) { ssd1306_write_command(SSD1306_CMD_DISPLAY_ON); } void ssd1306_display_off(void) { ssd1306_write_command(SSD1306_CMD_DISPLAY_OFF); } void ssd1306_clear(void) { for (uint16_t i = 0; i < SSD1306_WIDTH * SSD1306_HEIGHT / 8; i++) { ssd1306_write_data(0x00); } } /** * @brief 在SSD1306屏幕上绘制一个像素点 * * 在SSD1306 OLED显示屏上绘制一个像素点,如果指定位置超出屏幕范围,则不执行任何操作。 * * @param x 像素点的x坐标 * @param y 像素点的y坐标 * @param color 像素点的颜色,非零值表示绘制像素点,零值表示清除像素点 */ void ssd1306_draw_pixel(uint8_t x, uint8_t y, uint8_t color) { if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) { return; } if (color) { buffer[x + (y / 8) * SSD1306_WIDTH] |= (1 << (y % 8)); } else { buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8)); } } /** * @brief 更新SSD1306 OLED显示屏的内容 * * 此函数将缓冲区中的数据写入SSD1306 OLED显示屏,从而更新显示内容。 * * 首先,通过发送命令设置列地址和页地址,然后将缓冲区中的数据逐行写入显示屏。 * * @note 在调用此函数之前,需要将需要显示的数据写入缓冲区。 */ void ssd1306_update_screen(void) { for (uint8_t i = 0; i < SSD1306_HEIGHT / 8; i++) { ssd1306_write_command(SSD1306_CMD_COLUMN_ADDR); ssd1306_write_command(0); ssd1306_write_command(SSD1306_WIDTH - 1); ssd1306_write_command(SSD1306_CMD_PAGE_ADDR); ssd1306_write_command(i); ssd1306_write_command(i); for (uint8_t j = 0; j < SSD1306_WIDTH; j++) { ssd1306_write_data(buffer[j + i * SSD1306_WIDTH]); } } }