📄 i2c.c
字号:
/*! \file i2c.c \brief I2C interface using AVR Two-Wire Interface (TWI) hardware. */
//*****************************************************************************
//
// File Name : 'i2c.c'
// Title : I2C interface using AVR Two-Wire Interface (TWI) hardware
// Author : Pascal Stang - Copyright (C) 2002-2003
// Created : 2002.06.25
// Revised : 2003.03.02
// Version : 0.9
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
//#include <iom128.h>
//#include <avr/signal.h>
//#include <avr/interrupt.h>
#include "i2c.h"
//#include "rprintf.h" // include printf function library
//#include "uart2.h"
// Standard I2C bit rates are:
// 100KHz for slow speed
// 400KHz for high speed
//#define I2C_DEBUG
// I2C state and address variables
static volatile eI2cStateType I2cState;
static u08 I2cDeviceAddrRW;
// send/transmit buffer (outgoing data)
static u08 I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
static u08 I2cSendDataIndex;
static u08 I2cSendDataLength;
// receive buffer (incoming data)
static u08 I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
static u08 I2cReceiveDataIndex;
static u08 I2cReceiveDataLength;
// function pointer to i2c receive routine
//! I2cSlaveReceive is called when this processor
// is addressed as a slave for writing
static void (*i2cSlaveReceive)(u08 receiveDataLength, u08* recieveData);
//! I2cSlaveTransmit is called when this processor
// is addressed as a slave for reading
static u08 (*i2cSlaveTransmit)(u08 transmitDataLengthMax, u08* transmitData);
// functions
void i2cInit(void)
{
// set pull-up resistors on I2C bus pins
// TODO: should #ifdef these
// sbi(PORTC, 0); // i2c SCL on ATmega163,323,16,32,etc
// sbi(PORTC, 1); // i2c SDA on ATmega163,323,16,32,etc
sbi(PORTD, 0); // i2c SCL on ATmega128,64
sbi(PORTD, 1); // i2c SDA on ATmega128,64
// clear SlaveReceive and SlaveTransmit handler to null
i2cSlaveReceive = 0;
i2cSlaveTransmit = 0;
// set i2c bit rate to 100KHz
i2cSetBitrate(100);
// enable TWI (two-wire interface)
sbi(TWCR, TWEN);
// set state
I2cState = I2C_IDLE;
// enable TWI interrupt and slave address ACK
// sbi(TWCR, TWIE);
sbi(TWCR, TWEA);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// enable interrupts
//sei();
// __enable_interrupt();
}
void i2cSetBitrate(u16 bitrateKHz)
{
u08 bitrate_div;
// set i2c bitrate
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
// for processors with additional bitrate division (mega128)
// SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
// set TWPS to zero
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
#endif
// calculate bitrate division
bitrate_div = ((F_CPU/1000l)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
outb(TWBR, bitrate_div);
}
void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn)
{
// set local device address (used in slave mode only)
outb(TWAR, ((deviceAddr&0xFE) | (genCallEn?1:0)) );
}
void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(u08 receiveDataLength, u08* recieveData))
{
i2cSlaveReceive = i2cSlaveRx_func;
}
void i2cSetSlaveTransmitHandler(u08 (*i2cSlaveTx_func)(u08 transmitDataLengthMax, u08* transmitData))
{
i2cSlaveTransmit = i2cSlaveTx_func;
}
/*inline*/ void i2cSendStart(void)
{
// send start condition
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
}
void i2cSendStop(void)
{
// transmit stop condition
// leave with TWEA on for slave receiving
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)|BV(TWSTO));
}
void i2cWaitForComplete(void)
{
// wait for i2c interface to complete operation
Watch = 10;
while( !(inb(TWCR) & BV(TWINT)) && Watch );
Watch =0;
}
void i2cSendByte(u08 data)
{
// save data to the TWDR
outb(TWDR, data);
// begin send
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
void i2cReceiveByte(u08 ackFlag)
{
// begin receive over i2c
if( ackFlag )
{
// ackFlag = TRUE: ACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// ackFlag = FALSE: NACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
}
u08 i2cGetReceivedByte(void)
{
// retieve received data byte from i2c TWDR
return( inb(TWDR) );
}
u08 i2cGetStatus(void)
{
// retieve current i2c status from i2c TWSR
return( inb(TWSR) );
}
void i2cMasterSend(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_TX;
// save data
I2cDeviceAddrRW = (deviceAddr & 0xFE); // RW cleared: write operation
for(i=0; i<length; i++)
I2cSendData[i] = *data++;
I2cSendDataIndex = 0;
I2cSendDataLength = length;
// send start condition
i2cSendStart();
}
void i2cMasterReceive(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_RX;
// save data
I2cDeviceAddrRW = (deviceAddr|0x01); // RW set: read operation
I2cReceiveDataIndex = 0;
I2cReceiveDataLength = length;
// send start condition
i2cSendStart();
// wait for data
while(I2cState);
// return data
for(i=0; i<length; i++)
*data++ = I2cReceiveData[i];
}
u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
// cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with write
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MT_SLA_ACK)
{
// send data
while(length)
{
i2cSendByte( *data++ );
i2cWaitForComplete();
length--;
}
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
Watch = 10;
while( !(inb(TWCR) & BV(TWSTO)) && Watch );
Watch =0;
// enable TWI interrupt
// sbi(TWCR, TWIE);
return retval;
}
u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
// cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with read
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MR_SLA_ACK)
{
// accept receive data and ack it
while(length > 1)
{
length--;
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*data = i2cGetReceivedByte();
*data++;
// decrement length
}
// accept receive data and nack it (last-byte signal)
i2cReceiveByte(FALSE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
// enable TWI interrupt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -