单片机常用总线讲解.docx
《单片机常用总线讲解.docx》由会员分享,可在线阅读,更多相关《单片机常用总线讲解.docx(62页珍藏版)》请在冰豆网上搜索。
单片机常用总线讲解
第8章单片机常用总线讲解
8.1
C总线接口
80C51单片机本身不具有总线接口,但是通过软件进行模拟,可以挂接具有
C接口的芯片。
8.1.1
C总线的介绍
串行扩展总线在单片机系统中的应用是目前单片机技术发展的一种趋势。
在目前比较流行的几种串行扩展总线中,总线以其严格的规范和众多带接口的外围器件而获得广泛应用。
总线是PHILIPS公司推出的芯片间串行传输总线,它由两根线组成,一根是串行时钟线(SCL),一根是串行数据线(SDA)。
主控器利用串行时钟线发出时钟信号,利用串行数据线发送或接收数据。
总线由主控器电路引出,凡具有接口的电路(受控器)都可以挂接在总线上,主控器通过总线对受控器进行控制。
随着总线研究的深入,总线已经广泛应用于视/音频领域、IC卡行业和一些家电产品中,在智能仪器、仪表和工业测控领域也越来越多地得到应用。
8.1.2
总线的特点
总线的广泛应用是同它卓越的性能和简便的操作方法分不开的。
总线的特点主要表现在以下几个方面:
硬件结构上具有相同的硬件接口界面。
总线系统中,任何一个总线接口的外围器件,不论其功能差别有多大,都是通过串行数据线(SDA)和串行时钟线(SCL)连接到总线上。
这一特点给用户在设计用用系统中带来了极大的便利性。
用户不必理解每个总线接口器件的功能如何,只需将器件的SDA和SCL引脚连到总线上,然后对该器件模块进行独立的电路设计,从而简化了系统设计的复杂性,提高了系统抗干扰的能力。
线接口器件地址具有根大的独立性。
每个接口芯片具有唯一的器件地址,由于不能发出串行时钟信号而只能作为从器件使用。
各器件之间互不干扰,相互之间不能进行通信,各个器件可以单独供电。
单片机与器件之间的通信是通过独一无二的器件地址来实现的。
软件操作的一致性。
由于任何器件通过总线与单片机进行数据传送的方式是基本一样的,这就决定了总线软件编写的一致性。
PHILIPS公司在推出
总线的同时,也为
总线制订了严格的规范,如:
接口的电气特性、信号时片、信号传输的定义等。
规范的严密性,结构的独立性和硬、软件接口界面的一致性.极大地方便了
总线设计的模块化和规范化,伴随面来的是用户在使用
总线时的“傻瓜”化。
8.1.3
总线数据的传输规则
①在总线上的数据线SDA和时钟线SCL都是双向传输线,它们的接口各自通过一个上拉电阻接到电源正端。
当总线空闲时,SDA和SCL必须保持高电平。
为了使总线上所有电路的输出能完成一个线“与”的功能,各接口电路的输出端必须是开路漏极或开路集电极。
②进行数据传送时.在时钟信号高电平期间.数据线上的数据必须保持稳定;只有时钟线上的信号为低电平期间.数据线上的高电平或低电平才允许变化,如图8.1.1所示。
图8-1数据的有效性
③在
总线的工作过程中,当时钟线保持高电平期间,数据线由高电平向低电平变化定义为起始信号(S)。
而数据线由低电平向高电平的变化定义为一个终止倌号(P),如图8.1.2所示,起始信号和终止信号均由主控器产生。
起始条件停止条件
图8-2起始和停止条件
总线传送的每一字节均为8位,但每启动一次总线,传输的字节数没有限制,由主控器发送时钟脉冲及起始信号、寻址字节和停止信号,受控器件必须在收到每个数据字节后做出响应,在传送一个字节后的第9个时钟脉冲位,受控器输出低电平作为应答信号。
此时.要求发送器在第9个时钟脉冲位上释放SDA线,以便受控器演出应答信号,将SDA线拉或低电平,表示对接收数据的认可,应答信号用--A--C--K或--A表示.非应答信号用--A--C--K或--A表示,当确认后,主控器可通过产生一个停止信号来终止总线数据传输。
总线数据传输示意图如图8.1.3所示。
起始地址读/写应答数据应答数据应答停止
信号信号
图8-3总线数据传输示意图
需要说明的是,当主控器接收数据时,在最后一个数据字节,必须发送一个非应答位,使受控器释放SDA线,以便主控器产生一个停止信号来终止总线数据传输。
3.
总线数据的读写格式
总线上传送数据的格式是指为被传送的各项有用数据安排的先后顺序,这种格式是人们根据串行通信的特点,传送数据的有效性、准确性和可靠性而制定的。
另外,总线上数据的传送还是双向的,也就是说主控器在指令操纵下,既能向受控器发送数据(写入),也能接收受控器中某寄存器中存放的数据(读取).所以传送数据的格式有“写格式”与“读格式”之分。
(1)写格式
总线数据的写格式如图8-4所示
图8-4总线数据的写格式
写格式是指主控器向受控器发送数据,工作过程是:
先由主控器发出启动信号(S),随后传送一个带读/写(R/--W)标记的从地址(SLAVEADD)字节,从地址只有7bit长,第8位是读/写位(R/--W),用来确定数据传送的方向,对于写格式,R/--W应为“0”,表示主控器将发送数据给受控器,接着传送第二个字节,即从地址的子地址(SUBADD),若受控器有多字节的控制项目,该子地址是指首(第一个)地址,因为子地址在受控器中都是按顺序编制的,这就便于某受控器的数据一次传送完毕;接着才是若干字节的控制数据的传送,每传送一个字节的地址或数据后的第9位是受控器的应答信号,数据传送的顺序要靠主控器中程序的支持才能实现,数据发送完毕后,由主控器发出停止信号(P)。
(2)读格式
读格式如图8.1.5所示。
与写格式不同,读格式首先要找到读取数据的受控器的地址,包括从地址和子地址,所以格式中在启动读之前,用写格式发送受控器,再启动读格式,不过前3个应答信号因为是指向受控器,所以应由受控器发出;然后,所有数据字节的应答信号因为是指向主控制器,因此由主控器发出。
不过最后的A=1。
图8-5受控器向主控器发送数据(读格式)
重点提示在设置众多受控器中,为了将控制数据可靠地传逆给指定的受控IC,必须使每一块IC编制一个地址码,通常称为从地址,显然从地址不能在不同的IC间重复使用。
主控器发送寻址字节时,总线上所有受控器都将寻址字节中的7位地址与自己的从地址相比较,如果两者相同,则该器件就是被寻址的受控器(从器件),受控器内部的n个数据地址(子地址)的首地址由子地址数据字节指出,
总线接口内部具有子地址指针自动加1功能,所以主控器不必一一发送n个数据字节的子地址。
4.单片机模拟
总线通信
单片机在模拟
总线通信时,需写出如下几个关键部分的程序:
总线初始化、启动信号、应答信号、停止信号、写—个字节、读—个字节。
下面分别给出具体函数的写法供大家参考,在阅读代码时请参考前面相关部分的文字描述及时序图。
(1)总线初始化
voidint()//将总线都拉高以释放总线
{
SCL=1;
delay();
SDA=1;
delay();
}
(2)启动信号
voidstart()//SCL在高电平期间,SDA一个下降沿启动信号。
{
SDA=1;
delay();
SCL=1;
delay();
SDA=0;
delay();
}
(3)应答信号
voidrespons()
{
uchari=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay();
}
SCL在高电平期间,SDA被从设备拉为低电平表示应答。
上面代码中有一个(SDA==1)和(i<255)相与的关系,表示若在一段时间内没有收到从器件的应答则主器件默认从器件已经收到数据而不在等待应答信号,这一点是作者后加的一步,大家可不必深究,因为如果不加这个延时退出,一旦从器件没有发送应答信号,程序将永远停止在这里,而真正的程序中是不允许这样的情况发生的。
(4)停止信号
voidstop()//SCL在高电平期间,SDA一个上升沿停止信号。
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
(5)写一个字节
voidwritebyte(uchardate)
{
uchari,temp;
temp=date;
for(i=0;i<8;i++)
{
Temp=temp<<1;
SCL=0;
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
SCL=0;
delay();
SDA=1;
delay();
}
串行发送一个字节时,需要把这个字节中的8位一位一位地发出去,“Temp=temp<<1;”表示将temp左移—位,最高位将移入PSW寄存器的CY位中,然后将CY赋给SDA进而在SCL的控制下发送出去。
(6)读一个字节
ucharreadbyte()
{
uchari,k;
SCL=0;
delay();
SDA=1;
for(i=0;i<8;i++)
{
SCL=1;
delay();
k=(k<<1)|SDA;
SCL=0;
delay();
}
delay();
returnk;
}
同样的,串行接收——个字节时需将8位一位一位地接收,然后再组合成一个字节,上面代码中我们定义了一个临时变量k,将k左移一位后与SDA进行“或″运算,依次把8个独立的位放入一个字节中来完成接收。
8.1.4总线实例应用(AT24C02)
具有
总线接口的
PROM有多个厂家的多种类型产品。
在此仅介绍ATMEL公司生产的AT24C系列
PROM。
主要型号有AT24C01/02/04/08/16等,其对应的存储容量分别为128x8/256x8/521x8/1024x8/2048x8。
采用这类芯片可解决掉电数据保存问题,可对所存数据保存100年.并可多次擦写,擦写次数可达10万次以上。
在一些应用系统设计中,有时需要对工作数据进行掉电保护,如电子式电能表等智能化产品。
若采用普通存储器,在掉电时需要备引电池供电,并需要在硬件上增加掉电检测电路。
但存在电池不可靠及扩展存储芯片占用单片机过多口线的缺点。
采用具有
总线接口的串行
PROM器件可很好地解决掉电数据保存问题,且硬件电路简单。
下面以AT24C02芯片为例,介绍具有
总线接口的
PROM的具体应用。
AT24C02芯片的常用封装形式有直插(DIP8)式和贴片(SO-8)式两种,实物图分别如图8.1.6和图8.1.7所示。
图8-6直插式AT24C02图8-7贴片式AT24C02
无论是直插式还是贴片式,其引脚功能与序号都一样,引脚图如图8.1.8所示。
图8-8AT24C02引脚图
各引脚功能如下:
1,2,3,(A0、A1、A2)——可编程地址输入端。
4(GND)——电源地。
5(SDA)——串行数据输入/输出端。
6(SCL)——串行时钟输入端。
7(WP)——写保护输入端,用于硬件数据保护。
当其为低电平时,可以对整个存储器进行正常的读/写操作;当其为高电平时,存储器具有写保护功能,但读操作不受影响。
8(
)——电源正端。
2.存储结构与寻址
AT24C02的存储容量为2KB,内部分成32页,每页8B,共2S6B,操作时有两种寻址方式;芯片寻址和片内子地址寻址。
(1)芯片寻址。
AT24C02的芯片地址为1010,其地址控制字格式为1010A2A1A0R/W。
其中A2,A1,A0为可编程地址选择位。
A2,A1,A0引脚接高、低电平后得到确定的三位编码,与1010形成7位编码,即为该器件的地址码。
R/------W为芯片读写控制位,该位为0,表示对芯片进行写操作;该位为1,表示对芯片进行读操作。
(2)片内子地址寻址。
芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单元。
3.读/写操作时序
串行
PROM一般有两种写入方式:
一种是字节写入方式,另一种是页写入方式。
页写入方式允许在一个写周期内(10ms左右)对一个字节到一页的若干字节进行编程写入,AT24C02的页面人小为8B。
采用页写方式可提高写入效率,但也容易发生事故。
AT24C系列片内地址在接收到每—个数据字节后自动加1,故装载—顷以内数据字节时,只需输入首地址,如果写到此页的最后—个字节,主器件继续发送数据,数据将重新从该页的首地址写入,进而造成原来的数据丢失,这就是页地址空间的“上卷”现象。
解决“上卷”的方法是:
在第8个数据后将地址强制加1,或是将下一页的旨地址重新赋给寄存器。
(1)字节写入方式。
单片机在—次数据帧巾只访问
PROM一个单元。
该方式下,单片机先发送启动信号,然后送—个字节的控制字,再送一个字节的存储器单元子地址,上述几个宁节都得到
PROM响应后,再发送8位数据,最后发送1位停止信号。
发送格式如图8.1.9所示。
图8-9字节写入方式发送格式
(2)页写入方式。
单片机在一个数据与周期内可以连续访问1页(8个)PROM存储单元。
在该方式中,单片机先发送启动信号,接着送个字节的控制字,再送1个字节的存储器起始单元地址,上述几个字节都得到
PROM应答后就可以发送最多1页的数据,并顺序存放在以指定起始地址开始的相继单元中,最后以停止信号结束。
页写入帧格式如图8.1.10所示。
图8-10页写入帧格式
(3)指定地址读操作。
读指定地址单元的数据。
单片机在启动信号后先发送含有片选地址的写操作控制字,PROM应答后再发送1个(2KB以内的
PROM)字节的指定单元的地址,PROM应答后再发送1含有片选地址的读操作控制字,此时如果
PROM做出应答,被访问单元的数据就会按SCL信号同步出现在串行数据/地址线SDA上。
这种读操作的数据帧格式如叫8.1.11所示。
图8-11指定地址读操作数据帧格式
(4)指定地址连续读。
此种方式的读地址控制与前面指定地址读相同。
单片机接收到每个字节数据后应做出应答,只要
PROM检测到应答信号,其内部的地址寄存器就自动加1指向下一单元,并顺序将指向的单元的数据送到SDA串行数据线上。
当需要结束读操作时,单片机接收到数据后在需要应答的时刻发送一个非应答信号,接着再发送一个停止信号即可。
这种读操作的数据帧格式如图8.1.12所示。
图8-12指定地址连续读数据帧格式
4.TX-1C实验板上AT24C02连接图。
TX-1C实验板上AT24C02与单片机连接如图8.1.13所示,其中A0,A1,A2与WP都接地,SDA接单片机P2.0脚,SCL接单片机P2.1脚,SDA与SCL分别与
之 间接一10kΩ上拉电阻,因为AT24C02总线内部是漏极开路形式,不接上拉电阻无法确定总线空队列的电平状态。
图8-13TX-1实验板上AT24C02连接图
例:
用C语言编写程序,在TX—1C实验板上实现如下功能:
利用定时器产生一个0~99秒变化的秒表,并且显示在数码管上,每过一秒将这个变化的数写入板上AT24C02内部。
当关闭实验板电源,并再次打开实验板电源时,单片机先从ATZ4C02中将原来写入的数读取出来,接着此数继续变化并显示在数码管上。
通过本实验可以看到,若向AT24C02中成功写入,并且成功读取则数码管上显示的数会接着关闭实验板时的数继续显示,否则有可能显示乱码。
新建文件part2.6_1.c.程序代码如下:
#include
#defineucharunsignedchar
#defineuintunsignedint
bitwrite=0;//写24C02的标志;
sbitsda=P2^0;
sbitscl=P2^1;
sbitdula=P2^6;
sbitwela=P2^7;
ucharsec,tcnt;
ucharcodetable[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
voiddelay()
{;;}
voiddelay1m(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voidstart()//开始信号
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
Voidstop()//停止
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
Voidrespons()//应答
{
uchari;
scl=1;
delay();
while((sda==1)&&(i<255))
i++;
scl=0;
delay();
}
Voidint()//将总线都拉高以释放总线
{
scl=1;
delay();
sda=1;
delay();
}
voidwrite_byte(uchardate)
{
uchari,temp;
temp=date;
for(i=0;i<8;i++)
{
Temp=temp<<1;
scl=0;
delay();
sda=CY;
delay();
scl=1;
delay();
}
scl=0;
delay();
sda=1;
delay();
}
ucharread_byte()
{
uchari,k;
scl=0;
delay();
sda=1;
for(i=0;i<8;i++)
{
scl=1;
delay();
k=(k<<1)|sda;
scl=0;
delay();
}
delay();
returnk;
}
voidwrite_add(ucharsddress,uchardate)
{
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
ucharread_add(ucharsddress)
{
uchardate;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
returndate;
}
voiddisplay(ucharbai_c,ucharsh_c)//显示程序
{
dula=0;
P0=table[bai_c];//显示第一位
duan=1;
duan=0;
wela=0;
P0=0x7e;
wela=1;
wela=0;
delay1ms(5);
dula=0;
P0=table[sh_c];//显示第二位
dula=1;
dula=0;
wela=0;
P0=0x7d;
wela=1;
wela=0;
delay1ms(5);
}
voidmain()
{
init();
sec=read_add
(2);
if(sec>100)
sec=0;
TMOD=0x01;//定时器工作在方式1
ET0=1;
EA=1;
TH0=(65536-50000)/256;//对TH0TL0赋值
TL0=(65536-50000)%256;//使定时器0.05秒中断一次
TR0=1;
while
(1)
{
display(sec/10,sce%10);
if(write==1)
{
write=0;//清0
write_add(2,sec);//在24c02的地址2中写入数据sec
}
}
}
voidt0()interrupt1//定时中断服务函数
{
TH0=(65536-50000)/256;//对TH0TL0赋值
TL0=(65536-50000)%256;//对装计数初值
tcnt++;//每过50mstcnt加一
if(tcnt==20)//计满20次(1秒)时
{
tcnt=0;//重新再计
sec++;
write=1;//1秒写一次24C02
if(sce==100)//定时100秒,再从零开始计时
sec=0;
}
}
分析如下:
(1)“voiddelay(){;;}”是—个微秒级延时函数,以前编写的延时函数内部都是用变量递增或是递减来实现延时,而这个函数是用空语句来实现短时间延时的,在Keil软件中设置晶振为11.0592MHz时,该延时函数延时人概4~5微秒,用来操作
总线时用。
(2)“voidwrite_add(ucharsddress,uchardate)”和“ucharread_add(ucharsddress)
”两个函数分别实现向AT24CO2的任—地址写—字节的数据和从AT24CO2中任一地址读取—字节数据的功能,函数操作步骤完全遵循前面讲解的操作原理,请人家参考对照。
(3)sec=read_add
(2);//读出保存的数据赋给sec
if(sec>100)//以防止首次读取出错误数据
sec=0;
在主程序的开始处先读取上次写入AT24C02的数据,下面两句是为了防止第一次操作AT24C02时出现意外而加的,若是全新的AT24C02芯片或是以前已经被别人写过的不知道是什么内容的芯片,首次上电后读出来的数据我们无法知道,若是大于100的数将无法在数码管上显示向造成乱码,若是100以内的数还好处理。
人家可自行修改程序使错误出现,再尝试修改程序看能否将错误排除。
实例演示实际现象如图8.1.14所示。
图8-14实际现象效果图
8.2SPI总线接口
8.2.1SPI总线的介绍
SPI,SerialPerripheralInterface,串行外围设备接口,是Motorola公司推出的一种同步串行接口技术.SPI总线在物理上是通过接在外围设备微控制器(PICmicro)上面的微处理控制单元(MCU)上叫作同步串行端口(SynchronousSerialPort)的模块(Module)来实现的,它允许MCU以全双工的同步串行方式,与各种外围设备进行高速数据通信.
SPI主要应用在EEPROM,Flash,实时时钟(RTC),数模转换器(ADC),数字信号处理器(DSP)以及数字信号解码器之间.它在芯片中只占用四根管脚(Pin)用来控制以及数据传输,节约了芯片的pin数目,同时为PCB