TWI(IIC)使用范例AT24C02

2016-12-14 09:58:53来源:http://blog.csdn.net/zhiyu520/article/details/1850459作者:zhiyu520人点击

第七城市

这不,看了OURAVR网站的范例,稍微修改了一下,帖在这里当做个笔记.


//usart.h#include<avr/io.h>//管脚定义#definePIN_RXD0//PD0RXD#definePIN_TXD1//PD1TXD//常量定义#defineBAUDRATE9600//波特率voidput_c(unsignedcharc);voidput_s(unsignedchar*ptr);voidinit_USART(void);//usart.c#include"usart.h"voidput_c(unsignedcharc)//发送采用查询方式...{while(!(UCSRA&(1<<UDRE)));UDR=c;}voidput_s(unsignedchar*ptr)...{while(*ptr)...{put_c(*ptr++);}put_c(0x0D);put_c(0x0A);//结尾发送回车换行}voidinit_USART(void)//USART初始化...{//USART96008,n,1PC上位机软件(超级终端等)也要设成同样的设置才能通讯UCSRC=(1<<URSEL)|0x06;UBRRL=(F_CPU/BAUDRATE/16-1)%256;UBRRH=(F_CPU/BAUDRATE/16-1)/256;UCSRA=0x00;UCSRB=(1<<TXEN);//使能接收中断,使能接收,使能发送}//TWI_main.c/**//***************************************************名称:AVRTWI使用范例_AT24C02********作者:zhiyu****编译器:WINAVR20070525********参考:http://www.ouravr.com/guide_index.html(TWI范例(AT24C02))****日期:2007.07.26********芯片:M16L****时钟源:外部4M晶振********结果:测试成功****问题:中断里面的state部分不理解,如自加操作,其他基本没什么问题***********************************************//**//*本程序简单的示范了如何使用ATMEGA16的TWI读写AT24C02IICEEPROMTWI协议(即IIC协议,请认真参考IIC协议的内容,否则根本就不能掌握)一主多从的应用,M16作主机(M16做从机和多主多从的应用不多,请自行参考相关文档)中断模式(因为AVR的速度很高,而IIC的速度相对较低,采用查询模式会长时间独占CPU,令CPU的利用率明显下降。特别是IIC速度受环境影响只能低速通讯时,对系统的实时性产生严重的影响。查询模式可以参考其它文档和软件模拟IIC的文档)AT24C02/04/08的操作特点出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAGICE硬件仿真器*/#include<avr/io.h>#include<avr/interrupt.h>#include<util/delay.h>#include"usart.h"#include<util/twi.h>//定义了各种模式下的状态码列表(TWSR已屏蔽预分频位),本文后面附上中文描述//管脚定义#definepinSCL0//PC0SCL#definepinSDA1//PC1SDA//为保险起见,最好在SCL/SDA接上1~10K的外部上拉电阻到VCC。#defineFREQ4//FREQ为系统振荡周期(以MHZ为单位,因为现在用的是外部4M晶振,所以FREQ=4)#definefSCL100000//TWI时钟为100KHz//预分频系数=1(TWPS=0)#ifF_CPU#defineTWBR_SET10;//TWBR必须大于等于10#else#defineTWBR_SET(F_CPU/fSCL-16)/2;//计算TWBR值#endif#defineTW_ACT(1<//TWCR只能IN/OUT,直接赋值比逻辑运算(|=&=)更节省空间#defineSLA_24CXX0xA0//24Cxx系列的厂商器件地址(高四位)#defineADDR_24C020x00//AT24C02的地址线A2/1/0全部接地,SLAW=0xA0+0x00<<1+0x00,SLAR=0xA0+0x00<<1+0x01//TWI_操作状态#defineTW_BUSY0#defineTW_OK1#defineTW_FAIL2//TWI_读写命令状态#defineOP_BUSY0#defineOP_RUN1//TWI读写操作公共步骤#defineST_FAIL0//出错状态#defineST_START1//START状态检查#defineST_SLAW2//SLAW状态检查#defineST_WADDR3//ADDR状态检查//TWI读操作步骤#defineST_RESTART4//RESTART状态检查#defineST_SLAR5//SLAR状态检查#defineST_RDATA6//读取数据状态检查,循环n字节//TWI写操作步骤#defineST_WDATA7//写数据状态检查,循环n字节#defineFAIL_MAX20//重试次数最大值//定义全局变量unsignedcharORGDATA[8]=...{65,66,67,68,69,70,71,72};//原始数据:64:A;66:B;67:c……unsignedcharCMPDATA[8];//比较数据unsignedcharBUFFER[256];//缓冲区,可以装载整个AC24C02的数据structstr_TWI//TWI数据结构...{volatileunsignedcharSTATUS;//TWI_操作状态unsignedcharSLA;//从设备的器件地址unsignedintADDR;//从设备的数据地址unsignedchar*pBUF;//数据缓冲区指针unsignedintDATALEN;//数据长度unsignedcharSTATE;//TWI读写操作步骤unsignedcharFAILCNT;//失败重试次数};structstr_TWIstrTWI;//TWI的数据结构变量//仿真时在watch窗口,监控这些全局变量。//AT24C02的读写函数(包括随机读,连续读,字节写,页写)//根据sla的最低位决定(由中断程序中判断)//bit0=1TW_READ读//bit0=0TW_WRITE写//sla器件地址(不能搞错)//addrEEPROM地址(0~1023)//*ptr读写数据缓冲区//len读数据长度(1~1024),写数据长度(1or8or16)//返回值是否能执行当前操作//此函数参考《AVR单片机GCC程序设计》P72和P120voidDelayMs(unsignedintt)...{unsignedinti;for(i=0;i<t;i++)_delay_loop_2(FREQ*4-1);}unsignedcharTWI_RW(unsignedcharsla,unsignedintaddr,unsignedchar*ptr,unsignedintlen)...{unsignedchari;if(strTWI.STATUS==TW_BUSY)...{//TWI忙,不能进行操作returnOP_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<<TWSTA)|TW_ACT;//启动start信号returnOP_RUN;}/**//*TWI中断函数这个函数流程只是考虑了器件地址后有一个字节数据(命令)地址的IIC器件(大部分IIC接口器件都是这种类型,常见的例如AT24C01/02/04/08/16,DS1307,DS1721等)对于有两个字节数据地址的IIC器件(例如AT24C32/64/128/256等大容量EEPROM),请稍作改动//根据strTWI.SLA的最低位决定//bit0=1TW_READ读//bit0=0TW_WRITE写虽然中断服务程序很长,但每次只执行一个case,所以耗时并不长。*/ISR(TWI_vect)...{//IIC中断unsignedcharaction,state,status;action=strTWI.SLA&TW_READ;//取操作模式state=strTWI.STATE;status=TWSR&0xF8;//屏蔽预分频位if((status>=0x60)||(status==0x00))...{//总线错误或从机模式引发的中断,不予处理return;}switch(state)...{caseST_START://START状态检查if(status==TW_START)...{//发送start信号成功TWDR=strTWI.SLA&0xFE;//发送器件地址写SLAWTWCR=TW_ACT;//触发下一步动作,同时清start发送标志}else...{//发送start信号出错state=ST_FAIL;}break;caseST_SLAW://SLAW状态检查if(status==TW_MT_SLA_ACK)...{//发送器件地址成功TWDR=strTWI.ADDR;//发送eeprom地址TWCR=TW_ACT;//触发下一步动作}else...{//发送器件地址出错state=ST_FAIL;}break;caseST_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;caseST_RESTART://RESTART状态检查,只有读操作模式才能跳到这里if(status==TW_REP_START)...{//发送restart信号成功TWDR=strTWI.SLA|TW_READ;//发器件地址读SLAR(原来的程序只是TWDR=strTWI.SLA,不得)TWCR=TW_ACT;//触发下一步动作,同时清start发送标志}else...{//重发start信号出错state=ST_FAIL;}break;caseST_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;caseST_RDATA://读取数据状态检查,只有读操作模式才能跳到这里state--;//循环,直到读完指定长度数据if(status==TW_MR_DATA_ACK)...{//读取数据成功,但不是最后一个数据*strTWI.pBUF++=TWDR;if(strTWI.DATALEN--)...{//还有多个数据TWCR=(1<<TWEA)|TW_ACT;//设定ACK,触发下一步动作}else...{//准备读最后一个数据TWCR=TW_ACT;//设定NAK,触发下一步动作}}elseif(status==TW_MR_DATA_NACK)...{//已经读完最后一个数据*strTWI.pBUF++=TWDR;TWCR=(1<<TWSTO)|TW_ACT;//发送停止信号,不会再产生中断了strTWI.STATUS=TW_OK;}else...{//读取数据出错state=ST_FAIL;}break;caseST_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;//保存状态}intmain(void)...{unsignedchari;unsignedintm,n,k,t;//上电默认DDRx=0x00,PORTx=0x00输入,无上拉电阻PORTA=0xFF;//不用的管脚使能内部上拉电阻。PORTB=0xFF;PORTC=0xFF;//SCL,SDA使能了内部的10K上拉电阻//串口初始化DDRD=(1<<PIN_TXD);//TXD为输出PORTD=0xFF;init_USART();//TWI初始化TWSR=0x00;//预分频=4^0=1TWBR=TWBR_SET;TWAR=0x00;//主机模式,该地址无效TWCR=0x00;//关闭TWI模块sei();//使能全局中断put_s("Hello!");put_s("这是一个简单TWI程序");put_s("请你仔细对照数据");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)...{put_s("TWI写操作FAIL!");}DelayMs(10);//延时等待编程完成put_s("TWI写操作succeed!");while(1)...{//从0x10地址开始读出8个字节数据放入CMPDATA数组中i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x10,&CMPDATA[0],8);while(strTWI.STATUS==TW_BUSY);//等待操作完成//如果不加等待,则需要检测返回值i才能知道当前操作是否执行了//0OP_BUSY之前的操作没完成,没执行当前操作//1OP_RUN当前操作执行中if(strTWI.STATUS==TW_FAIL)...{put_s("TWI读操作FAIL!");}//读取成功,对比ORGDATA和CMPDATA的数据put_s("原来ORGDATA的数据:");for(m=0;m<8;m++)...{put_c(ORGDATA[m]);put_c('');}put_c(0x0D);put_c(0x0A);put_s("新的CMPDATA的数据:");for(n=0;n<8;n++)...{put_c(CMPDATA[n]);put_c('');}put_c(0x0D);put_c(0x0A);//读取整个AC24C02的数据i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x00,&BUFFER[0],256);//从0x00地址开始读出256个字节数据(整个ATC24C02)while(strTWI.STATUS==TW_BUSY);//等待操作完成put_s("整个AC24C02的数据:");for(k=0,t=1;k<256;k++,t++)...{if(BUFFER[k]>=65&&BUFFER[k]<=72)put_c(BUFFER[k]);elseput_c(48);put_c('');if(t==16)...{put_c(0x0D);put_c(0x0A);t=0;}}put_c(0x0D);put_c(0x0A);DelayMs(50000);//延时,好看数据};}//Makefile,主要的几项,只是针对我这里的程序,要灵活运用哦MCU=atmega16F_CPU=4000000TARGET=mainSRC=TWI_main.cusart.c//多文件编译才会用到这一项,可以参考这个帖子:http://www.mcublog.com/blog/user1/4266/archives/2006/6145.html

当然了,看一下协议本身是很重要的,也是一定的.这个例子不错,值得一看.


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台