1 基本原理1.1 IIC总线
需要注意的是,高四位对于同种芯片而言,都是一样的。例如AT24C02芯片的高四位固定为1010。
1.2 AT24C02芯片
2 源代码
/*---------------------函数功能:
IIC总线 AT24C02
-----------------------------------------*/
#include<pic.h>// 调用PIC16f87XA单片机的头文件
#include"delay.h"//调用延时子函数的头文件
__CONFIG(0xFF32);//芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关
//__CONFIG(HS&WDTDIS&LVPDIS);
/*-----------宏定义--------------*/
#define uint unsigned int
#define uchar unsigned char
#define SDA RC4 // IIC的数据线
#define SCL RC3 // IIC的时钟线
/*-----------子函数声明--------------*/
void IIC_start(void); // IIC启动信号函数
void IIC_end(void); // IIC终止信号函数
void write_1Byte(uchar buf);//向IIC总线写一个字节的函数
char read_1Byte(); //从IIC总线读一个字节的函数
void write_AT24C02(char address,char databuf); //向AT24C02芯片的指定地址写一个字节的数据
char read_AT24C02(char address); //从AT24C02芯片的指定地址读一个字节的数据
/*-----------主函数--------------*/
void main()
{
char bufdata;
// data direction register is TRISA.
// Setting a TRISA bit (= 1) will make the corresponding PORTA pi an input.
// Clearing a TRISA bit (= 0) will make the corresponding PORTA pin an output.
TRISD=0x00; //RD作为输出口,作为LED灯的显示
PORTD=0x00; //LED的初值为0
delay(1000);
while(1)
{
bufdata=read_AT24C02(0x18);// 从AT24C02中地址0x18读出数据
PORTD=bufdata;
delay(1000);
bufdata=bufdata+1;
PORTD=bufdata;
delay(1000);
write_AT24C02(0x18,bufdata);//将+1的数据保存在0x18中
}
}
/*************IIC启动信号函数***************/
void IIC_start(void)
{
//为什么这样写,见IIC的时序图
SDA=1;
SCL=1;
asm("NOP");
asm("NOP");
SDA=0;
asm("NOP");
asm("NOP");
SCL=0;
asm("NOP");
asm("NOP");
}
/*************IIC终止信号函数***************/
void IIC_end(void)
{
SDA=0;
SCL=0;
asm("NOP");
asm("NOP");
SCL=1;
asm("NOP");
asm("NOP");
SDA=1;
asm("NOP");
asm("NOP");
SCL=0;//拉低
asm("NOP");
asm("NOP");
}
/*************向IIC总线写一个字节(8 bit)的函数***************/
void write_1Byte(uchar buf)
{
int k=0;
for(k=0;k<8;k++)
{
//将最高位写到SDA总线上去
//SDA=buf&0x80; // 等价于下面的if语句
if(buf&0x80) // 提取buf的最高位数据
SDA=1; //如果buf的最高位为1,就写1
else
SDA=0; //如果buf的最高位为0,就写0
asm("NOP");
asm("NOP");
SCL=1;
asm("NOP");
SCL=0; //时钟信号归零
asm("NOP");
buf=buf<<1; //左移一位,准备提取下一个待写的数据
}
// 每接收到一个字节的数据后,从机必须产生一个应答信号给主机。
// 应答器件在第9个时钟周期将SDA线拉低,表示已经接收了一个八位数据
TRISC4=1; //RC4作为输入,SDA引脚接的是RC4口 开始读数据,读SDA的值
asm("NOP");
SCL=1;
asm("NOP");
asm("NOP");
//if(RC4=0) //说明SDA=0,即成功接收
SCL=0;
TRISC4=0;
}
/*************向IIC总线读一个字节(8 bit)的函数***************/
char read_1Byte()
{
int k=0;
char t_byte=0x00;
TRISC4=1; //RC4作为输入,SDA引脚接的是RC4口 开始读数据,读SDA的值
for(k=0;k<8;k++)
{
t_byte=t_byte<<1; //左移一位
SCL=1;
asm("NOP");
asm("NOP");
//读 SDA的值
if(SDA=1)
t_byte=t_byte|0x01;//写1 只对最低位有影响
else
t_byte=t_byte&0xfe;//写0
SCL=0;
asm("NOP");
asm("NOP");
}
TRISC4=0;
return t_byte; // 返回的是一个字节 eg:0x3f
}
/*************向AT24C02芯片的指定地址写一个字节的数据***************/
void write_AT24C02(char address,char databuf)
{
IIC_start(); //发送起始信号
//AT24C02芯片寄存器: 1010 A2 A1 A0 R/W_n AT24C02芯片的高四位固定为1010
// A2A1A0:从机选择,一共可以接八个AT24C02芯片。 A2A1A0=000,选择第一个芯片。 R/W_n:读/写
//选择某一个从器件(确定用哪一个芯片)
write_1Byte(0xa0); //发送从器件地址000,选择第一个芯片。R/W_n=0,表示写
//指定该器件内部的某一个地址(确定芯片内部地址)
write_1Byte(address); //指定该芯片内部的某一个地址(一共有256个地址)
//向该芯片的指定地址里面写数据
write_1Byte(databuf); //向指定地址发送数据
IIC_end(); //发送结束信号
}
/*************从AT24C02芯片的指定地址读一个字节的数据***************/
char read_AT24C02(char address)
{
char buf;
//AT24C02芯片寄存器: 1010 A2 A1 A0 R/W_n AT24C02芯片的高四位固定为1010
// A2A1A0:从机选择,一共可以接八个AT24C02芯片。 A2A1A0=000,选择第一个芯片。 R/W_n:读/写
IIC_start(); //发送起始信号
//选择某一个从器件(确定用哪一个芯片)
write_1Byte(0xa0); //发送从器件地址000,选择第一个芯片。R/W_n=0,表示写
//指定该器件内部的某一个地址(确定芯片内部地址)
write_1Byte(address); //指定该芯片内部的某一个地址(一共有256个地址)
//在传输过程中,当需要改变传送方向时(写<->读),起始信号IIC_start()和从机地址write_1Byte(0xa1)都被重复产生一次
//由于写变成读,所以需要下面两条指令
IIC_start(); //再次启动
//选择某一个从器件(确定用哪一个芯片) 此时要准备读数据
write_1Byte(0xa1); //发送从器件地址,选择第一个芯片。R/W_n=1,表示读
//读出该芯片指定地址的数据
buf=read_1Byte();
IIC_end(); //发送结束信号
return buf; // 返回的是一个字节 eg:0x3f
}
|