打印
[51单片机]

51模拟IIC问题,能写不能读

[复制链接]
2504|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
perry_peng|  楼主 | 2014-5-28 11:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Proteus仿真时可以,实际操作时能写不能读。请帮忙看看。
编译器用sdcc 3.4

/**<
* \fn i2c_write_byte(c)
* \brief Writes a byte to device.
* \param c data
*/
void i2c_write_byte(uint8 c)
{
  uint8 i;

  for (i = 0; i < 8; i++) {
    set_sda(c & 0x80);
    set_scl_high();
    delay_4us();
    c <<= 1;
    set_scl_low();
    delay_4us();
  }
}

/**<
* \fn i2c_read_byte()
* \brief Reads a byte from device.
* \return Returned data.
*/
uint8 i2c_read_byte(void)
{
  uint8 i, c = 0;

  for (i = 0; i < 8; i++) {
    set_scl_high();
    delay_4us();
    c <<= 1;
    c |= get_sda();
    set_scl_low();
    delay_4us();
  }

  return c;
}

uint8 pcf8574_write_port(uint8 slave, uint8 bits)
{
  uint8 ret = 1;

  /* START condition.
   */
  set_sda_high();
  set_scl_high();
  delay_4us();
  set_sda_low();
  delay_4us();
  set_scl_low();

  delay_xms(5);

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

  /**< ACK condition.
   */
  set_sda_high();
  delay_4us();
  set_scl_high();
  delay_4us();
  ACC = get_sda();
  set_scl_low();
  delay_4us();
  if (ACC)
    goto __i2c_write_finish;

  delay_xms(5);

  i2c_write_byte(bits);
  /**< ACK condition.
   */
  set_sda_high();
  delay_4us();
  set_scl_high();
  delay_4us();
  ACC = get_sda();
  set_scl_low();
  delay_4us();
  if (ACC)
    goto __i2c_write_finish;

  ret = 0;

__i2c_write_finish:
  delay_xms(5);

  /**< STOP condition.
   */
  set_sda_low();
  delay_4us();
  set_scl_high();
  delay_4us();
  set_sda_high();

  delay_xms(30);

  return ret;
}

uint8 pcf8574_read_port(uint8 slave, uint8 *out)
{
  uint8 ret = 1;

  /**< START condition.
   */
  set_sda_high();
  set_scl_high();
  delay_4us();
  set_sda_low();
  delay_4us();
  set_scl_low();

  delay_xms(5);

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

  /**< ACK condition.
   */
  set_sda_high();
  delay_4us();
  set_scl_high();
  delay_4us();
  ACC = get_sda();
  set_scl_low();
  delay_4us();
  if (ACC)
    goto __i2c_read_finish;

  delay_xms(5);

  *out = i2c_read_byte();

  /**< NAK condition.
   */
  set_sda_high();
  set_scl_high();
  delay_4us();
  set_scl_low();
  set_sda_low();
  delay_4us();

  ret = 0;

__i2c_read_finish:
  delay_xms(5);

  /**< STOP condition.
   */
  set_sda_low();
  delay_4us();
  set_scl_high();
  delay_4us();
  set_sda_high();

  delay_xms(30);

  return ret;
}

相关帖子

沙发
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需要注意一些情况,首先要注意数据线的输入输出切换。其次是否应答。再者注意好读写控制。对于时序调试,我个人觉得最好的方式就是使用示波器,看看波形是否正确,也就是看看软件对应的硬件行为。

使用特权

评论回复
5
loliweive| | 2014-5-29 09:16 | 只看该作者
uint8 i2c_read_byte(void),这个函数不应该带有地址形参吗?

使用特权

评论回复
6
perry_peng|  楼主 | 2014-5-29 12:42 | 只看该作者
yewuyi 发表于 2014-5-28 11:28
读比写稍微复杂一点而已,多了一个‘写’的过程。

读步骤一般如下:

明白了,是少了4,5步骤。

使用特权

评论回复
7
perry_peng|  楼主 | 2014-5-29 12:43 | 只看该作者
ningling_21 发表于 2014-5-28 12:49
LZ流程好像没搞清楚...

没错,是流程没理解清楚。

使用特权

评论回复
8
perry_peng|  楼主 | 2014-5-29 12:44 | 只看该作者
本帖最后由 perry_peng 于 2014-5-29 12:58 编辑

谢谢大家指导,我用的pcf8574,没有第3步,所以我直接读时用的4,5,6步。

使用特权

评论回复
9
perry_peng|  楼主 | 2014-5-29 12:48 | 只看该作者
loliweive 发表于 2014-5-29 09:16
uint8 i2c_read_byte(void),这个函数不应该带有地址形参吗?

这个函数是没有参数的,只是模拟一个读动作。数据从IO读出来,而IO已经定义成宏。

使用特权

评论回复
10
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

主题

639

帖子

2

粉丝