模拟I2C读写24C256、PCF8563

更新时间:2023-07-17 10:46:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

主函数

#include <stdio.h>//包含文件

#include <reg52.h>

#include <intrins.h>

#include<serial.h>

#include"i2c.h"

#define Byte unsigned char//宏定义

#define uint unsigned int

#define uchar unsigned char

#define device_16bit_Waddress 0xa0//器件写数据地址24c256

#define device_16bit_Raddress 0xa1//器件读数据地址24c256

#define device_8bit_Waddress 0xa2 //定义PCF8563的写数据地址

#define device_8bit_Raddress 0xa3 //定义PCF8563的读数据地址

#define debug 0

/*sbit SCL= P3^5;

sbit SDA =P3^4;*/

/*sbit SCL= P1^5;

sbit SDA =P1^6;*/

sbit SCL= P3^4;

sbit SDA =P3^3;

/*延时子程序,大概10ms左右*/

void delay()

{

uint i,j;

for(i=0;i<10;i++)

{

for(j=0;j<1000;j++)

{

;

}

}

}

/*开始I2C数据发送或接收*/

void Start_I2C()//在时钟线为高,数据线从高电平跳到低电平时,开始传送

{

SDA=1; //数据先

_nop_(); //延时一段时间

_nop_();

SCL=1; //时钟线为高,等数据线下降才开始

_nop_();

_nop_();

_nop_();

_nop_();

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SDA=0; //数据线下降拉,启动了

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

SCL=0;

}

/*结束数据传送*/

void Stop_I2C()

{

SDA=0; //时钟线为高时,数据线上升沿为结束信号

_nop_();

_nop_();

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();

SDA=1;

_nop_();

_nop_();

_nop_();

_nop_();

SCL=0;

}

/*发送字节子程序,入口参数为要发送的数据,无返回变量,分8位进行发送*/

void Sent_Byte(Byte Data)

{

Byte BitCount; //定义发送的位数

for(BitCount=0;BitCount<8;BitCount++)

{

_nop_();

_nop_();

if((Data<<BitCount)&0x80) SDA=1;//移位判断发送的数据是1还是0

else SDA=0;

_nop_();

_nop_();

SCL=1; //置位SCL,通知从器件开始接收数据,SCL上升沿发数据

_nop_(); //SCL为1,数据线电平不能变

_nop_();

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

_nop_();

_nop_();

SCL=0; //钳住总线,等下次接收

}

}

/*应答子程序,无入口参数,返回值是应答位*/

bit Ack_Check()

{

SDA=1; //先置时钟线为高,第九位数据过来会强行把数据线拉低

_nop_();

_nop_();

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();

F0=SDA; //将数据线上的该位保存到F0中

SCL=0;

if(F0==1)

return 1;//没有应答,返回1,否则返回0

else return 0;

}

/*接收字节子函数,先接收高位,再接收低位无入口参数,返回值是一个无符号型的一个8位的数*/

Byte Rec_Byte()

{

Byte BitCount, RecData=0;

for(BitCount=0;BitCount<8;BitCount++)

{

SDA=1; //数据线先给1的话,如果从器件发0给主器件

_nop_(); //SDA会拉低,那主器件接收到的为0,否则不拉低,接收到的为1

_nop_(); //这相当释放数据总线一样

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

F0=SDA; //用F0来保存当前数据线上的值 SCL=0;

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

if(F0)

{

RecData=RecData<<1;

RecData=RecData|0x01;

}

else RecData=RecData<<1;

}

return(RecData);

}

/*发送数据子函数,入口参数是16位的器件地址和要发送的数据,无返回值*/

Sent_Data16(uint address,Byte Data)

{

bit ack_temp; //响应寄存位

uchar addr_H,addr_L;

addr_H=(uchar)(address>>8);

addr_L=(uchar)(address&0x00ff) ;

Start_I2C(); //启动传送

Sent_Byte(device_16bit_Waddress);//先发送器件地址

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(addr_H); //再发送内存地址高八位

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

Sent_Byte(addr_L); //再发送内存地低八位

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(Data); //发送数据

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Stop_I2C(); //停止

}

/*接收数据子程序,入口参数是从器件的16位内存地址,返回值是读到的值*/

Byte Rec_Data16(uint address)

{

Byte RecByte; //定义接收到的数

bit ack_temp; //响应位

uchar addr_H,addr_L;

addr_H=(uchar)(address>>8);

addr_L=(uchar)(address&0x00ff) ;

Start_I2C(); //开化信号

Sent_Byte( device_16bit_Waddress);//先进行一次伪写操作

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(addr_H); //再发送内存地址

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(addr_L); //再发送内存地址

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Start_I2C(); //再一次启动信号

Sent_Byte( device_16bit_Raddress);//发送器件读地址

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SendCommString("ACK ERROR");

}

}

RecByte=Rec_Byte(); //接收数据

/*ack_temp=Ack_Check();//一个字节一个字节读不需要应答

if(ack_temp==1)

{

SendCommString("ACK OK");

}

else {

SendCommString("ACK ERROR");

}*/

Stop_I2C(); //停止信号

return(RecByte);

}

/*发送数据子函数,入口参数是8位器件地址和要发送的数据,无返回值*/

Sent_Data8(Byte address,Byte Data)

{

bit ack_temp; //响应寄存位

Start_I2C(); //启动传送

Sent_Byte(device_8bit_Waddress);//先发送器件地址

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(address); //再发送内存地址

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SendCommString("ACK ERROR");

}

}

Sent_Byte(Data); //发送数据

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Stop_I2C(); //停止

}

/*接收数据子程序,入口参数是8位从器件的内存地址,返回值是读到的值*/

Byte Rec_Data8(address)

{

Byte RecByte; //定义接收到的数

bit ack_temp; //响应位

Start_I2C(); //开化信号

Sent_Byte(device_8bit_Waddress);//先进行一次伪写操作

ack_temp=Ack_Check(); //接收应答位

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Sent_Byte(address); //再发送内存地址

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Start_I2C(); //再一次启动信号

Sent_Byte(device_8bit_Raddress );//发送器件读地址

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

RecByte=Rec_Byte(); //接收数据

ack_temp=Ack_Check();

if(debug==1)

{

if(ack_temp==0)

{

SendCommString("ACK OK");

}

else

{

SendCommString("ACK ERROR");

}

}

Stop_I2C(); //停止信号

return(RecByte);

}

main()

{

Byte xdata i, m[20];

serial_init();

T0_init();

if(debug==1)

{

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

SendCommString("serial ok");

}

Sent_Data16(0x0020,13);//向从器件地址发四个数据

delay();

Sent_Data16(0x0021,14);

delay();

Sent_Data16(0x0022,15);

delay();

Sent_Data16(0x0023,16);

delay();

m[0]=Rec_Data16(0x0020);//将接收到的数据保存在一个数组中

m[1]=Rec_Data16(0x0021);

m[2]=Rec_Data16(0x0022);

m[3]=Rec_Data16(0x0023);

ES=0;

TI=0;

for(i=0;i<4;i++) //通过串行口对接收到的数显示

{

SBUF=m[i];

while(!TI); //串行发送

TI=0;

}

ES=1;

/*Sent_Data8(0x00,1);//向从器件地址发四个数据

delay();

Sent_Data8(0x01,2);

delay();

Sent_Data8(0x02,3);

delay();

Sent_Data8(0x03,4);

delay();

m[0]=Rec_Data8(0x00);//将接收到的数据保存在一个数组中

m[1]=Rec_Data8(0x01);

m[2]=Rec_Data8(0x02);

m[3]=Rec_Data8(0x03);

ES=0;

TI=0;

for(i=0;i<4;i++) //通过串行口对接收到的数显示

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

{

SBUF=m[i];

while(!TI); //串行发送

TI=0;

}

ES=1;*/

while(1); //等待

}

串口部分:

#include "reg52.h"

#include "intrins.h"

#include "serial.h"

#define uchar unsigned char

#define uint unsigned int

uchar rec_data[30];//上位机传来的命令数据长度为:4(STAR)+4(TEST等)+3(010长度等)+data+2(CRC)+3(END),16+data,数据长度暂时定为30

uchar xdata send_data[120];//由于上传数据时data比较长,有数字通道数据和模拟通道数据还有开关量通道数据

uchar rec_over_flag;//接收串行口0和串行口1一帧数据结束标志

uchar xdata send_num,send_length;//232需要发送的数据的长度和还需要发送的长度 uchar rec_tail;//接受232数据时保存是接受第几个数据的变量

/*发送一帧232数据子程序*/

void SendCommString(unsigned char *base)

{

if (base[0]==0) return;

for (;;)

{

if (base[send_length]==0) break;

send_data[send_length]=base[send_length];

send_length++;

}

SBUF=send_data[0];

send_num=send_length;

while(send_length!=0);

}

/*串行口初始化函数*/

void serial_init()//初始化串行口函数,设置串行口波特率为9600,8位数据位,一位停止位,无校验位

{ //使用T1做波特率发生器

SCON|=0x50;//8位异步收发,允许串行口接收数据,TI和RI初始化为0

PCON=0x80; // SMOD = 1;

SCON = 0x50; // Mode 1, 8-bit UART, enable receiption 19200 TH1=0xfd;

TL1=0xfd;

模拟I2C总线读写24C256和PCF8563,扩展成读写一切I2C总线的设备

TR1=1;

TMOD|=0x20;//8Bit

ES=1;

EA=1;

}

/*定时器0初始化*/

void T0_init(void)

{

TMOD|=0x01;//初始化定时器0包括T0的工作方式为1,初值为定时10ms,开中断 TH0=(65536-10000)/256;

TL0=(65536-10000)%256;

ET0=1;

}

/*定时器0中断服务函数*/

void t0_isp(void) interrupt 1

{

TF0=0;//定时器0中断标志清零

TR0=0;//关闭计数器

rec_over_flag=1;//10ms没有新数据,需要将接收到得数据打包

rec_data[rec_tail]=0;//结束标志

rec_tail=0;

}

/*串行口中断服务函数*/

void serial_isp(void )interrupt 4//串行口中断服务函数,接收上位机的命令或下位机的数据 {

if(RI)//接收到了新数据

{

TH0=(65536-10000)/256;

TL0=(65536-10000)%256;

TR0=1;

RI=0;

rec_data[rec_tail]=SBUF;

rec_tail++;

}

if(TI)

{

TI=0;

send_length=send_length-1;

if(send_length!=0)

{

SBUF=send_data[send_num-send_length];

}

}

}

本文来源:https://www.bwwdw.com/article/6ia1.html

Top