一、简介
使用0.96寸IIC屏幕作为遥控动作的显示界面。
外设引脚
stm32f103c8t6单片机IIC引脚有两组
使用I2C1,对应的时钟与数据线分别为PB6、PB7。
IIC屏幕指令
// OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
// OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
// OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
// OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
// OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
// OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
// OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
// OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
// OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
// OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
// OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
// OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
// OLED_WR_Byte(0x00,OLED_CMD);//-not offset
// OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
// OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
// OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
// OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
// OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
// OLED_WR_Byte(0x12,OLED_CMD);
// OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
// OLED_WR_Byte(0x30,OLED_CMD);//Set VCOM Deselect Level
// OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
// OLED_WR_Byte(0x02,OLED_CMD);//
// OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
// OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
I2C_ByteWrite(0xAE,OLED_CMD); //关闭显示
I2C_ByteWrite(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
I2C_ByteWrite(0x80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
I2C_ByteWrite(0xA8,OLED_CMD); //设置驱动路数
I2C_ByteWrite(0X3F,OLED_CMD); //默认0X3F(1/64)
I2C_ByteWrite(0xD3,OLED_CMD); //设置显示偏移
I2C_ByteWrite(0X00,OLED_CMD); //默认为0
I2C_ByteWrite(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
I2C_ByteWrite(0x8D,OLED_CMD); //电荷泵设置
I2C_ByteWrite(0x14,OLED_CMD); //bit2,开启/关闭
I2C_ByteWrite(0x20,OLED_CMD); //设置内存地址模式
I2C_ByteWrite(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
I2C_ByteWrite(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
I2C_ByteWrite(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
I2C_ByteWrite(0xDA,OLED_CMD); //设置COM硬件引脚配置
I2C_ByteWrite(0x12,OLED_CMD); //[5:4]配置
I2C_ByteWrite(0x81,OLED_CMD); //对比度设置
I2C_ByteWrite(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
I2C_ByteWrite(0xD9,OLED_CMD); //设置预充电周期
I2C_ByteWrite(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
I2C_ByteWrite(0xDB,OLED_CMD); //设置VCOMH 电压倍率
I2C_ByteWrite(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
I2C_ByteWrite(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
I2C_ByteWrite(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
I2C_ByteWrite(0xAF,OLED_CMD); //开启显示
二、编码
2.1、IIC协议与IO口模拟IIC
协议内容
//起始信号
void I2C_Start(void)
{
OLED_SDA_Set();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Clr();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}
结束信号
void I2C_Stop(void)
{
OLED_SDA_Clr();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Set();
}
等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SDA_Set();
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}
写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
if(dat&0x80)//将dat的8位从最高位依次写入
{
OLED_SDA_Set();
}
else
{
OLED_SDA_Clr();
}
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();//将时钟信号设置为低电平
dat<<=1;
}
}
发送一个字节
mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode){Send_Byte(0x40);}
else{Send_Byte(0x00);}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
2.2、库函数配置
2.2.1、IIC库函数配置
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; /* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
I2C_InitStructure.I2C_OwnAddress1 =0x78; //主机的I2C地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /* I2C的寻址模式 */
I2C_InitStructure.I2C_ClockSpeed = 400000; /* 通信速率 */
I2C_Init(I2C1, &I2C_InitStructure); /* I2C1 初始化 */
I2C_Cmd(I2C1, ENABLE);
2.2.2、向IIC外设写数据库函数配置
void I2C_ByteWrite(uint8_t addr,uint8_t data)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(I2C1, 0x78, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, addr);//寄存器地址
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, data);//发送数据
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}
2.2.3、写指令与写数据
void WriteCmd(unsigned char I2C_Commangd)
{
I2C_ByteWrite(0x00,I2C_Commangd);
}
void WriteData(unsigned char I2C_Data) // 写数据
{
I2C_ByteWrite(0x40,I2C_Data);
}
void WriteByte(unsigned char mode,unsigned char I2C_Operation)
{
if(mode==0x01)
{
I2C_ByteWrite(0x40,I2C_Operation);
}
else
{
I2C_ByteWrite(0x00,I2C_Operation);
}
}
2.2.4、从设备向从IIC总线读数据
uint8_t I2C_ByteRead(uint8_t REG_Address) //从IIC设备寄存器中读取一个字节
{
uint8_t REG_data;
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);//起始信号
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,SlaveAddress,I2C_Direction_Transmitter);//发送设备地址+写信号
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//
I2C_Cmd(I2C1,ENABLE);
I2C_SendData(I2C1,REG_Address);//发送存储单元地址,从0开始
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTART(I2C1,ENABLE);//起始信号
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,SlaveAddress,I2C_Direction_Receiver);//发送设备地址+读信号
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_AcknowledgeConfig(I2C1,DISABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
while(!(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)));
REG_data=I2C_ReceiveData(I2C1);//读出寄存器数据
return REG_data;
}
2.2.5、OLED指令初始化
//OLED的初始化
void OLED_Init(void)
{
delay_ms(1000);
WriteCmd(0xAE); //关闭显示
WriteCmd(0xD5); //设置时钟分频因子,震荡频率
WriteCmd(0x80); //[3:0],分频因子;[7:4],震荡频率
WriteCmd(0xA8); //设置驱动路数
WriteCmd(0X3F); //默认0X3F(1/64)
WriteCmd(0xD3); //设置显示偏移
WriteCmd(0X00); //默认为0
WriteCmd(0x40); //设置显示开始行 [5:0],行数.
WriteCmd(0x8D); //电荷泵设置
WriteCmd(0x14); //bit2,开启/关闭
WriteCmd(0x20); //设置内存地址模式
WriteCmd(0x02); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
WriteCmd(0xA1); //段重定义设置,bit0:0,0->0;1,0->127;
WriteCmd(0xC0); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
WriteCmd(0xDA); //设置COM硬件引脚配置
WriteCmd(0x12); //[5:4]配置
WriteCmd(0x81); //对比度设置
WriteCmd(0xEF); //1~255;默认0X7F (亮度设置,越大越亮)
WriteCmd(0xD9); //设置预充电周期
WriteCmd(0xf1); //[3:0],PHASE 1;[7:4],PHASE 2;
WriteCmd(0xDB); //设置VCOMH 电压倍率
WriteCmd(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
WriteCmd(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
WriteCmd(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示
WriteCmd(0xAF); //开启显示
}
2.3、OLED屏幕编码
OLED的ARM,每一行为一页,每一页有128个字节(8行128列即8*128bit 高电平熄灭,低电平点亮),共8页。
页寻址:在页寻址模式下,读/写显示RAM后,列地址指针自动增加1。如果列地址指针到达列结束地址。列地址指针复位,用户重新设置行地址指针,以便访问新页。
设置坐标
- 通过命令(B0h-B7h)设置目标显示位置页起始地址
- 通过命令(00h-0Fh)设置列起始地址低位
- 通过命令(10h-1Fh)设置列起始地址高位
void OLED_SetPos(unsigned char x, unsigned char y)
{
WriteCmd(0xb0+y);//0xb0起始地址 1011 0000 // x[0~7]行 y[0~127]列
WriteCmd(((x&0xf0)>>4)|0x10);// 第四位 0001 1111 设置高位
WriteCmd((x&0x0f)|0x01); // 第0位 0000 0001 设置低位
}