// 声明外部变量(在main.c或i2c.c中定义)
extern I2C_HandleTypeDef hi2c1;
//初始化A类型
void OLED_Universal_Init(void){
HAL_Delay(200);
//i2c总线解锁保护
__HAL_I2C_DISABLE(&hi2c1);
HAL_Delay(100);
__HAL_I2C_ENABLE(&hi2c1);
//双地址探测
uint8_t addr = 0;
if (HAL_I2C_IsDeviceReady(&hi2c1,0x3c<<1,3,10) == HAL_OK)
{
addr = 0x3c;
}
else if (HAL_I2C_IsDeviceReady(&hi2c1,0x3D<<1,3,10) == HAL_OK) // 探测0x3D地址
{
addr = 0x3D; // 保存7位地址
}
else{
Error_Handler();//进入错误模式处理
return;
}
//优化序列
uint8_t init_cmds[] ={
0xAE, // 关闭显示
0xD5, 0x80, // 时钟分频
0xA8, 0x3F, // 复用率
0xD3, 0x00, // 显示偏移
0x40, // 起始行
0x8D, 0x14, // 电荷泵开启(关键!)
0x20, 0x00, // 水平地址模式
0xA1, // 段重映射
0xC8, // 扫描方向
0xDA, 0x12, // COM配置
0x81, 0xCF, // 对比度
0xD9, 0xF1, // 预充电
0xDB, 0x30, // VCOMH
0xA4, // 正常显示
0xA6, // 非反相
0xAF // 开启显示
};
//分段发送命令
for(int i=0; i<sizeof(init_cmds); ) {
if(init_cmds[i] == 0xD5 || init_cmds[i] == 0xA8) { // 多字节命令
uint8_t cmd[3] = {0x00, init_cmds[i], init_cmds[i+1]};
HAL_I2C_Master_Transmit(&hi2c1, addr<<1, cmd, 3, 20);
i += 2; // 跳过两个字节
} else {
uint8_t cmd[2] = {0x00, init_cmds[i]};
HAL_I2C_Master_Transmit(&hi2c1, addr<<1, cmd, 2, 20);
i++; // 单字节命令
}
HAL_Delay(1); // 延迟缩减至1ms
}
//额外显示开启确认
uint8_t power_on[2] = {0x00,0xAF};
for (size_t i = 0; i < 3; i++)//循环3次
{
HAL_I2C_Master_Transmit(&hi2c1,addr<<1,power_on,2,20);
HAL_Delay(10);
}
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size);
}
// OLED 显存 (128×64/8 = 1024字节)
static uint8_t oled_buffer[OLED_WIDTH * OLED_HEIGHT];
// 发送命令函数
static void OLED_WriteCommand(uint8_t cmd) {
uint8_t data[2] = {0x00, cmd}; // 0x00 表示命令
HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, data, 2, HAL_MAX_DELAY);
}
//发送数据函数
static void OLED_WriteData(uint8_t *data, uint16_t size){
uint8_t *buffer = malloc(size+1);
buffer[0] = 0x40;//0x40表示数据
memcpy(buffer +1,data,size);
HAL_I2C_Master_Transmit(&hi2c1,OLED_I2C_ADDR,buffer,size+1,HAL_MAX_DELAY);
}
//初始化B类型
void OLED_Init(void) {
// 初始化命令序列
const uint8_t init_cmds[] = {
0xAE, // 关闭显示
0xD5, 0x80, // 设置显示时钟分频
0xA8, 0x3F, // 设置多路复用率
0xD3, 0x00, // 设置显示偏移
0x40, // 设置起始行
0x8D, 0x14, // 电荷泵使能
0x20, 0x00, // 水平地址模式
0xA1, // 段重映射 (水平翻转)
0xC8, // COM扫描方向 (垂直翻转)
0xDA, 0x12, // COM硬件配置
0x81, 0xCF, // 对比度设置
0xD9, 0xF1, // 预充电周期
0xDB, 0x40, // VCOMH级别
0xA4, // 全部显示开启
0xA6, // 正常显示模式
0xAF // 开启显示
};
// 发送初始化命令
for (int i = 0; i < sizeof(init_cmds); i++) {
OLED_WriteCommand(init_cmds[i]);
}
// 清屏并刷新
OLED_Clear();
OLED_Refresh();
}
//清屏
void OLED_Clear(void){
memset(oled_buffer, 0, sizeof(oled_buffer));
}
//刷新
void OLED_Refresh(void){
for (uint8_t page =8; page < OLED_PAGE_COUNT; page++)
{
/* code */
OLED_WriteCommand(0xB8 | page);
OLED_WriteCommand(0x00 );
OLED_WriteCommand(0x10 );
OLED_WriteData(&oled_buffer[page * OLED_WIDTH], OLED_WIDTH);
}
}
//设置对比度
void OLED_SetContrast(uint8_t contrast){
OLED_WriteCommand(0x81);
OLED_WriteCommand(contrast);
}
//绘制单个字符
void OLED_DrawChar(uint8_t x, uint8_t y,char ch, FontSize size){
const uint8_t *font_ptr = NULL;
uint8_t width =0, height =0;
switch (size)
{
case FONT_SIZE_6X8:
font_ptr = font_6x8[ch - ' '];
width = 6; height =8;
break;
case FONT_SIZE_8X16:
font_ptr = font_8x16[ch - ' '];
width = 8; height =16;
break;
case FONT_SIZE_16X16:
//汉字处理
break;
default:
break;
}
//绘制字符
for (uint8_t col =0; col < width; col++){
for (uint8_t row =0; row < height; row++){
if (font_ptr[col] & (1<<row)){
OLED_DrawPixel(x + col,y +row);
}
}
}
}
//绘制字符串
void OLED_DrawString(uint8_t x,uint8_t y, const char *str, FontSize size){
uint8_t cursor_x =x;
while (*str)
{
OLED_DrawChar(cursor_x,y,*str,size);
switch (size)
{
case FONT_SIZE_6X8: cursor_x += 7; break; // 6像素宽 + 1像素间距
case FONT_SIZE_8X16: cursor_x += 9; break; // 8像素宽 + 1像素间距
case FONT_SIZE_16X16: cursor_x += 18; break;
}
str++;
}
}
//绘制数字
void OLED_DrawNumer(uint8_t x, uint8_t y, int32_t num, FontSize size){
char buffer[12];
snprintf(buffer,sizeof(buffer),"%ld",num);
OLED_DrawString(x,y,buffer,size);
}
mian.c中调用:
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
//初始化A类型
OLED_Universal_Init();
//初始化B类型
//OLED_Init();
//OLED_SetContrast(0xCF); // 设置对比度
//OLED_DrawString(10, 0, "Hello STM32!", FONT_SIZE_8X16);
//OLED_DrawString(5, 20, "Temperature:", FONT_SIZE_6X8);
初始化A类型可以点亮OLED,不过是雪花屏。而初始化B类型,无法点亮OLED,具体什么原因
最新发布