OLED为常用的外设,主要用于显示功能,常用接口为I2C、SPI。而I2C只需要2线就可以实现,更为常见。I2C可以用软件模拟I2C以及硬件的I2C驱动。软件I2C可以灵活选择GPIO来实现,在不同的单片机中移方便,但是速度相比硬件i2c慢,占用资源多。而硬件I2C速度快,占用资源小,但是硬件I2C需要指的IO,而且在有些单片机硬件i2c的兼容性不是很好,移植性差。
IO的选取,这次移植为硬件i2c驱动OLED屏。开饭盒派的开发板上面有I2C的插座,接的IO为SCK-PB6,SDA-PB7。
I2C的初始化
void OLED_I2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
I2C_InitTypeDef I2C_InitStruct = {0};
CW_SYSCTRL->AHBEN_f.GPIOB = 1; //打开GPIOB的时钟
CW_SYSCTRL->APBEN1_f.I2C1 = 1U; //打开I2c1的时钟
//端口复用
PB06_AFx_I2C1SCL();
PB07_AFx_I2C1SDA();
//配置IO输出
GPIO_InitStructure.Pins = I2C1_SCL_GPIO_PIN | I2C1_SDA_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStructure);
//配置I2C1
I2C_InitStruct.I2C_Baud = 0x1; // 48000 000/(8*(1+11) = 500k
I2C_InitStruct.I2C_BaudEn = ENABLE;
I2C_InitStruct.I2C_FLT = DISABLE;
I2C_InitStruct.I2C_AA = DISABLE;
I2C1_DeInit();
I2C_Master_Init(CW_I2C1,&I2C_InitStruct);//初始化I2C为主机模式
I2C_Cmd(CW_OLED_I2C, ENABLE);
}
发送一个byte的函数:
//向OLED寄存器地址写一个byte的数据
int I2C_WriteByte(uint8_t addr,uint8_t data)
{
uint8_t u8i = 0, u8State;
uint16_t timeout = 0xffff;
I2C_GenerateSTART(CW_OLED_I2C, ENABLE);
//获取状态
while(1)
{
while((0 == I2C_GetIrq(CW_OLED_I2C)) && timeout--);
if(timeout == 0) return 1;
u8State = I2C_GetState(CW_OLED_I2C);
switch(u8State)
{
case 0x08: //发送完START信号
I2C_GenerateSTART(CW_OLED_I2C, DISABLE);
I2C_Send7bitAddress(CW_OLED_I2C, OLED_ADDR, 0x00);
break;
case 0x18: //发送完SLA+W信号,ACK已收到
I2C_SendData(CW_OLED_I2C, addr);
break;
case 0x28:
I2C_SendData(CW_OLED_I2C, data);
u8i ++;
break;
case 0x20: //发送完SLA+W后从机返回NACK
break;
case 0x38: //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲载 或者 主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
I2C_GenerateSTART(CW_OLED_I2C, ENABLE);
break;
case 0x30:
I2C_GenerateSTOP(CW_OLED_I2C, ENABLE);
break;
default:
break;
}
if(u8i>1)
{
I2C_GenerateSTOP(CW_OLED_I2C, ENABLE);
I2C_ClearIrq(CW_OLED_I2C);
break;
}
I2C_ClearIrq(CW_OLED_I2C);
}
return 0;
}
函数中主要编程思想为轮询查询I2C的状态寄存器,根据不同的状态来确定下一个状态。
在写好发送一个byte的函数上,根据OLED的数据手册,定义好发送数据与命令函数如下:
//写指令
void WriteCmd(unsigned char I2C_Command)
{
I2C_WriteByte(0x00,I2C_Command);
}
//写数据
void WriteData(unsigned char I2C_Data)
{
I2C_WriteByte(0x40,I2C_Data);
}
至此,最基本的代码已经移植完毕代码与字库我附在后面。
在主函数里面调用OLED的初始化,然后清屏,显示效果如下:
oled.zip
(6.04 KB)
|