📄 i2crtc.c
字号:
#include "i2crtc.h"
#define RTC_ADDRESS 0xA2 // I2C address of Real Time Clock
#define TIMEOUT 0xAA0F // timer reload value gives 22ms timeout period
// for waiting on SLAve address + Write ack
//void init_i2c(void);
void rtc_write_byte(unsigned char address, unsigned char byte);
unsigned char rtc_read_byte(unsigned char address, unsigned char maskoff);
unsigned char bcdtochar(unsigned char bcdnum);
unsigned char chartobcd(unsigned char n);
void i2c_isr(void);
//void start_timer(void);
//void stop_timer(void);
unsigned char mask[] = {0xA8, 0x1F, 0x7F, 0x7F, 0x3F, 0x3F, 0x07, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// mask values for registers
enum i2c_states { DATA_BYTE, FINISHED, DUMMY_WRITE }; // states of operations
// during a write the DATA_BYTE state is when the next byte to
// be written is the data byte. The FINISHED state is when the
// data byte has been written
// during a read the DUMMY_WRITE is the state during the dummy
// write to set the register address to read
enum i2c_operations { READ, WRITE }; // possible I2C operations are Read and Write
unsigned char i2c_storage_address; // holds the address of the register to read or write
unsigned char i2c_byte; // holds the value to write or the value read from a register
unsigned char i2c_state; // holds the I2C state - DATA_BYTE, FINISHED or DUMMY_WRITE
unsigned char i2c_status; // holds the status - I2C_BUSY, I2C_OK or I2C_ERROR
unsigned char i2c_operation; // holds the operation - READ or WRITE
/*
// function init_i2c
// initializes the I2C peripheral
void init_i2c(void)
{
P1M1 |= 0xC0; // set P1.6 and P1.7 open drain
P1M2 |= 0xC0;
TMOD |= 0x01; // timer 0 mode 1
ES1 = 1; // enable SIO1 interrupts
EA = 1; // global interrupt enable
}
*/
// function chartobcd
// converts a decimal value to the BCD equivalent
// decimal values must be stored in the Real Time Clock in BCD format
// passed is the decimal value to convert
// returned is the BCD equivalent
unsigned char chartobcd(unsigned char n)
{
return ((n / 10) << 4) | (n % 10);
}
// function bcdtochar
// converts a number in BCD format to the decimal equivalent
// decimal values must be stored in the Real Time Clock in BCD format
// passed is the BCD format value
// returned is the decimal equivalent
unsigned char bcdtochar(unsigned char bcdnum)
{
return (bcdnum & 0x0f) + (bcdnum >> 4) * 10;
}
/*
// function rtc_write_byte
// stores a byte in a specific register in the Real Time Clock
// passed is the register address and the byte to store
// nothing is returned
// result of the operation is stored in i2c_status and may be
// I2C_OK or I2C_ERROR
void rtc_write_byte(unsigned char address, unsigned char byte)
{
i2c_storage_address = address; // copy the register address
i2c_byte = chartobcd(byte); // convert to BCD and copy the byte
i2c_status = I2C_BUSY; // I2C is now busy
i2c_operation = WRITE; // a write operation is being performed
S1CON = 0x40; // enable the I2C perhiperal
// no acknowledgements will be returned
STA = 1; // request a start condition is transmitted
// therefore putting I2C perhiperal in Master Transmitter mode
while(i2c_status == I2C_BUSY); // wait until I2C is not busy
}
// function rtc_read_byte
// reads a byte from a specific register in the Real Time Clock, performing
// optional masking of the result
// passed is the address of the register to read and a flag to indicate
// if masking is required - may be MASK or NOMASK
// the decimal value is returned
// result of the operation is stored in i2c_status and may be
// I2C_OK or I2C_ERROR
unsigned char rtc_read_byte(unsigned char address, unsigned char maskoff)
{
i2c_storage_address = address; // copy the register address
i2c_status = I2C_BUSY; // I2C is now busy
i2c_operation = READ; // read operation is being performed
i2c_state = DUMMY_WRITE; // initially a dummy write has to be
// performed to set the register address
S1CON = 0x40; // enable the I2C peripheral
// no acknowledgements will be returned
STA = 1; // request a start condition is transmitted
// therefore putting I2C peripheral in Master Transmitter mode
while(i2c_status == I2C_BUSY); // wait until I2C is no longer busy
if (maskoff) i2c_byte &= mask[address]; // mask result if required
return bcdtochar(i2c_byte); // convert to decimal and return result
}
*/
/*
// function start_timer
// sets up and starts timer 0 - start of timeout period
// nothing is passed. nothing is returned
void start_timer(void)
{
TL0 = TIMEOUT & 0xFF; // set up timer 0 reload value
TH0 = (TIMEOUT >> 8) & 0xFF;
TR0 = 1; // start timer 0
}
// function stop_timer
// stops timer 0 and clears overflow flag
// nothing is passed. nothing is returned
void stop_timer(void)
{
TR0 = 0; // stop timer 0
TF0 = 0; // clear overflow flag
}
*/
/*
// function i2c_isr
// I2C interrupt service routine
// the interrupt is triggered on each I2C event. The I2C peripheral state
// is stored in the S1STA SFR
// different actions are performed depending on the peripheral state
// nothing is passed. nothing is returned.
// Note: if debugging printfs are inserted into this function the execution
// will be slowed down to the point where the timeout occurs.
void i2c_isr(void) interrupt 5 using 1
{
switch(S1STA)
{
// START CONDITION TRANSMITTED
case 0x08:
STA = 0; // clear flag so another start condition is not transmitted
start_timer(); // start timer to measure timeout period
S1DAT = RTC_ADDRESS & 0xFE; // transmit Slave Address + Write command (SLA + W)
break;
// REPEATED START CONDITION TRANSMITTED
case 0x10:
STA = 0; // clear flag so another start condition is not transmitted
if (i2c_operation == READ && i2c_state != DUMMY_WRITE) // if performing a read and we have completed the dummy write then...
{
S1DAT = RTC_ADDRESS | 0x01; // transmit Slave Address + Read command (SLA + R)
}
else
{
S1DAT = RTC_ADDRESS & 0xFE; // transmit Slave Address + Write command (SLA + W)
// this situation arises when no response was received from the
// Real Time Clock and another attempt is being made
}
break;
// SLAVE ADDRESS + WRITE TRANSMITTED - ACK RECEIVED
case 0x18:
stop_timer(); // stop timer - response was received within the timeout period
S1DAT = i2c_storage_address; // transmit the register address
i2c_state = DATA_BYTE; // next byte to be sent is the data byte
break;
// SLAVE ADDRESS + WRITE TRANSMITTED - NO ACK RECEIVED
case 0x20:
if (TF0) // if timer 0 has overflowed then timeout period has been reached
{
STO = 1; // request to transmit a stop condition - give up attempt to communicate
stop_timer(); // stop timer 0
i2c_status = I2C_ERROR; // status of operation is an error
}
else // still trying to communicate. The timeout period has not been reached
{
STA = 1; // request to transmit a repeated start condition
}
break;
// DATA BYTE OR REGISTER ADDRESS TRANSMITTED - ACK RECEIVED
case 0x28:
switch(i2c_state)
{
case DATA_BYTE: // next byte to be transmitted is the data byte
if (i2c_operation == READ) // if reading then this is the end of the dummy write
// no date byte is transmitted
{
STA = 1; // request to transmit repeated start condition. This will start off the read cycle
}
else
{
S1DAT = i2c_byte; // transmit data byte
i2c_state = FINISHED; // next time around in this state we are finished
}
break;
case FINISHED: // data byte has been successfully transmitted
STO = 1; // request to transmit a stop condition
i2c_status = I2C_OK; // status of operation is OK
break;
}
break;
// DATA BYTE OR REGISTER ADDRESS TRANSMITTED - NO ACK RECEIVED
case 0x30:
STO = 1; // no response from Real Time Clock. Request to transmit a stop condition
// we could invoke another timeout period here if desired
i2c_status = I2C_ERROR; // status of operation is ERROR
break;
// SLAVE ADDRESS + READ TRANSMITTED - ACK RECEIVED
case 0x40:
break; // don't do anything. Next time around a data byte will be received
// SLAVE ADDRESS + READ TRANSMITTED - NO ACK RECEIVED
case 0x48:
STO = 1; // no response from Real Time Clock. Request to transmit a stop condition
i2c_status = I2C_ERROR; // status of operation is ERROR
break;
// DATA BYTE RECEIVED - NO ACK RETURNED
case 0x58:
i2c_byte = S1DAT; // data byte has been received from the Real Time Clock
// no ack was returned as per the datasheet
i2c_status = I2C_OK; // status of operation is OK
STO = 1; // request to transmit a stop condition
break;
// UNKNOWN STATE
default:
STO = 1; // I2C peripheral is in a state not anticipated. Request to
// transmit a stop condition
i2c_status = I2C_ERROR; // status of operation is ERROR
ES1 = 0; // disable I2C interrupts
break;
}
SI = 0; // clear I2C interrupt flag. This will initiate
// another operation on the I2C bus and possibly
// another I2C interrupt being requested
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -