Cześć,
Postanowiłem zbudować sobie miernik poziomu CO2 w powietrzu, wykorzystując czujnik SCD41, komunikujący się po magistrali I2C. Według datasheetów Atmegi 16 oraz SCD41 powinno to być dość proste do ogarnięcia, jednak czujnik cały czas milczał jak zaklęty. Po podsłuchaniu analizatorem stanów logicznych co też się dzieje na magistrali wychodzi na to, że Atmega 16 z jakiegoś powodu przekręca nadawany adres, przesuwając go o jeden bit w prawo - z 0x62 robi się 0x31. Niby mógłbym wołać czujnik pod 0xC4 (wtedy nadaje 0x62), ale też chciałem EEPROM I2C 24C02 użyć, a on ma już adres 0xA0 - nie da się go pomnożyć razy dwa, bo się 8-bitowa zmienna "przekręca". Kod obsługujący start:
Kod obsługujący wysyłanie
Kod wziąłem stąd: https://www.electronicwings.com/avr-atmega/atmega1632-i2c więc zakładam że powinien działać, no i zgadza się z przykładami z noty katalogowej Atmegi. Czyżby powodem dziwnego działania była niska częstotliwość zegara (1,8432 MHz) ?
Postanowiłem zbudować sobie miernik poziomu CO2 w powietrzu, wykorzystując czujnik SCD41, komunikujący się po magistrali I2C. Według datasheetów Atmegi 16 oraz SCD41 powinno to być dość proste do ogarnięcia, jednak czujnik cały czas milczał jak zaklęty. Po podsłuchaniu analizatorem stanów logicznych co też się dzieje na magistrali wychodzi na to, że Atmega 16 z jakiegoś powodu przekręca nadawany adres, przesuwając go o jeden bit w prawo - z 0x62 robi się 0x31. Niby mógłbym wołać czujnik pod 0xC4 (wtedy nadaje 0x62), ale też chciałem EEPROM I2C 24C02 użyć, a on ma już adres 0xA0 - nie da się go pomnożyć razy dwa, bo się 8-bitowa zmienna "przekręca". Kod obsługujący start:
uint8_t I2C_Start(uint8_t write_address)/* I2C start function */
{
uint8_t status; /* Declare variable */
TWCR=(1<<TWSTA)|(1<<TWEN)|(1<<TWINT); /* Enable TWI, generate START */
while(!(TWCR&(1<<TWINT))); /* Wait until TWI finish its current job */
status=TWSR&0xF8; /* Read TWI status register */
if(status!=0x08) /* Check weather START transmitted or not? */
return 0; /* Return 0 to indicate start condition fail */
TWDR= write_address; /* Write SLA+W in TWI data register */
TWCR=(1<<TWEN)|(1<<TWINT); /* Enable TWI & clear interrupt flag */
while(!(TWCR&(1<<TWINT))); /* Wait until TWI finish its current job */
status=TWSR&0xF8; /* Read TWI status register */
if(status==0x18) /* Check for SLA+W transmitted &ack received */
return 1; /* Return 1 to indicate ack received */
if(status==0x20) /* Check for SLA+W transmitted &nack received */
return 2; /* Return 2 to indicate nack received */
else
return 3; /* Else return 3 to indicate SLA+W failed */
}
Kod obsługujący wysyłanie
uint8_t I2C_Write(uint8_t data) /* I2C write function */
{
uint8_t status; /* Declare variable */
TWDR=data; /* Copy data in TWI data register */
TWCR=(1<<TWEN)|(1<<TWINT); /* Enable TWI and clear interrupt flag */
while(!(TWCR&(1<<TWINT))); /* Wait until TWI finish its current job */
status=TWSR&0xF8; /* Read TWI status register */
if(status==0x28) /* Check for data transmitted &ack received */
return 0; /* Return 0 to indicate ack received */
if(status==0x30) /* Check for data transmitted &nack received */
return 1; /* Return 1 to indicate nack received */
else
return 2; /* Else return 2 for data transmission failure */
}Kod wziąłem stąd: https://www.electronicwings.com/avr-atmega/atmega1632-i2c więc zakładam że powinien działać, no i zgadza się z przykładami z noty katalogowej Atmegi. Czyżby powodem dziwnego działania była niska częstotliwość zegara (1,8432 MHz) ?