原创 M8---24C16读写程序

2008-7-5 09:53 4020 6 6 分类: MCU/ 嵌入式
#include <avr\io.h>
#include <avr\delay.h>
#include <inttypes.h>
#include "lcd.h"

/*******************************************************************************
* TWI_init: sets bitrate in TWBR and prescaler in TWSR
* TWI_action: writes command to TWCR and takes care of TWINT and TWEN setting
* waits for TWI action to be completed and returns status code
* TWI_start: generates start condition and returns status code
* TWI_stop: generate stop condition and returns status code
* TWI_write_data: writes data to TWI bus and returns status code
* TWI_read_data: reads data from bus to TWDR and returns status code.
* if put_ack > 0, an ACK will be sent after the data has been received.
* TWI_wait: waits for a given slave address to be ACKed. Only use if slave has
* ACKed its address before. Loops forever if slave not present!
* EE_read_data: reads one data byte from a given address
* returns different error codes (zero if success) and data in TWDR
* EE_write_data: write one data byte to a given address
* returns different error codes (zero if success)
*******************************************************************************/
void TWI_init(char bitrate, char prescaler);
char TWI_action(char command);
char TWI_start(void);
void TWI_stop(void);
char TWI_write_data(char data);
char TWI_read_data(char put_ack);
void TWI_wait(char slave);
char EE_write_byte(const int address, const char data);
char EE_read_byte(const int address);

#define EE_ADDR 0xA0

/******************************************************************************/
void main (void)
{
//init LCD
LCD_init();
//set TWBR = 32 for 100kHz SCL @ 8MHz
TWI_init(32, 0);

//write 0x55 @ 513 and print return value on LCD
LCD_puthex(EE_write_byte(513, 0x55));
//send stop
TWI_stop();
LCD_wait();
LCD_putchar(' ');
//wait for the EEPROM to finish the write operation
TWI_wait(EE_ADDR);
//read the write location again and print return code on LCD
LCD_puthex(EE_read_byte(513));
LCD_wait();
LCD_putchar(' ');
//print the value read from the EEPROM on the LCD
LCD_puthex(TWDR);
TWI_stop();
//LCD should now show "0x00 0x00 0x55_"
//where the _ is the blinking cursor.
}

/******************************************************************************/
void TWI_init(char bitrate, char prescaler)
//sets bitrate and prescaler
{
TWBR = bitrate;
//mask off the high prescaler bits (we only need the lower three bits)
TWSR = prescaler & 0x03;
}

/******************************************************************************/
char TWI_action(char command)
//starts any TWI operation (not stop), waits for completion and returns the status code
//TWINT and TWEN are set by this function, so for a simple data transfer just use TWI_action(0);
{ //make sure command is good
TWCR = (command|(1<<TWINT)|(1<<TWEN));
//wait for TWINT to be set after operation has been completed
while(!(TWCR & (1<<TWINT)));
//return status code with prescaler bits masked to zero
return (TWSR & 0xF8);
}

/******************************************************************************/
char TWI_start(void)
//uses TWI_action to generate a start condition, returns status code
{ //TWI_action writes the following command to TWCR: (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
return TWI_action(1<<TWSTA);
//return values should be 0x08 (start) or 0x10 (repeated start)
}

/******************************************************************************/
void TWI_stop(void)
//generates stop condition
{ //as TWINT is not set after a stop condition, we can't use TWI_action here!
TWCR = ((1<<TWINT)|(1<<TWSTO)|(1<<TWEN));
//status code returned is 0xF8 (no specific operation)
}

/******************************************************************************/
char TWI_write_data(char data)
//loads data into TWDR and transfers it. Works for slave addresses and normal data
//waits for completion and returns the status code.
{ //just write data to TWDR and transmit it
TWDR = data;
//we don't need any special bits in TWCR, just TWINT and TWEN. These are set by TWI_action.
return TWI_action(0);
//status code returned should be:
//0x18 (slave ACKed address)
//0x20 (no ACK after address)
//0x28 (data ACKed by slave)
//0x30 (no ACK after data transfer)
//0x38 (lost arbitration)
}

/******************************************************************************/
char TWI_read_data(char put_ack)
{ //if an ACK is to returned to the transmitting device, set the TWEA bit
if(put_ack)
return(TWI_action(1<<TWEA));
//if no ACK (a NACK) has to be returned, just receive the data
else
return(TWI_action(0));
//status codes returned:
//0x38 (lost arbitration)
//0x40 (slave ACKed address)
//0x48 (no ACK after slave address)
//0x50 (AVR ACKed data)
//0x58 (no ACK after data transfer)
}

/******************************************************************************/
void TWI_wait(char slave)
{
//send slave address until a slave ACKs it. Good for checking if the EEPROM
//has finished a write operation. Use carefully! If the wrong slave address
//is being waited for, this function will end in an infinite loop.
do {
TWI_start();
} while(TWI_write_data(slave) != 0x18);
TWI_stop();
}

/******************************************************************************/
char EE_write_byte(const int address, const char data)
{
char dummy;
//we need this for the first if()
dummy = TWI_start();
//if the start was successful, continue, otherwise return 1
if((dummy != 0x08) && (dummy != 0x10))
return TWSR;
//now send the EEPROM slave address together with the address bits 8..10 for page select
//address format:
//|bit7 |bit6 |bit5 |bit4 |bit3 |bit2 |bit1 |bit0 |
//| EE_ADDR   |  page select | R/W |
if(TWI_write_data(EE_ADDR|((address>>7) & 0x000E)) != 0x18)
return TWSR;
//now send the word address byte
if(TWI_write_data((char)(address)) != 0x28)
return TWSR;
//now send the data byte
if(TWI_write_data(data) != 0x28)
return TWSR;
//if everything was OK, return zero.
return 0;
}

/******************************************************************************/
char EE_read_byte(const int address)
{
char dummy;
//we need this for the first if()
dummy = TWI_start();
//as in EE_write_byte, first send the page address and the word address
if((dummy != 0x08) && (dummy != 0x10))
return TWSR;
if(TWI_write_data(EE_ADDR|((address>>7) & 0x000E)) != 0x18)
return TWSR;
if(TWI_write_data((char)(address)) != 0x28)
return TWSR;
//send a repeated start for entering master receiver mode
if(TWI_start() != 0x10)
return TWSR;
//send slave address, now with the read bit set
if(TWI_write_data((EE_ADDR|1)|((address>>7) & 0x000E)) != 0x40)
return TWSR;
//now get the data from the EEPROM, don't return ACK
if(TWI_read_data(0) != 0x58)
return TWSR;
//if everything was OK, return zero
return 0;
}

文章评论0条评论)

登录后参与讨论
我要评论
0
6
关闭 站长推荐上一条 /2 下一条