stm32 hal模拟iic oled
时间: 2023-10-01 16:09:50 浏览: 159
基于STM32的模拟IIC驱动OLED显示屏
好的,下面是一个基于STM32 HAL库的模拟I2C驱动OLED显示屏的示例代码。在本示例中,我们使用了STM32F103C8T6开发板和SSD1306 OLED显示屏。
```c
#include "stm32f1xx_hal.h"
#define I2C_SCL_Pin GPIO_PIN_6
#define I2C_SCL_GPIO_Port GPIOB
#define I2C_SDA_Pin GPIO_PIN_7
#define I2C_SDA_GPIO_Port GPIOB
#define OLED_ADDRESS 0x78
void i2c_start(void);
void i2c_stop(void);
void i2c_send_byte(uint8_t data);
void i2c_send_cmd(uint8_t cmd);
void i2c_send_data(uint8_t data);
void oled_init(void);
void oled_clear_screen(void);
void oled_write_char(uint8_t x, uint8_t y, uint8_t c);
I2C_HandleTypeDef hi2c1;
int main(void)
{
HAL_Init();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = I2C_SCL_Pin | I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
oled_init();
oled_clear_screen();
oled_write_char(0, 0, 'H');
oled_write_char(8, 0, 'e');
oled_write_char(16, 0, 'l');
oled_write_char(24, 0, 'l');
oled_write_char(32, 0, 'o');
while (1);
}
void i2c_start(void)
{
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_RESET);
}
void i2c_stop(void)
{
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_SET);
}
void i2c_send_byte(uint8_t data)
{
for (int i = 0; i < 8; i++) {
if (data & 0x80) {
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin, GPIO_PIN_RESET);
}
HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin, GPIO_PIN_RESET);
data <<= 1;
}
}
void i2c_send_cmd(uint8_t cmd)
{
i2c_start();
i2c_send_byte(OLED_ADDRESS << 1);
i2c_send_byte(0x00);
i2c_send_byte(cmd);
i2c_stop();
}
void i2c_send_data(uint8_t data)
{
i2c_start();
i2c_send_byte(OLED_ADDRESS << 1);
i2c_send_byte(0x40);
i2c_send_byte(data);
i2c_stop();
}
void oled_init(void)
{
i2c_send_cmd(0xAE); // 关闭OLED
i2c_send_cmd(0xD5); // 设置时钟分频因子,震荡频率
i2c_send_cmd(0x80); // 设置分频因子,震荡频率
i2c_send_cmd(0xA8); // 设置驱动路数
i2c_send_cmd(0x1F); // 默认0x3F(1/64),0x1F(1/32)
i2c_send_cmd(0xD3); // 设置显示偏移
i2c_send_cmd(0x00); // 默认为0
i2c_send_cmd(0x40); // 设置显示起始行
i2c_send_cmd(0x8D); // 电荷泵设置
i2c_send_cmd(0x14); // bit2,开启/关闭
i2c_send_cmd(0x20); // 设置内存地址模式
i2c_send_cmd(0x02); // 默认0x02
i2c_send_cmd(0xA0); // 设置段重新映射0->127
i2c_send_cmd(0xC8); // 设置COM扫描方向
i2c_send_cmd(0xDA); // 设置COM硬件引脚配置
i2c_send_cmd(0x12); // bit5,Alternative
i2c_send_cmd(0x81); // 对比度设置
i2c_send_cmd(0xEF); // 默认0x7F
i2c_send_cmd(0xD9); // 设置预充电周期
i2c_send_cmd(0xF1); // 默认0x22(1.22*Vcc)
i2c_send_cmd(0xDB); // 设置VcomH
i2c_send_cmd(0x40); // 默认0x20(0.77*Vcc)
i2c_send_cmd(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
i2c_send_cmd(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示
i2c_send_cmd(0xAF); // 打开OLED
}
void oled_clear_screen(void)
{
for (int i = 0; i < 8; i++) {
i2c_send_cmd(0xb0 + i); // 设置页地址(0~7)
i2c_send_cmd(0x00); // 设置显示位置—列低地址
i2c_send_cmd(0x10); // 设置显示位置—列高地址
for (int j = 0; j < 128; j++) {
i2c_send_data(0x00); // 需要发送的数据
}
}
}
void oled_write_char(uint8_t x, uint8_t y, uint8_t c)
{
c = c - 32;
i2c_send_cmd(0xb0 + y); // 设置页地址(0~7)
i2c_send_cmd(((x & 0xf0) >> 4) | 0x10); // 设置显示位置—列高地址
i2c_send_cmd((x & 0x0f) | 0x00); // 设置显示位置—列低地址
for (int i = 0; i < 8; i++) {
i2c_send_data(Font8x8[c][i]);
}
}
```
在上面的代码中,我们使用了GPIOB的6号和7号引脚分别作为模拟I2C总线的SCL和SDA线,使用了SSD1306 OLED显示屏。在主函数中,我们先初始化OLED,然后清空屏幕并写入一些字符。
在i2c_start()函数中,我们首先将SDA和SCL线都置为高电平,然后将SDA线拉低,接着将SCL线拉低。这样就完成了I2C总线的起始信号。
在i2c_stop()函数中,我们首先将SDA和SCL线都置为低电平,然后将SDA线拉高,接着将SCL线拉高。这样就完成了I2C总线的停止信号。
在i2c_send_byte()函数中,我们先将数据的最高位发送出去,然后依次将数据的其他位发送出去,每发送一位就将SCL线拉高再拉低,这样就完成了一个字节的发送。
在i2c_send_cmd()函数中,我们先发送起始信号,然后发送OLED的地址和写入标志,接着发送寄存器地址和要写入的数据。
在i2c_send_data()函数中,我们先发送起始信号,然后发送OLED的地址和写入标志,接着发送要写入的数据。
在oled_init()函数中,我们依次发送了一些命令,初始化了OLED显示屏。
在oled_clear_screen()函数中,我们先设置页地址,然后设置列地址,接着发送需要写入的数据,这样就可以清空屏幕了。
在oled_write_char()函数中,我们先计算出需要写入的字节的列地址和页地址,然后发送命令和数据,写入字符。
阅读全文