twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页wordWord文件下载.docx
- 文档编号:18058857
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:18
- 大小:24.56KB
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页wordWord文件下载.docx
《twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页wordWord文件下载.docx》由会员分享,可在线阅读,更多相关《twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页wordWord文件下载.docx(18页珍藏版)》请在冰豆网上搜索。
#include<
avr/io.h>
avr/signal.h>
avr/interrupt.h>
avr/delay.h>
//时钟定为外部晶振7.3728MHz,F_CPU=7372800
compat/twi.h>
//定义了各种模式下的状态码列表(TWSR已屏蔽预分频位),本文后面附上中文描述
//管脚定义
#definepinSCL0//PC0SCL
#definepinSDA1//PC1SDA
//为保险起见,最好在SCL/SDA接上1~10K的外部上拉电阻到VCC。
#definefSCL100000//TWI时钟为100KHz
//预分频系数=1(TWPS=0)
#ifF_CPU<
fSCL*36
#defineTWBR_SET10;
//TWBR必须大于等于10
#else
#defineTWBR_SET(F_CPU/fSCL-16)/2;
//计算TWBR值
#endif
#defineTW_ACT(1<
<
TWINT)|(1<
TWEN)|(1<
TWIE)
//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]=
{0xAA,0xA5,0x55,0x5A,0x01,0x02,0x03,0x04};
//原始数据
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)
//返回值是否能执行当前操作
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的最低位决定
虽然中断服务程序很长,但每次只执行一个case,所以耗时并不长。
SIGNAL(SIG_2WIRE_SERIAL)
{//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;
//发送器件地址写SLAW
TWCR=TW_ACT;
//触发下一步动作,同时清start发送标志
else
{//发送start信号出错
state=ST_FAIL;
break;
caseST_SLAW:
//SLAW状态检查
if(status==TW_MT_SLA_ACK)
{//发送器件地址成功
TWDR=strTWI.ADDR;
//发送eeprom地址
//触发下一步动作
{//发送器件地址出错
caseST_WADDR:
//ADDR状态检查
if(status==TW_MT_DATA_ACK)
{//发送eeprom地址成功
if(action==TW_READ)
{//读操作模式
//发送restart信号,下一步将跳到RESTART分支
{//写操作模式
TWDR=*strTWI.pBUF++;
//写第一个字节
strTWI.DATALEN--;
state=ST_WDATA-1;
//下一步将跳到WDATA分支
//触发下一步动作
{//发送eeprom地址出错
caseST_RESTART:
//RESTART状态检查,只有读操作模式才能跳到这里
if(status==TW_REP_START)
{//发送restart信号成功
TWDR=strTWI.SLA;
//发器件地址读SLAR
{//重发start信号出错
caseST_SLAR:
//SLAR状态检查,只有读操作模式才能跳到这里
if(status==TW_MR_SLA_ACK)
if(strTWI.DATALEN--)
{//多个数据
TWEA)|TW_ACT;
//设定ACK,触发下一步动作
{//只有一个数据
//设定NAK,触发下一步动作
caseST_RDATA:
//读取数据状态检查,只有读操作模式才能跳到这里
state--;
//循环,直到读完指定长度数据
if(status==TW_MR_DATA_ACK)
{//读取数据成功,但不是最后一个数据
*strTWI.pBUF++=TWDR;
{//还有多个数据
{//准备读最后一个数据
elseif(status==TW_MR_DATA_NACK)
{//已经读完最后一个数据
TWSTO)|TW_ACT;
//发送停止信号,不会再产生中断了
strTWI.STATUS=TW_OK;
{//读取数据出错
caseST_WDATA:
//写数据状态检查,只有写操作模式才能跳到这里
//循环,直到写完指定长度数据
{//写数据成功
if(strTWI.DATALEN)
{//还要写
{//写够了
//发送停止信号,不会再产生中断了
//启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来
//编程期间器件不响应任何命令
{//写数据失败
default:
//错误状态
if(state==ST_FAIL)
{//错误处理
strTWI.FAILCNT++;
if(strTWI.FAILCNT<
FAIL_MAX)
{//重试次数未超出最大值,
//发生错误,启动start信号
{//否则停止
strTWI.STATUS=TW_FAIL;
state++;
strTWI.STATE=state;
//保存状态
intmain(void)
//上电默认DDRx=0x00,PORTx=0x00输入,无上拉电阻
PORTA=0xFF;
//不用的管脚使能内部上拉电阻。
PORTB=0xFF;
PORTC=0xFF;
//SCL,SDA使能了内部的10K上拉电阻
PORTD=0xFF;
//TWI初始化
TWSR=0x00;
//预分频=0^4=1
TWBR=TWBR_SET;
TWAR=0x00;
//主机模式,该地址无效
TWCR=0x00;
//关闭TWI模块
sei();
//使能全局中断
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)
//操作失败?
_delay_ms(10);
//延时等待编程完成
while
(1)
i=TWI_RW(SLA_24CXX+(ADDR_24C02<
1)+TW_READ,0x10,&
CMPDATA[0],8);
//从0x10地址开始读出8个字节数据
//等待操作完成
//如果不加等待,则需要检测返回值i才能知道当前操作是否执行了
//0OP_BUSY之前的操作没完成,没执行当前操作
//1OP_RUN当前操作执行中
//读取成功,对比ORGDATA和CMPDATA的数据
1)+TW_READ,0x00,&
BUFFER[0],256);
//从0x00地址开始读出256个字节数据(整个ATC24C02)
两线串行接口总线定义
两线接口TWI很适合于典型的处理器应用。
TWI协议允许系统设计者只用两根双向传输线就可以将128个不同的设备互连到一起。
这两根线一是时钟SCL,一是数据SDA。
外部硬件只需要两个上拉电阻,每根线上一个。
所有连接到总线上的设备都(必须)有自己的地址。
注意:
就是说不能有两个相同地址的设备
TWI协议解决了总线仲裁的问题。
所有TWI兼容的器件的总线驱动都是漏极开路或集电极开路的。
这样就实现了对接口操作非常关键的线与功能。
TWI器件输出为"
0”时,TWI总线会产生低电平。
当所有的TWI器件输出为三态时,总线会输出高电平,允许上拉电阻将电压拉高。
为保证所有的总线操作,凡是与TWI总线连接的AVR器件必须上电。
与总线连接的器件数目受如下条件限制:
总线电容要低于400pF,而且可以用7位从机地址进行寻址。
两个不同的规范,一种是总线速度低于100kHz,而另外一种是总线速度高达400kHz。
SCL和SDA引脚
SCL与SDA为MCU的TWI接口引脚。
引脚的输出驱动器包含一个波形斜率限制器以满足TWI规范。
引脚的输入部分包括尖峰抑制单元以去除小于50ns的毛刺。
当相应的端口设置为SCL与SDA引脚时,可以使能I/O口内部的10K上拉电阻,这样可省掉外部的上拉电阻
注意:
如果要作高速通讯或者从机数量较多,最好还是外接合适的上拉电阻
比特率发生器单元
TWI工作于主机模式时,比特率发生器控制时钟信号SCL的周期。
具体由TWI状态寄存器TWSR的预分频系数以及比特率寄存器TWBR设定。
当TWI工作在从机模式时,不需要对比特率或预分频进行设定,但从机的CPU时钟频率必须大于TWI时钟线SCL频率的16倍。
注意,从机可能会延长SCL低电平的时间,从而降低TWI总线的平均时钟周期。
SCL的频率根据以下的公式产生:
fSCL=fCPU/((16+2(TWBR)(4^TWPS))
TWBR=TWI比特率寄存器的数值
TWPS=TWI状态寄存器预分频的数值
Note:
TWI工作在主机模式时,TWBR值应该不小于10,否则主机会在SDA与SCL产生错误输出作为提示信号。
问题出现于TWI工作在主机模式下,向从机发送Start+SLA+R/W的时候(不需要真的有从机与总线连接)。
控制单元
控制单元监听TWI总线,并根据TWI控制寄存器TWCR的设置作出相应的响应。
当TWI总线上产生需要应用程序干预处理的事件时,TWI中断标志位TWINT置位。
在下一个时钟周期,TWI状态寄存器TWSR被表示这个事件的状态码字所更新。
在其它时间里,TWSR的内容为一个表示无事件发生的特殊状态字。
一旦TWINT标志位置"
1”,时钟线SCL即被拉低,暂停TWI总线上的数据传输,让用户程序处理事件。
在下列状况出现时,TWINT标志位置位:
?
在TWI传送完START/REPEATEDSTART信号之后
在TWI传送完SLA+R/W数据之后
在TWI传送完地址字节之后
在TWI总线仲裁失败之后
在TWI被主机寻址之后(广播方式或从机地址匹配)
在TWI接收到一个数据字节之后
作为从机工作时,TWI接收到STOP或REPEATEDSTART信号之后
由于非法的START或STOP信号造成总线错误时
TWI寄存器说明
TWI比特率寄存器-TWBR
Bits7..0–TWI比特率寄存器
TWBR为比特率发生器分频因子。
比特率发生器是一个分频器,在主机模式下产生SCL时钟频率。
比特率计算公式请见前面的[比特率发生器单元]
TWI控制寄存器-TWCR
TWCR用来控制TWI操作。
它用来使能TWI,通过施加START到总线上来启动主机访问,产生接收器应答,产生STOP状态,以及在写入数据到TWDR寄存器时控制总线的暂停等。
这个寄存器还可以给出在TWDR无法访问期间,试图将数据写入到TWDR而引起的写入冲突信息。
Bit7–TWINT:
TWI中断标志
当TWI完成当前工作,希望应用程序介入时TWINT置位。
若SREG的I标志以及TWCR寄存器的TWIE标志也置位,则MCU执行TWI中断例程。
当TWINT置位时,SCL信号的低电平被延长。
TWINT标志的清零必须通过软件写"
1”来完成。
执行中断时硬件不会自动将其改写为"
0”。
要注意的是,只要这一位被清零,TWI立即开始工作。
因此,在清零TWINT之前一定要首先完成对地址寄存器TWAR,状态寄存器TWSR,以及数据寄存器TWDR的访问。
Bit6–TWEA:
使能TWI应答
TWEA标志控制应答脉冲的产生。
若TWEA置位,出现如下条件时接口发出ACK脉冲:
1.器件的从机地址与主机发出的地址相符合
2.TWAR的TWGCE置位时接收到广播呼叫
3.在主机/从机接收模式下接收到一个字节的数据
将TWEA清零可以使器件暂时脱离总线。
置位后器件重新恢复地址识别。
Bit5–TWSTA:
TWISTART状态标志
当CPU希望
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- twimain 基于 avr 系列 单片机 实现 i2c 通信 27 word
![提示](https://static.bdocx.com/images/bang_tan.gif)
链接地址:https://www.bdocx.com/doc/18058857.html