用c实现基于stm32f103rb的IIC通信协议0.91英寸oled屏幕显示数字
时间: 2023-06-17 16:03:24 浏览: 58
以下是基于STM32F103RB的I2C通信协议和0.91英寸OLED屏幕显示数字的C代码示例:
```c
#include "stm32f10x.h"
#include "oled.h"
/* 定义I2C通信地址 */
#define OLED_ADDR 0x78
/* 定义I2C总线速度 */
#define I2C_SPEED 100000
/* 定义OLED屏幕大小 */
#define OLED_WIDTH 128
#define OLED_HEIGHT 32
/* 定义OLED屏幕缓冲区 */
uint8_t OLED_BUF[OLED_WIDTH * OLED_HEIGHT / 8];
/* 初始化I2C */
void I2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* 使能GPIOB和I2C1时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* 配置PB6和PB7为复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* 配置I2C1为主模式和标准速度 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
I2C_Init(I2C1, &I2C_InitStructure);
/* 使能I2C1 */
I2C_Cmd(I2C1, ENABLE);
}
/* 发送数据到I2C设备 */
void I2C_SendData(uint8_t addr, uint8_t *buf, uint16_t len)
{
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
;
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
;
for (int i = 0; i < len; i++)
{
I2C_SendData(I2C1, buf[i]);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
}
I2C_GenerateSTOP(I2C1, ENABLE);
}
/* 初始化OLED屏幕 */
void OLED_Init(void)
{
/* 延时 */
for (int i = 0; i < 10000; i++)
;
/* 发送初始化命令 */
uint8_t init_cmd[] = {
0xAE, /* 关闭显示 */
0xD5, 0x80, /* 设置时钟分频因子,震荡频率 */
0xA8, 0x1F, /* 设置驱动路数(1/32)和偏移量 */
0xD3, 0x00, /* 设置显示偏移 */
0x40, /* 设置显示开始行[5:0],对于128x64的屏,第一行是0,第二行是0+64=64 */
0xA1, /* 设置段重定义,127->0,不翻转 */
0xC8, /* 设置COM扫描方向,从上到下 */
0xDA, 0x12, /* 设置COM硬件引脚配置 */
0x81, 0xCF, /* 设置对比度 */
0xD9, 0xF1, /* 设置预充电周期 */
0xDB, 0x40, /* 设置VCOMH 电压倍率 */
0xA4, /* 全局显示开启 */
0xA6, /* 设置显示方式,反相显示 */
0xAF, /* 打开显示 */
};
I2C_SendData(OLED_ADDR, init_cmd, sizeof(init_cmd));
}
/* 清空OLED屏幕缓冲区 */
void OLED_Clear(void)
{
for (int i = 0; i < sizeof(OLED_BUF); i++)
OLED_BUF[i] = 0x00;
}
/* 在OLED屏幕缓冲区指定位置显示数字 */
void OLED_ShowNumber(uint8_t x, uint8_t y, uint32_t num, uint8_t len)
{
uint8_t buf[16];
/* 将数字转换为字符串 */
sprintf((char *)buf, "%0*d", len, num);
/* 在OLED屏幕缓冲区指定位置显示字符串 */
for (int i = 0; i < len; i++)
{
for (int j = 0; j < 8; j++)
{
if (buf[i] & (1 << j))
OLED_BUF[(y / 8) * OLED_WIDTH + x + i * 6 + j] |= 1 << (y % 8);
else
OLED_BUF[(y / 8) * OLED_WIDTH + x + i * 6 + j] &= ~(1 << (y % 8));
}
}
}
/* 更新OLED屏幕 */
void OLED_Update(void)
{
/* 发送数据到OLED屏幕 */
for (uint8_t page = 0; page < OLED_HEIGHT / 8; page++)
{
uint8_t cmd[] = {
0xB0 + page, /* 设置页地址 */
0x02, /* 设置列地址低4位 */
0x10, /* 设置列地址高4位 */
};
I2C_SendData(OLED_ADDR, cmd, sizeof(cmd));
I2C_SendData(OLED_ADDR, &OLED_BUF[page * OLED_WIDTH], OLED_WIDTH);
}
}
int main(void)
{
/* 初始化I2C */
I2C_Init();
/* 初始化OLED屏幕 */
OLED_Init();
/* 清空OLED屏幕缓冲区 */
OLED_Clear();
/* 在OLED屏幕缓冲区指定位置显示数字 */
OLED_ShowNumber(0, 0, 12345, 5);
/* 更新OLED屏幕 */
OLED_Update();
while (1)
;
}
```
需要注意的是,以上代码仅供参考,具体实现需要根据所使用的OLED屏幕型号和I2C总线驱动芯片型号进行修改。同时,需要在工程中包含相应的头文件和源文件,并根据需要进行相应的配置。