📄 i2c_wr_rd.c
字号:
//AT24地址0xa0,采用页写入方式(连续字节写)写入CODE数组9个数据
//采用页读取方式读出0x00~0x08地址上9个字节数据
//PIC使用1M晶振,用软件模拟I2C接口
//SCL=RC0,SDA=RC1,用RB循环显示读取到的数据(隔一段时间换一个数据)
//在PROTEUS仿真软件上成功运行
#include<pic166x.h>
#define uchar unsigned char
#define nop() asm("nop") //当晶振提高时,此延时单元须加倍,以保证SCL,SDA电平宽度
#define SCL TRISC0
#define SDA TRISC1
void start_i2c();
void stop_i2c();
void send_byte(uchar c);
uchar receive_byte();
//void send_str(uchar sla,uchar suba,uchar*s,uchar no);
void delay_250ms();
void i2c_error();
void send_ack();
void send_nack();
uchar code[]={0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar get[0x09];
uchar no;
uchar ackk;
uchar c,data;
void main(void)
{
uchar i;
TRISA=0x00;
PORTA=0x0f;
TRISC=0xff;
PORTC=0x00;
TRISB=0x00;
PORTB=0x00;
//连续写入9个数据
start_i2c();
send_byte(0xa0);
if(ackk==0x00) i2c_error();
send_byte(0x00);
if(ackk==0x00) i2c_error();
for(i=0x00;i<0x09;)
{
send_byte(code[i++]);
if(ackk==0x00) i2c_error();
}
stop_i2c();
delay_250ms();
while(1)
{
//连续读取9个字节数据
start_i2c();
send_byte(0xa0);
if(ackk==0x00) i2c_error(); //无应答,显示错误
send_byte(0x00); //send word address
if(ackk==0x00) i2c_error();
start_i2c();
send_byte(0xa1);
if(ackk==0x00) i2c_error();
for(i=0x00;i<0x08;)
{
get[i++]=receive_byte();
send_ack();
}
get[0x08]=receive_byte();
send_nack();
stop_i2c();
for(i=0x00;i<0x09;i++) //循环显示读取到的9个数据
{
PORTB=get[i];
delay_250ms();
}
}
}
/*
while()
{
for(i=0x00;i<0x09;i++)
{
start_i2c();
send_byte(0xa0);
if(ack==0x00) i2c_error(); //无应答,显示错误
ssend_byte(i); //send word address
if(ack==0x00) i2c_error();
start_i2c();
send_byte(0xa1);
if(ack==0x00) i2c_error();
data=receive_byte();
send_nack();
stop_i2c();
PORTB=data;
delay_250ms();
delay_250ms();
}
}
}
*/
//***************I2C操作子程序(包括起始、结束、读、写)
void start_i2c()
{
SDA=1;
nop();
SCL=1;
nop(); nop(); nop(); nop(); nop();
SDA=0;
nop(); nop(); nop(); nop(); nop();
SCL=0;
nop(); nop();
}
void stop_i2c()
{
SDA=0;
nop();
SCL=1;
nop(); nop(); nop(); nop(); nop();
SDA=1;
nop(); nop(); nop(); nop(); nop();
}
void send_ack()
{
SDA=0;
SCL=0;
nop(); nop();nop(); nop();nop();
SCL=1;
nop(); nop(); nop();nop(); nop();
SCL=0; //release SCL to be free
}
void send_nack()
{
SDA=1;
SCL=0;
nop(); nop();nop(); nop();nop();
SCL=1;
nop(); nop(); nop();nop(); nop();
SCL=0; //SCL低电平为空闲状态
}
void send_byte(uchar c)
{
uchar bit_count;
for(bit_count=0x00;bit_count<0x08;bit_count++)
{
if((c<<bit_count)&0x80) SDA=1;
else SDA=0;
nop();
SCL=1;
nop(); nop(); nop(); nop();nop(); //SCL低电平时改变SDA值,SCL高电平时传递出去,故只需保证SCL高电平宽度
SCL=0;
}
//*******接收应答信号,ack=1表示收到应答****
nop(); nop();
SDA=1;
nop(); nop();
SCL=1;
nop(); nop(); nop();
ackk=0x01;
if(RC1==1)
{ ackk=0x00 ; } //接收方须在第9个SCL周期把SDA线拉低
SCL=0;
nop(); nop();
}
uchar receive_byte()
{
uchar retc,bit_count;
retc=0x00;
SDA=1;
for(bit_count=0x00;bit_count<0x08;bit_count++)
{
nop();
SCL=0;
nop(); nop(); nop(); nop(); nop();
SCL=1;
nop(); nop();
retc<<=0x01;
if(RC1==1) retc+=0x01; //数据在SCL为低时改变,而在SCL为高时稳定不变,所以在SCL高电平时读取SDA值
nop(); nop();
}
SCL=0;
nop(); nop();
return retc;
}
/*void send_str(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
start_i2c();
send_byte(sla);
if(ackk==0x00) i2c_error();
send_byte(suba);
if(ackk==0x00) i2c_error();
for(i=0;i<no;i++)
{
send_byte(*s);
if(ackk==0x00) i2c_error();
s++;
}
stop_i2c();
}
*/
void delay_250ms()
{
unsigned int d=24999;
while(--d);
}
void i2c_error() //RB7闪动8次表示总线操作失败1次
{
uchar i;
for(i=0x00;i<0x08;i++)
{
PORTB=~PORTB;
delay_250ms();
PORTB=~PORTB;
delay_250ms();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -