#include "i2c_master.h" #include uint8_t i2c_clock(uint8_t type); void i2c_init(void) { // Define SCL and SDA as Output DDRB |= (1 << 0) | (1 << 2); // Preload dataregister with "released level" data USIDR = 0xFF; // Use SCL and SDA pins // Select clock sources USICR = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK); // Clear flags and reset counter USISR = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC); } uint8_t i2c_start(uint8_t address) { // FOR REPEATED START // Release SCL PORTB |= (1 << 2); // Verify that SCL becomes high while (!( PINB & (1 << 2) )); // GENERATE START CONDITION // Force SDA LOW PORTB &= ~(1 << 0); // Pull SCL LOW PORTB &= ~(1 << 2); // Release SDA PORTB |= (1 << 0); return i2c_write(address); } uint8_t i2c_write(uint8_t data) { // Pull SCL LOW PORTB &= ~(1 << 2); // Setup data USIDR = data; // Send 8 bits on bus i2c_clock(8); // Enable SDA as input DDRB &= ~(1 << 0); // Receive 1 bit on bus & Check for NACK if (i2c_clock(1) & (1 << 0)) { return 1; } return 0; } uint8_t i2c_read(uint8_t nack) { // Enable SDA as input. DDRB &= ~(1 << 0); // Read 8 bits uint8_t result = i2c_clock(8); if (nack) { // Load NACK USIDR = 0xFF; } else { // Load ACK USIDR = 0x00; } i2c_clock(1); return result; } void i2c_stop(void) { // Pull SDA low PORTB &= ~(1 << 0); // Release SCL PORTB |= (1 << 2); // Wait for SCL to go high while (!( PINB & (1 << 2) )); // Release SDA PORTB |= (1 << 0); } uint8_t i2c_clock(uint8_t count) { uint8_t reg_temp = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC); // Counter counts number of edges // Overflow signals end of transmission reg_temp |= 16 - (count * 2); USISR = reg_temp; // Set clock source & toggle clock prepare reg_temp = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK) | (1 << USITC); do { // Generate positve SCL edge. USICR = reg_temp; // Wait for SCL to go high while (!( PINB & (1 << 2))); // Generate negative SCL edge USICR = reg_temp; } // Wait for counter overflow (all edges are completed) while (!( USISR & (1 << USIOIF))); // Read data reg_temp = USIDR; // Load dataregister with "released level" data USIDR = 0xFF; // Enable SDA as output DDRB |= (1 << 0); return reg_temp; }