憨豆龙 2024-03-29 10:37 采纳率: 0%
浏览 19
已结题

关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)

项目:使用模拟iic与ov2640通讯
环境:F407
问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化。
自己是初学,也不知道时序之类的有没有搞对,望解决。

下面是我的IIC基本操作函数

/**
* @brief  产生I2C通讯的起始信号
* @note   IIC起始信号  当SCL高电平时,SDA出现一个下降沿表示I2C总线启动信号 
* @param  None
* @retval None
*/
void I2C_GPIO_MakeStart(void)
{
    I2C_GPIO_SCL_High();
    I2C_GPIO_SDA_High();
    Delay_us(4);
     I2C_GPIO_SDA_Low();
    Delay_us(4);
    I2C_GPIO_SCL_Low();     //准备发送或接收数据 
    Delay_us(2);
}

/**
* @brief  产生I2C通讯的结束信号
* @note   IIC停止信号  当SCL高电平时,SDA出现一个上升沿表示I2C总线停止信号
* @param  None
* @retval None
*/
void I2C_GPIO_MakeEnd(void)
{
    I2C_GPIO_SDA_Low();
    I2C_GPIO_SCL_High();
  Delay_us(2);                
    I2C_GPIO_SDA_High(); //发送I2C总线结束信号    
}

/**
* @brief  MCU等待从设备应答信号到来
* @param  无
* @retval 1:接收应答失败  0:接收应答成功
*/
uint8_t I2C_GPIO_MCUwaitACK(void)
{
    uint8_t waitcount=0;
  I2C_GPIO_SDA_IN();
    
    I2C_GPIO_SDA_High();
    Delay_us(1);       
    //SCL在高电平下SDA数据有效
    I2C_GPIO_SCL_High();
    Delay_us(1);     
    
    while(I2C_GPIO_SDA_Read())
    {
        waitcount++;
        if(waitcount > 250 ){
            return 1;}
   }
    I2C_GPIO_SCL_Low();
    Delay_us(1);
    
    I2C_GPIO_SDA_OUT();
    return 0;  
}


/**
* @brief  MCU产生应答
* @note   一般不使用MCU产生应答信号,但连续读写的时候会使用。
*         经常使用的是MCU产生非应答,来结束一次读数据操作。
* @param  none
* @retval none
*/
void I2C_GPIO_MCUmakeACK(void)
{
    I2C_GPIO_SDA_Low();
    Delay_us(2);
    I2C_GPIO_SCL_High();
    Delay_us(2);
    I2C_GPIO_SCL_Low();
    Delay_us(2);
    I2C_GPIO_SDA_High();
}

/**
* @brief  MCU产生非应答
* @note   当主机接收数据时,它收到最后一个字节后,必须向从机发出一个结束传送的信号。
*         这个信号是通过对从机的“非应答信号”来实现的。
*         在SCL为高电平期间,SDA为高电平,即从机释放SDA线,允许主机产生一个停止信号。         
* @param  none
* @retval none
*/
void I2C_GPIO_MCUmakeNACK(void)
{
    I2C_GPIO_SCL_Low();
    I2C_GPIO_SDA_High();
    Delay_us(2);
    I2C_GPIO_SCL_High();
    Delay_us(2);
    I2C_GPIO_SCL_Low();
}

/**
* @brief  I2C写一个字节
* @note   
* @param  无
* @retval 暂无
*/
void I2C_GPIO_writebyte(uint8_t byte)
{
    uint8_t k;
    
  I2C_GPIO_SCL_Low();    //拉低时钟开始数据传输
  for(k=0;k<8;k++)
  {              
      if( byte & 0x80){
            I2C_GPIO_SDA_High();
        }
        else{
            I2C_GPIO_SDA_Low();
        }        
         byte<<=1; //byte左移一位赋值给byte      
       Delay_us(2);   
       I2C_GPIO_SCL_High();
       Delay_us(2); 
       I2C_GPIO_SCL_Low();
       Delay_us(2);
  }    
     //释放SDA总线
         I2C_GPIO_SDA_High();
}

/**
* @brief  IIC读取一个字节
* @note   
* @param  ack=1,发送ACK,ack=0,发送nACK 
* @retval 读到的8位数据
*/
uint8_t I2C_GPIO_readbyte(uint8_t ack)
{
    uint8_t i=0;
    uint8_t receive_data=0;
  
    I2C_GPIO_SDA_High();
    I2C_GPIO_SDA_IN();
  for(i=0;i<8;i++ )
      {   
              
              I2C_GPIO_SCL_Low();
              Delay_us(2);
              
              I2C_GPIO_SCL_High(); 
              receive_data = (receive_data<<1)|I2C_GPIO_SDA_Read();
              Delay_us(2);
            
    }                     
    I2C_GPIO_SDA_OUT();
  if (!ack){
        I2C_GPIO_MCUmakeNACK();//发送nACK
        }
  else{
        I2C_GPIO_MCUmakeACK(); //发送ACK  
        }            
  return receive_data;
}

uint8_t OV2640_WriteReg(uint8_t Addr, uint8_t Data)
{
    I2C_GPIO_SCL_Init();
    I2C_GPIO_SDA_OUT();
    
    //发送开始信号
  I2C_GPIO_MakeStart();
    
  //发送从设备地址
  I2C_GPIO_writebyte(OV2640_DEVICE_WRITE_ADDRESS); 
    
    //等待从机的应答
    if(I2C_GPIO_MCUwaitACK()) code = 1;
    
    //发送要写入寄存器的地址
    I2C_GPIO_writebyte(Addr);  
  if(I2C_GPIO_MCUwaitACK()) code = 2;
    
  //发送数据
  I2C_GPIO_writebyte(Data);  
  if(I2C_GPIO_MCUwaitACK()) code = 3;
 
    //发送停止信号
  I2C_GPIO_MakeEnd();
  
  //如果一切正常,返回0
    code =0;
  return code;
}

/**
  * @brief  从OV2640寄存器中读取一个字节的数据
  * @param  Addr: 寄存器地址
  * @retval 返回读取得的数据
  */
uint8_t OV2640_ReadReg(uint8_t Addr)
{
  uint8_t Data = 0;
    I2C_GPIO_SCL_Init();
    I2C_GPIO_SDA_OUT();
    
    //发送开始信号
  I2C_GPIO_MakeStart();
  
  //发送从设备地址(写)
  I2C_GPIO_writebyte(OV2640_DEVICE_WRITE_ADDRESS); 
  I2C_GPIO_MCUwaitACK();

  //发送要读取寄存器的地址
    I2C_GPIO_writebyte(Addr);  
  I2C_GPIO_MCUwaitACK();

  //发送重复开始信号
  I2C_GPIO_MakeStart();
    
    //发送从设备地址(读)
  I2C_GPIO_writebyte(OV2640_DEVICE_READ_ADDRESS); 
    I2C_GPIO_MCUwaitACK();
  
    //这里接收数据的同时发送了NACK
    Data = I2C_GPIO_readbyte(0);
    
  //发送停止信号
  I2C_GPIO_MakeEnd();

  /* return the read data */
  return Data;

  • 写回答

21条回答 默认 最新

  • 码农阿豪 Java领域优质创作者 2024-03-29 10:37
    关注
    获得0.60元问题酬金
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    在代码中,可以看到I2C_GPIO_writebyte和I2C_GPIO_readbyte函数是用来进行I2C通讯的。在读从机数据时,应该先发送从机地址,再发送要读取的寄存器地址,然后再进行数据读取。检查一下这一过程中时序是否正确。如果时序正确,那么可能是硬件接线或者从机芯片本身的问题。 以下是一份OV2640摄像头的I2C通讯代码,供参考:
    #define OV2640_ADDRESS      0x60
    uint8_t OV2640_ReadReg(uint8_t reg)
    {
        uint8_t value = 0;
        I2C_GPIO_MakeStart();
        I2C_GPIO_writebyte(OV2640_ADDRESS << 1);
        if(I2C_GPIO_MCUwaitACK()) {
           I2C_GPIO_MakeEnd();
           return 0xFF;
        }
        I2C_GPIO_writebyte(reg);
        if(I2C_GPIO_MCUwaitACK()) {
            I2C_GPIO_MakeEnd();
            return 0xFF;
        }
        I2C_GPIO_MakeStart();
        I2C_GPIO_writebyte((OV2640_ADDRESS << 1) | 1);
        if(I2C_GPIO_MCUwaitACK()) {
           I2C_GPIO_MakeEnd();
           return 0xFF;
        }
        value = I2C_GPIO_readbyte(0);
        I2C_GPIO_MakeEnd();
        return value;
    }
    uint8_t OV2640_WriteReg(uint8_t reg, uint8_t value)
    {
        I2C_GPIO_MakeStart();
        I2C_GPIO_writebyte(OV2640_ADDRESS << 1);
        if(I2C_GPIO_MCUwaitACK()) {
            I2C_GPIO_MakeEnd();
            return 1;
        }
        I2C_GPIO_writebyte(reg);
        if(I2C_GPIO_MCUwaitACK()) {
            I2C_GPIO_MakeEnd();
            return 1;
        }
        I2C_GPIO_writebyte(value);
        if(I2C_GPIO_MCUwaitACK()) {
            I2C_GPIO_MakeEnd();
            return 1;
        }
        I2C_GPIO_MakeEnd();
        return 0;
    }
    
    评论

报告相同问题?

问题事件

  • 系统已结题 4月6日
  • 赞助了问题酬金20元 3月29日
  • 创建了问题 3月29日

悬赏问题

  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!