请问I2C总线的驱动程序 要学会自己写嘛 还是平时写的时候只要复制过来,拿来用就可以 求指教啊!!!

请问I2C总线的驱动程序 要学会自己写嘛 还是平时写的时候只要复制过来,拿来用就可以 求指教啊!!!,第1张

如果你学单片机的哈,肯定是要学会自己写的,最起码你要能把别人的程序能调通,能通信,而且不同单片机的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_(); //等待一个机器周期

_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的应答子程序如何使用,单片机从外部器件读取数据后,该怎么进行应答 *** 作,这个子程序是否要返回值等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9482229.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-28
下一篇 2023-04-28

发表评论

登录后才能评论

评论列表(0条)

保存