熟悉了几天编译器,通过参考学长的代码,终于把四阵IIC的OLED点亮了。
IIC,即I²C,全称 Inter-Integrated Circuit,字面上的意思是集成电路之间,它其实是I²C Bus简称,所以中文应该叫 集成电路总线 ,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。(百度百科)
简单地说,IIC就是一种通信协议,是为了能让主板,或嵌入式系统等与其他外设模块进行通信而进行开发的。玩过stm32开发板的同学都知道,对于一块stm32核心开发板而言,要想使用其他的外设模块,就肯定要经过接线,写代码,烧录运行的这个过程。其实这个过程,就是一个stm32与外设模块通信的过程。接线,就是搭建通信的线路。写代码,就是制定通信的传输协议。烧录运行,就是正式的通信过程。只不过有的模块通信过程很简单,大家感觉不出来。外设和芯片间的通信可以形象地比喻成两个人讲话:i、你说的别人得能听懂:双方约定信号的协议。ii、你的语速别人得能接受:双方满足时序要求。但是随着科技的发展,模块越来越多,总不可能,每个模块都要制定一种通信协议,这样不现实。所以,总要有一些代表性的协议能够适应大部分的模块的通信。IIC这是这样一种协议,一个IIC总线上,可以挂载多个外接设备。IIC总线上的信息传送是根据SCL时钟信号,每一次数据为的发送都发生在一个单独的SCl时钟周期内。
IC协议的通信过程:要搭建IIC的通信线路,出除去电源之外,还需要两条线,分别是SDA和SCLK
SDA:数据信号线,用于传输数据
SCLK:时钟信号线,用于产生时钟频率,控制时序,实现协议过程
由此可以看出,由于是单总线进行数据传输,所以IIC协议是半双工的。
void IIC_Start()
{
OLED_SCLK_Set() ;
NOP();NOP();NOP(); //等待延时
OLED_SDIN_Set();
NOP();NOP();NOP(); //等待延时
OLED_SDIN_Clr();
NOP();NOP();NOP(); //等待延时
OLED_SCLK_Clr();
NOP();NOP();NOP(); //等待延时
}
void IIC_Stop()
{
OLED_SCLK_Set() ;
NOP();NOP();NOP(); //等待延时
OLED_SDIN_Clr();
NOP();NOP();NOP(); //等待延时
OLED_SDIN_Set();
NOP();NOP();NOP(); //等待延时
}
数据传输和响应信号
数据传输:SDA上的数据只能在SCL为低电平期间翻转变化,在SCL为高电平期间必须保持稳定,IIC设备只在SCL为高电平期间采集SDA数据。 响应信号(ACK):单片机发完8bit数据后就不再驱动总线了(SDA引脚变输入),而SDA和SDL硬件设计时都有上拉电阻,所以这时候SDA变成高电平。那么在第8个数据位,如果外接IIC设备能收到信号的话接着在第9个周期把SDA拉低,那么处理器检测到SDA拉低就能知道外接IIC设备数据已经收到。IIC数据从最高位开始传输(小端传输)。
void IIC_Wait_Ack()
{
OLED_SCLK_Set() ;
NOP();NOP();NOP();
OLED_SCLK_Clr();
NOP();NOP();NOP();
}
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
unsigned char m,da;
da=IIC_Byte;
NOP();NOP();NOP();
OLED_SCLK_Clr();
NOP();NOP();NOP();
for(i=0;i<8;i++)
{
m=da;
OLED_SCLK_Clr();
m=m&0x80;
if(m==0x80)
{OLED_SDIN_Set();}
else OLED_SDIN_Clr();
NOP();NOP();NOP();
da=da<<1;
OLED_SCLK_Set();
NOP();NOP();NOP();
OLED_SCLK_Clr();
NOP();NOP();NOP();
}
}
/**
* @name:Write_IIC_Command(unsigned char IIC_Command)
* @msg: IIC写一个命令
* @param {unsigned char} IIC_Command
* @return {*}
*/
void Write_IIC_Command(unsigned char IIC_Command)
{
IIC_Start();
Write_IIC_Byte(0x78);
IIC_Wait_Ack();
Write_IIC_Byte(0x00);
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
}
/**
* @name: Write_IIC_Data(unsigned char IIC_Data)
* @msg: IIC写一个数据
* @param {unsigned char} IIC_Data
* @return {*}
*/
void Write_IIC_Data(unsigned char IIC_Data)
{
IIC_Start();
Write_IIC_Byte(0x78); //D/C#=0; R/W#=0
IIC_Wait_Ack();
Write_IIC_Byte(0x40); //write data
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
}
/**
* @name: OLED_WR_Byte(unsigned dat,unsigned cmd)
* @msg: OLED写一个字节
* @param {unsigned} dat 写数据
* @param {unsigned} cmd 写命令
* @return {*}
*/
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd)
{
Write_IIC_Data(dat);
}
else
{
Write_IIC_Command(dat);
}
}
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); //更新显示
}
}
void OLED_On(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA); //更新显示
}
}
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else {
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}