当前位置:首页 > 单片机 > 单片机
[导读]/******************************************************************************************************************************************///总结: SCL为高电平时, SDA上的数据才有效// 传输数据 SCL = 1;

/*
********************************************************************
********************************************************************
*/

//总结: SCL为高电平时, SDA上的数据才有效
// 传输数据 SCL = 1; SDA = 1 或 SDA = 0 要求是稳定的数据
// 启动信号 SCL = 1; SDA = 1 ---> 0
// 停止信号 SCL = 1; SDA = 0 ---> 1
// 主要用proteus调试查看每次总线上的数据
// 主要调试i2cstar() 以及i2cstop()这两个函数, 只要这两个函数正确,一般就正确了。

//
//关于地址的说明
// 无论是写入还是读出,被操作器件容量在256字节以内时,一个字节(8位)的寻址范围即可满足要求。当容量为512字节
// (2页). 1k字节(4页)和2k字节(8页)时,采用占用器件引脚地址(A2,A1,A0)的办法,将引脚地址做为页地址(占用的引脚地址线悬空).
// 当容量在4K字节以上时,存储单元地址字节将用两个字节表示(高8位在前)
//


/* 应用例子
void main( void )
{
uchar ReadBuf[6];
LCD_init();
LCD_write_string( 1, 3, " I2C test " ); //测度液晶


I2cWriteDataToAddr( 0xa0, 0x0007, 'h' ); //在器件地址为0xa0的IIC器件上的0x0007这个地址写入'h'这个字符
I2cWriteDataToAddr( 0xa0, 0x0008, 'e' );
I2cWriteDataToAddr( 0xae, 0x0007, 'b' );
I2cWriteDataToAddr( 0xae, 0x0008, 'e' );
I2cWriteDataToAddr( 0xae, 0x0009, 'i' ); //器件地址 0xae, 字节地址 0x0009, 写入 'i'

LCD_write_char( 2, 1, I2cReadDataFromAddr( 0xa0, 0x0007 ) ); //把器件地址为0xa0的0x0007这个地址上的字节数据读出来
LCD_write_char( 2, 2, I2cReadDataFromAddr( 0xa0, 0x0008 ) );
LCD_write_char( 2, 3, I2cReadDataFromAddr( 0xae, 0x0007 ) );
LCD_write_char( 2, 4, I2cReadDataFromAddr( 0xae, 0x0008 ) );
LCD_write_char( 2, 5, I2cReadDataFromAddr( 0xae, 0x0009 ) );

I2c_Write_n( 0xa0, 0x0001, "0123456789", 10 ); //连续写10个字节
LCD_write_char( 2, 0, I2cReadDataFromAddr( 0xa0, 0x0001 ) );
LCD_write_char( 2, 1, I2cReadDataFromAddr( 0xa0, 0x0002 ) );
LCD_write_char( 2, 2, I2cReadDataFromAddr( 0xa0, 0x0003 ) );
LCD_write_char( 2, 3, I2cReadDataFromAddr( 0xa0, 0x0004 ) );
LCD_write_char( 2, 4, I2cReadDataFromAddr( 0xa0, 0x0005 ) );
LCD_write_char( 2, 5, I2cReadDataFromAddr( 0xa0, 0x0006 ) );
LCD_write_char( 2, 6, I2cReadDataFromAddr( 0xa0, 0x0007 ) );
LCD_write_char( 2, 7, I2cReadDataFromAddr( 0xa0, 0x0008 ) );
LCD_write_char( 2, 8, I2cReadDataFromAddr( 0xa0, 0x0009 ) );
LCD_write_char( 2, 9, I2cReadDataFromAddr( 0xa0, 0x000a ) );

I2c_Read_n( 0xa0, 0x0002, ReadBuf, 5 ); //连续读5个字节
LCD_write_array( 1, 4, ReadBuf );

while( 1 );
}
*/


#ifndef _24C64_H_
#define _24C64_H_

#include
#include

//数据类型说明
#define uchar unsigned char
#define uint unsigned int


//5us延时宏定义
#define NOP_5 _nop_(); _nop_(); _nop_(); _nop_(); _nop_();


//管脚连接信息
#define SCL P3_6
#define SDA P3_7

//定义读出数据缓冲区
//#define I2CSIZE 16 //定义16个字节 尽量不要太大,节省空间
//uchar xdata I2cBuffer[I2CSIZE];

//注意,在写函数中加入了5ms延时,如果晶振有变,则适当修改。
void delay_5ms();

//IIC函数
void I2cStart( void );//启动
void I2cStop( void );//终止
uchar WaitAsk( void );//等待应答
void SendAsk( void );//发送应答
void SendNoAsk( void );//发送非应答
void I2cWriteByte( uchar wbyte );//写字节
void I2cWriteDataToAddr( uchar DeviceAddress, uint ByteAddress, uchar Wdata );//写字节到某地址
uchar I2cReadByte( void );//读字节
uchar I2cReadDataFromAddr( uchar DeviceAddress, uint ByteAddress );//从某器件读字节
void I2c_Write_n( uchar DeviceAddress, uint ByteAddress, uchar *Wdata, uchar n );//写n个
void I2c_Read_n( uchar DeviceAddress, uint ByteAddress, uchar *rdatabuf, uchar n );//读n个

#endif // <24c64.h>


#define _24c64_c_
#include "24c64.h"

/*
********************************************************************
** 函数名:5ms延时函数
** 注意 :
** 说明 :
**
********************************************************************
*/
void delay_5ms( void )
{
uchar i;
uchar j;
uchar t;
for( t = 0; t < 10; t++ )
{
for( j = 0; j < 15; j ++ )
{
for( i = 0; i < 21; i++ )
{;}
}
}
}

/*
********************************************************************
** 函数名:i2c启动
** 注意 :
** 说明 :
********************************************************************
*/
void I2cStart( void )
{
//scl=1时
//sda由1-->0
SDA = 1; //准备下降沿
SCL = 1;
NOP_5;
SDA = 0;
NOP_5;

SCL = 0; //一定要
//SDA = 0;
}

/*
********************************************************************
** 函数名:i2c停止
** 注意 :
** 说明 :
********************************************************************
*/
void I2cStop( void )
{
//scl=1时
//sda由0-->1
SDA = 0; //准备上升沿
SCL = 1;
NOP_5;
SDA = 1;
NOP_5;

//SCL = 0; //本来书上说要此句,但发觉加入后仿真不正确...
//SDA = 0;
}

/*
********************************************************************
** 函数名:查询应答信号
** 注意 :
** 说明 :如果有应答返回 1
********************************************************************
*/
uchar WaitAsk( void )
{
uchar askflag = 0;

SDA = 1; //SDA置为输入

SCL = 1;
NOP_5; //5us后检测

if( SDA == 0 ) //检测sda线
askflag = 1; //有应答返回 1 表示成功

SCL = 0;

return askflag;
}

/*
********************************************************************
** 函数名:发送应答信号
** 注意 :
** 说明 :SCL = 1 , SDA = 0;
********************************************************************
*/
void SendAsk( void )
{
SDA = 0;

SCL = 1;
NOP_5;
SCL = 0; //在scl为高时,sda为0

SDA = 1;
}

/*
********************************************************************
** 函数名:发送非应答信号
** 注意 :
** 说明 :SCL = 1 , SDA = 1
********************************************************************
*/
void SendNoAsk( void )
{
SDA = 1;

SCL = 1;
NOP_5;
SCL = 0; //在scl为高时, sda为1

SDA = 0;
}

/*
********************************************************************
** 函数名 :写一个字节数据
** 入口参数: 字节数据wbyte
** 注意 :
** 说明 :可以用来写地址字节,也可以用来写数据字节
********************************************************************
*/
void I2cWriteByte( uchar wbyte )
{
uchar i;
for(i = 0; i < 8; i++ )
{
if( ( wbyte & 0x80 ) == 0x80 ) //!!!! 先发送高位,再发送低位.., 在数据传输时一定要注意此处细节
SDA = 1;
else
SDA = 0; //因为数据传输时要保持数据稳定, 因此要先准备好SDA上的数据才能进行SCL的变化

SCL = 1;
NOP_5;
SCL = 0;

wbyte = wbyte << 1;
}
}

/*
********************************************************************
** 函数名 :写一个字节数据到某器件某地址
** 入口参数: 器件地址DeviceAddress 字节地址ByteAddress 要写的字节数据Wdata
** 注意 :里面加有5ms延时。
** 说明 :I2cWriteDataToAddr( 0xa0, 0x08, 'a' );
********************************************************************
*/
void I2cWriteDataToAddr( uchar DeviceAddress, uint ByteAddress, uchar Wdata )
{
I2cStart();
I2cWriteByte( DeviceAddress );
WaitAsk(); //等待应答
I2cWriteByte( ByteAddress >> 8 ); //高8位
WaitAsk();
I2cWriteByte( ByteAddress ); //低8位
WaitAsk();
I2cWriteByte( Wdata );
WaitAsk();
I2cStop();

delay_5ms(); //发觉这里要加一小段延时,如果不加,则可以在外面加。
}

/*
********************************************************************
** 函数名 :读一个字节数据
** 入口参数: 无
** 注意 :
** 说明 :
********************************************************************
*/
uchar I2cReadByte( void )
{
uchar rbyte = 0;
uchar i = 0;
for(i = 0; i < 8; i++ )
{
rbyte = rbyte << 1; //非常注意...此语句不放在循环体内最后.

SDA = 1; //SDA为输入

SCL = 1;
NOP_5;

if( SDA == 1 )
rbyte = rbyte | 0x01;

SCL = 0;
}

return rbyte;
}


/*
********************************************************************
** 函数名 :写一个字节数据到某器件某地址
** 入口参数: 器件地址DeviceAddress 字节地址ByteAddress
** 出口参数: 读到的字节数据rdata
** 注意 :
** 说明 :I2cWriteDataToAddr( 0xa0, 0x08, 'a' );
********************************************************************
*/
uchar I2cReadDataFromAddr( uchar DeviceAddress, uint ByteAddress )
{
uchar rdata;

I2cStart();
I2cWriteByte( DeviceAddress );
WaitAsk(); //等待应答
I2cWriteByte( ByteAddress >> 8 ); //高8位
WaitAsk();
I2cWriteByte( ByteAddress ); //低8位
WaitAsk();

I2cStart();
I2cWriteByte( DeviceAddress | 0x01 ); //读
WaitAsk();
rdata = I2cReadByte();
SendNoAsk(); //不发送应答信号
I2cStop();

return rdata;
}

/*
********************************************************************
** 函数名 :连续写字节数据到某器件某地址之后的好几个单元
** 入口参数: 器件地址DeviceAddress 字节地址ByteAddress 要写的字节数据取址*Wdata 字节数据的个数n
** 注意 :里面加有5ms延时。
** 说明 :I2cWriteDataToAddr( 0xa0, 0x08, "hebei is a big pig!", 20 );
********************************************************************
*/
void I2c_Write_n( uchar DeviceAddress, uint ByteAddress, uchar *Wdata, uchar n )
{
uchar i = 0;
I2cStart();
I2cWriteByte( DeviceAddress );
WaitAsk(); //等待应答
I2cWriteByte( ByteAddress >> 8 ); //高8位
WaitAsk();
I2cWriteByte( ByteAddress ); //低8位
WaitAsk();

for( i = 0; i < n; i++ )
{
I2cWriteByte( *Wdata );
WaitAsk();
Wdata++;
}

I2cStop();

delay_5ms(); //发觉这里要加一小段延时,如果不加,则可以在外面加。
}

/*
********************************************************************
** 函数名 :写一个字节数据到某器件某地址
** 入口参数: 器件地址DeviceAddress 字节地址ByteAddress
** 出口参数: 读到的字节数据rdata
** 注意 :
** 说明 :I2c_Read_n( 0xa0, 0x0003, a, 10 ) //uchar a[10];
********************************************************************
*/
void I2c_Read_n( uchar DeviceAddress, uint ByteAddress, uchar *rdatabuf, uchar n )
{
uchar i = 0;

I2cStart(); //启动总线
I2cWriteByte( DeviceAddress );
WaitAsk(); //等待应答
I2cWriteByte( ByteAddress >> 8 ); //高8位
WaitAsk();
I2cWriteByte( ByteAddress ); //低8位
WaitAsk();

I2cStart();//重新启动
I2cWriteByte( DeviceAddress | 0x01 ); //读
WaitAsk();

for( i = 0; i < n; i++ )
{
*rdatabuf = I2cReadByte();
SendAsk(); //连续发送应答信号
rdatabuf++;
}

I2cStop();
}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

USB摄像头是一种采用USB接口的视频采集设备,其优点在于即插即用、操作简便,无需额外驱动程序,支持笔记本电脑,并且成本较低,可以支持远程网络观看。

关键字: usb摄像头 驱动程序

与两相双极步进电机的驱动电路相比,两相单极步进电机的驱动电路在输入段配置、内部逻辑及控制电路和驱动电路使用双通道方面基本相同,但是输出段的配置不同。

关键字: 四相步进电机 驱动程序 程序电路

本文介绍了如何实现嵌入式MICREL网卡的驱动程序开发和设计。首先,我们介绍了MICREL网卡的概述和工作原理。然后,详细探讨了驱动程序的开发流程,包括硬件和软件的配置以及驱动程序的编写和测试。最后,总结了几点注意事项和...

关键字: 嵌入式 MICREL网卡 驱动程序

在这篇文章中,小编将对OLED的相关内容和情况加以介绍以帮助大家增进对它的了解程度,和小编一起来阅读以下内容吧。

关键字: OLED 驱动程序 无源驱动

近日,英特尔发布了锐炫显卡的新版驱动更新。本次驱动更新涵盖了锐炫A770、A750、A380以及移动端的锐炫GPU,这使得英特尔锐炫整个家族的DX9性能都实现了显著提升。

关键字: 英特尔 显卡 驱动程序

摘 要:从硬件与软件方面介绍了基于PXI技术的1553B总线通讯模块的设计,并对PXI总线接口设计、驱动程序的开发、 SDRAM存储器的控制和1553B总线通信协议实现等关键技术进行了详细的阐述,为航空领域测控系统开发P...

关键字: PXI技术 驱动程序 SDRAM存储器 1553B总线

PnP全称Plug-and-Play,译文为即插即用。PnP的作用是自动配置低层计算机中的板卡和其他设备,然后告诉对应设备都做了什么。PnP的任务是把物理设备和软件设备驱动程序相配合,并操作设备,在每个设备和它的驱动程序...

关键字: PnP 驱动程序 操作设备

作 者:道哥,10年嵌入式开发老兵,专注于:C/C、嵌入式、Linux。关注下方公众号,回复【书籍】,获取Linux、嵌入式领域经典书籍;回复【PDF】,获取所有原创文章(PDF格式)。目录kill命令和信号使用kill...

关键字: 信号 应用程序 驱动程序

驱动程序本质上是软件代码,主要作用是计算机系统与硬件设备之间完成数据传送的功能,只有借助驱动程序,两者才能通信并完成特定的功能。

关键字: 驱动程序 硬件设备 UNIX

驱动程序(Device Driver)全称为“设备驱动程序”,是一种可以使计算机和设备通信的特殊程序,可以说相当于硬件的接口,操作系统只能通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常...

关键字: 驱动程序 声卡 设备
关闭
关闭