📄 twi.c
字号:
#include <iom8v.h>
#include <macros.h>
#include"twi.h"
static unsigned char ORGDATA[16];
struct str_TWI //TWI数据结构
{
volatile unsigned char STATUS; //TWI_操作状态
unsigned char SLA; //从设备的器件地址
unsigned int ADDR; //从设备的数据地址
unsigned char *pBUF; //数据缓冲区指针
unsigned int DATALEN; //数据长度
unsigned char STATE; //TWI读写操作步骤
unsigned char FAILCNT; //失败重试次数
};
struct str_TWI strTWI; //TWI的数据结构变量
//---------------------Function---------------------------------------------
void twi_init();
unsigned char TWI_RW(unsigned char sla,unsigned int addr,unsigned char *ptr,unsigned int len);
//--------------------------------------------------------------------------
void twi_init(void)
{
// unsigned char i;
//上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
//不用的管脚使能内部上拉电阻。
PORTB=0xFF;
PORTC=0xFF; //SCL,SDA使能了内部的10K上拉电阻
PORTD=0xFF;
//TWI初始化
TWSR=0x00; //预分频=0^4=1
TWBR=TWBR_SET;
TWAR=0x00; //主机模式,该地址无效
TWCR=0x00; //关闭TWI模块
//使能全局中断
strTWI.STATUS=TW_OK;
}
unsigned char TWI_RW(unsigned char sla,unsigned int addr,unsigned char *ptr,unsigned int len)
{
if (strTWI.STATUS==TW_BUSY)
{//TWI忙,不能进行操作
return OP_BUSY;
}
strTWI.STATUS=TW_BUSY; //考虑了24C04/08的EEPROM地址高位放在SLA里面
strTWI.SLA=sla;
strTWI.ADDR=addr;
strTWI.pBUF=ptr;
//UDR=*ptr;
strTWI.DATALEN=len;
strTWI.STATE=ST_START;
strTWI.FAILCNT=0;
TWCR=(1<<TWSTA)|TW_ACT; //启动start信号
return OP_RUN;
}
#pragma interrupt_handler twi_isr:18
void twi_isr(void)
{
//twi event
//}
//void SIGNAL(SIG_2WIRE_SERIAL)
//{//IIC中断
unsigned char action,state,status;
action=strTWI.SLA&TW_READ; //取操作模式
state=strTWI.STATE;
status=TWSR&0xF8; //屏蔽预分频位
if ((status>=0x60)||(status==0x00))
{//总线错误或从机模式引发的中断,不予处理
return;
}
//-----------------------------------------------------------------------------
switch(state)
{
case ST_START: //START状态检查
if(status==TW_START)
{//发送start信号成功
TWDR=strTWI.SLA&0xFE; //发送器件地址写SLAW
TWCR=TW_ACT; //触发下一步动作,同时清start发送标志
}
else
{//发送start信号出错
state=ST_FAIL;
}
break;
case ST_SLAW: //SLAW状态检查
if(status==TW_MT_SLA_ACK)
{//发送器件地址成功
TWDR=strTWI.ADDR/256; //发送eeprom地址
TWCR=TW_ACT; //触发下一步动作
}
else
{//发送器件地址出错
state=ST_FAIL;
}
break;
case ST_ADDR:
if(status==TW_MT_DATA_ACK)
{
TWDR=strTWI.ADDR%256; //发送eeprom地址
TWCR=TW_ACT;
}
else
{//发送器件地址出错
state=ST_FAIL;
}
break;
case ST_WADDR: //ADDR状态检查
if(status==TW_MT_DATA_ACK)
{//发送eeprom地址成功
if (action==TW_READ)
{//读操作模式
TWCR=(1<<TWSTA)|TW_ACT; //发送restart信号,下一步将跳到RESTART分支
}
else
{//写操作模式
TWDR=*strTWI.pBUF++; //写第一个字节
strTWI.DATALEN--;
state=ST_WDATA-1; //下一步将跳到WDATA分支
TWCR=TW_ACT; //触发下一步动作
}
}
else
{//发送eeprom地址出错
state=ST_FAIL;
}
break;
case ST_RESTART: //RESTART状态检查,只有读操作模式才能跳到这里
if(status==TW_REP_START)
{//发送restart信号成功
TWDR=strTWI.SLA; //发器件地址读SLAR
TWCR=TW_ACT; //触发下一步动作,同时清start发送标志
}
else
{//重发start信号出错
state=ST_FAIL;
}
break;
case ST_SLAR: //SLAR状态检查,只有读操作模式才能跳到这里
if(status==TW_MR_SLA_ACK)
{//发送器件地址成功
if (strTWI.DATALEN--)
{//多个数据
TWCR=(1<<TWEA)|TW_ACT; //设定ACK,触发下一步动作
}
else
{//只有一个数据
TWCR=TW_ACT; //设定NAK,触发下一步动作
}
}
else
{//发送器件地址出错
state=ST_FAIL;
}
break;
case ST_RDATA: //读取数据状态检查,只有读操作模式才能跳到这里
state--; //循环,直到读完指定长度数据
if(status==TW_MR_DATA_ACK)
{//读取数据成功,但不是最后一个数据
// UDR=TWDR;
*strTWI.pBUF=TWDR; //*strTWI.pBUF++=TWDR;
strTWI.pBUF++;
if (strTWI.DATALEN--)
{//还有多个数据
TWCR=(1<<TWEA)|TW_ACT; //设定ACK,触发下一步动作
}
else
{//准备读最后一个数据
TWCR=TW_ACT; //设定NAK,触发下一步动作
}
}
else if(status==TW_MR_DATA_NACK)
{//已经读完最后一个数据
*strTWI.pBUF=TWDR;//*strTWI.pBUF++=TWDR;
TWCR=(1<<TWSTO)|TW_ACT; //发送停止信号,不会再产生中断了
strTWI.STATUS=TW_OK;
}
else
{//读取数据出错
state=ST_FAIL;
}
break;
case ST_WDATA: //写数据状态检查,只有写操作模式才能跳到这里
state--; //循环,直到写完指定长度数据
if(status==TW_MT_DATA_ACK)
{//写数据成功
if (strTWI.DATALEN)
{//还要写
TWDR=*strTWI.pBUF++;
strTWI.DATALEN--;
TWCR=TW_ACT; //触发下一步动作
}
else
{//写够了
TWCR=(1<<TWSTO)|TW_ACT; //发送停止信号,不会再产生中断了
strTWI.STATUS=TW_OK;
//启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来
//编程期间器件不响应任何命令
}
}
else
{//写数据失败
state=ST_FAIL;
}
break;
default:
//错误状态
state=ST_FAIL;
break;
}
//------------------------------------------------------------------------------
if (state==ST_FAIL)
{//错误处理
strTWI.FAILCNT++;
if (strTWI.FAILCNT<FAIL_MAX)
{//重试次数未超出最大值,
TWCR=(1<<TWSTA)|TW_ACT; //发生错误,启动start信号
}
else
{//否则停止
TWCR=(1<<TWSTO)|TW_ACT; //发送停止信号,不会再产生中断了
strTWI.STATUS=TW_FAIL;
}
}
state++;
strTWI.STATE=state; //保存状态
}
/*
void uart0_init(void)
{
UCSRB=0x00;
UCSRA = 0x00;
UBRRL=(fosc/16/(baud+1))%256;
UBRRH=(fosc/16/(baud+1))/256;//设置UBRR
UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
// UCSRB=(1<<RXEN)|(1<<RXCIE)|(1<<TXEN)|(1<<TXCIE);
UCSRB=(1<<TXEN);
}
void main(void)
{
twi_init();
uart0_init();
// TWI_RW(SLA_24CXX+(ADDR_24C64<<1)+,0x10,&ORGDATA[0],16);
//TWI_RW(SLA_24CXX+(ADDR_24C64<<1)+TW_WRITE,0x00,&cc[0],16);
SEI();
TWI_RW(SLA_24CXX+(ADDR_24C64<<1)+TW_READ,0x00,cc,16);
//从0x10地址开始写入8个字节数据
while(strTWI.STATUS==TW_BUSY); //等待操作完成
if (strTWI.STATUS==TW_FAIL)
{
UDR=0x06;
//操作失败
}
// _delay_ms(10); //延时等待编程完成
UDR=cc[8];
while(1);
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -