I am trying to make an i2c keypad by using atmega8 (master receive and slave transmit mode). here is the master code
#define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> void I2C_INIT() { TWBR = 0x00; //CLEAR STATUS TWBR = 0x0C; //SET BIT RATE } void I2C_START() { TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA); while((TWCR & (1<<TWINT)) == 0); while((TWSR & (0xF8)) != 0x08); } void I2C_READAdress(/*unsigned char adress*/) { TWDR = 0b01000001; TWCR = (1<<TWINT)|(1<<TWEN); while((TWCR & (1<<TWINT)) == 0); while((TWSR & (0xF8)) != 0x40); } unsigned char i2c_read_data() { TWCR = (1<<TWINT)|(1<<TWEN); while((TWCR & (1<<TWINT)) == 0); while((TWSR & (0xF8)) != 0x58); return TWDR; } void I2C_stop() { TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); } int main(void) { DDRD=0xFF; I2C_INIT(); while (1) { I2C_START(); _delay_ms(1000); I2C_READAdress(); _delay_ms(1000); PORTD=i2c_read_data(); _delay_ms(1000); I2C_stop(); _delay_ms(1000); } }
here is slave code.
#define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> //////////////////////// KEYAPD ///////////////////////////// #define KEY_PRT PORTD #define KEY_DDR DDRD #define KEY_PIN PIND unsigned char keypad[4][4] = { {'A','3','2','1'}, {'B','6','5','4'}, {'C','9','8','7'}, {'D','#','0','*'}}; unsigned char colloc, rowloc; char keyfind() { while(1) { KEY_DDR = 0xF0; /* set port direction as input-output */ KEY_PRT = 0xFF; do { KEY_PRT &= 0x0F; /* mask PORT for column read only */ asm("NOP"); colloc = (KEY_PIN & 0x0F); /* read status of column */ }while(colloc != 0x0F); do { do { _delay_ms(20); /* 20ms key debounce time */ colloc = (KEY_PIN & 0x0F); /* read status of column */ }while(colloc == 0x0F); /* check for any key press */ _delay_ms (40); /* 20 ms key debounce time */ colloc = (KEY_PIN & 0x0F); }while(colloc == 0x0F); /* now check for rows */ KEY_PRT = 0xEF; /* check for pressed key in 1st row */ asm("NOP"); colloc = (KEY_PIN & 0x0F); if(colloc != 0x0F) { rowloc = 0; break; } KEY_PRT = 0xDF; /* check for pressed key in 2nd row */ asm("NOP"); colloc = (KEY_PIN & 0x0F); if(colloc != 0x0F) { rowloc = 1; break; } KEY_PRT = 0xBF; /* check for pressed key in 3rd row */ asm("NOP"); colloc = (KEY_PIN & 0x0F); if(colloc != 0x0F) { rowloc = 2; break; } KEY_PRT = 0x7F; /* check for pressed key in 4th row */ asm("NOP"); colloc = (KEY_PIN & 0x0F); if(colloc != 0x0F) { rowloc = 3; break; } } if(colloc == 0x0E) return(keypad[rowloc][0]); else if(colloc == 0x0D) return(keypad[rowloc][1]); else if(colloc == 0x0B) return(keypad[rowloc][2]); else return(keypad[rowloc][3]); } void i2c_slaveinit() { TWAR = 0b01000000; TWCR = (1<<TWEN)|(1<<TWEA)|(1<<TWINT); } void i2c_ACK() { TWCR = (1<<TWEN)|(1<<TWINT); while((TWCR & (1<<TWINT)) == 0); while((TWSR & (0xF8)) != 0xA8); /*TWDR = data; TWCR &= ~(1<<TWEA); TWCR = (1<<TWEN)|(1<<TWEA);*/ } void i2c_transmit(unsigned char data) { TWDR = data; TWCR &= ~(1<<TWEA); TWCR = (1<<TWEN)|(1<<TWINT); while((TWCR & (1<<TWINT)) == 0); while((TWSR & (0xF8)) != 0xC0); TWCR = (1<<TWEN)|(1<<TWEA)|(1<<TWINT); } void i2c_Match_ACK() { while((TWSR & (0xF8)) != 0xA8) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); while((TWCR & (1<<TWINT))==0); } } int main(void) { char x; i2c_slaveinit(); while (1) { //i2c_ACK(); i2c_Match_ACK(); x=keyfind(); i2c_transmit(x); } }
so I followed datasheet of atmega8 and first try to transmit a byte from slave and it works fine I get ACK after STA+R. then I try to put keypad code and I just replaced that byte with keyfind(); function which is also a char and now I don't get ACK after STA+R. is there any relation between them? can anyone help? here is pic of what is get