void I2CInit (void)
{
RCC->AHB1ENR |=1<<1;
RCC->APB1ENR |=1<<21;
GPIOB->MODER = (GPIOB->MODER &~(0xF<<16))|(0xA<<16);
GPIOB->OTYPER |=(0x3<<8);
GPIOB->OSPEEDR = (GPIOB->OSPEEDR &~(0xF<<16))|(0xA<<16);
GPIOB->AFR[1]= (GPIOB->AFR[1] &~(0xFF<<0))|(0x4<<0)|(0x4<<4);
I2C1->CR1 &=~1;
I2C1->CR2 = 16;
I2C1->CCR = 80;
I2C1->TRISE = 17;
I2C1->CR1 |=1;
}
void I2C_Write(uint8_t address,uint8_t reg,uint8_t data)
{
while (I2C1->SR2 &(1<<1)){}//等待总线空闲BUSY寄存器
I2C1->CR1 |=1<<8;//设置START位,启动I2C通信
while (!(I2C1->SR1 &1)){}//等待Start Bit标志置位,表示条件已成功发出,可以输入下一个字节
I2C1->DR =(address<<1);//发送设备地址(写模式)
while (!(I2C1->SR1 &(1<<1))){}//等待ADDR标志置位,表示地址已发送,并且从设备返回了应答
(void)I2C1->SR2;//清除ADDR标志,确保后续可以继续通信
while (!(I2C1->SR1 &(1<<7))){}
I2C1->DR = reg;
while (!(I2C1->SR1 &(1<<7))){}//等待TEX置位,来发送寄存器地址
I2C1->DR = data;//将真正要写入DR寄存器的数据DATA放入其中
while (!(I2C1->SR1 &(1<<2))){}//等待传输完成,
I2C1->CR1 |=1<<9;//设置STOP位,来停止I2C通信
}
void OledInit (void)// OLED初始化命令序列(I2C地址0x3C,控制字节0x00表示写命令)
{
for (volatile int i=0;i<=100000;i++);
I2C_Write(0x3C, 0x00, 0xAE); // 关闭显示
I2C_Write(0x3C, 0x00, 0xD5); // 设置时钟分频因子
I2C_Write(0x3C, 0x00, 0x80);
I2C_Write(0x3C, 0x00, 0xA8); // 设置多路复用比
I2C_Write(0x3C, 0x00, 0x3F); // 64点阵高度(0.96寸屏)
I2C_Write(0x3C, 0x00, 0xD3); // 设置显示偏移
I2C_Write(0x3C, 0x00, 0x00);
I2C_Write(0x3C, 0x00, 0x40); // 设置显示起始行
I2C_Write(0x3C, 0x00, 0x8D); // 启用内部DC-DC升压
I2C_Write(0x3C, 0x00, 0x14);
I2C_Write(0x3C, 0x00, 0x20); // 设置内存寻址模式
I2C_Write(0x3C, 0x00, 0x00); // 水平寻址模式
I2C_Write(0x3C, 0x00, 0xA1); // 段重定向设置(左右镜像)
I2C_Write(0x3C, 0x00, 0xC8); // COM输出扫描方向(上下翻转)
I2C_Write(0x3C, 0x00, 0xDA); // 设置COM引脚配置
I2C_Write(0x3C, 0x00, 0x12);
I2C_Write(0x3C, 0x00, 0x81); // 对比度控制
I2C_Write(0x3C, 0x00, 0xCF);
I2C_Write(0x3C, 0x00, 0xD9); // 设置预充电周期
I2C_Write(0x3C, 0x00, 0xF1);
I2C_Write(0x3C, 0x00, 0xDB); // 设置VCOMH电压
I2C_Write(0x3C, 0x00, 0x40);
I2C_Write(0x3C, 0x00, 0xA4); // 禁用全亮模式
I2C_Write(0x3C, 0x00, 0xA6); // 正常显示(非反色)
I2C_Write(0x3C, 0x00, 0xAF); // 开启显示
}
void OLED_Clear(void) //清屏函数
{
for (uint8_t page = 0; page < 8; page++) // SSD1306有8页(每页8行,共64行)
{
I2C_Write(0x3C, 0x00, 0xB0 + page); // 设置当前操作的页地址
I2C_Write(0x3C, 0x00, 0x00); // 设置列地址低4位
I2C_Write(0x3C, 0x00, 0x10); // 设置列地址高4位(起始列=0)
for (uint8_t i = 0; i < 128; i++) // 每页有128列
{
I2C_Write(0x3C, 0x40, 0x00); // 写入0x00,表示该点不亮
}
}
}
const unsigned char font_6x8[][6] = // 定义6x8字体点阵数据(仅包含空格到 '~' 的部分ASCII)
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 空格 ' '
{0x00, 0x00, 0x5F, 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, 0x50, 0x30, 0x00, 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, 0x00}, // '0'
{0x00, 0x42, 0x7F, 0x40, 0x00, 0x00}, // '1'
{0x42, 0x61, 0x51, 0x49, 0x46, 0x00}, // '2'
{0x21, 0x41, 0x45, 0x4B, 0x31, 0x00}, // '3'
{0x18, 0x14, 0x12, 0x7F, 0x10, 0x00}, // '4'
{0x27, 0x45, 0x45, 0x45, 0x39, 0x00}, // '5'
{0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00}, // '6'
{0x01, 0x71, 0x09, 0x05, 0x03, 0x00}, // '7'
{0x36, 0x49, 0x49, 0x49, 0x36, 0x00}, // '8'
{0x06, 0x49, 0x49, 0x29, 0x1E, 0x00}, // '9'
{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, 0x79, 0x41, 0x3E, 0x00}, // '@'
{0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00}, // 'A'
{0x7F, 0x49, 0x49, 0x49, 0x36, 0x00}, // 'B'
{0x3E, 0x41, 0x41, 0x41, 0x22, 0x00}, // 'C'
{0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00}, // 'D'
{0x7F, 0x49, 0x49, 0x49, 0x41, 0x00}, // 'E'
{0x7F, 0x09, 0x09, 0x09, 0x01, 0x00}, // 'F'
{0x3E, 0x41, 0x49, 0x49, 0x7A, 0x00}, // 'G'
{0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00}, // 'H'
{0x00, 0x41, 0x7F, 0x41, 0x00, 0x00}, // 'I'
{0x20, 0x40, 0x41, 0x3F, 0x01, 0x00}, // 'J'
{0x7F, 0x08, 0x14, 0x22, 0x41, 0x00}, // 'K'
{0x7F, 0x40, 0x40, 0x40, 0x40, 0x00}, // 'L'
{0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00}, // 'M'
{0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00}, // 'N'
{0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00}, // 'O'
{0x7F, 0x09, 0x09, 0x09, 0x06, 0x00}, // 'P'
{0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00}, // 'Q'
{0x7F, 0x09, 0x19, 0x29, 0x46, 0x00}, // 'R'
{0x46, 0x49, 0x49, 0x49, 0x31, 0x00}, // 'S'
{0x01, 0x01, 0x7F, 0x01, 0x01, 0x00}, // 'T'
{0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00}, // 'U'
{0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00}, // 'V'
{0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00}, // 'W'
{0x63, 0x14, 0x08, 0x14, 0x63, 0x00}, // 'X'
{0x07, 0x08, 0x70, 0x08, 0x07, 0x00}, // 'Y'
{0x61, 0x51, 0x49, 0x45, 0x43, 0x00}, // 'Z'
};
void OLED_ShowChar(uint8_t x, uint8_t y, char ch)
{
if (ch >= 'A' && ch <= 'Z') // 显示单个字符(6列宽)
{
const unsigned char *p = font_6x8[ch - ' '];
for (uint8_t i = 0; i < 6; i++)
{
I2C_Write(0x3C, 0x40, p[i]);
}
}
else if (ch == ' ') // 显式处理空格:写6个0x00
{
for (uint8_t i = 0; i < 6; i++)
{
I2C_Write(0x3C, 0x40, 0x00);
}
}
else // 其他非法字符显示为 '?'
{
const unsigned char *p = font_6x8['?' - ' '];
for (uint8_t i = 0; i < 6; i++)
{
I2C_Write(0x3C, 0x40, p[i]);
}
}
}
void OLED_ShowString(uint8_t x, uint8_t y, char *str)
{
uint8_t current_x = x;
while (*str)
{
OLED_ShowChar(current_x, y, *str++);
current_x += 6; // 每个字符宽6列
}
}
头文件我在前面已经加上了目前代码还有什么问题吗?我想要通过oled显示hello world,可是为什么现在屏是黑的?
最新发布