资讯详情

STC51入门笔记(郭天祥C语言)---第六节:串行口通信原理及操作流程

声明:本文只是对个人知识盲点、知识弱点和关键部分的总结。我希望你不喜欢它。梳理顺序是根据书的实际顺序进行梳理。请注明转载的来源。

作者:sumjess

一、并行与串行的基本通信方式:

随着单片机系统的广泛应用和计算机网络技术的普及,单片机的通信功能越来越重要。单片机通信是指单片机与计算机或单片机之间的信息交换。通常,我们使用更多的单片机和计算机之间的通信。 通信有两种并行和串行方式。在单片机系统和现代单片机测控系统中,串行通信主要用于信息交换。

并行通信通常是用多条数据线同时传输数据字节,,如下图所示,8位数据总线的通信系统将需要8条数据线一次传输8位数据(1字节)。此外,还需要 需要一条信号线和几条控制信号线,只适用于短距离数据传输。例如,旧打印机通过并口连接到计算机,现在传输速度非常快USB 2.0接口通信。由于并口通信使用较少,我们在这里只做一个简单的介绍,我们只需要理解。 在这里插入图片描述 并行通信控制简单,相对传输速度快,但由于传输线路较多,长途传输成本高, 同时接收发方有困难。 串行通信是将数据字节一个接一个地以传输线的形式传输。此时,只需要一条数据线,加上一条公共信号线和几条控制信号线。因为一次只能传输一个,所以至少有8个字节数据,如下图所示。

串行通信的必要过程是将并行数据转换为串行数据并发送到线路上。接收时,将串行信号转换为并行数据,以便由计算机和其他设备处理。 串行通信传输线路少,长途传输成本低,可使用电话网等现成设备,但数据传输控制比并行通信复杂。 串行通信有两种方式:异步串行通信同步串行通信 异步串行通信是指通信的发送和接收设备使用各自的时钟控制数据的发送和接收过程。为了协调双方的收发,要求,如下图所示。 异步通信以字符(构成帧)为单位传输,,但的,即字符之间不一定有“位间隔"的 整数倍关系, 但 。 异步通信一帧字符信息 4 部分组成: ,如下图所示。有些字符信息。字符之间有空闲字符。 异步通信的特点:不要求收发时钟严格一致,容易实现,设备成本小,但每个字符应附加2~用于起止位、验证位和停止位,每帧之间有间隔,因此传输效率不高。 异步串行通信通常用于单片机和单片机之间的通信。 发送方时钟应直接控制接收方时钟,使双方完全同步。此时,传输数据的位置之间的距离是位间隔的整数倍。同时,传输的字符之间没有间隙,即保持位同步和字符同步。发送方对接收方的同步可以通过外同步和自同步来实现,如下图左右所示。 面向字符的同步格式如下图所示。 此时,传输的数据和控制信息必须由规定的字符集(如ASCII由码)中的字符组成。图6.1.7中帧头1或2个同步字符SYN(ASCII码为16H)。SOH为序始字符(ASCII码为OlH),标题包含源地址、目标地址、路由指示等信息。STX为文始字符(ASCII码为02H),数据块开始表示传输。数据块是传送的正文内容,由多个字符组成,数据块后面是组终字符ETB(ASCII码为17H)或文终字符ETX(ASCII码为03H),然后是验证码。面向字符的典型同步程序,如IBM二进制同步规程BSC。 面向位的同步格式如下图所示。 此时,数据块被视为数据流,序列0111110被用作开始和结束的标志。为了避免0111110序列在数据流中引起的混乱,发送人总是在其发送的数据流中每5个连续1插入一个额外的0;接收人每检测到5个连续1,然后删除0。 典型的面向位同步协议,如ISO高级数据链路控制程序HDLC和IBM同步数据链路控制程序SDLC。 同步通信的特点是以特定位置组合0111110作为帧的开始和结束标志,传输的帧数据可以是任意位置。传输效率高,但硬件设备比异步通信更复杂。 (1)单工。单工是指数据传输。,反向传输无法实现。 (2)半双工。半双工是指数据传输两个方向,但需要。 (3)全双工。全双工是指数据。进行双向传输。种类型如下图左、下图中和下图右所示。 (1)奇偶校验 发送数据时,数据位跟随的一个是奇偶校准位(1或0)。奇校验时,数据中1和校验位1之和应为奇数;偶校验时,数据中1和校验位1之和应为偶数。接收字符时,检查1的数量。如果发现不一致,则表明数据传输过程中存在错误。 (2)代码和验证 代码和校验是发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据时同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和“进行比较,相符则无差错,否则即认为传送过程中出现了差错。 (3)循环冗余验证 该验证是通过某种数学操作实现有效信息与验证位之间的循环验证,通常用于磁盘信息的传输和存储区域的完整性验证。该验证方法具有较强的纠错能力,广泛应用于同步通信中。

二、RS-232 电平与TTL 电平转换:

关于RS-232电平与TTL电平的特提到了电平的特性,本节主要讲解了使用较多的计算机RS-232电平与单片机TTL电平之间的转换模式。早期的MC1488, 75188等芯片可以实现TTL电平到RS-232电平转换;MC1489, 75189等芯片可以实现RS-232电平到TTL转换电平。但是现在用的比较多MAX232, MAX202, HIN同时集成了232等芯片RS-232电平和TTL平之间的互转。为丰富大家的知识,下面首先讲解在没有M心(232这种现成电平转换芯片时,如何用二极管、三极管、电阻、电容等分立元件搭建一个简单的RS-232电平与TTL电平之间的转换电路。       (下图)       集成芯片内部都是由最基本电子元件组成,如电阻、电容、二极管、三极管等元件,为了方便用户使用,制造商把这些具有一定功能的分立元件封装到一个芯片内,这样就制成了我们使用的各种芯片。学会本电路后,我们也就基本搞清了MAX232芯片内部的大致结构。       MAX232是把TTL电平从ov和5V转换到3V15V或-3V-15 V之间。分析图下图,首先TTL电平TXD发送数据时,若发送低电平0,这时Q3导通,PCRXD由空闲时的低电平变高电平(如PC用中断接收的话会产生中断),满足条件。发送高电平1时,TXD为高电平,Q3截止,由于PCRXD内部高阻,而PCTXD平时是-3~-15V,通过D1和R7将其拉低PCRXD至-3-15V,此时计算机接收到的就是1。下面再反过来,PC发送信号,由单片机来接收信号。当PCTXD为低电平-3-(-15V)时,Q4截止,单片机端的RXD被R9拉到5V高电平;当PCTXD变高时,Q4导通,RXD被Q4拉到低电平,这样便实现的双向转换,这是一个很好的电路,值得大家学习。

      2. MAX232芯片实现RS-232电平与TTL电平转换       MAX232芯片是MAXIM公司生产的、包含两路接收器和驱动器的IC芯片,它的内部有一个电源电压变换器,可以把输入的+5V电源电压变换成为RS-232输出电平所需的+10V电压。所以,采用此芯片接口的串行通信系统只需单一的+5V电源就可以了。对千没有+12V电源的场合,其适应性更强,加之其价格适中,硬件接口简单,所以被广泛采用。       MAX232芯片实物如图6.2.2和6.2.3所示,其引脚结构和外围连接分别如图6.2.4和图6.2.5 所示。       图6.2.5中上半部分电容C1,C2,C3,C4及V+,V-是电源变换电路部分。在实际应用中,器件对电源噪声很敏感,因此Vee必须要对地加去耦电容Cs,其值为0.lµF。按芯片手册中介绍,电容C1,C2,C3,C4应取1.0µF/16V的电解电容,经大量实验及实际应用,这4个电容都可以选用O.lµF的非极性瓷片电容代替1.0µF/16V的电解电容,在具体设计电路时,这4个电容要尽量靠近MAX232芯片,以提高抗干扰能力。       图6.2.5下半部分为发送和接收部分。实际应用中,T1IN,T2IN可直接连接TTL/CMOS电平的51单片机串行发送端TXD;R10UT,R20UT可直接连接TTL/CMOS电平的51单片机的串行接收端RXD;T10UT,T20UT可直接连接PC机的RS-232串口的接收端RXD;R1IN,R2IN可直接连接PC机的RS-232串口的发送端TXD。       现从MAX232芯片中两路发送、接收中任选一路作为接口。要注意其发送、接收的引脚要对应。如使T1IN连接单片机的发送端TXD,则PC机的RS-232接收端RXD一定要对应接 T10UT引脚。同时,R10UT连接单片机的RXD引脚,PC机的RS-232发送端TXD对应接R1 IN引脚。       TX-1C实验板串口部分原理图如图6.2.6所示,实验板上实物如图6.2.7所示。       其数据传输过程如下:MAX232的11脚T1IN接单片机TXD端P3.1,TTL电平从单片机的TXD端发出,经过M心(232转换为RS-232电平后从MAX232的14脚T1OUT发出,再连接到实验板上串口座的第3脚,再经过随板配送的交叉串口线后,连接至PC机的串口座的第 2脚RXD端,至此计算机接收到数据。PC机发送数据时从PC机串口座第3脚TXD端发出数据,再逆向流向单片机的RXD端P3.0接收数据。       这里需要注意的是,MAX232与串口座连接时,无论是数据输出端,还是数据输入端,连接串口座的第2引脚或第3引脚都可以,选用不同的连接方法时,单片机与计算机之间的串口线都要谨慎选择,是选择平行串口线还是交叉串口线、是选择母头对母头串口线还是母头对公头串口线这些都要非常注意,每种选择都有对应的电路,但无论哪种搭配方式,大家必须要明白,在单片机与计算机之间必须要有一条数据能互相传输的回路,只要把握好每个交接点就一定能通信成功。

三、波特率与定时器初值的关系:

             单片机或计算机在串口通信时的速率用波特率表示,它定义为每秒传输二进制代码的位数,即1波特=1位/秒,单位是bps(位/秒)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的波特率为10位X240个/秒=2400bps。       串行接口或终端直接传送串行信息位流的最大距离与传输速率及传输线的电气特性也有关。当传输线使用每0.3m(约1英尺)有50pF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。当比特率超过1000bps时,最大传输距离迅速下降,如9600bps时最大距离下降到只有76m(约250英尺)。因此我们在做串口通信实验选择较高速率传输数据时,尽量缩短数据线的长度,为了能使数据安全传输,即使是在较低传输速率下也不要使用太长的数据线。              在串行通信中,收、发双方对发送或接收数据的速率要有约定。通过编程可对单片机串行口设定为4种工作方式,其中方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定时器T1的溢出率来决定。       串行口的。由于输入的移位时钟的来源不同,所以各种方式的波特率计算公式也不相同,以下是4种方式波特率的计算公式。       的波特率=fos/12。       的波特率=(2^SMOD/32) x(T1溢出率)。       的波特率=(2^SMOD/64)Xfoc。       的波特率=(2SMOD/32)x(Tl溢出率)。 式中,fosc为系统晶振频率,通常为12MHz或11.0592MHz; SMOD是PCON寄存器的最高位(关于PCON寄存器请看下一个知识点);T1溢出率即定时器Tl溢出的频率。

知识点:电源管理寄存器PCON

      电源管理寄存器在特殊功能寄存器中,字节地址为87H,不能位寻址,PCON用来管理单片机的电源部分,包括等。单片机复位时PCON全部被清0。其各位的定义如下表所示。       。 SMOD=0: 串口方式1, 2,3时,波特率正常。 SMOD=1: 串口方式1, 2,3时,波特率加倍。       。       GF1,GF0—。       PD—。 PD=0:单片机处于正常工作状态。 PD=1:单片机进入掉电(PowerDown)模式,可由外部中断低电平触发或由下降沿触发或者硬件复位模式唤醒,进入掉电模式后,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断继续工作。       。 IDL=0:单片机处于正常工作状态。 IDL=1:单片机进入空闲(Idle)模式,除CPU不工作外,其余仍继续工作,在空闲模式下可由任一个中断或硬件复位唤醒。       T1溢出率就是T1定时器溢出的频率,只要算出T1定时器每溢出一次所需的时间T,那么T的倒数1/T就是它的溢出率。这个问题还是比较容易理解的,在第3章讲解过定时器T0和T1方式1的操作方法,若我们设定定时器T1每50ms溢出一次,那么其溢出率就为20Hz,再将20代入串口波特率计算公式中即可求出相应的波特率,当然也可根据波特率反推出定时器的溢出率,进而计算出定时器的初值。通常单片机在通信时,波特率都较高,因此T1溢出率也必定很高,如果我们使用定时器1的工作方式1在中断中装初值的方法来求T1溢出率的话,在进入中断、装值、出中断这个过程中很容易产生时间上微小的误差,当多次操作时微小的误差不断累积,终会产生错误。有效的解决办法是,使用T1定时器的工作方式2,8位初值自动重装的8位定时器/计数器,定时器方式2逻辑结构图如图6.3.1所示。       在学习定时器方式2时可参考3.5节讲解的定时器方式1,在方式1中,当定时器计满溢出时,自动进入中断服务程序,然后我们需要手动再次给定时器装初值,而在后,,并且无须进入中断服务程序进行任何处理,这样定时器溢出的速率就会绝对稳定。:先设定M0M1选择定时器方式2,在TLX和THX中装入计算好的初值,启动定时器,然后TLX寄存器便在时钟的作用下开始加1计数,当TLX计满溢出后,CPU会自动将THX中的数装入TLX中,继续计数。因此我们在启动定时器之前必须先将TLX和THX中装好合适的数值,以让定时器输出产生的溢出率,这里TLX和THX中装的数值必须是一样的,因为每次计数溢出后TLX中装入的新值是从THX中取出的。       下面我们举一个例子来讲解根据已知波特率,如何计算定时器1 方式2下计数寄存器中的初值。       【例6.3.1】       解:设所求的数为X,则定时器每计256-X个数溢出一次,每计一个数的时间为一个机器周期,一个机器周期等于12个时钟周期,所以计一个数的时间为12/11.0592MHz(s), 那么定时器溢出一次的时间为[256-X]x12/11.0592MHz(s),T1的溢出率就是它的倒数,方式1的波特率=[(2SMOD)/32]x(T1溢出率),这里我们取SMOD=0,则2SMOD=1,将已知的数代入公式后得9600=(1/32)x11059200/[256-X]x12,求得X=253,转换成十六进制为0xFD。上面若将SMOD置1的话,那么X的值就变成250了。可见,在不变化X值的状态下,SMOD由0变1后,波特率便增加一倍。       大家一定要搞明白上面这段由波特率计算定时器初值的方法,通常波特率都是固定的一些数据,如1200,2400,4800,9600等,所以都是根据所要使用的波特率来求定时器初值,而没有说根据定时器初值来求波特率的,以后大家若要使用不同的波特率来做单片机和单片机之间或单片机与计算机之间的通信实验时,可参考上面的计算方法来求定时器初值。 大家可能会有疑惑,为什么单片机系统的晶振要选11.0592MHz 呢?通过上面的计算可能有些人已经明白了,我们用一个小知识点来为大家解答这个疑惑。

知识点:为什么51系列单片机常用11.0592MHz的晶振设计?

      常用波特率通常按规范取为1200, 2400,4800,9600,…,若采用晶振12MHz或6MHz,计算得出的T1定时初值将不是一个整数,这样通信时便会产生积累误差,进而产生波特率误差,影响串行通信的同步性能。解决的方法只有调整单片机的时钟频率fosc,通常采用11.0592MHz晶振。因为用它能够非常准确地计算出T1定时初值,即使对于较高的波特率(19600,19200),。 表6.3.2列出了串口方式1定时器1方式2产生常用波特率时,TL0和TH0中所装入的值。

四、51 单片机串行口结构描述:

      51 单片机的串行口是一个可编程全双工的通信接口, 具有 也可作为同步移位寄存器使用。       51 单片机的串行口主要由,两个寄存器共用一个地址99H,但在物理上是两个独立的寄存器,由指令操作决定访问哪一个寄存器。执行写指令时,访问串行发送寄存器;执行读指令时,访问串行接收寄存器。接收器具有双缓冲结构,即在从接收寄存器中读出前一个已收到的字节之前,便能接收第二个字节,如果第二个字节已经接收完毕,第一个字节还没有读出,则将丢失其中一个字节,编程时应引起注意。对千发送器,因为数据是由CPU控制和发送的,所以不需要考虑。       与串行口紧密相关的一个特殊功能寄存器是串行口控制寄存器SCON,它用来设定串行口的工作方式、接收/发送控制以及设置状态标志等。

知识点:串行口控制寄存器SCON

      串行口控制寄存器SCON在特殊功能寄存器中,字节地址为98H,可位寻址,等。单片机复位时SCON全部被清0。其各位的定义如表6.4.1所示。              SM2主要用于方式2和方式3。当接收机的SM2=1时,可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8是0还是1,均可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2, 可以实现多机通信。在方式0时,SM2必须是0。在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1。        REN=1:允许串行口接收数据; REN=0:禁止串行口接收数据。        在方式2或方式3中,是发送数据的笫9位,可以用软件规定其作用。可以用做数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式0和方式1中,该位未用。        在方式2或方式3中,是接收数据的笫9位,可作为奇偶校验位或地址帧/数据帧的标志位。在方式l时,若SM2=0,则RBS是接收到的停止位。        在方式0时,当串行发送笫8位数据结束时,或在其他方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发出中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。        在方式0时,当串行接收笫8位数据结束时,或在其他方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发出中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。       在这里,在下一节将重点介绍串口方式1,在后面的篇章对其他几种方式再做详细介绍。       (1),主要用于扩展并行输入或输出口。数据由RXD(P3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后,波特率固定为fosc/12。       (2),其中1位起始位,8 位数据位,1位停止位。TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。其传输波特率是可变的,对于51单片机,波特率由定时器1的溢出率决定。通常我们在做单片机与单片机串口通信、单片机与计算机串口通信、计算机与计算机串口通信时,基本都选择方式1,因此这种方式大家务必要完全掌握。       (3)口。TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。这两种方式下,起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TBS,接收时为RBS),停止位1位,一帧数据为11位。方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器Tl的溢出率决定。 方式2和方式3的差别仅在于波特率的选取方式不同,在两种方式下,接收到的停止位与SBUF,RBS及RI都无关。

五、串行口方式1编程与实现:

      串行口方式1是最常用的通信方式,其传送一帧数据的格式如图6.5.1所示。       串行口方式1传送。方式1数据输出时序图和数据输入时序图分别如图6.5.2和图6.5.3所示。       当数据被写入SBUF寄存器后,单片机自动开始从起始位发送数据,发送到停止位的开始时,由内部硬件将TI置1,向CPU申请中断,接下来可在中断服务程序中做相应处理,也可选择不进入中断。       用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当Rl=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置Rl=1,向CPU请求中断。       在具体操作串行口之前,需要对单片机的一些与串口有关的。具体步骤如下:       ① (编程TMOD寄存器);       ②计算T1的初值,装载TH1,TL1;       ③启动T1(编程TCON中的TR1位);       ④确定串行口工作方式(编程SCON寄存器);       ⑤串行口工作在中断方式时,要进行中断设置(编程IE, IP寄存器)。       下面我们用一个实例讲解串口方式1的具体使用方法和操作流程,在TX-IC实验板上实现如下功能。       【例6.5.1】在上位机上用串口调试助手发送一个字符X, 单片机收到字符后返回给上位机"I get X",串口波特率设为9600bps。新建文件Sumjess2.4_1.c,程序代码如下:

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar flag,a,i;
uchar code table[]="I get";
void init()
{
  TMOD=0x20;
  TH1=0xfd;
  TL1=0xfd;
  TR1=1;
  REN=1;
  SM0=0;
  SM1=1;
  EA=1;
  ES=1;
  }
void main()
{
  init();
  while(1)
  {
    if(flag==1)
	{
	  ES=0;
	  for(i=0;i<6;i++)
	  {
	    SBUF=table[i];
		while(!TI);
		TI=0;
		}
	   SBUF=a;
	   while(!TI);
	   TI=0;
	   ES=1;
	   flag=0;
	   }
	}
}
void ser() interrupt 4
{
   RI=0;
   a=SBUF;
   flag=1;
   }

      分析如下:       ① ";“,数组中的元素为字符串时,用双撇号将字符串引起来,空格也算一个字符。字符串由一个一个字符组成,因此也可写成另外一种方式"uchar code table[]={‘I’,’’,‘g’,‘e’,‘t’,’’};”,这里的每个字符用两个单撇号引起来,元素之间要用逗号隔开,空格也算一个字符。为叙述简便,建议大家选择第一种方式。       ② 初始化函数"void init()"中各句解释如下: ; //设定Tl定时器工作方式2 ; //定时器装初值 ; //定时器装初值 ; II启动Tl定时器 ; II允许串口接收 II设定串口工作方式1 ; II同上 ; II开总中断 ; II开串口中断       这里我们没有看到开定时器1中断的语旬,因为定时器1工作在,我们进中断后无事可做,因此无须打开定时器1的中断,更无须写定时器1的中断服务程序。       ③ ",在本程序中完成三件事:,因为程序既然产生了串口中断,那么肯定是收到或发送了数据,在开始时没有发送任何数据,那必然是收到了数据,此时RI会被硬件置1,进入串口中断服务程序后必须由软件清0,这样才能产生下一次中断;,这才是进入中断服务程序中最重要的目的;**将标志位flag置1,**以方便在主程序中查询判断是否已经收到数据。       ④ 进入大循环while()语句后,一直在检测标志位flag是否为1, 当检测到为1时,说明程序已经执行过串口中断服务程序,即收到了数据,否则始终检测flag的状态。当检测到flag置1后,先是将ES清0,原因是接下来要发送数据,若不关闭串口中断,当发送完数据后,单片机同样会申请串口中断,便再次进入中断服务程序,flag又被置1,主程序检测到flag为1,又回到这里再次发送,如此重复下去,程序便成了死循环,造成错误的现象,因此我们在发送数据前把串口中断关闭,等发送完数据后再打开串口中断,这样便可以安全地发送数据了。大家可亲自做实验,不要关闭串口,观察实验结果。       ⑤ 在发送数据时,当发送前面6个固定的字符时,使用了一个for循环语句,将前面数组中的字符依次发送出去,后面再接着发送从中断服务程序中读回来的SBUF中的数据时,当向SBUF 中写入一个数据后,使用"while(!TI);"等待是否发送完毕,因为当发送完毕后TI会由硬件置1,然后才退出"while(!TI);"接下来我们再将TI手动清0。       ⑥ 当接收数据时,我们写"a=SBUF;"语句,单片机便会自动将串口接收寄存器中的数据取走给a;当发送数据时,我们写"SBUF=a;“语句,程序执行完这条语句便自动开始将串口发送寄存器中的数据一位位从串口发送出去。很多初学者搞不明白,在这里再强调一下,SBUF是共用一个地址的两个独立的寄存器,单片机识别操作哪个寄存器的关键语句就是 “a=SBUF” 和"SBUF=a”。       串口调试助手设置及实验实拍照片如下图所示。

六、串行口打印在调试程序中的应用:

      中,举个例子说明它的用途:我们正在用单片机调试一个A/D芯片,单片机的外围只接了A/D芯片和串行口,当我们写好单片机程序下载后让其运行,可是我们根本不知道这个A/D芯片工作了没有?更不知道A/D芯片采集回来的数值对不对?这时如果我们使用串口打印功能,将单片机采集回来的A/D值经过处理后,发送到上位机上,在上位机上用一个简单的串口工具就可看见数据,这样我们在调试程序时便会方便许多。其次我们在调试其他程序时,在整个程序的不同地方,或是关键地方使用串口打印功能输出给上位机一个关键数据,我们就可知道程序中某些变量的实时数值,进一步得知程序运行的状况。       6.5节中我们将"I get"放在一个数组中,通过一个for循环连续发送给上位机,这实际上也算是串口打印功能的应用,但我们还有更方便的方法来运用它,本节我们将为大家介绍几个C51库函数中自带的与串口有关的非常有用的函数。       下面通过一个实例完整讲述串口打印功能的用法及相关注意事项,利用上位机与TX-1C实验板实现如下功能。       【例6.6.1】       下面是实现上述功能的完整例程,在调试本程序的时候遇到了许多很奇怪的错误现象,我在经过大量反复实验后总结出了一些非常重要的知识点,在例程的后面将一一描述,我们先来看例程,新建文件Sumjess2.4_2.c,程序代码如下:

      编译程序下载到实验板,打开串口调试助手,分别发送01,02,03,当开启A/D转换后,适当调节实验板上A/D电压调节电位器,可看到返回的电压实际值在变化,最终界面显示如图6.6.1所示。       分析如下:在分析本节例程之前,先来看上一节的例程。其实在6.5节串口测试程序中有个小问题:如果我们先打开串口调试助手软件,再打开实验板上电源的话,会看到上位机软件会在实验板刚一上电的时候收到一串字符’'I get",可是这时我们并没有向单片机发送任何命令,而单片机为何为主动发数据呢?也许大多数人并没有注意到这个现象,如果作为一个产品的话,这样的系统肯定不能算稳定工作的,6.5节的问题若没有解决,本节的例程将不可能调试成功,因此我们必须解决掉任何一个不正常的问题。       (1)先来解决6.5节的问题。我们在串口初始化函数中有这样几条语句:             REN=1;             SM0=0;             SM1=1;       这三位都是串行口控制寄存器SCON里面的,单片机刚上电时SCON被清0,因为串口方式为方式0,串行口为同步移位寄存器的输入/输出方式,当执行完REN置1这条语句后,它便直接开始从RXD引脚接收数据,并不管与它连接的系统有无发送数据,这时SM0和SM1还未被操作,可单片机串口寄存器已经收到数据,并且已经产生了串口中断,因此串口中断中的标志位flag将被置1,当运行完下面两条指令后,串口方式才被设置为方式1,这时才终止串口接收数据。当程序运行到while(1)大循环中时,因为串口中断服务程序中的标志位flag已经被置1,所以接下来将发送里面的"I get",至于后面的a被发送到上位机之后为什么变成了一个空格,这个由大家自己来研究。       本问题解决办法如下:       ① 将上面三条语句顺序改为             SM0=0;             SM1=1;             REN=1;       先设置串口模式,再允许串口接收,这样就会避开串口方式0接收数据。       ② 不要对SCON寄存器进行位操作,而是直接对整个寄存器进行设置,如SCON=0x50。大家可亲自做实验体检各种现象,若将本节实验中这三句改回原样后实验,产生的错误便不会如6.5节一样简单了,将会影响整个系统的正常运行,大家务必尝试一下。像这种看似很小的问题,在没有解决之前可能需要花费很长的时间才能找到问题的根源,我也不隐讳地告诉大家,我在调试本例程时,花了近3个小时才将它调试成功,无论如何也没有想到错误的原因竟然是因为把"REN=1;“这条语句提前写了两行,当然每解决一个问题,我们学到的知识都将更进一步,甚至更多,单片机是硬件,必须要经过大量的实验方可掌握,像这种现象光靠学书本上的理论,是永远都学不到的。       (2)#include<stdio.h>头文件中包含有我们要使用的函数printf()和puts()。我们到Keil\C51\INC文件夹下打开STDIO.H, 可看到里面申明了一些外部函数,内容如下:       extern char _getkey(void);       extern char getchar(void);       extern char ungetchar(char);       extern char putchar(char);       extern int printf(const char*,…);       extern int sprintf(char*,const char*,…);       extern int vprintf(const char*,char*);       extern int vsprinf(char*,const char*,char*);       extern chargets(char,int n);       extern int scanf(const char*,…);       extern int sscanf(char*,const char*,…);       extern int puts(const char*);       extern表示在这里申明的是一个外部函数,外部函数的函数体不在本文件中,而是在其他某个文件中写有这个函数的实现部分。       在本例中用到的printf()和puts()函数,在它内部都是由putchar()这个函数实现的,关于这两个函数的用法大家请看C51的帮助文件。在Keil\C5l\LIB文件夹下打开PUTCHAR.C文件可看到内容如下:       这个函数的主要作用是通过串口发送一个字符,在代码的最后我们看到有等待TI为1才将字符发送出去,否则一直等待下去,这也就是我们在本节例程中看到的每次在调用printf()和puts()函数之前先要手动将TI置1的原因,这一点至关重要,大家可改变例程亲自做实验,体验去掉TI=1后的现象。       (3)printf()和puts()的区别:从串口调试助手收到的数据我们可以看出,两个函数在参数中都加有”\n",即回车的意思。而puts()函数输出到上位机后还多了一个换行,这是区别之一;区别之二是,printf()可以在后面追加要输出的变量,而puts()只能输出字符串。       (4)在使用stdio.h这个头文件中的函数之前,必须将串口部分初始化完毕,最好将串口设置为方式1,波特率与上位机一致。       (5)在每次调用完printf()和puts()函数后,必须检测是否发送完毕,即检测TI是否为1,当发送完毕后要把TI清0,否则程序会出错,大家可自行验证。       (6)每次调用printf()和puts()函数之前,必须将串口中断先关闭。若不关闭串口中断,每发送一个字节,程序就会申请进入串口中断,从而导致程序出错。       (7)“ad_val=get_ad();“是将A/D采集回来的8位二进制数赋给ad_val,”(float)ad_val"的意思是将字符型变量ad_val的值强制转换成浮点型,然后经过”(float)ad_val*5.0/256.0"运算得出以浮点数表示的A/D实际采集到的电压标准值。注意:在浮点数运算中,原来是整数的常量后面需要加".0变成浮点数,原来是整数的变量需要强制转换成浮点数再进行运算。

标签: ic中能集成三极管吗二极管gf1m快恢复二极管rs3gf

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司