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口需要是开漏输出模式,和具体的口无关;
- 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;
}
}