📄 twi._c
字号:
WDR(); //喂狗;
// 关Twi_中断
TWCR&=~(1<<TWIE);
//发送开始条件
Twi_Start();
WDR(); //喂狗;
Twi_WaitForComplete();
// 发送器件读地址
Twi_SendByte( deviceAddr | 0x01 );
WDR(); //喂狗;
Twi_WaitForComplete();
// 检查器件是否可用
if( TWSR == TW_MR_SLA_ACK)
{
// 接收数据并回应
while(length > 1)
{
Twi_Ack();
Twi_WaitForComplete();
*data++ = TWDR;
length--;
WDR(); //喂狗;
}
// 接收数据无回应 (末位信号)
Twi_NoAcK();
Twi_WaitForComplete();
*data++ = TWDR;
}
else
{
// 如未回应器件地址,停止发送,返回错误
retval = TWI_ERROR_NODEV;
}
// 发送停止条件,保持TWEA以便从接收
Twi_Stop();
// 开Twi_中断
TWCR|=TWIE;
return retval;
}
/*********************************************************************************************************
** 函数名称:Twi_SlaveReceiveService
** 功能描述:此函数在本机被选中为从写入时运行
** 输 入: receiveDataLength:接收数据长度
** * receiveData:数据缓冲区指针
** 输 出:
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
void Twi_SlaveReceiveService()
{
uint8 i;
WDR(); //喂狗;
//此函数在本机被选中为从写入时运行
// 接收到的数据存入本地缓冲区
if((Twi_LocalBuffer.status==TWI_DATA_RECEIVE)&&(Twi_ReceiveBuffer.status==TWI_DATA_RECEIVE))
{
for(i=0;!EmptyQueue(&Twi_ReceiveBuffer); i++)
{
EnQueue(&Twi_LocalBuffer, DeQueue(&Twi_ReceiveBuffer));
}
Twi_ReceiveBuffer.status=TWI_DATA_FREE;
Twi_LocalBuffer.status=TWI_DATA_READY;
}
}
/*********************************************************************************************************
** 函数名称:Twi_SlaveTransmitService
** 功能描述:此函数在本机被选中为从读出时运行
** 输 入: transmitDataLengthMax
** 输 出:
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
uint8 Twi_SlaveTransmitService(void)
{
uint8 i=0;
WDR(); //喂狗;
//此函数在本机被选中为从读出时运行
//要发送的数据存入发送缓冲区
if ((Twi_LocalBuffer.status==TWI_DATA_SEND)&&Twi_SendBuffer.status==TWI_DATA_FREE)
{
InitQueue(&Twi_SendBuffer); //清除上次发送的信息
for(i=0; (Twi_LocalBuffer.count>0)&&(Twi_SendBuffer.errorcode!=QUEUE_OVERFLOW); i++)
{
EnQueue(&Twi_SendBuffer,DeQueue(&Twi_LocalBuffer));
}
Twi_SendBuffer.status= TWI_DATA_SEND;
Twi_LocalBuffer.status=TWI_DATA_FREE;
}
return i;
}
/*********************************************************************************************************
** 函数名称:
** 功能描述:Twi_ (TWI) 中断服务程序
** 输 入:
** 输 出:
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
#pragma interrupt_handler twi_isr: iv_TWI
void twi_isr(void)
{
//读状态位
uint8 status;
status = TWSR & TWSR_STATUS_MASK;
switch(status)
{
// 主方式
case TW_START: // 0x08: START 已发送
case TW_REP_START: // 0x10: 重复START 已发送
// 发送器件地址
Twi_SendByte(Twi_DeviceAddrRW);
break;
// 主发送,主接收状态码
case TW_MT_SLA_ACK: // 0x18: SLA+W 已发送;接收到ACK
case TW_MT_DATA_ACK: // 0x28: 数据已发送;接收到ACK
if((Twi_SendBuffer.count>0)&&(Twi_SendBuffer.status==TWI_DATA_SEND))
{
// 发送数据
Twi_SendByte( DeQueue(&Twi_SendBuffer));
}
else
{
// 发送停止条件,保持TWEA以便从接收
Twi_Stop();
// 设置状态
Twi_State = TWI_IDLE;
}
break;
case TW_MR_DATA_NACK: // 0x58: 接收到数据;NOT ACK 已返回
// 保存最终数据
EnQueue(&Twi_ReceiveBuffer,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以便从接收
Twi_Stop();
// 设置状态
Twi_State = TWI_IDLE;
break;
case TW_MT_ARB_LOST: // 0x38: SLA+W 或数据的仲裁失败
// 释放总线
TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
// 设置状态
Twi_State = TWI_IDLE;
break;
case TW_MR_DATA_ACK: // 0x50: 接收到数据,ACK 已返回
// 保存接收到的数据位
EnQueue(&Twi_ReceiveBuffer,TWDR);
// 检查是否接收完
case TW_MR_SLA_ACK: // 0x40: SLA+R 已发送,接收到ACK
if(!FullQueue(&Twi_ReceiveBuffer)&&(Twi_ReceiveBuffer.count<(Twi_ReceiveBuffer.memo-1))&&(Twi_ReceiveBuffer.status==TWI_DATA_RECEIVE))
// 数据位将接收 , 回复 ACK (传送更多字节)
Twi_Ack();
else
// 数据位将接收 , 回复 NACK (传送最后字节)
Twi_NoAcK();
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 已返回
// 被选中为从写入 (数据将从主机接收)
// 设置状态
Twi_State = TWI_SLAVE_RX;
// 缓冲准备
if ((Twi_ReceiveBuffer.status==TWI_DATA_FREE)&&(Twi_LocalBuffer.status==TWI_DATA_RECEIVE))
{
InitQueue(&Twi_ReceiveBuffer);
Twi_ReceiveBuffer.status=TWI_DATA_RECEIVE;
// 接收数据,回应 ACK
Twi_Ack(); // notice 自己增加,为适应缓冲区独占
}
else
// 拒绝接收数据,回应 NACK
Twi_NoAcK(); // notice 自己增加,为适应缓冲区独占
break;
case TW_SR_DATA_ACK: // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回
case TW_SR_GCALL_DATA_ACK: // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回
EnQueue(&Twi_ReceiveBuffer,TWDR);
//检查接收缓冲区状态
if(!FullQueue(&Twi_ReceiveBuffer))
{
// 接收数据,回应 ACK
Twi_Ack();
}
else
{
// 接收数据,回应 NACK
Twi_NoAcK();
}
break;
case TW_SR_DATA_NACK: // 0x88: 以前以自己的 SLA+W 被寻址;数据已经被接收,NOT ACK 已返回
case TW_SR_GCALL_DATA_NACK: // 0x98: 以前以广播方式被寻址;数据已经被接收,NOT ACK 已返回
// 接收数据,回应 NACK
Twi_NoAcK();
break;
case TW_SR_STOP: // 0xA0: 在以从机工作时接收到STOP或重复START
Twi_Ack();
// Twi_ 接收完成
Twi_SlaveReceiveService();
// 设置状态
Twi_State = TWI_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 已返回
// 被选中为从读出 (数据将从传回主机)
// 设置状态
Twi_State = TWI_SLAVE_TX;
// 数据请求
Twi_SlaveTransmitService();
case TW_ST_DATA_ACK: // 0xB8: TWDR 里数据已经发送,接收到ACK
// 发送数据位
if(Twi_SendBuffer.count>1)
// 回应 ACK
{ TWDR=DeQueue(&Twi_SendBuffer);
Twi_Ack();
}
else
// 回应 NACK
{ TWDR=DeQueue(&Twi_SendBuffer);
Twi_NoAcK();
}
break;
case TW_ST_DATA_NACK: // 0xC0: TWDR 里数据已经发送接收到NOT ACK
case TW_ST_LAST_DATA: // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
// 全部完成
// 从方式开放
Twi_Ack();
// 设置状态
Twi_SendBuffer.status=TWI_DATA_FREE;
Twi_State = TWI_IDLE;
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);
// 设置状态
Twi_State = TWI_IDLE;
break;
}
TwiErrorCode=status;
}
/*********************************************************************************************************
** 函数名称:Twi_Init
** 功能描述:TWI总线初始化
** 输 入:
** 输 出:
** 全局变量:
** 调用模块: Twi_SetBitrate()
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
void Twi_Init(void)
{
WDR(); //喂狗;
//设置总线上拉 此处注意:如果有外部上拉,可以不使用内部弱上拉
#if (CPU_TYPE == M64) || (CPU_TYPE == M128)
DDRD&=~(1<<0);
DDRD&=~(1<<1);
PORTD|=(1<<0); // Twi_ SCL on ATmega128,64
PORTD|=(1<<1); // Twi_ SDA on ATmega128,64
#endif
#if (CPU_TYPE == M32) || (CPU_TYPE == M16)
DDRC&=~(1<<0);
DDRC&=~(1<<1);
PORTC|=(1<<0); // Twi_ SCL on ATmega163,323,16,32,等
PORTC|=(1<<1); // Twi_ SDA on ATmega163,323,16,32,等
#endif
#if (CPU_TYPE == M8)
DDRC&=~(1<<5);
DDRC&=~(1<<4);
PORTC|=(1<<5); // Twi_ SCL on ATmega163,323,16,32,等
PORTC|=(1<<4); // Twi_ SDA on ATmega163,323,16,32,等
#endif
// 设置 Twi_ 波特率为 100KHz
Twi_SetBitrate(80);
// 清空从发送和从接收
Twi_SlaveReceive = 0;
Twi_SlaveTransmit = 0;
InitQueue(&Twi_SendBuffer);
InitQueue(&Twi_ReceiveBuffer);
InitQueue(&Twi_LocalBuffer);
// 状态设置
Twi_State = TWI_IDLE;
//设置从接收函数句柄(此函数在被选中为从接收时执行)
//Twi_SetSlaveReceiveHandler( Twi_SlaveReceiveService );
//设置从发送函数句柄(此函数在被选中为从发送时执行)
// Twi_SetSlaveTransmitHandler( Twi_SlaveTransmitService );
Twi_SetLocalDeviceAddr(0x50, 0);
// 开Twi_中断和回应 Twi_总线使能
TWCR=(1<<TWIE)|(1<<TWEN)|(1<<TWEA);
SEI(); // 开中断
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -