如果你学单片机的哈,肯定是要学会自己写的,最起码你要能把别人的程序能调通,能通信,而且不同单片机的I2C协议是有部分的不同的,例如有的I2C在接收的时候会发两次,第一次不是数据而是要把它读空,第二次才是数据,如果你用正常的单片机协议肯定就读不到数据了
//给你一个简单的可断电保存的计时程序,用的是24C08
#include <reg52h> // 包含51单片机寄存器定义的头文件
#include <intrinsh> //包含_nop_()函数定义的头文件
#define OP_READ 0xa1 // 器件地址以及读取 *** 作,0xa1即为1010 0001B
#define OP_WRITE 0xa0 // 器件地址以及写入 *** 作,0xa1即为1010 0000B
sbit SCL=P3^4; //将串行时钟总线SCL位定义在为P34引脚
sbit SDA=P3^5; //将串行数据总线SDA位定义在为P35引脚
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//定义共阳数码管显示字型码
unsigned char sec=0; //定义计数值,每过1秒,sec加1
unsigned int count; //定时中断次数
bit write=0; //写24C08的标志;
sbit shiwei=P2^6; //十位选通定义
sbit gewei=P2^7; //个位选通定义
sbit K5=P3^2; //清0按键
/
函数功能:延时1ms
/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/
函数功能:延时若干毫秒
入口参数:n
/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/
函数功能:开始数据传送
/
void start()
// 开始位
{
SDA = 1; //SDA初始化为高电平“1”
SCL = 1; //开始数据传送时,要求SCL为高电平“1”
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA = 0; //SDA的下降沿被认为是开始信号
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
}
/
函数功能:结束数据传送
/
void stop()// 停止位
{
SDA = 0; //SDA初始化为低电平“0” _n
SCL = 1; //结束数据传送时,要求SCL为高电平“1”
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA = 1; //SDA的上升沿被认为是结束信号
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA=0;
SCL=0;
}
/
函数功能:检测应答位
/
bit Ask() //检测应答
{
bit ack_bit; //储存应答位
SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,
//以让SDA线转由接收设备(AT24Cxx)控制
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 1; //根据上述规定,SCL应为高电平
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节
//若送高电平,表示没有接收到,传送异常 结束发送
SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
return ack_bit; // 返回AT24Cxx应答位
}
/
函数功能:从AT24Cxx读取数据
出口参数:x
/
unsigned char ReadData()
// 从AT24Cxx移入数据到MCU
{
unsigned char i;
unsigned char x; //储存从AT24Cxx中读出的数据
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL置为高电平
x<<=1; //将x中的各二进位向左移一位
x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中
SCL = 0; //在SCL的下降沿读出数据
}
return(x); //将读取的数据返回
}
/
函数功能:向AT24Cxx的当前地址写入数据
入口参数:y (储存待写入的数据)
/
//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0
void WriteCurrent(unsigned char y)
{
unsigned char i;
for(i = 0; i < 8; i++) // 循环移入8个位
{
SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S
//因为传送时高位在前,低位在后
_nop_(); //等待一个机器周期
SCL = 1; //在SCL的上升沿将数据写入AT24Cxx
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲
y <<= 1; //将y中的各二进位向左移一位
}
}
/
函数功能:向AT24Cxx中的指定地址写入数据
入口参数:add (储存指定的地址);dat(储存待写入的数据)
/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要 *** 作的AT24Cxx芯片,并告知要对其写入数据
Ask();
WriteCurrent(add); //写入指定地址
Ask();
WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据
Ask();
stop(); //停止数据传递
delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上
}
/
函数功能:从AT24Cxx中的当前地址读取数据
出口参数:x (储存读出的数据)
/
unsigned char ReadCurrent()
{
unsigned char x;
start(); //开始数据传递
WriteCurrent(OP_READ); //选择要 *** 作的AT24Cxx芯片,并告知要读其数据
Ask();
x=ReadData(); //将读取的数据存入x
stop(); //停止数据传递
return x; //返回读取的数据
}
/
函数功能:从AT24Cxx中的指定地址读取数据
入口参数:set_addr
出口参数:x
/
unsigned char ReadSet(unsigned char set_addr)
// 在指定地址读取
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要 *** 作的AT24Cxx芯片,并告知要对其写入数据
Ask();
WriteCurrent(set_addr); //写入指定地址
Ask();
return(ReadCurrent()); //从指定地址读出数据并返回
}
//
void LEDshow() //LED显示函数
{
P0=table[sec/10];
shiwei=0;
delaynms(2);
shiwei=1;
P0=table[sec%10];
gewei=0;
delaynms(2);
gewei=1;
}
//
/
函数功能:主函数
/
void main(void)
{
TMOD=0x01; //定时器0工作在方式1
ET0=1;
EA=1;
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //使定时器005秒中断一次
SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态
SCL = 1;
sec=ReadSet(2);//读出保存的数据赋于sec
TR0=1; //开始计时
while(1)
{
LEDshow();
if(write==1) //判断计时器是否计时一秒
{
write=0; //清零
WriteSet(2,sec); //在24c08的地址2中写入数据sec
}
if(K5==0){
delaynms(10);
if(K5==0){
sec=0;
}
}
}
}
//
void t0(void) interrupt 1 using 0 //定时中断服务函数
{
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //重装计数初值
count++; //每过50ms tcnt加一
if(count==20) //计满20次(1秒)时
{
count=0; //重新再计
sec++;
write=1; //1秒写一次24C08
if(sec==100) //定时100秒,在从零开始计时
{sec=0;}
}
}
void respons()
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay();
}
SCL在高电平期间,SDA被从设备拉低标示应答。
while((SDA==1)&&(i<255))标示若一定时间内没收到应答,则默认收到,不再等待,以免从设备无应答时程序永远停在这里。
详细看我空间
//
//LPC2103(主机)与AT24C02(从机)的I2C传输
//功能:将A数组中的n各字节写入AT24C02,再从AT24C02里读回数据到B数组
#include<lpc2103h>
//I2C控制寄存器的相应位:
#define AA 1<<2 //应答位
#define SI 1<<3 //中断标志
#define STO 1<<4 //停止标志
#define STA 1<<5 //起始标志
#define I2EN 1<<6 //I2C使能
#define AT24C02_device_address 0XA0
#define u8 unsigned char
//函数声明
void initialize(void);
void send(u8 device_address,u8 A,u8 memory_address,u8 number);
void start(void);
void start_repeat(void);
void stop(void);
void send_slave_address(u8 device_address);
void send_data(u8 byte);
void receive(u8 device_address,u8 memory_address,u8 B,u8 number);
int receive_data(u8);
void delay(int k);
u8 A[10]={0,1,2,3,4,5,6,7,8,9},B[10]={0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99};
int main()
{
initialize(); //I2C接口初始化
//向器件地址为AT24C02_device_address的器件发送字节,源地址为A,目标地址(AT24C02的数据指针)为0,字节数:10个
send(AT24C02_device_address,A,0,10);
delay(100000); //延时,手册上说两次写间隔至少5ms
//向器件地址为AT24C02_device_address的器件接收字节,源地址(AT24C02的数据指针)为1,目标地址为B,字节数:6个
receive(AT24C02_device_address,1,B,6);
while(1);
}
void initialize() //I2C接口初始化
{
I2C0CONCLR=AA|SI|STA|I2EN; // I2C0CO所有位清0
I2C0CONSET=I2EN; //I2C接口使能
PINSEL0=0X50; //选择P02为SCL0,P03为SDA0
I2C0SCLH=15;
I2C0SCLL=15; //位频率=PCLK/(I2C0SCLH+I2C0SCLL)
}
//向器件地址为device_address的器件发送字节,源地址为A,目标地址为memory_address,字节数:number个
void send(u8 device_address,u8 A,u8 memory_address,u8 number)
{
unsigned char i;
start(); //起始信号
send_slave_address(AT24C02_device_address); //发送器件地址+写
send_data(memory_address); // 发送24C02片内的数据地址
for(i=0;i<number;i++) //发送number个字节
{
send_data(A[i]); //发送字节A[i]
}
stop(); //停止信号
}
void start() //起始信号
{
I2C0CONSET=STA; //发送起始信号
I2C0CONCLR=SI; //中断标志清0
while(I2C0STAT!=0x08); //发送起始信号完毕
I2C0CONCLR=STA; //关闭起始信号
}
void start_repeat() //“重复起始”信号
{
I2C0CONSET=STA; //发送起始信号
I2C0CONCLR=SI; //中断标志清0
while(I2C0STAT!=0x10); //发送“重复起始”信号完毕
I2C0CONCLR=STA; //关闭起始信号
}
void stop() //发送停止信号
{
I2C0CONSET=STO; //发送停止信号
I2C0CONCLR=SI; //中断标志清0
}
void send_slave_address(u8 device_address) //发送器件地址device_address
{
I2C0DAT=device_address; //发送器件地址
I2C0CONCLR=SI; //中断标志清0
if((device_address&0x01)==0)while(I2C0STAT!=0x18); //如果是写 *** 作,等待:发送地址和收到应答
else while(I2C0STAT!=0x40); //如果是读 *** 作,等待:发送地址和收到应答
}
void send_data(u8 byte) //发送一个字节
{
I2C0DAT=byte; //发送一个字节
I2C0CONCLR=SI; //中断标志清0
while(I2C0STAT!=0x28); //等待:发送字节和收到应答
}
//向器件地址为device_address的器件接收字节,源地址为memory_address,目标地址为B,字节数:number个
void receive(u8 device_address,u8 memory_address,u8 B,u8 number)
{
unsigned char i;
start(); //发送起始信号
send_slave_address(device_address); //发送器件地址
send_data(memory_address); //发送器件的片内地址
start_repeat(); //发送“重复起始”信号
send_slave_address(device_address|1); //发送器件地址
for(i=0;i<number;i++) //发送number个字节
{ //将收到的字节放入B数组,i==(number-1)表示是否为最后一个字节
B[i]=receive_data(i==(number-1));
}
stop(); //发送停止信号
}
int receive_data(u8 last) //接收一个字节,发送应答或非应答
{
if(last) //如果是最后一个字节
{
I2C0CONCLR=AA;//发送一个非应答
I2C0CONCLR=SI;//中断标志清0
while(I2C0STAT!=0x58);//等待:接收数据直接和发出非ACK
}
else
{
I2C0CONSET=AA;//发送一个应答位
I2C0CONCLR=SI;//中断标志清0
while(I2C0STAT!=0x50);//等待:接收数据直接和ACK
}
return (I2C0DAT); //返回接收的字节
}
void delay(int k) //延时
{ while(k--);}
//
//实例85:将数据"0x0f"写入AT24C02再读出送P1口显示
#include <reg51h> // 包含51单片机寄存器定义的头文件
#include <intrinsh> //包含_nop_()函数定义的头文件
#define OP_READ 0xa1 // 器件地址以及读取 *** 作,0xa1即为1010 0001B
#define OP_WRITE 0xa0 // 器件地址以及写入 *** 作,0xa1即为1010 0000B
sbit SDA=P3^4; //将串行数据总线SDA位定义在为P34引脚
sbit SCL=P3^3; //将串行时钟总线SDA位定义在为P33引脚
/
函数功能:延时1ms
(3j+2)i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/
函数功能:延时若干毫秒
入口参数:n
/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/
函数功能:开始数据传送
/
void start()
// 开始位
{
SDA = 1; //SDA初始化为高电平“1”
SCL = 1; //开始数据传送时,要求SCL为高电平“1”
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA = 0; //SDA的下降沿被认为是开始信号
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
}
/
函数功能:结束数据传送
/
void stop()
// 停止位
{
SDA = 0; //SDA初始化为低电平“0” _n
SCL = 1; //结束数据传送时,要求SCL为高电平“1”
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA = 1; //SDA的上升沿被认为是结束信号
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA=0;
SCL=0;
}
/
函数功能:从AT24Cxx读取数据
出口参数:x
/
unsigned char ReadData()
// 从AT24Cxx移入数据到MCU
{
unsigned char i;
unsigned char x; //储存从AT24Cxx中读出的数据
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL置为高电平
x<<=1; //将x中的各二进位向左移一位
x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中
SCL = 0; //在SCL的下降沿读出数据
}
return(x); //将读取的数据返回
}
/
函数功能:向AT24Cxx的当前地址写入数据
入口参数:y (储存待写入的数据)
/
//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0
bit WriteCurrent(unsigned char y)
{
unsigned char i;
bit ack_bit; //储存应答位
for(i = 0; i < 8; i++) // 循环移入8个位
{
SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S
//因为传送时高位在前,低位在后
_nop_(); //等待一个机器周期
SCL = 1; //在SCL的上升沿将数据写入AT24Cxx
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲
y <<= 1; //将y中的各二进位向左移一位
}
SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,
//以让SDA线转由接收设备(AT24Cxx)控制
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 1; //根据上述规定,SCL应为高电平
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节
//若送高电平,表示没有接收到,传送异常
SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
return ack_bit; // 返回AT24Cxx应答位
}
/
函数功能:向AT24Cxx中的指定地址写入数据
入口参数:add (储存指定的地址);dat(储存待写入的数据)
/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要 *** 作的AT24Cxx芯片,并告知要对其写入数据
WriteCurrent(add); //写入指定地址
WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据
stop(); //停止数据传递
delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上
}
/
函数功能:从AT24Cxx中的当前地址读取数据
出口参数:x (储存读出的数据)
/
unsigned char ReadCurrent()
{
unsigned char x;
start(); //开始数据传递
WriteCurrent(OP_READ); //选择要 *** 作的AT24Cxx芯片,并告知要读其数据
x=ReadData(); //将读取的数据存入x
stop(); //停止数据传递
return x; //返回读取的数据
}
/
函数功能:从AT24Cxx中的指定地址读取数据
入口参数:set_addr
出口参数:x
/
unsigned char ReadSet(unsigned char set_addr)
// 在指定地址读取
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要 *** 作的AT24Cxx芯片,并告知要对其写入数据
WriteCurrent(set_addr); //写入指定地址
return(ReadCurrent()); //从指定地址读出数据并返回
}
/
函数功能:主函数
/
main(void)
{
SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态
SCL = 1;
WriteSet(0x36,0x0f); //在指定地址“0x36”中写入数据“0x0f”
P1=ReadSet(0x36); //从指定地址“0x36中读取数据并送P1口显示
}
以上就是关于请问I2C总线的驱动程序 要学会自己写嘛 还是平时写的时候只要复制过来,拿来用就可以 求指教啊!!!全部的内容,包括:请问I2C总线的驱动程序 要学会自己写嘛 还是平时写的时候只要复制过来,拿来用就可以 求指教啊!!!、求:51单片机模拟i2c总线程序、I2C的应答子程序如何使用,单片机从外部器件读取数据后,该怎么进行应答 *** 作,这个子程序是否要返回值等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)