学习过程中参考了力天 电子的“AVR 单片机软硬件设计入门教程”,我修改的程序放到附件了,主要实现的功能是:
尝试往24c04写入一段数据并读取,然后对比以验证是否读写成功, 成功则蜂鸣器循环响5次。
仿真过程中发现寄存器数据都OK,但是无法进入IIC中断函数,麻烦帮忙分析一下原因。
以下是IIC.c的源代码:
- #include
- //#include
- #include
- #define F_CPU 12000000UL//
- #include til/delay.h>
- #include
- //定义了各种模式下的状态码列表(TWSR已屏蔽预分频位),本文后面附上中文描述
- //管脚定义
- #define pinSCL 0 //PC0 SCL
- #define pinSDA 1 //PC1 SDA
- //为保险起见,最好在SCL/SDA接上1~10K的外部上拉电阻到VCC。
- #define fSCL 100000 //TWI时钟为100KHz
- //预分频系数=1(TWPS=0)
- #if F_CPU < fSCL*36
- #define TWBR_SET 10; //TWBR必须大于等于10
- #else
- #define TWBR_SET (F_CPU/fSCL-16)/2; //计算TWBR值
- #endif
- #define TW_ACT (1<
- // #define TW_ACT (1<
- //TWCR只能IN/OUT,直接赋值比逻辑运算(|= &=)更节省空间
- #define SLA_24CXX 0xA0 //24Cxx系列的厂商器件地址(高四位)
- // #define ADDR_24C02 0x00 // AT24C02的地址线A2/1/0全部接地,SLAW=0xA0+0x00<<1+0x00,SLAR=0xA0+0x00<<1+0x01
- #define ADDR_24C02 0x07 // LY-51S板上AT24C02的地址线A2/1/0全部接VCC,SLAW=0xA0+0x07<<1+0x00,SLAR=0xA0+0x07<<1+0x01
- //TWI_操作状态
- #define TW_BUSY 0
- #define TW_OK 1
- #define TW_FAIL 2
- //TWI_读写命令状态
- #define OP_BUSY 0
- #define OP_RUN 1
- //TWI读写操作公共步骤
- #define ST_FAIL 0 //出错状态
- #define ST_START 1 //START状态检查
- #define ST_SLAW 2 //SLAW状态检查
- #define ST_WADDR 3 //ADDR状态检查
- //TWI读操作步骤
- #define ST_RESTART 4 //RESTART状态检查
- #define ST_SLAR 5 //SLAR状态检查
- #define ST_RDATA 6 //读取数据状态检查,循环n字节
- //TWI写操作步骤
- #define ST_WDATA 7 //写数据状态检查,循环n字节
- #define FAIL_MAX 20 //重试次数最大值
- //定义全局变量
- unsigned char ORGDATA[8]=
- {0xAA,0xA5,0x55,0x5A,0x01,0x02,0x03,0x04}; //原始数据
- unsigned char CMPDATA[8]; //比较数据
- unsigned char BUFFER[256]; //缓冲区,可以装载整个AC24C02的数据
- 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的数据结构变量
- //仿真时在watch窗口,监控这些全局变量。
- //AT24C02的读写函数(包括随机读,连续读,字节写,页写)
- //根据sla的最低位决定(由中断程序中判断)
- //bit0=1 TW_READ 读
- //bit0=0 TW_WRITE 写
- // sla 器件地址(不能搞错)
- // addr EEPROM地址(0~1023)
- // *ptr 读写数据缓冲区
- // len 读数据长度(1~1024, 24c02最多只能读256个字节),写数据长度(1 or 8 or 16字节)
- // 返回值 是否能执行当前操作
- unsigned char TWI_RW(unsigned char sla,unsigned int addr, unsigned char *ptr, unsigned int len)
- {
- unsigned char i;
- if (strTWI.STATUS==TW_BUSY)
- {//TWI忙,不能进行操作
- return OP_BUSY;
- }
- strTWI.STATUS=TW_BUSY;
- i=(addr>>8)<<1;
- i&=0x06; //考虑了24C04/08的EEPROM地址高位放在SLA里面
- strTWI.SLA=sla+i;
- strTWI.ADDR=addr;
- strTWI.pBUF=ptr;
- strTWI.DATALEN=len;
- strTWI.STATE=ST_START;
- strTWI.FAILCNT=0;
- TWCR=(1<
- //while (!(TWCR & (1<
- return OP_RUN;
- }
- ISR(TWI_vect)
- {//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; //发送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<
- }
- 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<
- }
- else
- {//只有一个数据
- TWCR=TW_ACT; //设定NAK,触发下一步动作
- }
- }
- else
- {//发送器件地址出错
- state=ST_FAIL;
- }
- break;
- case ST_RDATA: //读取数据状态检查,只有读操作模式才能跳到这里
- state--; //循环,直到读完指定长度数据
- if(status==TW_MR_DATA_ACK)
- {//读取数据成功,但不是最后一个数据
- *strTWI.pBUF++=TWDR;
- if (strTWI.DATALEN--)
- {//还有多个数据
- TWCR=(1<
- }
- else
- {//准备读最后一个数据
- TWCR=TW_ACT; //设定NAK,触发下一步动作
- }
- }
- else if(status==TW_MR_DATA_NACK)
- {//已经读完最后一个数据
- *strTWI.pBUF++=TWDR;
- TWCR=(1<
- 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<
- strTWI.STATUS=TW_OK;
- //启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来
- //编程期间器件不响应任何命令
- }
- }
- else
- {//写数据失败
- state=ST_FAIL;
- }
- break;
- default:
- //错误状态
- state=ST_FAIL;
- break;
- }
- if (state==ST_FAIL)
- {//错误处理
- strTWI.FAILCNT++;
- if (strTWI.FAILCNT
- {//重试次数未超出最大值,
- TWCR=(1<
- }
- else
- {//否则停止
- TWCR=(1<
- strTWI.STATUS=TW_FAIL;
- }
- }
- state++;
- strTWI.STATE=state; //保存状态
- }
- void init_IIC(void)
- {
- // unsigned char i;
- // char j = 0;
- PORTC|=0x03; //SCL, SDA使能了内部的10k上拉电阻
- //TWI初始化
- TWSR = 0x00; //预分频=0^4=1
- TWBR = TWBR_SET;
- TWAR = 0x00; //主机模式, 该地址无效
- TWCR = 0x00; //关闭TWI模块
- strTWI.STATUS = TW_OK;
- }
- char test_24c02(void)
- {
- unsigned char i;
- char j = 0;
- init_IIC();
- strTWI.STATUS=TW_OK;
- TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_WRITE,0x10,&ORGDATA[0],8);
- //从0x10地址开始写入8个字节数据
- while (strTWI.STATUS==TW_BUSY); //等待操作完成
- if (strTWI.STATUS==TW_FAIL)
- {
- return(0); //操作失败?
- }
- _delay_ms(100); //延时等待编程完成(启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来)
- i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x10,&CMPDATA[0],8);
- //从0x10地址开始读出8个字节数据
- while (strTWI.STATUS==TW_BUSY); //等待操作完成
- //如果不加等待,则需要检测返回值i才能知道当前操作是否执行了
- // 0 OP_BUSY 之前的操作没完成,没执行当前操作
- // 1 OP_RUN 当前操作执行中
- if (strTWI.STATUS==TW_FAIL)
- {
- return(0); //操作失败?
- }
- //读取成功,对比ORGDATA和CMPDATA的数据
- i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x00,&BUFFER[0],256);
- //从0x00开始读出256个字节数据(整个ATC24C02)
- while(strTWI.STATUS==TW_BUSY); //等待操作完成
- for(i = 0;i < 8;i ++)
- {
- if(ORGDATA[i] != CMPDATA[i])
- {
- return(0);
- }
- }
- return(0xff);
- }
复制代码
0
已退回5积分
|
|
|
|