一、I2C配置函数
1. HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
**功能:**I2C主设备向从设备发送数据
参数说明:
hi2c:I2C句柄指针,包含I2C外设配置信息
DevAddress:从设备地址(7位地址,库函数内部会自动左移1位)
pData:指向要发送数据缓冲区的指针
Size:要发送数据的字节数
Timeout:传输超时时间(毫秒)
返回值:
HAL_OK:传输成功
HAL_ERROR:传输错误
HAL_BUSY:总线忙
HAL_TIMEOUT:传输超时
2. HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
**功能:**I2C主设备从从设备接收数据
参数说明:
hi2c:I2C句柄指针
DevAddress:从设备地址(7位地址)
pData:指向接收数据缓冲区的指针
Size:要接收数据的字节数
Timeout:接收超时时间(毫秒)
二、示例实验
1. 实验现象
系统启动后,OLED屏幕会先全屏点亮显示白色(用于硬件测试),然后立即清屏变为全黑,最终屏幕保持黑色显示状态。整个过程中通过I2C总线成功与SSD1306 OLED驱动芯片通信,完成了显示屏的初始化和基本显示控制。
2. 示例代码
I2C初始化
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1; // 使用I2C1外设
hi2c1.Init.ClockSpeed = 400000; // I2C时钟频率400kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 时钟占空比配置
hi2c1.Init.OwnAddress1 = 0; // 主机模式地址设为0
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址模式
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址
hi2c1.Init.OwnAddress2 = 0; // 第二地址设为0
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用通用呼叫
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 允许时钟拉伸
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler(); // 初始化失败进入错误处理
}
}
OLED初始化
/**
* @brief 检测I2C设备是否存在
*/
ErrorStatus OLED_CheckDevice(uint8_t slave_addr)
{
uint8_t dummy = 0;
// 发送0字节数据检测设备响应
if (HAL_I2C_Master_Transmit(&hi2c1, (slave_addr << 1), &dummy, 0, IIC_TIMEOUT) == HAL_OK)
{
return SUCCESS;
}
return ERROR;
}
/**
* @brief 向OLED写入单字节数据(命令或数据)
*/
ErrorStatus OLED_WriteByte(uint8_t cmd, uint8_t byte)
{
uint8_t buf[2] = {cmd, byte}; // 数据包:控制字节+数据字节
if (HAL_I2C_Master_Transmit(&hi2c1, OLED_SLAVER_ADDR << 1, buf, 2, IIC_TIMEOUT) == HAL_OK)
return SUCCESS;
printf("OLED_WriteByte 写入失败:cmd=0x%02X byte=0x%02X\r\n", cmd, byte);
return ERROR;
}
/**
* @brief 向OLED写入多字节数据
*/
ErrorStatus OLED_WriteBuffer(uint8_t cmd, uint8_t *buffer, uint32_t num)
{
uint8_t buf[256];
if(num > sizeof(buf) - 1)
{
printf("OLED_WriteBuffer 数据过长(%u)\r\n", num);
return ERROR;
}
buf[0] = cmd; // 第一个字节为控制字节
memcpy(&buf[1], buffer, num); // 复制数据到缓冲区
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, OLED_SLAVER_ADDR << 1, buf, num + 1, IIC_TIMEOUT);
if (status == HAL_OK)
return SUCCESS;
printf("OLED_WriteBuffer 写入失败:cmd=0x%02X len=%u\r\n", cmd, num);
return ERROR;
}
/**
* @brief 设置OLED显示位置
*/
void OLED_SetPos(uint8_t y, uint8_t x)
{
uint8_t pos_buf[3] = {
0xB0 + y, // 页地址命令
((x & 0xF0) >> 4) | 0x10, // 列地址高4位
(x & 0x0F) // 列地址低4位
};
OLED_WriteBuffer(OLED_WR_CMD, pos_buf, sizeof(pos_buf));
}
/**
* @brief 填充整个屏幕
*/
void OLED_Fill(uint8_t fill_data)
{
uint8_t data_buffer_temp[128] = {0};
memset(data_buffer_temp, fill_data, 128);
// 遍历8页,每页128列
for(uint8_t m = 0; m < 8; m++)
{
OLED_SetPos(m, 0);
OLED_WriteBuffer(OLED_WR_DATA, data_buffer_temp, OLED_ARRAY_SIZE(data_buffer_temp));
}
}
/**
* @brief 清屏函数
*/
void OLED_CLS(void)
{
OLED_Fill(0x00); // 填充0x00清屏
}
/**
* @brief 全屏点亮函数
*/
void OLED_FillFull(void)
{
OLED_Fill(0xFF); // 填充0xFF全亮
}
/**
* @brief OLED初始化
*/
void OLED_Init(void)
{
HAL_Delay(100); // 电源稳定延时
// 等待设备响应
while (OLED_CheckDevice(OLED_SLAVER_ADDR) != SUCCESS);
// OLED初始化命令序列
OLED_WriteByte(OLED_WR_CMD, 0xAE); // 关闭显示
OLED_WriteByte(OLED_WR_CMD, 0x20); // 设置内存寻址模式
OLED_WriteByte(OLED_WR_CMD, 0x02); // 页面寻址模式
OLED_WriteByte(OLED_WR_CMD, 0xB0); // 设置页起始地址
OLED_WriteByte(OLED_WR_CMD, 0xA1); // 设置列扫描方向正常
OLED_WriteByte(OLED_WR_CMD, 0xC8); // 设置行扫描方向正常
OLED_WriteByte(OLED_WR_CMD, 0x00); // 设置列地址低位
OLED_WriteByte(OLED_WR_CMD, 0x10); // 设置列地址高位
OLED_WriteByte(OLED_WR_CMD, 0x40); // 设置起始行地址
OLED_WriteByte(OLED_WR_CMD, 0x81); // 设置对比度控制
OLED_WriteByte(OLED_WR_CMD, 0xFF); // 对比度最大值
OLED_WriteByte(OLED_WR_CMD, 0xA1); // 设置列映射
OLED_WriteByte(OLED_WR_CMD, 0xA6); // 设置正常显示
OLED_WriteByte(OLED_WR_CMD, 0xA8); // 设置多路复用率
OLED_WriteByte(OLED_WR_CMD, 0x3F); // 1/64占空比
OLED_WriteByte(OLED_WR_CMD, 0xA4); // 整个显示开启
OLED_WriteByte(OLED_WR_CMD, 0xD3); // 设置显示偏移
OLED_WriteByte(OLED_WR_CMD, 0x00); // 无偏移
OLED_WriteByte(OLED_WR_CMD, 0xD5); // 设置显示时钟分频
OLED_WriteByte(OLED_WR_CMD, 0xF0); // 设置振荡器频率
OLED_WriteByte(OLED_WR_CMD, 0xD9); // 设置预充电周期
OLED_WriteByte(OLED_WR_CMD, 0x22); //
OLED_WriteByte(OLED_WR_CMD, 0xDA); // 设置COM引脚硬件配置
OLED_WriteByte(OLED_WR_CMD, 0x12); //
OLED_WriteByte(OLED_WR_CMD, 0xDB); // 设置VCOMH电平
OLED_WriteByte(OLED_WR_CMD, 0x20); //
OLED_WriteByte(OLED_WR_CMD, 0x8D); // 设置电荷泵
OLED_WriteByte(OLED_WR_CMD, 0x14); // 使能电荷泵
OLED_WriteByte(OLED_WR_CMD, 0xAF); // 开启显示
OLED_CLS(); // 清屏
OLED_FillFull(); // 全屏点亮测试
}
主函数
int main(void)
{
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟为72MHz
MX_USART1_UART_Init(); // 初始化串口用于调试信息输出
DWT_Init(); // 启动DWT计数器用于精确延时
MX_I2C1_Init(); // 初始化I2C1总线
OLED_Init(); // 初始化OLED显示屏
while (1)
{
// 主循环
}
}