0

ATmega32 应该作为从机来收集数据和 GPIO 控制。I2C 包裹应该看起来像 S(地址)(寄存器)([值])P 但是如果我在指定寄存器后发送 P 条件,Proteus 会自动发送附加字节,即使在 NACK 之后也右移。MCU 将寄存器左移。我使用带有内置 SDK 的 Atmel Studio 7。如何解决这个问题?

I2C中断服务程序

ISR(TWI_vect)
{
    //cli();
    
  switch(TW_STATUS)
  {
    case TW_SR_DATA_ACK:
      // received data from master, call the receive callback
      // расчет на то, что при приеме данных первым байтом 
      // будет регистр, куда будут записываться данные
      I2C_recv(TWDR, is_data_recv);
      
      if (is_data_recv == 0) {
          is_data_recv = 1;
          I2C_ack();
      }
      else I2C_nack();
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
    case TW_ST_SLA_ACK:
      // master is requesting data, call the request callback
      I2C_req();
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
    case TW_ST_DATA_ACK:
      // master is requesting data, call the request callback
      I2C_req();
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
    case TW_BUS_ERROR:
      // some sort of erroneous state, prepare TWI to be readdressed
      TWCR = 0;
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN); 
      break;
    case TW_SR_STOP:
      is_data_recv = 0;
      I2C_on_stop();
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
    default:
      //TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
  }
  
  
  //sei();
  //TWCR |= (1<<TWINT);
  TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEN);
} 

I2C 回调

// Прием по I2C регистров/данных
// Getting register/data from I2C
void i2c_receive_cb(uint8_t byte_received, uint8_t is_data) {
    if (is_data == 0) regaddr = byte_received;
    else regdata = byte_received;
}

// Выдача данных при задание одного из регистров на чтение
// Putting data to I2C if register is read-register
void i2c_response_cb() {
    uint8_t data_out = 0;
    //uint8_t ack = 0;
    switch (regdata)
    {
    case GET_ANALOG:
        data_out = (data_block % 2 == 0 ? analog_h[data_block] : analog_l[data_block]);
        data_block++;
        if (data_block > 15) {
            data_block = 0;
            I2C_nack();
        }
        else {
            I2C_ack();
        }
        //ack = 0;
        break;
    case GET_ERRORS:
        data_out = 0x66;                // Выдача кода ошибки
        I2C_nack();
    }
    
    I2C_transmitByte(data_out);
}

// Применение данных из регистра на запись, или сброс счетчика блоков данных
// Applying data from write registers or reset data blocks counter
void i2c_on_stop_cb() {
    data_block = 0;
}

项目链接

变形虫截图

4

1 回答 1

0

你好,你可以使用i2c-unit驱动,这个驱动已经测试过没有任何问题,这个驱动已经在很多库和代码中使用过!

驱动链接

于 2020-08-23T11:59:00.820 回答