目录

  • 快速使用
  • 硬知识
    • 串行口相关寄存器
      • 串行口控制寄存器SCON和PCON
      • 串行口数据缓冲寄存器SBUF
      • 从机地址控制寄存器SADEN和SADDR
      • 与串行口中断相关的寄存器IE和IPH、IP
    • 串行口工作模式
      • 串行口工作模式0:同步移位寄存器
      • 串行口工作模式1:8位UART,波特率可变
      • 串行口工作模式2:9位UART,波特率固定
      • 串行口工作模式3:9位UART,波特率可变
    • 串行通信中波特率的设置
  • 示例程序
    • USART.c
    • USART.h
    • 定时器2作为波特率发生器实验
      • main.c
      • 实验现象
    • 定时器1作为波特率发生器仿真实验
      • main.c
      • 实验现象
    • 串行口工作模式0发送实验
      • main.c
      • 实验现象

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


快速使用

可通过STC-ISP的波特率计算器直接生成初始化函数

6T模式下需将系统频率翻倍

1T的单片机不需要将系统频率翻倍,定时器时钟应为1T

范例程序中有写的很好的例程

硬知识

摘自《STC89C52系列单片机器件手册》

中断知识见【51单片机快速入门指南】3:中断系统

STC89C52系列单片机内部集成有一个功能很强的全双工串行通信口,与传统8051单片机
的串口完全兼容。设有 2 个互相独立的接收、发送缓冲器,可以同时发送和接收数据。发送缓
冲器只能写入而不能读出,接收缓冲器只能读出而不能写入,因而两个缓冲器可以共用一个
地址码( 99H )。两个缓冲器统称串行通信特殊功能寄存器 SBUF

       串行通信设有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。波特率由内部定时器/计数器产生,用软件设置不同的波特率和选择不同的工作方式。主机可通过查询或中断方式对接收/发送进行程序处理,使用十分灵活。
       STC89C52系列单片机串行口对应的硬件部分对应的管脚是P3.0/RxD和P3.1/TxD
       STC89C52系列单片机的串行通信口,除用于数据通信外,还可方便地构成一个或多个并行I/O口,或作串 — 并转换,或用于扩展串行外设等。

串行口相关寄存器

串行口控制寄存器SCON和PCON

STC89C52系列单片机的串行口设有两个控制寄存器:串行控制寄存器SCON和波特率选
择特殊功能寄存器PCON。
       串行控制寄存器SCON用于选择串行通信的工作方式和某些控制功能。其格式如下:
SCON : 串行控制寄存器 (可位寻址)

       SM0/FE:当PCON寄存器中的SMOD0/PCON.6位为1时,该位用于帧错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。它必须由软件清零
       当PCON寄存器中的SMOD0/PCON.6位为0时,该位和SM1一起指定串行通信的工作方式,如下表所示。
       其中SM0、SM1按下列组合确定串行口的工作方式:

       SM2:允许方式2或方式3多机通信控制位。在方式2或方式3时,如SM2位为1,REN位为1,则从机处于只有接收到RB8位为1(地址帧)时才激活中断请求标志位RI为1,并向主机请求中断处理。被确认为寻址的丛机则复位SM2位为0,从而才接收RB8为0的数据帧。
       在方式1时,如果SM2位为1,则只有在接收到有效的停止位时才置位中断请求标志位RI为1;在方式0时,SM2 应为0。
       REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。
       TB8: 在方式2或方式3,它为要发送的第9位数据,按需要由软件置位或清0。例如,可用作数据的校验位或多机通信中表示地址帧/数据帧的标志位。
       RB8: 在方式2或方式3,是接收到的第9位数据。在方式1,若SM2=0,则RB8是接收到的停止位。方式0不用RB8。
       TI: 发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位。
       RI: 接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1, 向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1(例外情况见SM2说明),必须由软件复位,即RI=0。

SCON的所有位可通过整机复位信号复位为全“0”。SCON的字节地址尾98H,可位寻址,各位地址为98H~~9FH,可用软件实现位设置。当用指令改变SCON的有关内容时,其改变的状态将在下一条指令的第一个机器周期的S1P1状态发生作用。如果一次串行发送已经开始,则输出TB8将是原先的值,不是新改变的值。
       串行通信的中断请求:当一帧发送完成,内部硬件自动置位TI,即TI=1,请求中断处理;当接收完一帧信息时,内部硬件自动置位RI,即RI=1,请求中断处理。由于TI和RI以“或逻辑”关系向主机请求中断,所以主机响应中断时事先并不知道是TI还是RI请求的中断,必须在中断服务程序中查询TI和RI进行判别,然后分别处理。因此,两个中断请求标志位均不能由硬件自动置位,必须通过软件清0,否则将出现一次请求多次响应的错误。

电源控制寄存器PCON中的SMOD/PCON.7用于设置方式1、方式2、方式3的波特率是否加倍。电源控制寄存器PCON格式如下:
       PCON : 电源控制寄存器 (不可位寻址)

       SMOD:波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;SMOD=0,则各工作方式的波特率不加倍。复位时SMOD=0。
       SMOD0:帧错误检测有效控制位。当SMOD0=1,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能;当SMOD0=0,SCON寄存器中的SM0/FE位用于SM0功能,和SM1一起指定串行口的工作方式。复位时SMOD0=0。

串行口数据缓冲寄存器SBUF

STC89C52系列单片机的串行口缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。
       串行通道内设有数据寄存器。在所有的串行通信方式中,在写入SBUF信号的控制下,把数据装入相同的9位移位寄存器,前面8位为数据字节,其最低位为移位寄存器的输出位。根据不同的工作方式会自动将“1”或TB8的值装入移位寄存器的第9位,并进行发送。
       串行通道的接收寄存器是一个输入移位寄存器。在方式0时它的字长为8位,其他方式时为 9位。当一帧接收完毕,移位寄存器中的数据字节装入串行数据缓冲器SBUF中,其第9位则装入SCON寄存器中的RB8位。如果由于SM2使得已接收到的数据无效时,RB8和SBUF中内容不变。
       由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该帧接收结束前从SBUF缓冲器中
将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线。

从机地址控制寄存器SADEN和SADDR

为了方便多机通信,STC89C52系列单片机设置了从机地址控制寄存器SADEN和SADDR。其中SADEN是从机地址掩模寄存器(地址为B9H,复位值为00H),SADDR是从机地址寄存器(地址为A9H,复位值为00H)。

与串行口中断相关的寄存器IE和IPH、IP

串行口中断允许位ES位于中断允许寄存器IE中,中断允许寄存器的格式如下:
       IE : 中断允许寄存器 (可位寻址)

       EA : CPU的总中断允许控制位,EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的中断允许控制位控制。
       ES : 串行口中断允许位,ES=1,允许串行口中断,ES=0,禁止串行口中断。

串行口中断优先级控制位PS/PSH位于中断优先级控制寄存器IP/IPH中,中断优先级控制寄
存器的格式如下:
       IPH: 中断优先级控制寄存器高(不可位寻址)

       IP : 中断优先级控制寄存器低 (可位寻址)

       PSH, PS: 串口1中断优先级控制位。
              当PSH=0且PS=0时,串口1中断为最低优先级中断(优先级0)
              当PSH=0且PS=1时,串口1中断为较低优先级中断(优先级1)
              当PSH=1且PS=0时,串口1中断为较高优先级中断(优先级2)
              当PSH=1且PS=1时,串口1中断为最高优先级中断(优先级3)

串行口工作模式

STC89C52系列单片机的串行通信有4种工作模式,可通过软件编程对SCON中的SM0、SM1的设置进行选择。其中模式1、模式2和模式3为异步通信,每个发送和接收的字符都带有1个启动位和1个停止位。在模式0中,串行口被作为1个简单的移位寄存器使用。

串行口工作模式0:同步移位寄存器

在模式0状态,串行通信工作在同步移位寄存器模式,当当单片机工作在6T模式时,其波特率固定为SYSclk/6。当单片机工作在12T时,其波特率固定为SYSclk/12串行口数据由RxD(RxD/P3.0)端输入,同步移位脉冲(SHIFTCLOCK)由TxD(TxD/P3.1)输出,发送、接收的是8位数据,低位在先
       模式0的发送过程:当主机执行将数据写入发送缓冲器SBUF指令时启动发送,串行口即将8位数据以SYSclk/12或SYSclk/6的波特率从RxD管脚输出(从低位到高位),发送完中断标志TI置"1"TxD管脚输出同步移位脉冲(SHIFTCLOCK)。波形如图8-1中“发送”所示。

当写信号有效后,相隔一个时钟,发送控制端SEND有效(高电平),允许RxD发送数据,同时允许TxD输出同步移位脉冲。一帧(8位)数据发送完毕时,各控制端均恢复原状态,只有TI保持高电平,呈中断申请状态。在再次发送数据前,必须用软件将TI清0
       模式0接收过程:模式0接收时,复位接收中断请求标志RI,即RI=0,置位允许接收控制位REN=1时启动串行模式0接收过程。启动接收过程后,RxD为串行输入端TxD为同步脉冲输出端。串行接收的波特率为SYSclk/12或SYSclk/6。其时序图如图8-1中“接收”所示。
       当接收完成一帧数据(8位)后,控制信号复位,中断标志RI被置"1",呈中断申请状态。当再次接收时,必须通过软件将RI清0
       工作于模式0时,必须清0多机通信控制位SM2,使不影响TB8位和RB8位。由于波特率固 定为SYSclk/12或SYSclk/6,无需定时器提供,直接由单片机的时钟作为同步移位脉冲。
       串行口工作模式0的示意图如图8-1所示
       由示意图中可见,由TX和RX控制单元分别产生中断请求信号并置位TI=1或RI =1,经“或门“ 送主机请求中断,所以主机响应中断后必须软件判别是TI还是RI请求中断,必须软件清0中断请求标志位TI或RI。

串行口工作模式1:8位UART,波特率可变

当软件设置SCON的SM0、SM1为“01” 时,串行通信则以模式1工作。此模式为8位UART格式,一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位。波特率可变,即可根据需要进行设置。TxD(TxD/P3.1)为发送信息,RxD(RxD/P3.0)为接收端接收信息,串行口为全双工接受/发送串行口。 图8-2为串行模式1的功能结构示意图及接收/发送时序图
       模式1的发送过程:串行通信模式发送时,数据由串行发送端TxD输出当主机执行一条写“SBUF“的指令就启动串行通信的发送,写“SBUF”信号还把“1” 装入发送移位寄存器的第9位,并通知TX控制单元开始发送。发送各位的定时是由16分频计数器同步。
       移位寄存器将数据不断右移送TxD端口发送,在数据的左边不断移入“0”作补充。当数据的最高位移到移位寄存器的输出位置,紧跟其后的是第9位“1” ,在它的左边各位全为 “0” ,这个状态条件,使TX控制单元作最后一次移位输出,然后使允许发送信号“SEND”失效,完成一帧信息的发送,并置位中断请求位TI,即TI=1,向主机请求中断处理。
       模式1的接收过程:当软件置位接收允许标志位REN,即REN=1时,接收器便以选定波特率的16分频的速率采样串行接收端口RxD,当检测到RxD端口从“1”→“0” 的负跳变时就启动接收器准备接收数据,并立即复位16分频计数器,将1FFH植装入移位寄存器。复位16分频计数器是使它与输入位时间同步。
       16分频计数器的16个状态是将1波特率(每位接收时间)均为16等份,在每位时间的7、 8、9状态由检测器对RxD端口进行采样,所接收的值是这次采样直经 “三中取二” 的值,即3次采样至少2次相同的值,以此消除干扰影响,提高可靠性。在起始位,如果接收到的值不为 “0”(低电平),则起始位无效,复位接收电路,并重新检测"1" →"0" 的跳变。如果接收到的起始位有效,则将它输入移位寄存器,并接收本帧的其余信息。
       接收的数据从接收移位寄存器的右边移入,已装入的1FFH向左边移出,当起始位"0"移到移位寄存器的最左边时,使RX控制器作最后一次移位,完成一帧的接收。若同时满足以下两个条件:

  1. RI=0;
  2. SM2=0或接收到的停止位为1。

则接收到的数据有效,实现装载入SBUF,停止位进入RB8,置位RI,即RI=1,向主机请求中断,若上述两条件不能同时满足,则接收到的数据作废并丢失,无论条件满足与否,接收器重又检测RxD端口上的"1" →"0"的跳变,继续下一帧的接收。接收有效,在响应中断后,必须由软件清0,即RI=0。通常情况下,串行通信工作于模式1时,SM2设置为"0"。
       串行通信模式1的波特率是可变的,可变的波特由定时器/计数器1或独立波特率发生器产生。
       串行通信模式1的波特率=2SMOD/32×2^{SMOD}/32×2SMOD/32×(定时器/计数器1溢出率)
       当单片机工作在12T模式时,定时器1的溢出率 = SYSclk/12/( 256 - TH1);
       当单片机工作在6T模式时, 定时器1的溢出率 = SYSclk /6/ ( 256 - TH1)

串行口工作模式2:9位UART,波特率固定

当SM0、SM1两位为10时,串行口工作在模式2。串行口工作模式2为9位数据异步通信UART模式,其一帧的信息由11位组成:1位起始位,8位数据位(低位在先),1位可编程位(第9位数据)和1位停止位。发送时可编程位(第9位数据)由SCON中的TB8提供,可软件设置为1或 0,或者可将PSW中的奇/偶校验位P值装入TB8(TB8既可作为多机通信中的地址数据标志位,
       又可作为数据的奇偶校验位)。接收时第9位数据装入SCON的RB8。TxD为发送端口,RxD为接收端口,以全双工模式进行接收/发送。
模式2的波特率为:
       串行通信模式2波特率=2SMOD/64×2^{SMOD}/64×2SMOD/64×(SYSclk系统工作时钟频率)
       上述波特率可通过软件对PCON中的SMOD位进行设置,当SMOD=1时,选择1/32(SYSclk);当SMOD=0时,选择1/64(SYSclk) ,故而称SMOD为波特率加倍位。可见,模式2的波特率基本上是固定的。 图8-3为串行通信模式2的功能结构示意图及其接收/发送时序图。
       由图8-3可知,模式2和模式1相比,除波特率发生源略有不同,发送时由TB8提供给移位寄存器第9数据位不同外,其余功能结构均基本相同,其接收/发送操作过程及时序也基本相同。
       当接收器接收完一帧信息后必须同时满足下列条件:

  1. RI=0
  2. SM2=0或者SM2=1,并且接收到的第9数据位RB8=1。

当上述两条件同时满足时,才将接收到的移位寄存器的数据装入SBUF和RB8中,并置位RI=1,向主机请求中断处理。如果上述条件有一个不满足,则刚接收到移位寄存器中的数据无效而丢失,也不置位RI。无论上述条件满足与否,接收器又重新开始检测RxD输入端口的跳变信息,接收下一帧的输入信息。
       在模式2中,接收到的停止位与SBUF、RB8和RI无关。
       通过软件对SCON中的SM2、TB8的设置以及通信协议的约定,为多机通信提供了方便。

串行口工作模式3:9位UART,波特率可变

当SM0、SM1两位为11时,串行口工作在模式3。 串行通信模式3为9位数据异步通信UART模式,其一帧的信息由11位组成:1位起始位,8位数据位(低位在先),1位可编程位(第9位数据)和1位停止位。发送时可编程位(第9位数据)由SCON中的TB8提供,可软件设置为1或0,或者可将PSW中的奇/偶校验位P值装入TB8(TB8既可作为多机通信中的地址数据标志位,又可作为数据的奇偶校验位)。接收时第9位数据装入SCON的RB8。TxD为发送端口,RxD为接收端口,以全双工模式进行接收/发送。
       模式3的波特率为:
       串行通信模式3波特率=2SMOD/32×2^{SMOD}/32×2SMOD/32×(定时器/计数器1的溢出率)
       当单片机工作在12T模式时,定时器1的溢出率 = SYSclk/12/( 256 - TH1);
       当单片机工作在6T模式时, 定时器1的溢出率 = SYSclk /6/ ( 256 - TH1)
       可见,模式3和模式1一样,其波特率可通过软件对定时器/计数器1或独立波特率发生器的设置进行波特率的选择,是可变的。 图8-4为串行口工作模式3的功能结构示意图及其接收/发送时序图。
       由图8-4可知,模式3和模式1相比,除发送时由TB8提供给移位寄存器第9数据位不同外,其余功能结构均基本相同,其接收发送操作过程及时序也基本相同。
       当接收器接收完一帧信息后必须同时满足下列条件:

  1. RI=0
  2. SM2=0或者SM2=1,并且接收到的第9数据位RB8=1。

当上述两条件同时满足时,才将接收到的移位寄存器的数据装入SBUF和RB8中,并置位RI=1,向主机请求中断处理。如果上述条件有一个不满足,则刚接收到移位寄存器中的数据无效而丢失,也不置位RI。无论上述条件满足与否,接收器又重新开始检测RxD输入端口的跳变信息,接收下一帧的输入信息。
       在模式3中,接收到的停止位与SBUF、RB8和RI无关。
       通过软件对SCON中的SM2、TB8的设置以及通信协议的约定,为多机通信提供了方便。

串行通信中波特率的设置

STC89C52系列单片机串行通信的波特率随所选工作模式的不同而异,对于工作模式0和模式2,其波特率与系统时钟频率SYSclk和PCON中的波特率选择位SMOD有关,而模式1和模式3的波特率除与SYSclk和PCON位有关外,还与定时器/计数器1或BRT独立波特率发生器设置有关。通过对定时器/计数器1或BRT独立波特率发生器的设置,可选择不同的波特率,所以这种波特率是可变的。
       串行通信模式0,其波特率与系统时钟频率SYSclk有关 。
       当用户在烧录用户程序时在STC-ISP编程器中设置单片机为6T/双倍速时,其波特率 =
SYSclk/12。
       当用户在烧录用户程序时在STC-ISP编程器中设置单片机为12T/单倍速时,其波特率 =
SYSclk/2。
       一旦SYSclk选定且单片机在烧录用户程序时在STC-ISP编程器设置好,则串行通信工作模式0的波特率固定不变。
       串行通信工作模式2,其波特率除与SYSclk有关外,还与SMOD位有关。
其基本表达式为:串行通信模式2波特率=2SMOD/64×2^{SMOD}/64×2SMOD/64×(SYSclk系统工作时钟频率)
       当SMOD=1时,波特率=2/64(SYSclk)=1/32(SYSclk);
       当SMOD=0时,波特率=1/64(SYSclk)。
       当SYSclk选定后,通过软件设置PCON中的SMOD位,可选择两种波特率。所以,这种模式的波特率基本固定。
       串行通信模式1和3,其波特率是可变的:
       模式1、3波特率=2SMOD/32×(定时器/计数器1的溢出率或BRT独立波特率发生器的溢出率)
       当单片机工作在12T模式时,定时器1的溢出率 = SYSclk/12/( 256 - TH1);
       当单片机工作在6T模式时, 定时器1的溢出率 = SYSclk /6/ ( 256 - TH1)
       通过对定时器/计数器1和BRT独立波特率发生器的设置,可灵活地选择不同的波特率。在实际应用中多半选用串行模式1或串行模式3。显然,为选择波特率,关键在于定时器/计数器1 和BRT独立波特率发生器的溢出率的计算。
为选择波特率,关键在于定时器/计数器1的溢出率。下面介绍如何计算定时器/计数器1的
溢出率。
       定时器/计数器1的溢出率定义为:单位时间(秒)内定时器/计数器1回0溢出的次数,即定时器/计数器1的溢出率=定时器/计数器1的溢出次数/秒。
       STC89C52系列单片机设有两个定时器/计数器,因定时器/计数器1具有4种工作方式,而常选用定时器/计数器1的工作方式2(8位自动重装)作为波特率的溢出率。设置定时器/计数器1工作于定时模式的工作方式2(8位自动重装),TL1的计数输入来自于SYSclk经12分频或不分频的脉冲。当单片机工作在12T模式,TL1的计数输入来自于SYSclk经12分频的脉冲;当单片机工作在6T模式,TL1的计数输入来自于SYSclk经6分频的脉冲。可见,定时器/计数器1的溢出率与SYSclk和自动重装值N有关,SYSclk越大,特别是N越大,溢出率也就越高。对于一般情况下,
       当单片机工作在12T模式时时,定时器/计数器1溢出一次所需的时间为:

当单片机工作在6T模式时,定时器/计数器1溢出一次所需的时间为

于是得定时器/计数器每秒溢出的次数,即
       当单片机工作在12T模式时,定时器/计数器1的溢出率=SYSclk/12×(28-N) (次/秒)
       当单片机工作在6T模式时, 定时器/计数器1的溢出率=SYSclk×6×(28-N) (次/秒)
       式中SYSclk为系统时钟频率,N为再装入时间常数。
       下表给出各种常用波特率与定时器/计数器1各参数之间的关系。
       常用波特率与定时器/计数器1各参数关系(T1x12/AUXR.6=0)

示例程序

stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
       由于STC单片机的定时器2才有波特率发生器,因此本示例中使用STC的头文件。

USART.c

#include "USART.h"char RxBuffer[RxBuffer_Len] = {0};
bit USART_Busy;void String_Analysis()
{}void USART_Init(uint8_t USART_Mode, bit Rx_Flag, uint8_t Priority, uint32_t SYSclk, uint32_t Baud_Rate, bit Double_Baud_Flag, bit USART_Timer)
{uint16_t THLx;Priority &= 3;USART_Mode &= 3;PCON = 0;PCON |= (uint8_t)Double_Baud_Flag << 7;         //波特率倍速控制SCON = 0;SCON |= (USART_Mode << 6);                        //设置工作模式REN = Rx_Flag;                                 //允许/禁止串行接收控制位IPH &= ~(1 << 4);                              //设置中断优先级IPH |= ((2 & Priority) << 3);                   //设置中断优先级PS  = (1 & Priority);                         //设置中断优先级if (USART_Mode == USART_MODE_1 || USART_Mode == USART_MODE_3) {if (USART_Timer){T2MOD = 0;                                //初始化定时器2模式寄存器T2CON = 0;                               //初始化定时器2控制寄存器THLx = 65536 - SYSclk / 32 / Baud_Rate;  //定时器2 16位自动重装载TL2 = THLx;                             //设置定时初始值TH2 = THLx >> 8;                        //设置定时初始值RCAP2L = THLx;                            //设置定时初始值RCAP2H = THLx >> 8;                     //设置定时初始值TR2 = 1;                              //定时器开启}else{TMOD &= 0x0F;                         //初始化定时器1寄存器TMOD |= 1 << 5;                          //定时器1 8位自动重装载THLx = 256 - (1 << (uint8_t)Double_Baud_Flag) * SYSclk / 12 / 32 / Baud_Rate;  TH1 = THLx;                                //设置定时初始值TL1 = THLx;                               //设置定时初始值TR1 = 1;                              //定时器开启}RCLK = USART_Timer;TCLK = USART_Timer;}ES = 1;                                           //允许串行口中断EA = 1;                                           //允许总中断
}/*----------------------------
UART interrupt service routine
----------------------------*/
void Usart_Isr() interrupt 4
{static uint16_t Str_Count = 0;if (RI){RI = 0;             //Clear receive interrupt flagRxBuffer[Str_Count] = SBUF; if(RxBuffer[Str_Count] == '\n'){for(++Str_Count; Str_Count < RxBuffer_Len; ++Str_Count)RxBuffer[Str_Count] = 0;Str_Count = 0;String_Analysis();}else++Str_Count;}if (TI){TI = 0;             //Clear transmit interrupt flagUSART_Busy = 0;        //Clear transmit USART_Busy flag}
}/*----------------------------
Send a byte data to UART
Input: dat (data to be sent)
Output:None
----------------------------*/
void SendData(char dat)
{while (USART_Busy);        //Wait for the completion of the previous data is sentACC = dat;              //Calculate the even parity bit P (PSW.0)if (P)                  //Set the parity bit according to P{#if (PARITYBIT == ODD_PARITY)TB8 = 0;            //Set parity bit to 0
#elif (PARITYBIT == EVEN_PARITY)TB8 = 1;            //Set parity bit to 1
#endif}else{#if (PARITYBIT == ODD_PARITY)TB8 = 1;            //Set parity bit to 1
#elif (PARITYBIT == EVEN_PARITY)TB8 = 0;            //Set parity bit to 0
#endif}USART_Busy = 1;SBUF = ACC;             //Send data to UART buffer
}/*----------------------------
Send a string to UART
Input: s (address of string)
Output:None
----------------------------*/
void SendString(char *s)
{while (*s)              //Check the end of the string{SendData(*s++);     //Send current char and increment string ptr}
}char putchar(char Char)
{SendData(Char);return Char;
}//适配vofa+串口示波器的JustFloat格式 浮点为大端
void SendFloat(unsigned char *Data) //发送一个字符
{char i;for(i=0;i<4;++i)SendData(Data[3-i]);
}

USART.h

#ifndef USART_H_
#define USART_H_#include <STC89C5xRC.H>
#include "stdint.h"
#include <stdio.h>#define RxBuffer_Len 20
extern char RxBuffer[];/*Define UART parity mode*/
#define NONE_PARITY     0       //None parity
#define ODD_PARITY      1       //Odd parity
#define EVEN_PARITY     2       //Even parity
#define MARK_PARITY     3       //Mark parity
#define SPACE_PARITY    4       //Space parity#define PARITYBIT NONE_PARITY //Testing even parity#define USART_MODE_0 0
#define USART_MODE_1 1
#define USART_MODE_2 2
#define USART_MODE_3 3#define Rx_ENABLE 1
#define Rx_DISABLE  0//STC单片机的4级优先级
#define STC_USART_Priority_Lowest   0
#define STC_USART_Priority_Lower    1
#define STC_USART_Priority_Higher   2
#define STC_USART_Priority_Highest  3#define DOUBLE_BAUD_ENABLE 1
#define DOUBLE_BAUD_DISABLE 0#define USART_TIMER_1 0                    //8位自动重装载
#define USART_TIMER_2 1                 //16位自动重装载void USART_Init(uint8_t USART_Mode, bit Rx_Flag, uint8_t Priority, uint32_t SYSclk, uint32_t Baud_Rate, bit Double_Baud_Flag, bit USART_Timer);
void SendData(char dat);
void SendFloat(unsigned char *Data);    //适配vofa+串口示波器的JustFloat格式 浮点为大端//适配vofa+串口示波器的JustFloat格式 结束符
#define SendEnd() {SendData(0x00);SendData(0x00);SendData(0x80);SendData(0x7f);}    #endif

定时器2作为波特率发生器实验

main.c

串口初始化为模式1,使能接收,串口中断优先级为最低,系统频率为11.0592MHz,波特率为115200,不加倍,设置定时器2为串口的波特率发生器,每隔0.5s回传收到的数据。

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "USART.h"void Delay1ms()     //@11.0592MHz
{unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}//主函数
void main(void)
{USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 115200, DOUBLE_BAUD_DISABLE, USART_TIMER_2);printf("USART Test.\r\n");while (1){Delay_ms(500);printf("%s", RxBuffer);}
}

实验现象

实验符合预期。

定时器1作为波特率发生器仿真实验

main.c

串口初始化为模式1,使能接收,串口中断优先级为最低,系统频率为12MHz波特率为4800,加倍此时误差为0.16%,是12MHz下定时器1能维持正常通讯的最高常见波特率),设置定时器1为串口的波特率发生器,每隔0.5s回传收到的数据。

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "USART.h"void Delay1ms()     //@12.000MHz
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}//主函数
void main(void)
{USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 12000000, 4800, DOUBLE_BAUD_ENABLE, USART_TIMER_1);printf("USART Test.\r\n");while (1){Delay_ms(500);printf("%s", RxBuffer);}
}

实验现象

仿真结果符合预期。

串行口工作模式0发送实验

main.c

串口初始化为模式0,不使能接收(发送模式),串口中断优先级为最低,之后的设置值对模式0没有意义,每隔0.5s发送"OK\n"。

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "USART.h"void Delay1ms()     //@12.000MHz
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}//主函数
void main(void)
{USART_Init(USART_MODE_0, Rx_DISABLE, STC_USART_Priority_Lowest, 11059200, 115200, DOUBLE_BAUD_DISABLE, USART_TIMER_2);while (1){Delay_ms(500);printf("OK\n");}
}

实验现象

此模式下可看作SPI通讯的变体
根据时序,逻辑分析仪设置为空闲时时钟线为高,LSB,数据在时钟的偶数缘有效

抓到的波形

【51单片机快速入门指南】3.3:USART 串口通信相关推荐

  1. 【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器

    目录 硬知识 DHT11 DHT22 通信协议 读取步骤 数据解读 DHT11 DHT22 示例程序 DHT11_22.c DHT11_22.h 测试程序 main.c 实验现象 DHT11 DHT2 ...

  2. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  3. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

  4. 【51单片机快速入门指南】4.4.3:Madgwick AHRS 九轴姿态融合获取四元数、欧拉角

    目录 传感器的方向 源码 Madgwick_9.c Madgwick_9.h 使用方法 测试 main.c 效果 STC15F2K60S2 22.1184MHz Keil uVision V5.29. ...

  5. 【51单片机快速入门指南】4.4.2:Mahony AHRS 九轴姿态融合获取四元数、欧拉角

    目录 传感器的方向 源码 Mahony_9.c Mahony_9.h 使用方法 测试 main.c 效果 STC15F2K60S2 22.1184MHz Keil uVision V5.29.0.0 ...

  6. 【51单片机快速入门指南】4.4:I2C 读取HMC5883L / QMC5883L 磁力计

    目录 硬知识 简介 操作模式 HMC5883L 连续测量模式 单次测量模式 闲置模式 QMC5883L 连续测量模式 待命模式 主要差异 寄存器 寄存器列表 HMC5883L QMC5883L 配置寄 ...

  7. 【51单片机快速入门指南】4.3.4: MPU6050使用Madgwick AHRS算法实现六轴姿态融合获取四元数、欧拉角

    目录 源码 Madgwick_6.c Madgwick_6.h 使用方法 测试程序 main.c 效果 STC89C516 32MHz Keil uVision V5.29.0.0 PK51 Prof ...

  8. 【51单片机快速入门指南】4.3.3: MPU6050使用Mahony AHRS算法实现六轴姿态融合获取四元数、欧拉角

    目录 源码 Mahony_6.c Mahony_6.h 使用方法 测试程序 main.c 效果 STC89C516 32MHz Keil uVision V5.29.0.0 PK51 Prof.Dev ...

  9. 【51单片机快速入门指南】4.3.2: MPU6050:一阶互补滤波、二阶互补滤波和卡尔曼滤波获取欧拉角

    目录 源码 MPU6050_Filter.c MPU6050_Filter.h 使用方法 测试程序 一阶互补滤波 效果 二阶互补滤波 效果 卡尔曼滤波 效果 总结 普中51-单核-A2 STC89C5 ...

最新文章

  1. Scrum Master的职业发展路线
  2. ApacheServerStatus开启
  3. Unity3D 游戏引擎之IOS高级界面发送消息与Unity3D消息的接收(九)
  4. Python学到什么程度可以面试工作?
  5. vue-resource全攻略
  6. Tomcat 的 DefaultServlet
  7. 常量指针与指针常量的区别(转帖)
  8. 目录下文件过多无法删除
  9. mongodb 命令补充
  10. day022 python (re模块和 模块)
  11. truffle migrate 强制重新部署合约
  12. 基于SSH的共享笔记系统
  13. pert计算公式期望值_PERT方法—用于计算各工序和工时的方法
  14. 求职面试准备——自我介绍
  15. VMWare安装Win10虚拟机详细教程
  16. 全市场等权中位数_市场指数估值周报20200418
  17. 计算机无线网络怎么连接打印机共享打印机,电脑如何连接无线打印机?网络打印机连接方法!,又快又好...
  18. 小和尚打水问题_老和尚和小和尚打水问题
  19. openwrt web框架luci简介,20行代码写一个前后端交互页面
  20. 去除安卓apk中的广告

热门文章

  1. 忘记 mysql 密码的取回方法
  2. dataguru北京线下沙龙-第二部 《Oracle 索引优化思路--案例分享 -- 刘盛》
  3. LAMP平台下构建Postfix邮件服务器
  4. 2016. 增量元素之间的最大差值
  5. 重学TCP协议(10)SYN flood 攻击
  6. iref streams_如何利用Neo4j Streams并建立即时数据仓库
  7. React学习笔记(持续更新)
  8. 【层次聚类】python scipy实现
  9. 为div添加滚动效果:
  10. HDU 2202 计算几何