一、简介
使用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  设置低位
}

















