找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4714|回复: 16
收起左侧

怎么写ii2c的协议,要注意些什么

[复制链接]
ID:386789 发表于 2018-10-9 14:49 | 显示全部楼层 |阅读模式
最近要做一个ii2c的从机协议程序,应该怎么入手,初步想法是用外部中断
回复

使用道具 举报

ID:164602 发表于 2018-10-9 16:33 | 显示全部楼层
个人理解:
IIC协议比较固定,可以找找别人的程序理解。当然,如果自己想试试,也可以,写好后看能不能用,能用最好,不能用,就对照别人的程序看看。
个人的经验:那个延时最不好搞!!!!!有的多一点延时就行不通,有的少了一点点也不行。发一个我最常用的IIC协议给你看看。
I2C.c程序:
#include"i2c.h"
/*******************************************************************************
* 函数名         : Delay1us()
* 函数功能                   : 延时
* 输入           : 无
* 输出                  : 无
*******************************************************************************/

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

}
/*******************************************************************************
* 函数名         : I2cStart()
* 函数功能                   : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
* 输入           : 无
* 输出                  : 无
* 备注           : 起始之后SDA和SCL都为0
*******************************************************************************/

void I2cStart()
{
        SDA=1;
        Delay10us();
        SCL=1;
        Delay10us();//建立时间是SDA保持时间>4.7us
        SDA=0;
        Delay10us();//保持时间是>4us
        SCL=0;                       
        Delay10us();               
}
/*******************************************************************************
* 函数名         : I2cStop()
* 函数功能                   : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
* 输入           : 无
* 输出                  : 无
* 备注           : 结束之后保持SDA和SCL都为1;表示总线空闲
*******************************************************************************/

void I2cStop()
{
        SDA=0;
        Delay10us();
        SCL=1;
        Delay10us();//建立时间大于4.7us
        SDA=1;
        Delay10us();               
}
/*******************************************************************************
* 函数名         : I2cSendByte(unsigned char num)
* 函数功能                   : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定
* 输入           : num
* 输出                  : 0或1。发送成功返回1,发送失败返回0
* 备注           : 发送完一个字节SCL=0,SDA=1
*******************************************************************************/

unsigned char I2cSendByte(unsigned char dat)
{
        unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。               
        for(a=0;a<8;a++)//要发送8位,从最高位开始
        {
                SDA=dat>>7;         //起始信号之后SCL=0,所以可以直接改变SDA信号
                dat=dat<<1;
                Delay10us();
                SCL=1;
                Delay10us();//建立时间>4.7us
                SCL=0;
                Delay10us();//时间大于4us               
        }
        SDA=1;
        Delay10us();
        SCL=1;
        while(SDA)//等待应答,也就是等待从设备把SDA拉低
        {
                b++;
                if(b>200)         //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
                {
                        SCL=0;
                        Delay10us();
                        return 0;
                }
        }
        SCL=0;
        Delay10us();
        return 1;               
}
/*******************************************************************************
* 函数名         : I2cReadByte()
* 函数功能                   : 使用I2c读取一个字节
* 输入           : 无
* 输出                  : dat
* 备注           : 接收完一个字节SCL=0,SDA=1.
*******************************************************************************/

unsigned char I2cReadByte()
{
        unsigned char a=0,dat=0;
        SDA=1;                        //起始和发送一个字节之后SCL都是0
        Delay10us();
        for(a=0;a<8;a++)//接收8个字节
        {
                SCL=1;
                Delay10us();
                dat<<=1;
                dat|=SDA;
                Delay10us();
                SCL=0;
                Delay10us();
        }
        return dat;               
}
/*******************************************************************************
* 函数名         : I2cReadRespon()
* 函数功能                   : 接收完一个字节之后产生应答,以便接着接收下一个字节
* 输入           : 无
* 输出                  : 无
* 备注           : 接收完一个字节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

这个程序,是用于24C02的,符合I2C协议的一般要求。
回复

使用道具 举报

ID:23606 发表于 2018-10-9 16:46 | 显示全部楼层
论坛里面很多,搜一下
回复

使用道具 举报

ID:7485 发表于 2018-10-9 16:52 | 显示全部楼层
ii2c协议是一种通信协议,凡是采用这种协议的器件,都是一定要按照这个协议(约定的时序)编写程序。
回复

使用道具 举报

ID:387733 发表于 2018-10-9 18:05 | 显示全部楼层
论坛里主机协议的多,从机协议的不多,但是从机是主机的对手机,因此做从机协议可以多看看主机的。另外要搞通IIC的通讯协议的时序,根据时序写程序。
回复

使用道具 举报

ID:386789 发表于 2018-10-9 18:06 | 显示全部楼层
是从机协议,不是主机协议,在百度找了很久都没有想关的协议,要怎么操作的时序图
回复

使用道具 举报

ID:246050 发表于 2018-10-9 19:18 | 显示全部楼层
这个肯定是时序最要注意的啦
回复

使用道具 举报

ID:387733 发表于 2018-10-9 19:36 | 显示全部楼层
网上找来的,可能会有所帮助吧

/****************************************************************/
bit iic_start_decide()    //IIC 开始判断
{
         while(SCL==0);                                       //开始不满足条件
        while((SCL==1)&&(SDA==1));                 //开始条件
         if((SCL==1)&&(SDA==0))                               //开始
         {
          while(SCL==1);                                        //等待到时钟开始低跳变
          return 1;
         }
         else
         return 0;
}

/****************************************************************/
bit iic_stop_decide()                        //IIC 结束判断
{
        while(SCL==0);                                //结束不满足条件
        if((SCL==1)&&(0==SDA))                        //结束
        {
          while(SDA==0);                                //等待到数据开始高跳变
          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);        //当时钟为低时,数据无效,等待
          if(SDA==1)
                  rdata++;
          while(SCL==1);        //防止在一个高电平时读8次
         }
        return (rdata);
}
/****************************************************************/
bit iic_ack_decide()
{
        bit ack_flag;                //局部变量
        SDA=0;                                        ////8位发送完毕,释放数据线SDA,准备接收应答位
        while(SCL==0);        //等待SCL变高电平
        //ack_flag=0;
        while(SCL==1);        //等待SCL变高电平
        SDA=1;
        ack_flag=1;
        return(ack_flag);
}
回复

使用道具 举报

ID:390615 发表于 2018-10-9 21:22 | 显示全部楼层
兄弟,你研究到了吗?我近来也在做这个,听说从机的时序是很难模拟的
回复

使用道具 举报

ID:386789 发表于 2018-10-10 09:28 | 显示全部楼层
sxhwdz 发表于 2018-10-9 19:36
网上找来的,可能会有所帮助吧

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

谢谢,哥们
回复

使用道具 举报

ID:386789 发表于 2018-10-10 09:29 | 显示全部楼层
authority 发表于 2018-10-9 21:22
兄弟,你研究到了吗?我近来也在做这个,听说从机的时序是很难模拟的

兄弟,一起研究一下,我打算先用外部中断来调试
回复

使用道具 举报

ID:155507 发表于 2018-10-10 10:54 | 显示全部楼层
你可以用STC8,有硬件I2C。
硬件I2C只要把数据送到指定的寄存器就可以了,不用自己写时序什么的。

  1. /* I2C从机模式(查询方式) */
  2. // 芯片型号 : 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;                                       //设备地址标志
  17. bit isma;                                       //存储地址标志
  18. unsigned char addr;
  19. unsigned char pdata buffer[256];

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

  23.     I2CCFG = 0x81;                              //使能I2C从机模式
  24.     I2CSLADR = 0x5a;                            //设置从机设备地址为5A
  25.     I2CSLST = 0x00;
  26.     I2CSLCR = 0x00;                             //禁止从机模式中断

  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. }


复制代码
回复

使用道具 举报

ID:155507 发表于 2018-10-10 10:56 | 显示全部楼层
  1. //芯片型号 : STC8A8K64S4A12
  2. //STC8单片机 I2C从机模式(中断方式)

  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;                                       //设备地址标志
  17. bit isma;                                       //存储地址标志
  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从机模式
  70.     I2CSLADR = 0x5a;                            //设置从机设备地址为5A
  71.     I2CSLST = 0x00;
  72.     I2CSLCR = 0x78;                             //使能从机模式中断
  73.     EA = 1;

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

  78.     while (1);
  79. }

复制代码
回复

使用道具 举报

ID:155507 发表于 2018-10-10 10:57 | 显示全部楼层
  1. //芯片型号 : STC8A8K64S4A12
  2. //STC8单片机 测试I2C从机模式代码的主机代码

  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;                             //发送START命令
  24.     Wait();
  25. }

  26. void SendData(char dat)
  27. {
  28.     I2CTXD = dat;                               //写数据到数据缓冲区
  29.     I2CMSCR = 0x02;                             //发送SEND命令
  30.     Wait();
  31. }

  32. void RecvACK()
  33. {
  34.     I2CMSCR = 0x03;                             //发送读ACK命令
  35.     Wait();
  36. }

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

  43. void SendACK()
  44. {
  45.     I2CMSST = 0x00;                             //设置ACK信号
  46.     I2CMSCR = 0x05;                             //发送ACK命令
  47.     Wait();
  48. }

  49. void SendNAK()
  50. {
  51.     I2CMSST = 0x01;                             //设置NAK信号
  52.     I2CMSCR = 0x05;                             //发送ACK命令
  53.     Wait();
  54. }

  55. void Stop()
  56. {
  57.     I2CMSCR = 0x06;                             //发送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主机模式
  75.     I2CMSST = 0x00;

  76.     Start();                                    //发送起始命令
  77.     SendData(0x5a);                             //发送设备地址+写命令
  78.     RecvACK();
  79.     SendData(0x00);                             //发送存储地址
  80.     RecvACK();
  81.     SendData(0x12);                             //写测试数据1
  82.     RecvACK();
  83.     SendData(0x78);                             //写测试数据2
  84.     RecvACK();
  85.     Stop();                                     //发送停止命令

  86.     Start();                                    //发送起始命令
  87.     SendData(0x5a);                             //发送设备地址+写命令
  88.     RecvACK();
  89.     SendData(0x00);                             //发送存储地址高字节
  90.     RecvACK();
  91.     Start();                                    //发送起始命令
  92.     SendData(0x5b);                             //发送设备地址+读命令
  93.     RecvACK();
  94.     P0 = RecvData();                            //读取数据1
  95.     SendACK();
  96.     P2 = RecvData();                            //读取数据2
  97.     SendNAK();
  98.     Stop();                                     //发送停止命令

  99.     P_SW2 = 0x00;

  100.     while (1);
  101. }

复制代码
回复

使用道具 举报

ID:386789 发表于 2018-10-10 13:43 | 显示全部楼层
回复

使用道具 举报

ID:390615 发表于 2018-10-28 10:06 | 显示全部楼层

我也觉得总不能依赖stc提供的硬件i2c,自己需要懂得模拟才是万全之策
回复

使用道具 举报

ID:275111 发表于 2020-4-1 10:45 | 显示全部楼层
我在网上找了下,键盘IC一般实际上是3线制,I2C 2根,中断1根。  现在就是要求只用I2C来做从机。感觉无从下手。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表