#define TWPS0 0
#define TWPS1 1
#define TWEN 2
#define TWIE 0
#define TWEA 6
#define TWINT 7
#define TWSTA 5
#define TWSTO 4
// TWSR values (not bits)
// Master
#define TW_START 0x08
#define TW_REP_START 0x10
// Master Transmitter
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
// Master Receiver
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
// Slave Transmitter
#define TW_ST_SLA_ACK 0xA8
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
#define TW_ST_DATA_ACK 0xB8
#define TW_ST_DATA_NACK 0xC0
#define TW_ST_LAST_DATA 0xC8
// Slave Receiver
#define TW_SR_SLA_ACK 0x60
#define TW_SR_ARB_LOST_SLA_ACK 0x68
#define TW_SR_GCALL_ACK 0x70
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
#define TW_SR_DATA_ACK 0x80
#define TW_SR_DATA_NACK 0x88
#define TW_SR_GCALL_DATA_ACK 0x90
#define TW_SR_GCALL_DATA_NACK 0x98
#define TW_SR_STOP 0xA0
// Misc
#define TW_NO_INFO 0xF8
#define TW_BUS_ERROR 0x00
// defines and constants
#define TWCR_CMD_MASK 0x0F
#define TWSR_STATUS_MASK 0xF8
// return values
#define I2C_OK 0x00
#define I2C_ERROR_NODEV 0x01
#define I2C_SEND_DATA_BUFFER_SIZE 0x20
#define I2C_RECEIVE_DATA_BUFFER_SIZE 0x20
#define F_CPU 8000000
#define TRUE 1
#define FALSE 0
// types
typedef enum
{
I2C_IDLE = 0, I2C_BUSY = 1,
I2C_MASTER_TX = 2, I2C_MASTER_RX = 3,
I2C_SLAVE_TX = 4, I2C_SLAVE_RX = 5
} eI2cStateType;
//i2c.c
#include
#include "i2c.h"
// I2C标准波特率:
// 低速 100KHz
// 高速 400KHz
// I2C 状态和地址变量
static volatile eI2cStateType I2cState;
static unsigned char I2cDeviceAddrRW;
// 发送缓冲区
static unsigned char I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
static unsigned char I2cSendDataIndex;
static unsigned char I2cSendDataLength;
// 接收缓冲区
static unsigned char I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
static unsigned char I2cReceiveDataIndex;
static unsigned char I2cReceiveDataLength;
unsigned char localBuffer[] = "!!";
unsigned char localBufferLength = 0x20;
// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive
static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit
static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData);
//设置总线速率
void i2cSetBitrate(unsigned int bitrateKHz)
{
unsigned char bitrate_div;
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
// 对于用速率分频的AVR (mega128)
// SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
// set TWPS to zero
TWSR&=~(1<
// 计算分频
bitrate_div = ((F_CPU/1000l)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
TWBR = bitrate_div;
}
//总线初始化
void i2cInit(void)
{
//设置总线上拉
#ifdef _MEGA128_INCLUDED_
//#ifdef _MEGA64_INCLUDED_
PORTD.0=1; // i2c SCL on ATmega128,64
PORTD.1=1; // i2c SDA on ATmega128,64
#else
PORTC.0=1; // i2c SCL on ATmega163,323,16,32,等
PORTC.1=1; // i2c SDA on ATmega163,323,16,32,等
#endif
// 清空从发送和从接受
i2cSlaveReceive = 0;
i2cSlaveTransmit = 0;
// 设置 i2c 波特率为 100KHz
i2cSetBitrate(100);
// I2C总线使能
TWCR|=1<
I2cState = I2C_IDLE;
// 开I2C中断和回应
TWCR|=1<
#asm("sei");
}
void i2cSetLocalDeviceAddr(unsigned char deviceAddr, unsigned char genCallEn)
{
// 设置本机从地址 (从方式时)
TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);
}
void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(unsigned char receiveDataLength, unsigned char* recieveData))
{
i2cSlaveReceive = i2cSlaveRx_func;
}
void i2cSetSlaveTransmitHandler(unsigned char (*i2cSlaveTx_func)(unsigned char transmitDataLengthMax, unsigned char* transmitData))
{
i2cSlaveTransmit = i2cSlaveTx_func;
}
inline void i2cSendStart(void)
{
TWCR=TWCR&TWCR_CMD_MASK|(1<
inline void i2cSendStop(void)
{
// 发送停止条件,保持TWEA以便从接收
TWCR=TWCR&TWCR_CMD_MASK|(1<
inline void i2cWaitForComplete(void)
{
// 等待i2c 总线操作完成
while( !(TWCR&(1<
inline void i2cSendByte(unsigned char data)
{
// 装载数据到 TWDR
TWDR=data;
// 发送开始
TWCR=TWCR&TWCR_CMD_MASK|(1<
inline void i2cReceiveByte(unsigned char ackFlag)
{
//开始通过 i2c 接收
if( ackFlag )
{
// ackFlag = TRUE: 数据接收后回应ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<
else
{
// ackFlag = FALSE: 数据接收后无回应
TWCR=TWCR&TWCR_CMD_MASK|(1<
}
inline unsigned char i2cGetReceivedByte(void)
{
// 返回接收到的数据
return( TWDR );
}
inline unsigned char i2cGetStatus(void)
{
// 返回总线状态
return(TWSR);
}
void i2cMasterSend(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
unsigned char i;
// 等待总线准备完成
while(I2cState);
// 设置状态
I2cState = I2C_MASTER_TX;
// 准备数据
I2cDeviceAddrRW = (deviceAddr & 0xFE); // RW 为0: 写操作
for(i=0; i
I2cSendDataIndex = 0;
I2cSendDataLength = length;
// 发送开始条件
i2cSendStart();
}
void i2cMasterReceive(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
unsigned char i;
// 等待总线准备完成
while(I2cState);
// 设置状态
I2cState = I2C_MASTER_RX;
// 保存数据
I2cDeviceAddrRW = (deviceAddr|0x01); // RW 为1 : 读操作
I2cReceiveDataIndex = 0;
I2cReceiveDataLength = length;
// 发送开始条件
i2cSendStart();
//等待数据准备好
while(I2cState);
// 取数据
for(i=0; i
}
unsigned char i2cMasterSendNI(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
unsigned char retval = I2C_OK;
// 关I2C中断
TWCR&=~(1<
// 发送开始条件
i2cSendStart();
i2cWaitForComplete();
// 发送器件写地址
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// 检查器件是否可用
if( TWSR == TW_MT_SLA_ACK)
{
// 发送数据
while(length)
{
i2cSendByte( *data++ );
i2cWaitForComplete();
length--;
}
}
else
{
// 如未回应器件地址,停止发送,返回错误
retval = I2C_ERROR_NODEV;
}
// 发送停止条件,保持TWEA以便从接收
i2cSendStop();
while( !(TWCR&(1<
// 开I2C中断
TWCR|=(1<
return retval;
}
unsigned char i2cMasterReceiveNI(unsigned char deviceAddr, unsigned char length, unsigned char *data)
{
unsigned char retval = I2C_OK;
// 关I2C中断
TWCR&=~(1<
//发送开始条件
i2cSendStart();
i2cWaitForComplete();
// 发送器件读地址
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// 检查器件是否可用
if( TWSR == TW_MR_SLA_ACK)
{
// 接收数据并回应
while(length > 1)
{
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
length--;
}
// 接收数据无回应 (末位信号)
i2cReceiveByte(FALSE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
}
else
{
// 如未回应器件地址,停止发送,返回错误
retval = I2C_ERROR_NODEV;
}
// 发送停止条件,保持TWEA以便从接收
i2cSendStop();
// 开I2C中断
TWCR|=TWIE;
return retval;
}
eI2cStateType i2cGetState(void)
{
return I2cState;
}
// I2C (TWI) 中断服务程序
interrupt [TWI] void twi_isr(void)
{
//读状态位
unsigned char status;
status = TWSR & TWSR_STATUS_MASK;
switch(status)
{
// 主方式
case TW_START: // 0x08: START 已发送
case TW_REP_START: // 0x10: 重复START 已发送
// 发送器件地址
i2cSendByte(I2cDeviceAddrRW);
break;
// 主发送,主接收状态码
case TW_MT_SLA_ACK: // 0x18: SLA+W 已发送;接收到ACK
case TW_MT_DATA_ACK: // 0x28: 数据已发送;接收到ACK
if(I2cSendDataIndex < I2cSendDataLength)
{
// 发送数据
i2cSendByte( I2cSendData[I2cSendDataIndex++] );
}
else
{
// 发送停止条件,保持TWEA以便从接收
i2cSendStop();
// 设置状态
I2cState = I2C_IDLE;
}
break;
case TW_MR_DATA_NACK: // 0x58: 接收到数据;NOT ACK 已返回
// 保存最终数据
I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
//继续发送条件
case TW_MR_SLA_NACK: // 0x48: SLA+R 已发送,接收到NOT ACK
case TW_MT_SLA_NACK: // 0x20: SLA+W 已发送,接收到NOT ACK
case TW_MT_DATA_NACK: // 0x30: 数据已发送,接收到NOT ACK
// 发送停止条件,保持TWEA以便从接收
i2cSendStop();
// 设置状态
I2cState = I2C_IDLE;
break;
case TW_MT_ARB_LOST: // 0x38: SLA+W 或数据的仲裁失败
// 释放总线
TWCR=TWCR&TWCR_CMD_MASK|(1<
I2cState = I2C_IDLE;
break;
case TW_MR_DATA_ACK: // 0x50: 接收到数据,ACK 已返回
// 保存接收到的数据位
I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
// 检查是否接收完
case TW_MR_SLA_ACK: // 0x40: SLA+R 已发送,接收到ACK
if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
// 数据位将接收 , 回复 ACK (传送更多字节)
i2cReceiveByte(TRUE);
else
// 数据位将接收 , 回复 NACK (传送最后字节)
i2cReceiveByte(FALSE);
break;
// 从接收状态码
case TW_SR_SLA_ACK: // 0x60: 自己的SLA+W 已经被接收,ACK 已返回
case TW_SR_ARB_LOST_SLA_ACK:// 0x68: SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收,ACK 已返回
case TW_SR_GCALL_ACK: // 0x70: 接收到广播地址,ACK 已返回
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: SLA+R/W 作为主机的仲裁失败;接收到广播地址,ACK 已返回
// 被选中为从写入 (数据将从主机接收)
// 设置状态
I2cState = I2C_SLAVE_RX;
// 缓冲准备
I2cReceiveDataIndex = 0;
// 接收数据,回应 ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<
case TW_SR_DATA_ACK: // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回
case TW_SR_GCALL_DATA_ACK: // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回
I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
//检查接收缓冲区状态
if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
{
// 接收数据,回应 ACK
i2cReceiveByte(TRUE);
}
else
{
// 接收数据,回应 NACK
i2cReceiveByte(FALSE);
}
break;
case TW_SR_DATA_NACK: // 0x88: 以前以自己的 SLA+W 被寻址;数据已经被接收,NOT ACK 已返回
case TW_SR_GCALL_DATA_NACK: // 0x98: 以前以广播方式被寻址;数据已经被接收,NOT ACK 已返回
// 接收数据,回应 NACK
i2cReceiveByte(FALSE);
break;
case TW_SR_STOP: // 0xA0: 在以从机工作时接收到STOP或重复START
TWCR=TWCR&TWCR_CMD_MASK|(1<
if(i2cSlaveReceive)
i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
// 设置状态
I2cState = I2C_IDLE;
break;
// 从发送
case TW_ST_SLA_ACK: // 0xA8: 自己的SLA+R 已经被接收,ACK 已返回
case TW_ST_ARB_LOST_SLA_ACK:// 0xB0: SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收,ACK 已返回
// 被选中为从读出 (数据将从传回主机)
// 设置状态
I2cState = I2C_SLAVE_TX;
// 数据请求
if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
I2cSendDataIndex = 0;
//
case TW_ST_DATA_ACK: // 0xB8: TWDR 里数据已经发送,接收到ACK
// 发送数据位
TWDR=I2cSendData[I2cSendDataIndex++];
if(I2cSendDataIndex < I2cSendDataLength)
// 回应 ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<
// 回应 NACK
TWCR=TWCR&TWCR_CMD_MASK|(1<
case TW_ST_DATA_NACK: // 0xC0: TWDR 里数据已经发送接收到NOT ACK
case TW_ST_LAST_DATA: // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
// 全部完成
// 从方式开放
TWCR=TWCR&TWCR_CMD_MASK|(1<
I2cState = I2C_IDLE;
break;
case TW_NO_INFO: // 0xF8: 没有相关的状态信息;TWINT = “0”
// 无操作
break;
case TW_BUS_ERROR: // 0x00: 由于非法的START 或STOP 引起的总线错误
// 内部硬件复位,释放总线
TWCR=TWCR&TWCR_CMD_MASK|(1<
I2cState = I2C_IDLE;
break;
}
}
// 从操作
void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData)
{
unsigned char i;
//此函数在本机被选中为从写入时运行
// 接收到的数据存入本地缓冲区
for(i=0; i
localBuffer[i] = *receiveData++;
}
localBufferLength = receiveDataLength;
}
unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)
{
unsigned char i;
//此函数在本机被选中为从读出时运行
//要发送的数据存入发送缓冲区
for(i=0; i
*transmitData++ = localBuffer[i];
}
localBuffer[0]++;
return localBufferLength;
}
#define TARGET_ADDR 0xA0
//测试 (24xxyy 器件)
void testI2cMemory(void)
{
unsigned char i;
unsigned char txdata[66];
unsigned char rxdata[66];
txdata[0] = 0;
txdata[1] = 0;
for(i=0; i<16; i++)
txdata[2+i] = localBuffer[i];
// 发送地址和数据
i2cMasterSendNI(TARGET_ADDR, 18, txdata);
txdata[18] = 0;
// 发送地址
i2cMasterSendNI(TARGET_ADDR, 2, txdata);
// 接收数据
i2cMasterReceiveNI(TARGET_ADDR, 16, rxdata);
//
rxdata[16] = 0;
}
void main(void)
{
i2cInit();
//设置从接收函数句柄(此函数在被选中为从接收时执行)
i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );
//设置从发送函数句柄(此函数在被选中为从发送时执行)
i2cSetSlaveTransmitHandler( i2cSlaveTransmitService );
testI2cMemory();
}
上一篇:AVR简单的串口通信程序
下一篇:使用AVR定时/计数器的PWM功能设计要点
推荐阅读最新更新时间:2024-03-16 15:08
- 热门资源推荐
- 热门放大器推荐