找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4677|回復(fù): 16
打印 上一主題 下一主題
收起左側(cè)

怎么寫ii2c的協(xié)議,要注意些什么

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:386789 發(fā)表于 2018-10-9 14:49 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
最近要做一個(gè)ii2c的從機(jī)協(xié)議程序,應(yīng)該怎么入手,初步想法是用外部中斷
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:164602 發(fā)表于 2018-10-9 16:33 | 只看該作者
個(gè)人理解:
IIC協(xié)議比較固定,可以找找別人的程序理解。當(dāng)然,如果自己想試試,也可以,寫好后看能不能用,能用最好,不能用,就對(duì)照別人的程序看看。
個(gè)人的經(jīng)驗(yàn):那個(gè)延時(shí)最不好搞。。。!有的多一點(diǎn)延時(shí)就行不通,有的少了一點(diǎn)點(diǎn)也不行。發(fā)一個(gè)我最常用的IIC協(xié)議給你看看。
I2C.c程序:
#include"i2c.h"
/*******************************************************************************
* 函數(shù)名         : Delay1us()
* 函數(shù)功能                   : 延時(shí)
* 輸入           : 無
* 輸出                  : 無
*******************************************************************************/

void Delay10us()
{
        unsigned char a,b;
        for(b=1;b>0;b--)
                for(a=2;a>0;a--);

}
/*******************************************************************************
* 函數(shù)名         : I2cStart()
* 函數(shù)功能                   : 起始信號(hào):在SCL時(shí)鐘信號(hào)在高電平期間SDA信號(hào)產(chǎn)生一個(gè)下降沿
* 輸入           : 無
* 輸出                  : 無
* 備注           : 起始之后SDA和SCL都為0
*******************************************************************************/

void I2cStart()
{
        SDA=1;
        Delay10us();
        SCL=1;
        Delay10us();//建立時(shí)間是SDA保持時(shí)間>4.7us
        SDA=0;
        Delay10us();//保持時(shí)間是>4us
        SCL=0;                       
        Delay10us();               
}
/*******************************************************************************
* 函數(shù)名         : I2cStop()
* 函數(shù)功能                   : 終止信號(hào):在SCL時(shí)鐘信號(hào)高電平期間SDA信號(hào)產(chǎn)生一個(gè)上升沿
* 輸入           : 無
* 輸出                  : 無
* 備注           : 結(jié)束之后保持SDA和SCL都為1;表示總線空閑
*******************************************************************************/

void I2cStop()
{
        SDA=0;
        Delay10us();
        SCL=1;
        Delay10us();//建立時(shí)間大于4.7us
        SDA=1;
        Delay10us();               
}
/*******************************************************************************
* 函數(shù)名         : I2cSendByte(unsigned char num)
* 函數(shù)功能                   : 通過I2C發(fā)送一個(gè)字節(jié)。在SCL時(shí)鐘信號(hào)高電平期間,保持發(fā)送信號(hào)SDA保持穩(wěn)定
* 輸入           : num
* 輸出                  : 0或1。發(fā)送成功返回1,發(fā)送失敗返回0
* 備注           : 發(fā)送完一個(gè)字節(jié)SCL=0,SDA=1
*******************************************************************************/

unsigned char I2cSendByte(unsigned char dat)
{
        unsigned char a=0,b=0;//最大255,一個(gè)機(jī)器周期為1us,最大延時(shí)255us。               
        for(a=0;a<8;a++)//要發(fā)送8位,從最高位開始
        {
                SDA=dat>>7;         //起始信號(hào)之后SCL=0,所以可以直接改變SDA信號(hào)
                dat=dat<<1;
                Delay10us();
                SCL=1;
                Delay10us();//建立時(shí)間>4.7us
                SCL=0;
                Delay10us();//時(shí)間大于4us               
        }
        SDA=1;
        Delay10us();
        SCL=1;
        while(SDA)//等待應(yīng)答,也就是等待從設(shè)備把SDA拉低
        {
                b++;
                if(b>200)         //如果超過2000us沒有應(yīng)答發(fā)送失敗,或者為非應(yīng)答,表示接收結(jié)束
                {
                        SCL=0;
                        Delay10us();
                        return 0;
                }
        }
        SCL=0;
        Delay10us();
        return 1;               
}
/*******************************************************************************
* 函數(shù)名         : I2cReadByte()
* 函數(shù)功能                   : 使用I2c讀取一個(gè)字節(jié)
* 輸入           : 無
* 輸出                  : dat
* 備注           : 接收完一個(gè)字節(jié)SCL=0,SDA=1.
*******************************************************************************/

unsigned char I2cReadByte()
{
        unsigned char a=0,dat=0;
        SDA=1;                        //起始和發(fā)送一個(gè)字節(jié)之后SCL都是0
        Delay10us();
        for(a=0;a<8;a++)//接收8個(gè)字節(jié)
        {
                SCL=1;
                Delay10us();
                dat<<=1;
                dat|=SDA;
                Delay10us();
                SCL=0;
                Delay10us();
        }
        return dat;               
}
/*******************************************************************************
* 函數(shù)名         : I2cReadRespon()
* 函數(shù)功能                   : 接收完一個(gè)字節(jié)之后產(chǎn)生應(yīng)答,以便接著接收下一個(gè)字節(jié)
* 輸入           : 無
* 輸出                  : 無
* 備注           : 接收完一個(gè)字節(jié)SCL=0
*******************************************************************************/
//void I2cReadRespon()
//{
//        SDA=0;
//        Delay10us();
//        SDA=1;
//        Delay10us();
//}


I2C.H程序:
#ifndef __I2C_H_
#define __I2C_H_

#include<reg51.h>
sbit SCL=P2^1;
sbit SDA=P2^0;

void I2cStart();
void I2cStop();
unsigned char I2cSendByte(unsigned char dat);
unsigned char I2cReadByte();
void I2cReadRespon();
#endif

這個(gè)程序,是用于24C02的,符合I2C協(xié)議的一般要求。
回復(fù)

使用道具 舉報(bào)

板凳
ID:23606 發(fā)表于 2018-10-9 16:46 | 只看該作者
論壇里面很多,搜一下
回復(fù)

使用道具 舉報(bào)

地板
ID:7485 發(fā)表于 2018-10-9 16:52 | 只看該作者
ii2c協(xié)議是一種通信協(xié)議,凡是采用這種協(xié)議的器件,都是一定要按照這個(gè)協(xié)議(約定的時(shí)序)編寫程序。
回復(fù)

使用道具 舉報(bào)

5#
ID:387733 發(fā)表于 2018-10-9 18:05 | 只看該作者
論壇里主機(jī)協(xié)議的多,從機(jī)協(xié)議的不多,但是從機(jī)是主機(jī)的對(duì)手機(jī),因此做從機(jī)協(xié)議可以多看看主機(jī)的。另外要搞通IIC的通訊協(xié)議的時(shí)序,根據(jù)時(shí)序?qū)懗绦颉?/td>
回復(fù)

使用道具 舉報(bào)

6#
ID:386789 發(fā)表于 2018-10-9 18:06 | 只看該作者
是從機(jī)協(xié)議,不是主機(jī)協(xié)議,在百度找了很久都沒有想關(guān)的協(xié)議,要怎么操作的時(shí)序圖
回復(fù)

使用道具 舉報(bào)

7#
ID:246050 發(fā)表于 2018-10-9 19:18 | 只看該作者
這個(gè)肯定是時(shí)序最要注意的啦
回復(fù)

使用道具 舉報(bào)

8#
ID:387733 發(fā)表于 2018-10-9 19:36 | 只看該作者
網(wǎng)上找來的,可能會(huì)有所幫助吧

/****************************************************************/
bit iic_start_decide()    //IIC 開始判斷
{
         while(SCL==0);                                       //開始不滿足條件
        while((SCL==1)&&(SDA==1));                 //開始條件
         if((SCL==1)&&(SDA==0))                               //開始
         {
          while(SCL==1);                                        //等待到時(shí)鐘開始低跳變
          return 1;
         }
         else
         return 0;
}

/****************************************************************/
bit iic_stop_decide()                        //IIC 結(jié)束判斷
{
        while(SCL==0);                                //結(jié)束不滿足條件
        if((SCL==1)&&(0==SDA))                        //結(jié)束
        {
          while(SDA==0);                                //等待到數(shù)據(jù)開始高跳變
          return 1;
         }
         else
         {
                 return 0;
        }
}
/****************************************************************/
uchar iic_receive()
{
         uchar i;
         uchar rdata='0';

         SDA=1;
         for(i=0;i<8;i++)
         {
          rdata<<=1;
          while(SCL==0);        //當(dāng)時(shí)鐘為低時(shí),數(shù)據(jù)無效,等待
          if(SDA==1)
                  rdata++;
          while(SCL==1);        //防止在一個(gè)高電平時(shí)讀8次
         }
        return (rdata);
}
/****************************************************************/
bit iic_ack_decide()
{
        bit ack_flag;                //局部變量
        SDA=0;                                        ////8位發(fā)送完畢,釋放數(shù)據(jù)線SDA,準(zhǔn)備接收應(yīng)答位
        while(SCL==0);        //等待SCL變高電平
        //ack_flag=0;
        while(SCL==1);        //等待SCL變高電平
        SDA=1;
        ack_flag=1;
        return(ack_flag);
}
回復(fù)

使用道具 舉報(bào)

9#
ID:390615 發(fā)表于 2018-10-9 21:22 | 只看該作者
兄弟,你研究到了嗎?我近來也在做這個(gè),聽說從機(jī)的時(shí)序是很難模擬的
回復(fù)

使用道具 舉報(bào)

10#
ID:386789 發(fā)表于 2018-10-10 09:28 | 只看該作者
sxhwdz 發(fā)表于 2018-10-9 19:36
網(wǎng)上找來的,可能會(huì)有所幫助吧

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

謝謝,哥們
回復(fù)

使用道具 舉報(bào)

11#
ID:386789 發(fā)表于 2018-10-10 09:29 | 只看該作者
authority 發(fā)表于 2018-10-9 21:22
兄弟,你研究到了嗎?我近來也在做這個(gè),聽說從機(jī)的時(shí)序是很難模擬的

兄弟,一起研究一下,我打算先用外部中斷來調(diào)試
回復(fù)

使用道具 舉報(bào)

12#
ID:155507 發(fā)表于 2018-10-10 10:54 | 只看該作者
你可以用STC8,有硬件I2C。
硬件I2C只要把數(shù)據(jù)送到指定的寄存器就可以了,不用自己寫時(shí)序什么的。

  1. /* I2C從機(jī)模式(查詢方式) */
  2. // 芯片型號(hào) : STC8A8K64S4A12

  3. #include "reg51.h"
  4. #include "intrins.h"

  5. sfr     P_SW2       =   0xba;

  6. #define I2CCFG          (*(unsigned char volatile xdata *)0xfe80)
  7. #define I2CMSCR         (*(unsigned char volatile xdata *)0xfe81)
  8. #define I2CMSST         (*(unsigned char volatile xdata *)0xfe82)
  9. #define I2CSLCR         (*(unsigned char volatile xdata *)0xfe83)
  10. #define I2CSLST         (*(unsigned char volatile xdata *)0xfe84)
  11. #define I2CSLADR        (*(unsigned char volatile xdata *)0xfe85)
  12. #define I2CTXD          (*(unsigned char volatile xdata *)0xfe86)
  13. #define I2CRXD          (*(unsigned char volatile xdata *)0xfe87)

  14. sbit    SDA         =   P1^4;
  15. sbit    SCL         =   P1^5;

  16. bit isda;                                       //設(shè)備地址標(biāo)志
  17. bit isma;                                       //存儲(chǔ)地址標(biāo)志
  18. unsigned char addr;
  19. unsigned char pdata buffer[256];

  20. void main()
  21. {
  22.     P_SW2 = 0x80;

  23.     I2CCFG = 0x81;                              //使能I2C從機(jī)模式
  24.     I2CSLADR = 0x5a;                            //設(shè)置從機(jī)設(shè)備地址為5A
  25.     I2CSLST = 0x00;
  26.     I2CSLCR = 0x00;                             //禁止從機(jī)模式中斷

  27.     isda = 1;                                   //用戶變量初始化
  28.     isma = 1;
  29.     addr = 0;
  30.     I2CTXD = buffer[addr];

  31.     while (1)
  32.     {
  33.         if (I2CSLST & 0x40)
  34.         {
  35.             I2CSLST &= ~0x40;                   //處理START事件
  36.         }
  37.         else if (I2CSLST & 0x20)
  38.         {
  39.             I2CSLST &= ~0x20;                   //處理RECV事件
  40.             if (isda)
  41.             {
  42.                 isda = 0;                       //處理RECV事件(RECV DEVICE ADDR)
  43.             }
  44.             else if (isma)
  45.             {
  46.                 isma = 0;                       //處理RECV事件(RECV MEMORY ADDR)
  47.                 addr = I2CRXD;
  48.                 I2CTXD = buffer[addr];
  49.             }
  50.             else
  51.             {
  52.                 buffer[addr++] = I2CRXD;        //處理RECV事件(RECV DATA)
  53.             }
  54.         }
  55.         else if (I2CSLST & 0x10)
  56.         {
  57.             I2CSLST &= ~0x10;                   //處理SEND事件
  58.             if (I2CSLST & 0x02)
  59.             {
  60.                 I2CTXD = 0xff;
  61.             }
  62.             else
  63.             {
  64.                 I2CTXD = buffer[++addr];
  65.             }
  66.         }
  67.         else if (I2CSLST & 0x08)
  68.         {
  69.             I2CSLST &= ~0x08;                   //處理STOP事件
  70.             isda = 1;
  71.             isma = 1;
  72.         }
  73.     }
  74. }


復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

13#
ID:155507 發(fā)表于 2018-10-10 10:56 | 只看該作者
  1. //芯片型號(hào) : STC8A8K64S4A12
  2. //STC8單片機(jī) I2C從機(jī)模式(中斷方式)

  3. #include "reg51.h"
  4. #include "intrins.h"

  5. sfr     P_SW2       =   0xba;

  6. #define I2CCFG          (*(unsigned char volatile xdata *)0xfe80)
  7. #define I2CMSCR         (*(unsigned char volatile xdata *)0xfe81)
  8. #define I2CMSST         (*(unsigned char volatile xdata *)0xfe82)
  9. #define I2CSLCR         (*(unsigned char volatile xdata *)0xfe83)
  10. #define I2CSLST         (*(unsigned char volatile xdata *)0xfe84)
  11. #define I2CSLADR        (*(unsigned char volatile xdata *)0xfe85)
  12. #define I2CTXD          (*(unsigned char volatile xdata *)0xfe86)
  13. #define I2CRXD          (*(unsigned char volatile xdata *)0xfe87)

  14. sbit    SDA         =   P1^4;
  15. sbit    SCL         =   P1^5;

  16. bit isda;                                       //設(shè)備地址標(biāo)志
  17. bit isma;                                       //存儲(chǔ)地址標(biāo)志
  18. unsigned char addr;
  19. unsigned char pdata buffer[256];

  20. void I2C_Isr() interrupt 24 using 1
  21. {
  22.     _push_(P_SW2);
  23.     P_SW2 |= 0x80;

  24.     if (I2CSLST & 0x40)
  25.     {
  26.         I2CSLST &= ~0x40;                       //處理START事件
  27.     }
  28.     else if (I2CSLST & 0x20)
  29.     {
  30.         I2CSLST &= ~0x20;                       //處理RECV事件
  31.         if (isda)
  32.         {
  33.             isda = 0;                           //處理RECV事件(RECV DEVICE ADDR)
  34.         }
  35.         else if (isma)
  36.         {
  37.             isma = 0;                           //處理RECV事件(RECV MEMORY ADDR)
  38.             addr = I2CRXD;
  39.             I2CTXD = buffer[addr];
  40.         }
  41.         else
  42.         {
  43.             buffer[addr++] = I2CRXD;            //處理RECV事件(RECV DATA)
  44.         }
  45.     }
  46.     else if (I2CSLST & 0x10)
  47.     {
  48.         I2CSLST &= ~0x10;                       //處理SEND事件
  49.         if (I2CSLST & 0x02)
  50.         {
  51.             I2CTXD = 0xff;
  52.         }
  53.         else
  54.         {
  55.             I2CTXD = buffer[++addr];
  56.         }
  57.     }
  58.     else if (I2CSLST & 0x08)
  59.     {
  60.         I2CSLST &= ~0x08;                       //處理STOP事件
  61.         isda = 1;
  62.         isma = 1;
  63.     }

  64.     _pop_(P_SW2);
  65. }

  66. void main()
  67. {
  68.     P_SW2 = 0x80;

  69.     I2CCFG = 0x81;                              //使能I2C從機(jī)模式
  70.     I2CSLADR = 0x5a;                            //設(shè)置從機(jī)設(shè)備地址為5A
  71.     I2CSLST = 0x00;
  72.     I2CSLCR = 0x78;                             //使能從機(jī)模式中斷
  73.     EA = 1;

  74.     isda = 1;                                   //用戶變量初始化
  75.     isma = 1;
  76.     addr = 0;
  77.     I2CTXD = buffer[addr];

  78.     while (1);
  79. }

復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

14#
ID:155507 發(fā)表于 2018-10-10 10:57 | 只看該作者
  1. //芯片型號(hào) : STC8A8K64S4A12
  2. //STC8單片機(jī) 測(cè)試I2C從機(jī)模式代碼的主機(jī)代碼

  3. #include "reg51.h"
  4. #include "intrins.h"

  5. sfr     P_SW2       =   0xba;

  6. #define I2CCFG          (*(unsigned char volatile xdata *)0xfe80)
  7. #define I2CMSCR         (*(unsigned char volatile xdata *)0xfe81)
  8. #define I2CMSST         (*(unsigned char volatile xdata *)0xfe82)
  9. #define I2CSLCR         (*(unsigned char volatile xdata *)0xfe83)
  10. #define I2CSLST         (*(unsigned char volatile xdata *)0xfe84)
  11. #define I2CSLADR        (*(unsigned char volatile xdata *)0xfe85)
  12. #define I2CTXD          (*(unsigned char volatile xdata *)0xfe86)
  13. #define I2CRXD          (*(unsigned char volatile xdata *)0xfe87)

  14. sbit    SDA         =   P1^4;
  15. sbit    SCL         =   P1^5;

  16. void Wait()
  17. {
  18.     while (!(I2CMSST & 0x40));
  19.     I2CMSST &= ~0x40;
  20. }

  21. void Start()
  22. {
  23.     I2CMSCR = 0x01;                             //發(fā)送START命令
  24.     Wait();
  25. }

  26. void SendData(char dat)
  27. {
  28.     I2CTXD = dat;                               //寫數(shù)據(jù)到數(shù)據(jù)緩沖區(qū)
  29.     I2CMSCR = 0x02;                             //發(fā)送SEND命令
  30.     Wait();
  31. }

  32. void RecvACK()
  33. {
  34.     I2CMSCR = 0x03;                             //發(fā)送讀ACK命令
  35.     Wait();
  36. }

  37. char RecvData()
  38. {
  39.     I2CMSCR = 0x04;                             //發(fā)送RECV命令
  40.     Wait();
  41.     return I2CRXD;
  42. }

  43. void SendACK()
  44. {
  45.     I2CMSST = 0x00;                             //設(shè)置ACK信號(hào)
  46.     I2CMSCR = 0x05;                             //發(fā)送ACK命令
  47.     Wait();
  48. }

  49. void SendNAK()
  50. {
  51.     I2CMSST = 0x01;                             //設(shè)置NAK信號(hào)
  52.     I2CMSCR = 0x05;                             //發(fā)送ACK命令
  53.     Wait();
  54. }

  55. void Stop()
  56. {
  57.     I2CMSCR = 0x06;                             //發(fā)送STOP命令
  58.     Wait();
  59. }

  60. void Delay()
  61. {
  62.     int i;

  63.     for (i=0; i<3000; i++)
  64.     {
  65.         _nop_();
  66.         _nop_();
  67.         _nop_();
  68.         _nop_();
  69.     }
  70. }

  71. void main()
  72. {
  73.     P_SW2 = 0x80;

  74.     I2CCFG = 0xe0;                              //使能I2C主機(jī)模式
  75.     I2CMSST = 0x00;

  76.     Start();                                    //發(fā)送起始命令
  77.     SendData(0x5a);                             //發(fā)送設(shè)備地址+寫命令
  78.     RecvACK();
  79.     SendData(0x00);                             //發(fā)送存儲(chǔ)地址
  80.     RecvACK();
  81.     SendData(0x12);                             //寫測(cè)試數(shù)據(jù)1
  82.     RecvACK();
  83.     SendData(0x78);                             //寫測(cè)試數(shù)據(jù)2
  84.     RecvACK();
  85.     Stop();                                     //發(fā)送停止命令

  86.     Start();                                    //發(fā)送起始命令
  87.     SendData(0x5a);                             //發(fā)送設(shè)備地址+寫命令
  88.     RecvACK();
  89.     SendData(0x00);                             //發(fā)送存儲(chǔ)地址高字節(jié)
  90.     RecvACK();
  91.     Start();                                    //發(fā)送起始命令
  92.     SendData(0x5b);                             //發(fā)送設(shè)備地址+讀命令
  93.     RecvACK();
  94.     P0 = RecvData();                            //讀取數(shù)據(jù)1
  95.     SendACK();
  96.     P2 = RecvData();                            //讀取數(shù)據(jù)2
  97.     SendNAK();
  98.     Stop();                                     //發(fā)送停止命令

  99.     P_SW2 = 0x00;

  100.     while (1);
  101. }

復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

15#
ID:386789 發(fā)表于 2018-10-10 13:43 | 只看該作者
回復(fù)

使用道具 舉報(bào)

16#
ID:390615 發(fā)表于 2018-10-28 10:06 | 只看該作者

我也覺得總不能依賴stc提供的硬件i2c,自己需要懂得模擬才是萬全之策
回復(fù)

使用道具 舉報(bào)

17#
ID:275111 發(fā)表于 2020-4-1 10:45 | 只看該作者
我在網(wǎng)上找了下,鍵盤IC一般實(shí)際上是3線制,I2C 2根,中斷1根。  現(xiàn)在就是要求只用I2C來做從機(jī)。感覺無從下手。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表