原创 I2C总线的模拟

2009-5-26 21:20 3339 6 9 分类: MCU/ 嵌入式

        I2C总线在很多器件中都有应用,如串行A/D器件I2C通信应用是比较成熟的,还有一些存储芯片也用到I2C总线通信,如AT24Cxx等,学单片机不学这些东西好像有点说不过,在一些比51高一点的单片机中有专门的I2C通信寄存器,在这些单片机中只需要对这些相应的寄存器作一些设置就可以直接使用了就如51单片机中的异步串行通信一样,只有做一些设置就可以使用了。但在51单片机中没有I2C寄存器,若想使用带有I2C总线的器件那就用51的I/O模拟相应的通信时序了。这样就可以使用带有这些通信协议的器件了!


        想要模拟这个总线协会得先看懂这些通信协议的时序图,这对写程序来说十分的重要,时序看错了也就不能正确进行通信了下面是IIC总线的相关说明


         I<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。IIC的起始信号与终止信号的时序图



起始和终止信号 SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


数据传送格式1)字节传送与应答


每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。



下面的程序的对ATC04的读写


#include<AT89X52.H>
#include"delay.h"
#define uint  unsigned int
#define uchar unsigned char
#define DADDr 0xa0
#define WRITE 0x00
#define READ  0x01
//#define IO P1
//********************************************///
///*******************************************///
///************各个功能定义*******************///
//char dis[]={0x00};
#define SCL P0_0
#define SDA P0_1


/********************************/
/*函数名称:start()             */
/*函数功能:起始信号函数        */
/*参    数:无                  */
/*返    回:无                  */
/*备    注:SCL线为高电平期间   */
/*          SDA线由高电平向低电 */
/*          平的变化表示起始信号*/
/********************************/
void start(void)
{
    SCL="0"; delay2us(2);
 SDA=1; delay2us(2);
    SCL="1"; delay2us(2);
    SDA="0"; delay2us(2);
}


/********************************/
/*函数名称:stop()              */
/*函数功能:结束信号函数        */
/*参    数:无                  */
/*返    回:无                  */
/*备    注:SCL线为高电平期间   */
/*          SDA线由低电平向高电 */
/*          平的变化表示终止信号*/
/********************************/
void stop(void)              
{
    SCL="0"; delay2us(5);
 SDA=0; delay2us(2);
    SCL="1"; delay2us(2);
    SDA="1"; delay2us(2);
}


/********************************/
/*函数名称:DEVICE_ack_HOST()   */
/*函数功能:应答信号函数        */
/*参    数:无                  */
/*返    回:无                  */
/*备    注:从器件对MCU的应答   */
/********************************/
void DEVICE_ack_HOST(void)            
{
 SCL=0;delay2us(2);
 SDA=1;delay2us(2);
 SCL=1;delay2us(2);
}


/********************************/
/*函数名称:HOST_ack_DEVICE()   */
/*函数功能:反向应答信号函数    */
/*参    数:无                  */
/*返    回:无                  */
/*备    注:MCU对从器件的应答   */
/********************************/
void HOST_ack_DEVICE(void)
{
 SCL=0;
 SDA=0;delay2us(2);
 SCL=1;delay2us(2);
}


/********************************/
/*函数名称:shift8()            */
/*函数功能:八位字节移出函数    */
/*参    数:date 移出的数据     */
/*返    回:无                  */
/*备    注:无                  */
/********************************/
void shift8(char date)       
{
    uchar i;
    for(i=0;i<8;i++)
    {
        SCL="0";
        delay2us(5);
  if((date&0x80)==0x80)
   SDA=1;
  else
   SDA=0;
        SCL="1";
  delay2us(5);
  date<<=1;
    }
}


/********************************/
/*函数名称:HOST_re_b_DEVICE()  */
/*函数功能:主机接从器件一个字节*/
/*参    数:无                  */
/*返    回:rdata 返回的字节    */
/*备    注:无                  */
/********************************/
char revice_byte(void)
{
 uchar i="8";
 char rdata;
 while(i--)
 {
     SCL="0";
  rdata=(rdata<<1)|SDA;
        delayms(1);
        SCL="1";
  delayms(1);
 }
 return(rdata);
}
/********************************/
/*函数名称:WR_IIC_Byte()       */
/*函数功能:对IIC写单个字节     */
/*参    数:address 数据地址    */
/*          dat 要写入的数据    */
/*返    回:无                  */
/*备    注:无                  */
/********************************/
void WR_IIC_Byte(uchar address,char dat)
{
    start();
    shift8(DADDr|WRITE);
    DEVICE_ack_HOST();
    shift8(address);
    DEVICE_ack_HOST();
    shift8(dat);
    DEVICE_ack_HOST();
    stop();
}


/********************************/
/*函数名称:WR_IIC_Page()       */
/*函数功能:对IIC页写数据       */
/*参    数:n 要写入的字节数    */
/*          waddress 要写入的数 */
/*          据的首地址          */
/*          word 要写入的数据   */
/*返    回:无                  */
/*备    注:无                  */
/********************************/
void WR_IIC_Page(uchar n,uchar waddress,char *word)
{
 start();
 shift8(DADDr|WRITE);
 DEVICE_ack_HOST();
 shift8(waddress);
 DEVICE_ack_HOST();
 while(n--)
 {
  shift8(*word++);
  DEVICE_ack_HOST();
 }
 stop();
}
/********************************/
/*函数名称:RD_IIC_Current()    */
/*函数功能:读当地址数据        */
/*参    数:无                  */
/*返    回:rdat 要读回的数据   */
/*备    注:无                  */
/********************************/
char RD_IIC_Current()
{
 char rdat;
 start();
 shift8(DADDr|READ);
 DEVICE_ack_HOST();
 rdat=revice_byte();
// HOST_ack_DEVICE();
 stop();
 return rdat;
}
/********************************/
/*函数名称:RD_IIC_Random()     */
/*函数功能:读随机地址数据      */
/*参    数:无                  */
/*返    回:rdat 要读回的数据   */
/*备    注:无                  */
/********************************/
char RD_IIC_Random(uchar waddress)
{
 char rdat;
 start();
 shift8(DADDr|WRITE);
 DEVICE_ack_HOST();
 shift8(waddress);
 DEVICE_ack_HOST();
 rdat=RD_IIC_Current();
 return rdat;
}
/********************************/
/*函数名称:RD_IIC_Sequential() */
/*函数功能:连续读取数据        */
/*参    数:n 连续读回的字节数  */
/*          waddress 首地址     */
/*返    回:rdat 要读回的数据   */
/*备    注:无                  */
/********************************/
char* RD_IIC_Sequential(uchar n,uchar waddress)
{
 char *rdat;
 start();
 shift8(DADDr|WRITE);
 DEVICE_ack_HOST();
 shift8(waddress);
 DEVICE_ack_HOST();
 start();
 shift8(DADDr|READ);
 while(n--)
 {
  (*rdat++)=revice_byte();
  HOST_ack_DEVICE();
 }
 stop();
 return rdat;
}


 


pdf

PARTNER CONTENT

文章评论3条评论)

登录后参与讨论

用户1414082 2009-5-30 21:01

赞~

用户545094 2009-5-29 22:48

不错

用户222665 2009-5-29 08:52

看过
相关推荐阅读
用户171506 2009-05-24 22:26
4X4矩阵键盘程序
        4x4键盘的程序有扫描法与线反法,但我个人认为用线反法较好,用扫描法得依次扫描所有行或列,如果用线反法就简单多了。先使键盘的行置为低、列置为高(或列置为高、行置为低),接着读回端口的值...
用户171506 2009-05-22 21:55
51单片机定时器使用
传统51单片机的资源并不多,算起来有这么几样:四组I/O口,一个异步串行通信UART,两个定时/计数器(T0、T1)还有5个相应的中断。        MCS—51子系列单片机有2个定时器/计数器,即...
EE直播间
更多
我要评论
3
6
关闭 站长推荐上一条 /3 下一条