简单理解下什么是IIC
I2C(Inter-Integrated Circuit BUS) 集成电路总线,该总线由NXP(原PHILIPS)公司设计,多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
总线信号 :
SDA :串行数据线
SCL :串行时钟
总线空闲状态 :
SDA :高电平
SCL :高电平
起始位:SCL为高电平期间 SDA出现下降沿
终止位:SCL为高电平期间 SDA出现上升沿
数据传输 :SDA的数据在SCL高电平期间被写入从机。所以SDA的数据变化要发生在SCL低电平期间。
#ifndef _IIC_H
#define _IIC_H
#include "msp430f5529.h"
//IIC通信接口引脚输出宏定义
#define SCL_HIGH P6OUT|=BIT3 //定义引脚6.3为高电平时的输出
#define SCL_LOW P6OUT&=~BIT3//定义引脚6.3为低电平时的输出
#define SDA_HIGH P6OUT|=BIT4//定义引脚6.4为高电平时的输出
#define SDA_LOW P6OUT&=~BIT4//定义引脚6.4为低电平时的输出
#define XLevelL 0x00//低位地址
#define XLevelH 0x10//高位地址
#define XLevel ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column 128//最大屏幕像素宽度
#define Max_Row 64 //最大屏幕像素宽度
#define Brightness 0xCF //IIC起始地址
#define X_WIDTH 128//屏幕像素宽度
#define Y_WIDTH 64 //屏幕像素高度
void IIC_delayus(unsigned int i);
void IIC_ioinit(void);//初始化IIC
void IIC_start(void);//开始IIC通信
void IIC_stop(void);//结束IIC通信
void IIC_writebyte(unsigned char IIC_byte);//写字节
void IIC_writecmd(unsigned char IIC_command);//写命令
void IIC_writedata(unsigned char IIC_data);//写数据
void LCD_Set_Pos(unsigned char x, unsigned char y);//设置显示位置
void LCD_CLS(void);//清屏
void LCD_Init(void);//OLED屏初始化
void LCD_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char Char_Size);//显示字符
void LCD_ShowString(unsigned char x,unsigned char y,unsigned char *chr,unsigned char Char_Size);//显示字符串
void LCD_ShowNum(unsigned char x,unsigned char y,unsigned long num,unsigned char len,unsigned char size2);//显示数字
unsigned long oled_pow(unsigned char m,unsigned char n);//字符求幂函数
#endif //_IIC_H
#include "IIC.h"
#include "font.h"
//延时函数延时=4*i
void IIC_delayus(unsigned int i)
{
unsigned int j,k;
for(k=0;k<i;k++)
for(j=0;j<4;i++);
}
//IIC初始化函数
void IIC_ioinit()
{
P6DIR|=BIT1|BIT2|BIT3|BIT4; //配置IIC IO口为输出方向
P6REN|=BIT3|BIT4; //配置IIC IO口使能上拉电阻
P6OUT&=~BIT1;//6.1 拉高
P6OUT|=BIT2;//6.2 拉低
}
//开始一个IIC通信
void IIC_start()
{
//产生信号上升沿
SCL_HIGH;//SCL拉高
SDA_HIGH;//SDA拉高
//接下来产生SDA信号下降沿,注意,这里SDA一定比SCL先拉低
//IIC_delayus(2);
SDA_LOW;//SDA拉低
//IIC_delayus(2);
SCL_LOW;//SCL拉低
//主机开始读写信号产生完毕
}
//停止IIC通信
void IIC_stop()
{
SCL_LOW;
SDA_LOW;
//IIC_delayus(2);
//接下来产生SDA信号上升沿,注意,这里SCL一定比SDA先拉高
SCL_HIGH;
SDA_HIGH;
//IIC_delayus(2);
}
//IIC发送一个byte
void IIC_writebyte(unsigned char IIC_byte)
{
unsigned char i;
//一个字节8bit因此,循环从0开始到7共8次写数据
for(i=0;i<8;i++)
{
if(IIC_byte&0x80) //如果写满8字节且不为0
SDA_HIGH;//拉高SDA信号
else//没有写满8字节
SDA_LOW;//写入0
SCL_HIGH;//拉高SCL结束一bit的写
SCL_LOW;//拉低SCL使得SDA可写
IIC_byte<<=1; //IIC_byte左移一位,故名思意了
//假设IIC_byte数据为字符c 那么它的二进制就是01100011写入寄存器就是
//第一遍循环11000110
//第二遍循环10001100
//第三遍循环00011000
//第四遍循环00110000
//第五遍循环01100000
//第六遍循环11000000
//第七遍循环10000000
//第八遍循环00000000 全为0拉高SDA
}
SDA_HIGH;//恢复拉高SDA
SCL_HIGH;//恢复拉高SCL
SCL_LOW;//拉低SCL等待SDA电平变动
}
void IIC_writecmd(unsigned char IIC_command)
{
IIC_start();
IIC_writebyte(0x78); //Slave address,SA0=0 从机寄存器地址
IIC_writebyte(0x00); //发送指令写指令
IIC_writebyte(IIC_command);//写入指令
IIC_stop();//结束IIC通信
}
void IIC_writedata(unsigned char IIC_data)
{
IIC_start();
IIC_writebyte(0x78); //IIC写从机起始地址
IIC_writebyte(0x40); //write data写数据
IIC_writebyte(IIC_data);//写入字符数据
IIC_stop();
}
/**************************LCD 设置坐标*******************************/
void LCD_Set_Pos(unsigned char x, unsigned char y)
{
//OLED寄存器指令集查看OLED芯片手册
IIC_writecmd(0xb0+y);
IIC_writecmd(((x&0xf0)>>4)|0x10);
IIC_writecmd((x&0x0f)|0x01);
}
/***************************LCD复位************************************/
void LCD_CLS(void)
{
unsigned char y,x;
for(y=0;y<8;y++)
{
IIC_writecmd(0xb0+y);
IIC_writecmd(0x01);
IIC_writecmd(0x10);
for(x=0;x<X_WIDTH;x++)
IIC_writedata(0);
}
}
/***************************LCD初始化************************************/
void LCD_Init(void)
{
IIC_ioinit();
IIC_writecmd(0xAE); //display off
IIC_writecmd(0x20); //Set Memory Addressing Mode
IIC_writecmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
IIC_writecmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
IIC_writecmd(0xc8); //Set COM Output Scan Direction
IIC_writecmd(0x00);//---set low column address
IIC_writecmd(0x10);//---set high column address
IIC_writecmd(0x40);//--set start line address
IIC_writecmd(0x81);//--set contrast control register
IIC_writecmd(0x7f);
IIC_writecmd(0xa1);//--set segment re-map 0 to 127
IIC_writecmd(0xa6);//--set normal display
IIC_writecmd(0xa8);//--set multiplex ratio(1 to 64)
IIC_writecmd(0x3F);//
IIC_writecmd(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content
IIC_writecmd(0xd3);//-set display offset
IIC_writecmd(0x00);//-not offset
IIC_writecmd(0xd5);//--set display clock divide ratio/oscillator frequency
IIC_writecmd(0xf0);//--set divide ratio
IIC_writecmd(0xd9);//--set pre-charge period
IIC_writecmd(0x22); //
IIC_writecmd(0xda);//--set com pins hardware configuration
IIC_writecmd(0x12);
IIC_writecmd(0xdb);//--set vcomh
IIC_writecmd(0x20);//0x20,0.77xVcc
IIC_writecmd(0x8d);//--set DC-DC enable
IIC_writecmd(0x14);//
IIC_writecmd(0xaf);//--turn on oled panel
LCD_CLS();
LCD_Set_Pos(0,0);
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void LCD_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char Char_Size)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1)//如果,字符坐标大于行最大像素值写到下一行开始位置
{
x=0;
y=y+2;
}
if(Char_Size ==16)//如果字符刚好等于16字符
{
LCD_Set_Pos(x,y);
for(i=0;i<8;i++)
IIC_writedata(F8X16[c*16+i]);
LCD_Set_Pos(x,y+1);
for(i=0;i<8;i++)
IIC_writedata(F8X16[c*16+i+8]);
}
else //否则写到下一行
{
LCD_Set_Pos(x,y);
for(i=0;i<6;i++)
IIC_writedata(F6x8[c][i]);
}
}
//显示一个字符号串
void LCD_ShowString(unsigned char x,unsigned char y,unsigned char *chr,unsigned char Char_Size)
{
unsigned char j=0;
while (chr[j]!='\0')//遍历字符串,x+8相当于每个字符间隔8个坐标 循环调用显示字符函数,直到字符串为空
{
LCD_ShowChar(x,y,chr[j],Char_Size);
x+=8;
if(x>128)
{
x=0;
y+=2;
}
j++;
}
}
//m^n函数
unsigned long oled_pow(unsigned char m,unsigned char n)
{
unsigned long result=1;
while(n--)result*=m;
return result;
}
//显示一个数字将数字取模获取每一位的数字,以字符的形式显示
//当输入数字为9876时坐标为0,0时
//取得每一位数
//第一遍循环 9876%10=987 余6 6+'0'='6' 坐标 x=0 y=0
//第二遍循环 987%10=98 余7 7+'0'='7‘ 坐标 x=0+8=8 y=0
//第三遍循环 98%10=9 余6 6+'0'='7' 坐标 x=8+8=16 y=0
//第四遍循环 9%10=0 余9 9+'0'='9' 坐标 x=16+8=24 y=0
//其他以此类推
void LCD_ShowNum(unsigned char x,unsigned char y,unsigned long num,unsigned char len,unsigned char size2)
{
unsigned char t,temp;
//unsigned char enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
LCD_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}