First I tried to use USI module for TWI implementation. As for me resulting code was too "fat" for 2Kb FLASH and there was no need for full TWI feature support (the only TWI device in my project was AM2320).
After some time spent on datasheet reading and hardware testing I've wrote a C library for these sensors. Please note that AM2320_ReadData function writes raw data to variables. This notice is actual for negative temperature values, where 0x8000 bit is set.
AM2320 Datasheet
Header file:
/* * AM2320S.h * * Created: 23.05.2016 17:30:13 * Author: TSX */ #ifndef AM2320S_H_ #define AM2320S_H_ #include <avr/io.h> #define AM2320_PORT PORTD #define AM2320_DDR DDRD #define AM2320_PIN PIND #define AM2320_SDA_BIT 3 #define AM2320_SCL_BIT 2 #ifdef __cplusplus extern "C" { #endif extern void AM2320_Init(void); // Returns raw sensor data to variables. Be careful for negative temperature =) extern uint8_t AM2320_ReadData(uint16_t * tempValue, uint16_t * humiValue); #ifdef __cplusplus } #endif #endif /* AM2320S_H_ */
Code file:
/* * AM2320S.c * * Created: 23.05.2016 17:29:50 * Author: TSX */ #include "AM2320S.h" #include <util/delay.h> /************************************************************************/ /* Port functions */ /************************************************************************/ #define SDA_LOW AM2320_DDR |= _BV(AM2320_SDA_BIT) #define SDA_HIGH AM2320_DDR &= ~_BV(AM2320_SDA_BIT) #define SCL_LOW AM2320_DDR |= _BV(AM2320_SCL_BIT) #define SCL_HIGH AM2320_DDR &= ~_BV(AM2320_SCL_BIT) #define SCL_IS_LOW (!(AM2320_PIN & _BV(AM2320_SCL_BIT))) #define SCL_WAIT_HIGH while (!(AM2320_PIN & _BV(AM2320_SCL_BIT))) {} static void _bus_delay(void) { _delay_us(50); } #ifdef USE_Q_DELAY static void _bus_q_delay(void) { _delay_us(30); } #else #define _bus_q_delay() _bus_delay() #endif static void SCL_SetHigh(void) { SCL_HIGH; _bus_delay(); } static void SCL_SetLow(void) { SCL_LOW; _bus_delay(); } /************************************************************************/ /* Bus functions */ /************************************************************************/ static void _bus_start(void) { SCL_HIGH; // prepare // I2C start condition SDA_LOW; _bus_delay(); SCL_SetLow(); } static void _bus_stop(void) { SDA_LOW; _bus_delay(); SCL_HIGH; _bus_q_delay(); SDA_HIGH; _bus_delay(); } static uint8_t _bus_write(uint8_t data) { for (uint8_t i = 0; i<8; i++) { SCL_SetLow(); if (data & 0x80) SDA_HIGH; // MSB first else SDA_LOW; _bus_delay(); SCL_SetHigh(); SCL_WAIT_HIGH; data <<= 1; } SCL_SetLow(); SDA_HIGH; _bus_delay(); // Byte sent, wait for slave ACK SCL_HIGH; SCL_WAIT_HIGH; // wait for slave ack _bus_delay(); _Bool ack = !(AM2320_PIN & _BV(AM2320_SDA_BIT)); SCL_SetLow(); return (uint8_t)ack; } static uint8_t _bus_read(_Bool sendAck) { uint8_t data = 0; for (uint8_t i=0; i<8; i++) { SCL_SetLow(); SCL_SetHigh(); SCL_WAIT_HIGH; if (AM2320_PIN & _BV(AM2320_SDA_BIT)) data |= (0x80 >> i); } SCL_SetLow(); // Generate ACK/NACK if (sendAck) SDA_LOW; else SDA_HIGH; _bus_delay(); SCL_SetHigh(); SCL_SetLow(); SDA_HIGH; _bus_q_delay(); return data; } static uint16_t crc16(uint8_t *ptr, uint8_t len) { uint16_t crc =0xFFFF; uint8_t i; while(len--) { crc ^=*ptr++; for(i=0;i<8;i++) { if (crc & 0x01) { crc>>=1; crc^=0xA001; } else { crc>>=1; } } } return crc; } void AM2320_Init(void) { AM2320_DDR &= ~(_BV(AM2320_SCL_BIT)|_BV(AM2320_SDA_BIT)); AM2320_PORT &= (_BV(AM2320_SCL_BIT)|_BV(AM2320_SDA_BIT)); } uint8_t AM2320_ReadData(uint16_t * tempValue, uint16_t * humiValue) { uint8_t buffer[8]; // Wake up _bus_start(); _bus_write(0xB8); _delay_ms(1); _bus_stop(); _bus_start(); _bus_write(0xB8); _bus_write(0x03); _bus_write(0x00); _bus_write(0x04); _bus_stop(); _delay_ms(1); _bus_start(); _bus_write(0xB8 + 1); _delay_us(50); for (uint8_t i = 0; i<7; i++) { buffer[i] = _bus_read(1); } buffer[7] = _bus_read(0); _bus_stop(); uint16_t Rcrc = ((uint16_t)buffer[7] << 8)+buffer[6]; if (Rcrc == crc16(buffer, 6)) { *humiValue = ((uint16_t)buffer[2] << 8) + buffer[3]; *tempValue = ((uint16_t)buffer[4] << 8) + buffer[5]; return 1; } return 0; }
Hi! Are you tested this Code with Atmel Studio?
ReplyDelete