156 lines
4.8 KiB
C
156 lines
4.8 KiB
C
/**
|
||
* @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]);
|
||
}
|
||
}
|
||
}
|