收藏 分销(赏)

第7单 串行通信2.doc

上传人:pc****0 文档编号:8734597 上传时间:2025-02-28 格式:DOC 页数:17 大小:473KB 下载积分:10 金币
下载 相关 举报
第7单 串行通信2.doc_第1页
第1页 / 共17页
第7单 串行通信2.doc_第2页
第2页 / 共17页


点击查看更多>>
资源描述
二.方式1: 8位数据异步通讯方式 1. 设定为10位异步通信方式:1个起始位(“0”),8位数据位,1个停止位(“1”)。 2. RXD:接收数据端。 TXD:发送数据端。【注意和方式0不一样,恢复正常】 3.波特率:用T1作为波特率发生器 4.发送:在TI=0时,当把数据写入SBUF后,即可启动发送,串行口内自动把发送缓冲器中的数据送入发送移位寄存器。发送移位寄存器先发一位起始位,接着按先低位后高位,再发停止位,从而完成一帧的发送。串行数据均由TXT端输出,TI在发送停止位时,由硬件置TI=1。 接收:在RI=0和REN=1的条件下。在接收到第9数据位(即停止位)时,接收电路必须满足以下两个条件: RI=0且SM2=0; 接收到的停止位为“1”时, 才能把接收到的8位字符存入“SBUF(接收)”中,把停止位送入RB8中,使RI=1并发出串行口中断请求(若中断开放)。若上述条件不满足,则这次收到的数据就被舍去,不装入“SBUF(接收)”中,这是不能允许的,因为这意味着丢失了一组接收数据。 在方式1下,发送时钟、接收时钟和通信波特率都由定时器溢出率脉冲经过32分频得到,并可由SMOD=1倍频。因此,方式1的波特率是可变的。 其实,SM2是用于方式2和方式3的。在方式1下,SM2应设为“0”。 方式1时序图: 三.方式2和方式3 方式2和方式3都是11为异步收发。两者的差异仅在于通信波特率有所不同:方式2的波特率由fosc经过32或64分频后提供;方式3的波特率由定时器T1(或T2)的溢出率经32分频后提供。 方式2和方式3的发送过程类似于方式1,所不同的是方式2和方式3有9位有效数据位。发送时,CPU除要把发送字符装入“SBUF(发送)”外,还要把第9位数据位预先装入SCON的TB8中。第9数据位可由用户安排,可以是奇偶校验位,也可以是其它控制位。 第9数据位的值装入TB8后,便可用一条以SBUF为目的的传送指令把发送数据装入SBUF来启动发送过程。一帧数据发送完后,TI=1,CPU便可通过查询TI来以同样方法发送下一个字符帧。 方式2和方式3的接收过程也和方式1类似。所不同的是:方式1时RB8中存放的是停止位,方式2和方式3时RB8中存放的是第9数据位。因此,方式2和方式3时必须满足接收有效字符的条件变为:RI=0且SM2=0或收到的第9数据位为“1”,只有上述两个条件同时满足,接收到的字符才能送入SBUF,第9数据位才能装入RB8中,并使RI=1;否则,这次收到的数据无效,RI也不置位。 其实,上述第一个条件(RI=0)是要求SBUF空,即用户应预先读走SBUF中的信息,以便让接收电路确认它已空。第二个条件(SM2=0)是提供了利用SM2和第9数据位共同对接收加以控制:如果第9数据位是奇偶校验位,则可令SM2=0,以保证串口能可靠接收;如果要求利用第9数据位参与接收控制,则可令SM2=1,然后依靠第9数据位的状态来决定接收是否有效。 方式2、3时序图: 7.3.4 串行口的编程及应用 一.串行口的初始化编程 1.串行口控制寄存器SCON位的确定 根据工作方式确定SM0、SM1位;对于方式2和方式3还要确定SM2位;如果是接收端,则置允许接收位REN为1;如果方式2和方式3发送数据,则应将发送数据的第9位写入TB8中。 2.设置波特率 串行通信,收、发双方发送或接收的波特率必须一致。 方式0和方式2的波特率是固定的; 方式1和方式3的波特率是可变的,由T1溢出率确定。 定时器的不同工作方式,得到的波特率的范围不一样,这是由T1在不同工作方式下计数位数的不同所决定。 (1)方式0时,波特率固定为晶体振荡频率fosc的1/12(fosc /12),不受SMOD位值的影响。若fosc = 12 MHz,波特率为1Mbit/s。 (2)方式2时,波特率仅与SMOD位的值有关。 方式2 波特率 =  如果SMOD=0,则所选波特率为fosc /64;如果SMOD=1,则所选波特率为fosc /32。 若fosc = 12 MHz: SMOD = 0,波特率 = 187.5 kbit/s;SMOD = 1,波特率 为375 kbit/s。 (3)方式1或方式3,常用T1作为波特率发生器,其关系式为 : (7-1) 由式(7-1)见,T1溢出率和SMOD的值共同决定方式1或方式3的波特率。 【注:定时器T1的溢出率定义为定时时间的倒数 定时时间可参见CAP5 T1的定时时间=计数值×机器周期 = T1的溢出率=1/定时时间t= 所以: 波特率 = (2SMOD/32)×fosc/[12 ×(2n-初值)] 其中:N为定时器T1的位数,它和定时器T1的设定方式有关。即 如果定时器T1为方式0,则N=13; 如果定时器T1为方式1,则N=16; 如果定时器T1为方式2,则N=8。 在实际设定波特率时,T1常设置为方式2定时(自动装初值),即TL1作为8位计数器,TH1存放定时初值。这种方式操作方便,也避免因软件重装初值带来的定时误差。 实际使用时,经常根据已知波特率和时钟频率fosc来计算T1的初值X。为避免繁杂的初值计算,常用的波特率和初值X间的关系常列成下表的形式,以供查用。 下表列出了常用波特率与定时器T1的初值关系表 波特率 fosc (MHz) SMOD 定时器T1 所选方式 相应初值 模式1、3 9.6K 12 0 0 2 FD 4.8K 12 0 0 2 FB 2.4K 12 0 0 2 F3 1.2K 12 0 0 2 E6 0.6K 12 0 0 2 CC B=9600,初值=252.74=253=FD B=4800,初值=249.48=250=FB B=2400,初值=242.97=243=128+64+32+16+2+1=F3 B=1200,初值=229.95=230=128+64+32+4+2=11100110=E6 B=600,初值=203.92=204=128+64+8+4=CC 4种方式比较: 方式 波特率 传送位数 发送端 接收端 用途 0 1/12 Fosc (固定不变) 8(数据) RXD RXD 接移位寄存器,扩充并口 1 2SMOD/32T1溢出率 10(起始位、8位数据位、 停止位) TXD RXD 单机通信 2 2SMOD/64T1fosc 11(第9位为1:地址; 为0:数据) TXD RXD 多机通信 3 2SMOD/32T1溢出率 11位(同方式2) TXD RXD 多机通信 二.串行口的应用 通常用于三种情况: 利用方式0扩展并行I/O口; 利用方式1实现点对点的双机通信; 利用方式2或方式3实现多机通信。 1.利用方式0扩展并行I/O口 MCS-51单片机的串行口在方式0时,当外接一个串入并出的移位寄存器,就可以扩展并行输出口,当外接一个并入串出的移位寄存器时,就可以扩展并行输入口。 AT89S51的串口的方式0是同步串行通信接口。方式0的典型应用是外扩串行输入并行输出的同步移位寄存器74LS164,实现并行I/O的扩展。 【例14-5】图14-2是利用串行口方式0通过74LS164外接8个LED发光二极管的接口电路,编写程序使发光二极管轮流显示。图中CLK端为同步脉冲输入端。STB为控制端,当STB=0时,则8位并行输出端关闭,但是允许串行数据从A和B端输入。当STB=1时,A和B输入端关闭,但允许8位并行数据输出。 H = HIGH(高)电平 h = 先于低-至-高时钟跃变一个建立时间 (set-up time) 的 HIGH(高)电平 L = LOW(低)电平 l = 先于低-至-高时钟跃变一个建立时间 (set-up time) 的 LOW(低)电平 q = 小写字母代表先于低-至-高时钟跃变一个建立时间的参考输入 (referenced input) 的状态↑ = 低-至-高时钟跃变 当8位串行数据发送完毕后,引起中断,在中服务程序中,串行发出下一个8位数据。参考程序如下。 图14-2 串行口方式0外接8个LED发光二极管的接口电路 【已调试,cap72、CAP72LED、CAP72LED2】 #include <reg51.h> #include<stdio.h> sbit P10 = P1^0; unsigned char nIndex; void Delay(unsigned int count); main() { SCON = 0x00; /* 串行口初始化为方式0*/ ES=1; EA=1; /* 全局中断允许 */ nIndex=1; SBUF=nIndex; P10=0; // MR为复位端 while(1) {;} } void Serial_Port() interrupt 4 using 0 { if(TI= =1) { TI=0; // 清除串行发送中断请求 P10=1; // Delay( 500); nIndex<<=1; if(nIndex= =0) nIndex=1; SBUF=nIndex; } } void Delay(count ) { unsigned char j; unsigned int i; for(i=0;i<count;i++) for(j=0;j<120;j++); } #include <reg51.h> sbit P10=P1^0; unsigned char nIndex; void delay(unsigned int count); void main(void) { SCON=0x00; ES=1; EA=1; nIndex=1; SBUF=nIndex; P10=0; while(1); } void serial_port() interrupt 4 using 0 { if(TI==1) { TI=0; P10=1; delay(1000); nIndex<<=1; if(nIndex==0) nIndex=1; SBUF=nIndex; } } void delay(unsigned int count) { unsigned char j; unsigned int i; for(i=0;i<count;i++) for(j=0;j<120;j++); } #include <reg51.h> sbit P10=P1^0; unsigned char nIndex; unsigned char zixing[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; void delay(unsigned int count); void main(void) { SCON=0x00; P10=0; P10=1; SBUF=0x92; // LED 上显示数字“5”,只发送一次,没有用中断 while(1); } #include <reg51.h> sbit P10=P1^0; unsigned char zixing[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; void delay(unsigned int count); void main(void) { SCON=0x00; ES=1; EA=1; SBUF=zixing[0]; P10=0; while(1); } void serial_port() interrupt 4 using 0 { if(TI= =1) { TI=0; P10=1; delay(1000); SBUF=zixing[nIndex]; } } void delay(unsigned int count) { unsigned char j; unsigned int i; for(i=0;i<count;i++) for(j=0;j<120;j++); } (2)方式0接收应用举例 图7-8为串行口外接两片8位并行输入串行输出的寄存器74LS165扩展两个8位并行输入口的电路。 当74LS165的端由高到低负跳变时,并行输入端的数据被置入寄存器;当= 1,且时钟禁止端(第15脚)为低电平时,允许TXD(P3.1)串行移位脉冲输入,这时在移位脉冲作用下,数据由右向左方向移动,以串行方式进入串行口的接收缓冲器中。 图7-8 扩展74LS165作为并行输入口 在图7-8中: TXD(P3.1)作为移位脉冲输出与所有75LS165的移位脉冲输入端CLK相连; RXD(P3.0)作为串行数据输入端与74LS165的串行输出端SO相连;P1.0与相连,用来控制74LS165的串行移位或并行输入; 74LS165的时钟禁止端(第15脚)接地,表示允许时钟输入。 当扩展多个8位输入口时,相邻两芯片的首尾(QH与SIN)相连。 在方式0,SCON中的TB8、RB8位没有用到,发送或接收完8位数据由硬件使TI或RI中断标志位置“1”,CPU响应TI或RI中断,在中断服务程序中向发送SBUF中送入下一个要发送的数据或从接收SBUF中把接收到的1B存入内部RAM中。 #include <reg51.h> sbit SPL = P2^5; void delay(unsigned int count) { unsigned char k; while(count--) { for(k=0;k<120;k++); // 延时1ms } } void main(void) { SCON = 0x10; // 0001 0000;方式0,REN=1 while(1) { SPL = 0; SPL = 1; // S/L端出现正跳变 while(RI = = 0); RI = 0; P0 = SBUF; delay(20); } } 7.3.2 单片机双机通信 在很多应用系统中,需要单片机之间进行通信。在串行通信中,如果通信的两个单片机之间距离很短(1m以内),则可以将两个单片机的串口直接相连,用串行方式进行通信,这时一个单片机的发送线(TXD)应与另一个单片机的接收线(RXD)相连。 如果两个需要相互通信的单片机之间距离较远(30m以内),可采用RS232接口延长通信距离,此时必须将单片机的TTL电平与RS232标准电平进行转换。需要在两个单片机接口部分增加RS232电平转换芯片,常用的此类芯片有MAX232等。 如果两个需要相互通信的单片机之间距离很远,可以采用RS485总线方式进行通信,该方式的传输距离一般在1500m以内,通信双方都需要采用MAX485芯片将TTL信号变为差模信号进行传送。 如果需要采用无线通信方式,可以在单片机串口上连接无线数据传输模块来实现。只要通信双方的单片机上都有无线传输模块,模块的通信方式设定一致(波特率、无线信号频率等),且单片机通信程序中的波特率与模块的相同,则基于无线方式的串口通信也非常简单。 通信双方约定发送方为甲机,接收方为乙机。首先甲机发送一个联络数据(0XAA),乙机接收到后响应应答信号(0XBB),然后接收甲机发送的数据。 如果乙机接收到的数据不正确(检查的累加和),就向甲机发送0XFF,甲机收到0XFF后重传数据。 如果乙机接收到的数据正确(检查的累加和),就向甲机发送0X00,甲机收到0X00后重传数据。 #include <reg51.h> unsigned char data[10],chksum; void init(void) // 甲机串口初始化程序 { TMOD=0x20; // 0010 0000, 定时器T1,定时方式2(自动重载方式),Gate(T1)=0 TH1=0xFD; // 设定波特率9600 TL1=0xFD; //PCON=0x00; // 设为0,可以省略 SCON=0x50; // 0101 0000,串口工作在方式1,允许接收REN=1 TR1=1; // 启动定时器T1 } void send(void) //甲机发送子程序 { unsigned char k; do // 循环与乙机联络,等待乙机的回答信号“0XBB” { SBUF=0xAA; // 向乙机发送联络信号“0XAA” while(TI= =0); // 等待发送“0XAA”结束 TI=0; // 清除TI标志 while(RI= =00); // 等待乙机发送响应信号 RI=0; } while(SBUF!=0xBB); // 判定回答信号是否是“0XBB”,如果不是,继续联络 do // 接收到乙机的0XBB联络信号后,开始发送data[10]数组中的数据 { // 或者接收到乙机发来的不是0X00,继续do循环 chksum=0; for(k=0;k<10;k++) // 循环10次,发送数据,并对所发数据进行累加 { SBUF=data[k]; // 发送数据 chksun+=data[k]; // 同时累加所发数据的和 while(TI= =0); // 等待数据发送结束 TI=0; // 清除TI标志 } SBUF=chksun; // 10个数据发送完后,发送累加和结果 while(TI= =0); TI=0; while(RI= =0); // 接收乙机发回的累加和数据校验结果 RI=0; } while(SBUF!=0x00); // 如果接收到的不是0X00,继续do循环,重发数据 } void main(void) // 甲机主程序 { init(); send(); while(1); } void init(void) // 乙机串口初始化程序 { TMOD=0x20; // 0010 0000, 定时器T1,定时方式2(自动重载方式),Gate(T1)=0 TH1=0xFD; // 设定波特率9600 TL1=0xFD; //PCON=0x00; // 设为0,可以省略 SCON=0x50; // 0101 0000,串口工作在方式1,允许接收REN=1 TR1=1; // 启动定时器T1 } void recv(void) // 乙机接收程序 { unsigned char k; while(1) { while(RI= =0); // 等待接收甲机的联络信号0XAA RI=0; if (SBUF!=0XAA) // 判断接收的数据是否是“0XAA” { // 如果不是“0XAA”,则向甲机发送“0XFF”, SBUF=0XFF; // 向甲机发送0XFF while(TI= =0); // 等待发送结束 TI=0; } else // 接收到的是“0XAA”,则发回应答“0XBB”跳出循环,进入接收数据状态 { SBUF=0XBB; // 发回应答信号“0XBB”【自己加的】 While(TI= =0); 【等待发送“0XBB”结束】 TI=0; 【】 break; // 跳出while(1)循环【如果甲机不能接收0XBB,怎么办?】 } } while(1) // 接收到正确的联络信号0XAA后,开始接收数据 { chksum=0; for(k=0;k<10;k++) // 循环接收10个数据 { while(RI= =0); // 等待一个数据的接收完成 RI=0; data[k]=SBUF; // 接收到的数据放入data数组中 chksum+=data[k]; // 累加接收到的数据 } while(RI= =0); // 等待接收甲机发送累加和数据 RI=0; if(SBUF= =chksum) // 如果接收的累加和数据与本机的累加和结果一样 { SBUF=0X00; // 向甲机发送“0X00”信号,表示数据正确 while(TI= =0); // 等待发送0X00的完成 TI=0; break; // 退出while(1)循环 } else // 如果接收的累加和数据与本机的累加和结果不一样 { SBUF=0XFF; // 则向甲机发送0XFF,表示累加和结果不一样 while(TI= =0); // 等待发送结束【只要非“0X00”,就表示结果不一样】 TI=0; } } } void main(void) // 乙机主程序 { init(); recv (); while(1); } ×××××××××××××××××××××××××××××××××××××× 【例5-4】用8051单片机的串行口外接串入并出的芯片CD4094扩展并行输出口控制一组发光二极管,使发光二极管从左至右延时轮流显示。 CD4094是一块8位的串入并出的芯片,带有一个控制端STB。 当STB=0时,打开串行输入控制门,在时钟信号CLK的控制下,数据从串行输入端DATA一个时钟周期(CLK)一位依次输入; 当STB=1,打开并行输出控制门,CD4094中的8位数据并行输出。使用时,8051串行口工作于方式0,8051的TXD接CD4094的CLK,RXD接DATA,STB用P1.0控制,8位并行输出端接8个发光二极管。 #include <reg51.h> //包含特殊功能寄存器库 sbit P10=P1^0; void main( ) { unsigned char i,j; SCON=0x00; //M1M0=00,方式0; j=0x01; //P10=0; //for (; ;) While(1) { P10=0; //STB=0,打开串行输入控制门 SBUF=j; while (!TI);//等待发送完,发送完后TI=1 P10=1; //STB=1,打开并行输出控制门 TI=0; for (i=0; i<=254; i++) {;} j=j*2; if (j= =0x00) j=0x01; } }
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服