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;
}