×
嵌入式 > 技术百科 > 详情

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

发布时间:2020-05-28 发布时间:
|
[cpp] view plain copy
 
 print?
  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. ;   /*判断发送位*/  
  92.        else  SDA=0;                  
  93.      _Nop();  
  94.      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/  
  95.       _Nop();   
  96.       _Nop();               /*保证时钟高电平周期大于4μs*/  
  97.       _Nop();  
  98.       _Nop();  
  99.       _Nop();           
  100.      SCL=0;   
  101.     }  
  102.       
  103.     _Nop();  
  104.     _Nop();  
  105.     SDA=1;               /*8位发送完后释放数据线,准备接收应答位*/  
  106.     _Nop();  
  107.     _Nop();     
  108.     SCL=1;  
  109.     _Nop();  
  110.     _Nop();  
  111.     _Nop();  
  112.     if(SDA==1)ack=0;       
  113.        else ack=1;        /*判断是否接收到应答信号*/  
  114.     SCL=0;  
  115.     _Nop();  
  116.     _Nop();  
  117. }  
  118.   
  119. /******************************************************************* 
  120.                  字节数据传送函数                
  121. 函数原型: uchar  RcvByte(); 
  122. 功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号), 
  123.      发完后请用应答函数。   
  124. ********************************************************************/     
  125. uchar  RcvByte()  
  126. {  
  127.   uchar retc;  
  128.   uchar BitCnt;  
  129.     
  130.   retc=0;   
  131.   SDA=1;             /*置数据线为输入方式*/  
  132.   for(BitCnt=0;BitCnt<8;BitCnt++)  
  133.       {  
  134.         _Nop();             
  135.         SCL=0;       /*置时钟线为低,准备接收数据位*/  
  136.         _Nop();  
  137.         _Nop();         /*时钟低电平周期大于4.7μs*/  
  138.         _Nop();  
  139.         _Nop();  
  140.         _Nop();  
  141.         SCL=1;       /*置时钟线为高使数据线上数据有效*/  
  142.         _Nop();  
  143.         _Nop();  
  144.         retc=retc<<1;  
  145.         if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */  
  146.         _Nop();  
  147.         _Nop();   
  148.       }  
  149.   SCL=0;      
  150.   _Nop();  
  151.   _Nop();  
  152.   return(retc);  
  153. }  
  154.   
  155. /******************************************************************** 
  156.                      应答子函数 
  157. 原型:  void Ack_I2c(bit a); 
  158.   
  159. 功能:主控器进行应答信号,(可以是应答或非应答信号) 
  160. ********************************************************************/  
  161. void Ack_I2c(bit a)  
  162. {  
  163.     
  164.   if(a==0)SDA=0;     /*在此发出应答或非应答信号 */  
  165.         else SDA=1;  
  166.   _Nop();  
  167.   _Nop();  
  168.   _Nop();        
  169.   SCL=1;  
  170.     _Nop();  
  171.     _Nop();              /*时钟低电平周期大于4μs*/  
  172.     _Nop();  
  173.     _Nop();  
  174.     _Nop();    
  175.  SCL=0;                /*清时钟线,钳住I2C总线以便继续接收*/  
  176.     _Nop();  
  177.     _Nop();      
  178. }  
  179.   
  180. /******************************************************************* 
  181.                     向无子地址器件发送字节数据函数                
  182. 函数原型: bit  ISendByte(uchar sla,ucahr c);   
  183. 功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla. 
  184.            如果返回1表示操作成功,否则操作有误。 
  185. 注意:    使用前必须已结束总线。 
  186. ********************************************************************/  
  187. bit ISendByte(uchar sla,uchar c)  
  188. {  
  189.    Start_I2c();               /*启动总线*/  
  190.    SendByte(sla);            /*发送器件地址*/  
  191.      if(ack==0)return(0);  
  192.    SendByte(c);               /*发送数据*/  
  193.      if(ack==0)return(0);  
  194.   Stop_I2c();                 /*结束总线*/   
  195.   return(1);  
  196. }  
  197.   
  198. /******************************************************************* 
  199.                     向有子地址器件发送多字节数据函数                
  200. 函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);   
  201. 功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 
  202.           地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 
  203.            如果返回1表示操作成功,否则操作有误。 
  204. 注意:    使用前必须已结束总线。 
  205. ********************************************************************/  
  206. bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)  
  207. {  
  208.    uchar i;  
  209.   
  210.    Start_I2c();               /*启动总线*/  
  211.    SendByte(sla);            /*发送器件地址*/  
  212.      if(ack==0)return(0);  
  213.    SendByte(suba);            /*发送器件子地址*/  
  214.      if(ack==0)return(0);  
  215.   
  216.    for(i=0;i
  217.     {     
  218.      SendByte(*s);               /*发送数据*/  
  219.        if(ack==0)return(0);  
  220.      s++;  
  221.     }   
  222.  Stop_I2c();                 /*结束总线*/   
  223.   return(1);  
  224. }  
  225. /******************************************************************* 
  226.                     向无子地址器件读字节数据函数                
  227. 函数原型: bit  IRcvByte(uchar sla,ucahr *c);   
  228. 功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地 
  229.           址sla,返回值在c. 
  230.            如果返回1表示操作成功,否则操作有误。 
  231. 注意:    使用前必须已结束总线。 
  232. ********************************************************************/  
  233. bit IRcvByte(uchar sla,uchar *c)  
  234. {  
  235.    Start_I2c();                /*启动总线*/  
  236.    SendByte(sla+1);           /*发送器件地址*/  
  237.      if(ack==0)return(0);  
  238.    *c=RcvByte();               /*读取数据*/  
  239.      Ack_I2c(1);               /*发送非就答位*/  
  240.   Stop_I2c();                  /*结束总线*/   
  241.   return(1);  
  242. }  
  243.   
  244. /******************************************************************* 
  245.                     向有子地址器件读取多字节数据函数                
  246. 函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);   
  247. 功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 
  248.           地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 
  249.            如果返回1表示操作成功,否则操作有误。 
  250. 注意:    使用前必须已结束总线。 
  251. ********************************************************************/  
  252. bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)  
  253. {  
  254.    uchar i;  
  255.   
  256.    Start_I2c();               /*启动总线*/  
  257.    SendByte(sla);            /*发送器件地址*/  
  258.      if(ack==0)return(0);  
  259.    SendByte(suba);            /*发送器件子地址*/  
  260.      if(ack==0)return(0);  
  261.   
  262.    Start_I2c();  
  263.    SendByte(sla+1);  
  264.       if(ack==0)return(0);  
  265.   
  266.    for(i=0;i
  267.     {     
  268.      *s=RcvByte();               /*发送数据*/  
  269.       Ack_I2c(0);                /*发送就答位*/    
  270.      s++;  
  271.     }   
  272.    *s=RcvByte();  
  273.     Ack_I2c(1);                 /*发送非应位*/  
  274.  Stop_I2c();                    /*结束总线*/   
  275.   return(1);  
  276. }  
  277.                         /*    完毕      */  
 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
激光跟踪仪市场2023年有望达5.216亿美元