Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1064734
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-04 16:56:32

 

I2C总线时序模拟(二)-加深理解总线协议

 152人阅读 评论(0)  举报
 分类:
IIC总线(9) 51单片机(2) 
  1. /******************************************************************** 
  2. 此程序是I2C操作平台(主方式的软件平台)的底层的C子程序,如发送数据 
  3. 及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,它很方便的 
  4. 与用户程序连接并扩展.....   
  5.    
  6.     注意:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作  
  7. 一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ) 
  8. ********************************************************************/                  
  9. #include           /*头文件的包含*/  
  10. #include   
  11.   
  12. #define  uchar unsigned char /*宏定义*/  
  13. #define  uint  unsigned int  
  14.   
  15. #define  _Nop()  _nop_()        /*定义空指令*/  
  16.   
  17. /* 常,变量定义区 */  
  18.    
  19.                                                  /*端口位定义*/  
  20. sbit SDA=P1^3;            /*模拟I2C数据传送位*/  
  21. sbit SCL=P1^2;            /*模拟I2C时钟控制位*/  
  22.   
  23.                                                  /*状态标志*/  
  24. bit ack;             /*应答标志位*/  
  25.      
  26.   
  27. /******************************************************************* 
  28.                      起动总线函数                
  29. 函数原型: void  Start_I2c();   
  30. 功能:       启动I2C总线,即发送I2C起始条件. 
  31.    
  32. ********************************************************************/  
  33. void Start_I2c()  
  34. {  
  35.   SDA=1;   /*发送起始条件的数据信号*/  
  36.   _Nop();  
  37.   SCL=1;  
  38.   _Nop();    /*起始条件建立时间大于4.7us,延时*/  
  39.   _Nop();  
  40.   _Nop();  
  41.   _Nop();  
  42.   _Nop();      
  43.   SDA=0;   /*发送起始信号*/  
  44.   _Nop();    /* 起始条件锁定时间大于4μs*/  
  45.   _Nop();  
  46.   _Nop();  
  47.   _Nop();  
  48.   _Nop();         
  49.   SCL=0;   /*钳住I2C总线,准备发送或接收数据 */  
  50.   _Nop();  
  51.   _Nop();  
  52. }  
  53.   
  54. /******************************************************************* 
  55.                       结束总线函数                
  56. 函数原型: void  Stop_I2c();   
  57. 功能:       结束I2C总线,即发送I2C结束条件. 
  58.    
  59. ********************************************************************/  
  60. void Stop_I2c()  
  61. {  
  62.   SDA=0;  /*发送结束条件的数据信号*/  
  63.   _Nop();   /*发送结束条件的时钟信号*/  
  64.   SCL=1;  /*结束条件建立时间大于4μs*/  
  65.   _Nop();  
  66.   _Nop();  
  67.   _Nop();  
  68.   _Nop();  
  69.   _Nop();  
  70.   SDA=1;  /*发送I2C总线结束信号*/  
  71.   _Nop();  
  72.   _Nop();  
  73.   _Nop();  
  74.   _Nop();  
  75. }  
  76.   
  77. /******************************************************************* 
  78.                  字节数据传送函数                
  79. 函数原型: void  SendByte(uchar c); 
  80. 功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 
  81.      此状态位进行操作.(不应答或非应答都使ack=0 假)      
  82.      发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 
  83. ********************************************************************/  
  84. void  SendByte(uchar c)  
  85. {  
  86.  uchar BitCnt;  
  87.    
  88.  for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/  
  89.     {  
  90.      if((c</*判断发送位*/  
  91.        else  SDA=0;                  
  92.      _Nop();  
  93.      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/  
  94.       _Nop();   
  95.       _Nop();               /*保证时钟高电平周期大于4μs*/  
  96.       _Nop();  
  97.       _Nop();  
  98.       _Nop();           
  99.      SCL=0;   
  100.     }  
  101.       
  102.     _Nop();  
  103.     _Nop();  
  104.     SDA=1;               /*8位发送完后释放数据线,准备接收应答位*/  
  105.     _Nop();  
  106.     _Nop();     
  107.     SCL=1;  
  108.     _Nop();  
  109.     _Nop();  
  110.     _Nop();  
  111.     if(SDA==1)ack=0;       
  112.        else ack=1;        /*判断是否接收到应答信号*/  
  113.     SCL=0;  
  114.     _Nop();  
  115.     _Nop();  
  116. }  
  117.   
  118. /******************************************************************* 
  119.                  字节数据传送函数                
  120. 函数原型: uchar  RcvByte(); 
  121. 功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号), 
  122.      发完后请用应答函数。   
  123. ********************************************************************/     
  124. uchar  RcvByte()  
  125. {  
  126.   uchar retc;  
  127.   uchar BitCnt;  
  128.     
  129.   retc=0;   
  130.   SDA=1;             /*置数据线为输入方式*/  
  131.   for(BitCnt=0;BitCnt<8;BitCnt++)  
  132.       {  
  133.         _Nop();             
  134.         SCL=0;       /*置时钟线为低,准备接收数据位*/  
  135.         _Nop();  
  136.         _Nop();         /*时钟低电平周期大于4.7μs*/  
  137.         _Nop();  
  138.         _Nop();  
  139.         _Nop();  
  140.         SCL=1;       /*置时钟线为高使数据线上数据有效*/  
  141.         _Nop();  
  142.         _Nop();  
  143.         retc=retc<<1;  
  144.         if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */  
  145.         _Nop();  
  146.         _Nop();   
  147.       }  
  148.   SCL=0;      
  149.   _Nop();  
  150.   _Nop();  
  151.   return(retc);  
  152. }  
  153.   
  154. /******************************************************************** 
  155.                      应答子函数 
  156. 原型:  void Ack_I2c(bit a); 
  157.   
  158. 功能:主控器进行应答信号,(可以是应答或非应答信号) 
  159. ********************************************************************/  
  160. void Ack_I2c(bit a)  
  161. {  
  162.     
  163.   if(a==0)SDA=0;     /*在此发出应答或非应答信号 */  
  164.         else SDA=1;  
  165.   _Nop();  
  166.   _Nop();  
  167.   _Nop();        
  168.   SCL=1;  
  169.     _Nop();  
  170.     _Nop();              /*时钟低电平周期大于4μs*/  
  171.     _Nop();  
  172.     _Nop();  
  173.     _Nop();    
  174.  SCL=0;                /*清时钟线,钳住I2C总线以便继续接收*/  
  175.     _Nop();  
  176.     _Nop();      
  177. }  
  178.   
  179. /******************************************************************* 
  180.                     向无子地址器件发送字节数据函数                
  181. 函数原型: bit  ISendByte(uchar sla,ucahr c);   
  182. 功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla. 
  183.            如果返回1表示操作成功,否则操作有误。 
  184. 注意:    使用前必须已结束总线。 
  185. ********************************************************************/  
  186. bit ISendByte(uchar sla,uchar c)  
  187. {  
  188.    Start_I2c();               /*启动总线*/  
  189.    SendByte(sla);            /*发送器件地址*/  
  190.      if(ack==0)return(0);  
  191.    SendByte(c);               /*发送数据*/  
  192.      if(ack==0)return(0);  
  193.   Stop_I2c();                 /*结束总线*/   
  194.   return(1);  
  195. }  
  196.   
  197. /******************************************************************* 
  198.                     向有子地址器件发送多字节数据函数                
  199. 函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);   
  200. 功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 
  201.           地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 
  202.            如果返回1表示操作成功,否则操作有误。 
  203. 注意:    使用前必须已结束总线。 
  204. ********************************************************************/  
  205. bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)  
  206. {  
  207.    uchar i;  
  208.   
  209.    Start_I2c();               /*启动总线*/  
  210.    SendByte(sla);            /*发送器件地址*/  
  211.      if(ack==0)return(0);  
  212.    SendByte(suba);            /*发送器件子地址*/  
  213.      if(ack==0)return(0);  
  214.   
  215.    for(i=0;i
  216.     {     
  217.      SendByte(*s);               /*发送数据*/  
  218.        if(ack==0)return(0);  
  219.      s++;  
  220.     }   
  221.  Stop_I2c();                 /*结束总线*/   
  222.   return(1);  
  223. }  
  224. /******************************************************************* 
  225.                     向无子地址器件读字节数据函数                
  226. 函数原型: bit  IRcvByte(uchar sla,ucahr *c);   
  227. 功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地 
  228.           址sla,返回值在c. 
  229.            如果返回1表示操作成功,否则操作有误。 
  230. 注意:    使用前必须已结束总线。 
  231. ********************************************************************/  
  232. bit IRcvByte(uchar sla,uchar *c)  
  233. {  
  234.    Start_I2c();                /*启动总线*/  
  235.    SendByte(sla+1);           /*发送器件地址*/  
  236.      if(ack==0)return(0);  
  237.    *c=RcvByte();               /*读取数据*/  
  238.      Ack_I2c(1);               /*发送非就答位*/  
  239.   Stop_I2c();                  /*结束总线*/   
  240.   return(1);  
  241. }  
  242.   
  243. /******************************************************************* 
  244.                     向有子地址器件读取多字节数据函数                
  245. 函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);   
  246. 功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 
  247.           地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 
  248.            如果返回1表示操作成功,否则操作有误。 
  249. 注意:    使用前必须已结束总线。 
  250. ********************************************************************/  
  251. bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)  
  252. {  
  253.    uchar i;  
  254.   
  255.    Start_I2c();               /*启动总线*/  
  256.    SendByte(sla);            /*发送器件地址*/  
  257.      if(ack==0)return(0);  
  258.    SendByte(suba);            /*发送器件子地址*/  
  259.      if(ack==0)return(0);  
  260.   
  261.    Start_I2c();  
  262.    SendByte(sla+1);  
  263.       if(ack==0)return(0);  
  264.   
  265.    for(i=0;i
  266.     {     
  267.      *s=RcvByte();               /*发送数据*/  
  268.       Ack_I2c(0);                /*发送就答位*/    
  269.      s++;  
  270.     }   
  271.    *s=RcvByte();  
  272.     Ack_I2c(1);                 /*发送非应位*/  
  273.  Stop_I2c();                    /*结束总线*/   
  274.   return(1);  
  275. }  
  276.                         /*    完毕      */  
阅读(498) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~