STM32点亮OLED12864I2C

Proteus原理图

image.png

其中STM32设置时钟10M

I2C通信原理

24. I2C—读写EEPROM — [野火]STM32库开发实战指南——基于野火MINI开发板 文档

I2C代码

主要包括起始位、数据、结束位

#ifndef I2C_BY_GPIO_H
#define I2C_BY_GPIO_H
#include "stm32f10x.h"

void i2c_delay(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(uint8_t cmd);
#endif
#include "i2c_by_gpio.h"

#define OLED_SCL GPIO_Pin_6
#define OLED_SDA GPIO_Pin_7

void i2c_delay(void)
{
    uint8_t i;

    /*
    下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化

    循环次数为10时,SCL频率 = 205KHz
    循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
    循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
    */
    for (i = 0; i < 10; i++);
}

void i2c_start(void)
{
    GPIO_WriteBit(GPIOB,OLED_SDA,Bit_SET);
    GPIO_WriteBit(GPIOB,OLED_SCL,Bit_SET);
    i2c_delay();
    GPIO_WriteBit(GPIOB,OLED_SDA,Bit_RESET);
    i2c_delay();
    GPIO_WriteBit(GPIOB,OLED_SCL,Bit_RESET);
    i2c_delay();
}

void i2c_stop(void)
{
    GPIO_WriteBit(GPIOB,OLED_SDA,Bit_RESET);
    GPIO_WriteBit(GPIOB,OLED_SCL,Bit_SET);
    i2c_delay();
    GPIO_WriteBit(GPIOB,OLED_SDA,Bit_SET);
    i2c_delay();
}
void i2c_write_byte(uint8_t cmd) {

    u8 i;
    for(i=0;i<8;i++)
    {
      if(cmd&0x80)
         GPIO_WriteBit(GPIOB,OLED_SDA,Bit_SET);
      else
         GPIO_WriteBit(GPIOB,OLED_SDA,Bit_RESET);
      i2c_delay();
      GPIO_WriteBit(GPIOB,OLED_SCL,Bit_SET);
      i2c_delay();
      GPIO_WriteBit(GPIOB,OLED_SCL,Bit_RESET);
      i2c_delay();
      if(i==7)
      {
          GPIO_WriteBit(GPIOB,OLED_SDA,Bit_SET);
      }
      cmd <<=1;
      i2c_delay();
    }
    // 忽略 ACK(拉高 SDA 释放)
    GPIO_WriteBit(GPIOB, OLED_SDA, Bit_SET);
    GPIO_WriteBit(GPIOB, OLED_SCL, Bit_SET);
    i2c_delay();
    GPIO_WriteBit(GPIOB, OLED_SCL, Bit_RESET);
    i2c_delay();
}

OLED配置接口

总结:
1.写命令是发送0x00 cmd
2.写数据是发送0x00 data
3.通过GPIO口实现I2C, GPIO口需要是开漏输出模式,和具体的口无关;

  1. TODO:如何通过标准库实现?
#ifndef OLED_12864_H
#define OLED_12864_H
#include "stm32f10x.h"

#define OLED_SCL GPIO_Pin_6
#define OLED_SDA GPIO_Pin_7
#define OLED_I2C_ADDR      (0x3C << 1)   // SSD1306 I2C地址(默认0x3C)
#define OLED_WIDTH         128
#define OLED_HEIGHT        64
#define OLED_PAGE_COUNT    (OLED_HEIGHT / 8)


void OLED_GPIO_I2C_Init(void);
void OLED_WriteCmd(uint8_t cmd);
void OLED_WriteData(uint8_t data);
void OLED_Init(void);
void OLED_SetPos(uint8_t x, uint8_t y);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t x, uint8_t y, char ch);
void OLED_ShowString(uint8_t x, uint8_t y, const char *str);
#endif
#include "oled_12864.h"
#include "i2c_by_gpio.h"

void OLED_GPIO_I2C_Init()
{
    // i2c1的PB6/7设置为开漏模式
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = OLED_SCL|OLED_SDA;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void OLED_WriteCmd(uint8_t cmd) {

    i2c_start();
    i2c_write_byte(OLED_I2C_ADDR); // 发送 OLED 地址 + 写
    i2c_write_byte(0x00);          // 控制字节:命令
    i2c_write_byte(cmd);           // 实际命令
    i2c_stop();
}
void OLED_WriteData(uint8_t data) {

    i2c_start();
    i2c_write_byte(OLED_I2C_ADDR); // 发送 OLED 地址 + 写
    i2c_write_byte(0x40);          // 控制字节:数据
    i2c_write_byte(data);          // 实际数据
    i2c_stop();
}

void OLED_Init()
{    
    OLED_WriteCmd(0xAE); // 关闭显示
    OLED_WriteCmd(0x20); OLED_WriteCmd(0x00); // 设置内存地址模式 0x00:水平
    OLED_WriteCmd(0xB0); // 设置页起始地址
    OLED_WriteCmd(0xC8); // COM 扫描方向 remapped
    OLED_WriteCmd(0x00); // 设置低列地址
    OLED_WriteCmd(0x10); // 设置高列地址
    OLED_WriteCmd(0x40); // 设置起始行
    OLED_WriteCmd(0x81); OLED_WriteCmd(0x7F); // 对比度
    OLED_WriteCmd(0xA1); // 设置 Segment 重映射
    OLED_WriteCmd(0xA6); // 正常显示(A7反显)
    OLED_WriteCmd(0xA8); OLED_WriteCmd(0x3F); // 多路复用率
    OLED_WriteCmd(0xA4); // 显示全部点 OFF
    OLED_WriteCmd(0xD3); OLED_WriteCmd(0x00); // 显示偏移
    OLED_WriteCmd(0xD5); OLED_WriteCmd(0x80); // 设置时钟分频
    OLED_WriteCmd(0xD9); OLED_WriteCmd(0xF1); // 预充电周期
    OLED_WriteCmd(0xDA); OLED_WriteCmd(0x12); // COM 引脚配置
    OLED_WriteCmd(0xDB); OLED_WriteCmd(0x40); // VCOMH 电压
    OLED_WriteCmd(0x8D); OLED_WriteCmd(0x14); // 使能电荷泵
    OLED_WriteCmd(0xAF); // 打开显示
}

void OLED_SetPos(uint8_t x, uint8_t y)
{
    OLED_WriteCmd(0xB0 + y);                  // 设置页地址(0~7)
    OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10);  // 高4位列地址
    OLED_WriteCmd((x & 0x0F));                // 低4位列地址
}

void OLED_Clear()
{
    for (uint8_t page = 0; page < OLED_PAGE_COUNT; page++) {
        OLED_SetPos(0, page);
        for (uint8_t col = 0; col < OLED_WIDTH; col++) {
            OLED_WriteData(0x00);
        }
    }
}

/* Standard ASCII 6x8 font */
const uint8_t ssd1306xled_font6x8[][6]=
{
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
   0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
   0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
   0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
   0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
   0x00, 0x23, 0x13, 0x08, 0x64, 0x62, // %
   0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
   0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
   0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
   0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
   0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
   0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
   0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
   0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
   0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
   0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
   0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
   0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
   0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
   0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
   0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
   0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
   0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
   0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
   0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
   0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
   0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
   0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
   0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
   0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
   0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
   0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
   0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
   0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
   0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
   0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
   0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
   0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
   0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
   0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
   0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
   0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
   0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
   0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
   0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
   0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
   0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
   0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
   0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
   0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
   0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
   0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
   0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
   0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
   0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
   0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
   0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
   0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
   0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
   0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
   0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
   0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
   0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
   0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
   0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
   0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
   0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
   0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
   0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
   0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
   0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
   0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
   0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
   0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
   0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
   0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
   0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
   0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
   0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
   0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
   0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
   0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
   0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
   0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
   0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
   0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
   0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
   0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
   0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
   0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
   0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
   0x00, 0x00, 0x08, 0x77, 0x00, 0x00, // {
   0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, // |
   0x00, 0x00, 0x77, 0x08, 0x00, 0x00, // }
   0x00, 0x10, 0x08, 0x10, 0x08, 0x00, // ~
   0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines // DEL
   0x00 /* This byte is required for italic type of font */
 };

void OLED_ShowChar(uint8_t x, uint8_t y, char ch)
{
    if (x > OLED_WIDTH - 6) {
        x = 0;
        y++;
    }
    OLED_SetPos(x, y);
    for (uint8_t i = 0; i < 6; i++) {
        OLED_WriteData(ssd1306xled_font6x8[ch - 32][i]);
    }
}

void OLED_ShowString(uint8_t x, uint8_t y, const char *str)
{
    while (*str) {
        OLED_ShowChar(x, y, *str++);
        x += 6;
        if (x > OLED_WIDTH - 6) {
            x = 0;
            y++;
        }
        if (y >= OLED_PAGE_COUNT)
            break;
    }
}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容