[51单片机] 51模拟IIC问题,能写不能读

[复制链接]
2995|9
 楼主| perry_peng 发表于 2014-5-28 11:02 | 显示全部楼层 |阅读模式
Proteus仿真时可以,实际操作时能写不能读。请帮忙看看。
编译器用sdcc 3.4

  1. /**<
  2. * \fn i2c_write_byte(c)
  3. * \brief Writes a byte to device.
  4. * \param c data
  5. */
  6. void i2c_write_byte(uint8 c)
  7. {
  8.   uint8 i;

  9.   for (i = 0; i < 8; i++) {
  10.     set_sda(c & 0x80);
  11.     set_scl_high();
  12.     delay_4us();
  13.     c <<= 1;
  14.     set_scl_low();
  15.     delay_4us();
  16.   }
  17. }

  18. /**<
  19. * \fn i2c_read_byte()
  20. * \brief Reads a byte from device.
  21. * \return Returned data.
  22. */
  23. uint8 i2c_read_byte(void)
  24. {
  25.   uint8 i, c = 0;

  26.   for (i = 0; i < 8; i++) {
  27.     set_scl_high();
  28.     delay_4us();
  29.     c <<= 1;
  30.     c |= get_sda();
  31.     set_scl_low();
  32.     delay_4us();
  33.   }

  34.   return c;
  35. }

  36. uint8 pcf8574_write_port(uint8 slave, uint8 bits)
  37. {
  38.   uint8 ret = 1;

  39.   /* START condition.
  40.    */
  41.   set_sda_high();
  42.   set_scl_high();
  43.   delay_4us();
  44.   set_sda_low();
  45.   delay_4us();
  46.   set_scl_low();

  47.   delay_xms(5);

  48.   ///< SLAVE address.
  49.   i2c_write_byte(0x40 | (slave & 0x07) << 1);

  50.   /**< ACK condition.
  51.    */
  52.   set_sda_high();
  53.   delay_4us();
  54.   set_scl_high();
  55.   delay_4us();
  56.   ACC = get_sda();
  57.   set_scl_low();
  58.   delay_4us();
  59.   if (ACC)
  60.     goto __i2c_write_finish;

  61.   delay_xms(5);

  62.   i2c_write_byte(bits);
  63.   /**< ACK condition.
  64.    */
  65.   set_sda_high();
  66.   delay_4us();
  67.   set_scl_high();
  68.   delay_4us();
  69.   ACC = get_sda();
  70.   set_scl_low();
  71.   delay_4us();
  72.   if (ACC)
  73.     goto __i2c_write_finish;

  74.   ret = 0;

  75. __i2c_write_finish:
  76.   delay_xms(5);

  77.   /**< STOP condition.
  78.    */
  79.   set_sda_low();
  80.   delay_4us();
  81.   set_scl_high();
  82.   delay_4us();
  83.   set_sda_high();

  84.   delay_xms(30);

  85.   return ret;
  86. }

  87. uint8 pcf8574_read_port(uint8 slave, uint8 *out)
  88. {
  89.   uint8 ret = 1;

  90.   /**< START condition.
  91.    */
  92.   set_sda_high();
  93.   set_scl_high();
  94.   delay_4us();
  95.   set_sda_low();
  96.   delay_4us();
  97.   set_scl_low();

  98.   delay_xms(5);

  99.   ///< SLAVE address.
  100.   i2c_write_byte(0x41 | (slave & 0x07) << 1);

  101.   /**< ACK condition.
  102.    */
  103.   set_sda_high();
  104.   delay_4us();
  105.   set_scl_high();
  106.   delay_4us();
  107.   ACC = get_sda();
  108.   set_scl_low();
  109.   delay_4us();
  110.   if (ACC)
  111.     goto __i2c_read_finish;

  112.   delay_xms(5);

  113.   *out = i2c_read_byte();

  114.   /**< NAK condition.
  115.    */
  116.   set_sda_high();
  117.   set_scl_high();
  118.   delay_4us();
  119.   set_scl_low();
  120.   set_sda_low();
  121.   delay_4us();

  122.   ret = 0;

  123. __i2c_read_finish:
  124.   delay_xms(5);

  125.   /**< STOP condition.
  126.    */
  127.   set_sda_low();
  128.   delay_4us();
  129.   set_scl_high();
  130.   delay_4us();
  131.   set_sda_high();

  132.   delay_xms(30);

  133.   return ret;
  134. }
yewuyi 发表于 2014-5-28 11:28 | 显示全部楼层
读比写稍微复杂一点而已,多了一个‘写’的过程。

读步骤一般如下:
1、启动总线
2、发送从器件地址和写控制位
3、发送从器件待读出数据的地址
4、再次启动总线
5、发送从器件地址和读控制位
6、执行单字节数据读函数,并且在读到数据后向从器件发出一次应答
7、如果需要连续读多个数据,可以继续执行上一步,否则主器件发出结束总线的时序
ningling_21 发表于 2014-5-28 12:49 | 显示全部楼层
LZ流程好像没搞清楚...
vkic007 发表于 2014-5-28 22:47 | 显示全部楼层
模拟IIC需要注意一些情况,首先要注意数据线的输入输出切换。其次是否应答。再者注意好读写控制。对于时序调试,我个人觉得最好的方式就是使用示波器,看看波形是否正确,也就是看看软件对应的硬件行为。
loliweive 发表于 2014-5-29 09:16 | 显示全部楼层
uint8 i2c_read_byte(void),这个函数不应该带有地址形参吗?
 楼主| perry_peng 发表于 2014-5-29 12:42 | 显示全部楼层
yewuyi 发表于 2014-5-28 11:28
读比写稍微复杂一点而已,多了一个‘写’的过程。

读步骤一般如下:

明白了,是少了4,5步骤。
 楼主| perry_peng 发表于 2014-5-29 12:43 | 显示全部楼层
ningling_21 发表于 2014-5-28 12:49
LZ流程好像没搞清楚...

没错,是流程没理解清楚。
 楼主| perry_peng 发表于 2014-5-29 12:44 | 显示全部楼层
本帖最后由 perry_peng 于 2014-5-29 12:58 编辑

谢谢大家指导,我用的pcf8574,没有第3步,所以我直接读时用的4,5,6步。
 楼主| perry_peng 发表于 2014-5-29 12:48 | 显示全部楼层
loliweive 发表于 2014-5-29 09:16
uint8 i2c_read_byte(void),这个函数不应该带有地址形参吗?

这个函数是没有参数的,只是模拟一个读动作。数据从IO读出来,而IO已经定义成宏。
 楼主| perry_peng 发表于 2014-5-29 12:49 | 显示全部楼层
vkic007 发表于 2014-5-28 22:47
模拟IIC需要注意一些情况,首先要注意数据线的输入输出切换。其次是否应答。再者注意好读写控制。对于时序 ...

用过示波器抓过,对照代码也没错。是读操作流程没弄清楚。:P
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:Will there be that one day, you left me.

5

主题

640

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部