📄 i2cslave.c
字号:
//i2c.c
#include <iom16v.h>
#include <eeprom.h>
#include "i2c.h"
// I2C标准波特率:
// 低速 100KHz
// 高速 400KHz
unsigned char localBuffer[] = "!!";
unsigned char localBufferLength = 0x20;
unsigned char i2csendmax;
unsigned char I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
unsigned char I2cSendDataIndex;
unsigned char I2cSendDataLength;
unsigned char I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
unsigned char I2cReceiveDataIndex;
unsigned char I2cReceiveDataLength;
unsigned char i2creceive_b; //接收到命令
unsigned char i2creadtime_b; //
// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive
void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:I2cSlaveTransmit
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<<TWPS0);
TWSR&=~(1<<TWPS1);
#endif
// 计算分频 CPU=7.3728M
bitrate_div = ((F_CPU/1000l)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
//UDR=bitrate_div;
TWBR = bitrate_div;
UDR=TWBR;
} **********/
void i2cSetBitrate(void)
{
TWSR&=~(1<<TWPS0);
TWSR&=~(1<<TWPS1);
}
//总线初始化
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|=(1<<0); // 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();// 从机模式不需要设置
// I2C总线使能
TWCR|=1<<TWEN; //中断使能
// 状态设置
I2cState = I2C_IDLE;
// 开I2C中断和回应
TWCR|=1<<TWIE;
TWCR|=1<<TWEA;
// asm("sei");
i2cSetLocalDeviceAddr(I2C_ADDR);//设置从地址
}
void i2cSetLocalDeviceAddr(unsigned char deviceAddr)
{
// 设置本机从地址 (从方式时) 需根据实际修改 末位强制为0,非广播方式
//TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);
TWAR=deviceAddr&0xFE; //地址不需要右移
}
/*****************
void i2cSetLocalDeviceAddr(unsigned char deviceAddr, unsigned char genCallEn)
{
// 设置本机从地址 (从方式时) 需根据实际修改 末位强制为0,非广播方式
//TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);
TWAR=deviceAddr&0xFE
} ****************/
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;
}
void i2cSendStart(void)
{
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTA);
}
void i2cSendStop(void)
{
// 发送停止条件,保持TWEA以便从接收
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
}
void i2cWaitForComplete(void)
{
// 等待i2c 总线操作完成
while( !(TWCR&(1<<TWINT)) );
}
void i2cSendByte(unsigned char data)
{
// 装载数据到 TWDR
TWDR=data;
// 发送开始
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
}
void i2cReceiveByte(unsigned char ackFlag)
{
//开始通过 i2c 接收
if( ackFlag )
{
// ackFlag = TRUE: 数据接收后回应ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
}
else
{
// ackFlag = FALSE: 数据接收后无回应
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
}
}
unsigned char i2cGetReceivedByte(void)
{
// 返回接收到的数据
return( TWDR );
}
unsigned char i2cGetStatus(void)
{
// 返回总线状态
return(TWSR);
}
// 从操作
void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData)
{
unsigned char i;
//此函数在本机被选中为从写入时运行
// 接收到的数据存入本地缓冲区
for(i=0; i<receiveDataLength; i++)
{
localBuffer[i] = *receiveData++;
}
localBufferLength = receiveDataLength; //接收的数据个数
}
unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)
{
unsigned char i;
//此函数在本机被选中为从读出时运行
//要发送的数据存入发送缓冲区
for(i=0; i<localBufferLength; i++)
{
*transmitData++ = localBuffer[i];
}
localBuffer[0]++;
return localBufferLength;
}
/**********************************************/
eI2cStateType i2cGetState(void)
{
return I2cState;
}
// I2C (TWI) 中断服务程序
//interrupt [TWI] void twi_isr(void)
#pragma interrupt_handler twi_isr:18
void twi_isr(void)
{
//读状态位
unsigned char status;
status = TWSR & TWSR_STATUS_MASK;
switch(status)
{
/********************************************/
// 从接收状态码
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 已返回
// 被选中为从写入 (数据将从主机接收)
// 设置状态
//UDR=0x66;
I2cState = I2C_SLAVE_RX;
// 缓冲准备
I2cReceiveDataIndex = 0;
// 接收数据,回应 ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
break;
//----------------------------读取数据,有应答位-----------------------
case TW_SR_DATA_ACK: // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回
// case TW_SR_GCALL_DATA_ACK: // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回
I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
//UDR=I2cReceiveData[I2cReceiveDataIndex-1];
//检查接收缓冲区状态 是否溢出
if(I2cReceiveDataIndex < 7)//
{
// 接收数据,回应 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<<TWINT)|(1<<TWEA);
// i2c 接收完成
// if(i2cSlaveReceive)
// i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
// 设置状态
I2cState = I2C_IDLE; //i2c接受结束,可以处理数据
i2creceive_b=1; //i2c命令处理申请
break;
// ---------------------从发送------------------------------------
case TW_ST_SLA_ACK: // 0xA8: 自己的SLA+R 已经被接收,ACK 已返回
case TW_ST_ARB_LOST_SLA_ACK:// 0xB0: SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收,ACK 已返回
// 被选中为从读出 (数据将从传回主机)
// 设置状态
//UDR=0x65;
I2cState = I2C_SLAVE_TX;
/* if(catt[0]==catt[1])
{
I2cReceiveData[0]=catt[0];
}
else if(catt[0]==catt[2])
{I2cReceiveData[0]=catt[0];
}
else if(catt[1]==catt[2])
{I2cReceiveData[0]=catt[2];
}*/
// I2cSendData[0]=catt;
// 数据请求 需要发送的字节长度
// if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData); //更改发送数据长度
I2cSendDataIndex = 0;
if(i2creadtime_b)
{
i2csendmax=7; //发送时间数据7字节
}
else {
i2csendmax=3;//正常发送3字节
}
// I2cSendData[0]=EEPROMread(0xff);
case TW_ST_DATA_ACK: // 0xB8: TWDR 里数据已经发送,接收到ACK
// 发送数据位
TWDR=I2cSendData[I2cSendDataIndex++];
// UDR=I2cSendData[I2cSendDataIndex-1];
// if(I2cSendDataIndex==1)
//{
//I2cSendData[0]=catt;
// UDR=0x55;//}
PORTA|=0x80;//PA7置高,取消申请
if(I2cSendDataIndex < i2csendmax) //发送字节
// 回应 ACK
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
else
// 回应 NACK
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
i2creadtime_b=0;
break;
//##################################################################
case TW_ST_DATA_NACK: // 0xC0: TWDR 里数据已经发送接收到NOT ACK
case TW_ST_LAST_DATA: // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
// 全部完成
// 从方式开放
//UDR=0xff;
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
// 设置状态
I2cState = I2C_IDLE;
//i2creceive_b=1;
//UDR=0x55;
i2creadtime_b=0;
break;
case TW_NO_INFO: // 0xF8: 没有相关的状态信息;TWINT = “0”
// 无操作
break;
case TW_BUS_ERROR: // 0x00: 由于非法的START 或STOP 引起的总线错误
// 内部硬件复位,释放总线
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTO)|(1<<TWEA);
// 设置状态
I2cState = I2C_IDLE;
//i2creceive_b=1;
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -