找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12847|回复: 6
收起左侧

51单片机模拟I2c接口 原理与程序

  [复制链接]
ID:290266 发表于 2018-3-24 19:18 | 显示全部楼层 |阅读模式
1、I2c启动 1.png

    由上图可知SDA在SCL为高电平时由高变为低表示启动I2c,注意时间。


2、I2c关闭 2.png

    由上图可知SDA在SCL为高电平时由低变为高表示启动I2c,注意时间。

3、数据0 3.png

    由上图可知SDA在SCL为高电平时拉低表示0,注意时间。



4、数据1 4.png

    由上图可知SDA在SCL为高电平时拉高表示0,注意时间。

5、I2c写数据(数据由51到设备) 5.jpg
由上图可以看书写数据的步骤为:1)启动I2c;
2)写入设备地址(七位设备地址加一位读写命令,最后1为读,0为写);
3)等待应答(由设备发出,读数据时由51给应答),这一步可以和第二部写在一个函数中;
4)写入数据要存放的地址;
5)等待应答;
6)写入数据;
7)等待应答;
8)关闭I2c。
若将等待应答与写数据放在一个函数中可简化为:1)启动I2c;
2)写入设备地址

3)写入数据要存放的地址;

4)写入数据;

5)关闭I2c。

6、I2c读数据(51从设备中读取数据) 6.jpg

由上图可以看书写数据的步骤为:1)启动I2c;
2)写入设备地址;

3)写入要读取数据存放的地址;

4)启动I2c;

5)写入设备地址(第八位为1,表示读数据);
6)读数据;
7)给设备发送应答信号;
8)关闭I2c;

7、对应的51程序
  1. #include <STC12C5A60S2.H>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4.         
  5. sbit SCL=P2^1;
  6. sbit SDA=P2^0;
  7. uchar code duan[]=
  8. {
  9.         0xfc,0x60,0xda,
  10.         0xf2,0x66,0xb6,
  11.         0xbe,0xe0,0xfe,0xf6
  12. };

  13. void delay(uint time)
  14. {
  15.         uint i,j;
  16.         for(i=0;i<time;i++)
  17.                 for(j=0;j<10;j++);
  18. }

  19. void I2c_start()
  20. {
  21.         SDA=1;
  22.         delay(1);
  23.         SCL=1;
  24.         delay(1);           
  25.         SDA=0;
  26.         delay(1);      
  27.         SCL=0;
  28.         delay(1);
  29. }


  30. void I2c_stop()
  31. {
  32.         SDA=0;
  33.         delay(1);
  34.         SCL=1;
  35.         delay(1);      
  36.         SDA=1;
  37.         delay(1);
  38. }

  39. //·¢Ëíack
  40. void I2c_sendAck(bit ack)
  41. {
  42.     SDA = ack;      
  43.     SCL = 1;      
  44.     delay(1);   
  45.     SCL = 0;
  46.                 delay(1);
  47.                
  48. }

  49. //»ñè¡ack
  50. bit I2c_getAck(void)
  51. {
  52.     bit ack;        
  53.     SDA = 1;        
  54.     SCL = 1;        
  55.     delay(1);   
  56.     ack = SDA;      
  57.     SCL = 0;
  58.     return ack;
  59. }

  60. uchar I2c_read()
  61. {
  62.         uchar i,dat=0;
  63.         SDA=1;
  64.         delay(1);
  65.         for(i=0;i<8;i++)
  66.         {
  67.                 SCL=1;
  68.                 delay(1);
  69.                 dat<<=1;
  70.                 dat|=SDA;
  71.                 delay(1);
  72.                 SCL=0;
  73.         }
  74.         return dat;
  75. }

  76. void I2c_write(uchar dat)
  77. {
  78.         uchar i;
  79.         for(i=0;i<8;i++)
  80.         {
  81.                 SDA=dat>>7;
  82.                 dat<<=1;
  83.                 delay(1);
  84.                 SCL=1;
  85.                 delay(1);
  86.                 SCL=0;
  87.                 delay(1);
  88.         }
  89.         I2c_getAck();
  90. }

  91. void I2c_toDevice(uchar deviceAdd,uchar datAdd,uchar dat)
  92. {
  93.         I2c_start();
  94.         I2c_write(deviceAdd);
  95.         I2c_write(datAdd);
  96.         I2c_write(dat);
  97.         I2c_stop();
  98. }
  99. uchar I2c_fromDevice(uchar deviceAdd,uchar datAdd  )
  100. {
  101.         uchar dat;
  102.         I2c_start();
  103.         I2c_write(deviceAdd);
  104.         I2c_write(datAdd);
  105.         I2c_start();
  106.         I2c_write(deviceAdd+1);
  107.         dat=I2c_read();
  108.         I2c_sendAck(1);
  109.         I2c_stop();
  110.         return dat;
  111. }

  112. void main()
  113. {
  114.         uchar num;
  115.         I2c_toDevice(0xa0,3,7);
  116.         delay(130);
  117.         num=I2c_fromDevice(0xa0,3);
  118.         while(1)
  119.         {
  120.                 P0=0x00;
  121.                 P1=duan[num];
  122.                 delay(10);
  123.                 P1=0x00;
  124.         }

  125. }
复制代码

8、注意事项
1)关闭I2c和启动I2c之间要有1ms间隔,给IO口准备时间,否则乱码。
2)关于应答,当写数据时由设备应答,读数据时MCU应答。
3)读数据时启动两次I2c。


回复

使用道具 举报

ID:74784 发表于 2018-3-24 22:14 | 显示全部楼层
有汇编代码吗?
回复

使用道具 举报

ID:138443 发表于 2018-3-24 22:39 | 显示全部楼层
不错,支持楼主,支持51hei
回复

使用道具 举报

ID:296886 发表于 2018-3-25 21:38 | 显示全部楼层
挺好的啊
回复

使用道具 举报

ID:200295 发表于 2021-4-14 17:52 | 显示全部楼层
刚好用到,谢谢楼主分享。
回复

使用道具 举报

ID:940533 发表于 2021-9-4 15:16 | 显示全部楼层
应用代码中void I2c_start()和void I2c_stop(),程序变的可运行,好评
回复

使用道具 举报

ID:161164 发表于 2021-9-7 15:29 | 显示全部楼层
试了整天,Protues 里的I2C Debugger 都是收到A0 FF FF
看了其他文章才知道,等ACK时要先把SDA 置0
bit I2c_getAck(void)
{
    bit ack;        
    SDA = 0;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<        
    SCL = 1;        
    delay(1);   
    ack = SDA;      
    SCL = 0;
    return ack;
}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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