单片机学习笔记---串口通信(2)

目录

串口内部结构

串口相关寄存器

串口控制寄存器SCON

SM0和SM1

SM2

REN

TB8和RB8

TI和RI

电源控制寄存器PCON

SMOD

扫描二维码关注公众号,回复: 17376401 查看本文章

串口工作方式

方式0

方式0输出:

方式0输入

方式1

方式1输出。

方式1输入

方式2和方式3

方式2和方式3输出:

方式2和方式3输入:

波特率的计算

串口配置步骤

1.确定T1的工作方式

2.确定串口的工作方式

3.计算我们T1的初值(设定波特率)

4.启动T1(TCON中的TR1位)

5.如果使用中断,需要开启串口中断控制位


续上一篇:

单片机学习笔记---串口通信(1)-CSDN博客

串口内部结构

这张图是我们51单片机的串口内部的结构图。 右边的两个脚,TXD对应到单片机的P3.1的附加功能,然后RXD对应到单片机的P3.0引脚的附加功能。

同样,对这个P3.1和P3.0相应的寄存器配置就可以使用串口的功能了。

左边这一块全是单片机内部的结构。

最重要的一块是在SBUF数据缓存期,也就是特殊功能均器的数据缓存期

SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器

我们要进行发送数据和接收数据的话,它的数据是存放在SBUF这个缓存区当中的

如果我们要读取串口的接收数据的话,我们是读取这个SBUF

然后要发送的话也是先把数据存到SBUF这个寄存器当中,然后由我们对应的寄存器控制它发送出去。

串口通信是异步的串行通信,它有波特率,那这个波特率是如何产生的?

波特率依靠的就是TH1和TL1的计算,波特率计算后续我们还会介绍到。(TH1和TL1是定时器1的功能,在使用串口通信的时候,也必须要配置TH1和TL1的工作方式,通常在这里,TH1和TL1是工作在方式2自动重载的模式 )。

这里有一个SMOD,这是通过对应的寄存器来控制倍频。

如果不倍频的话,那就是相当于这个开关打到上面这一块:

如果是倍频的话,就要将对应的值除以2,再传输到我们对应的接收和发送控制器。

接收和发送控制器根据对应的SBUF里面的传输数据控制这个控制门和移位寄存器。

如果是接收的话,把对应的RXD的数据接收到SBUF里面,然后,SBUF接收完成之后,控制寄存器会将对应的RI置1,也就是接收中断。之后就会发送串口中断的请求,向CPU发送中断请求执行中断。

也就是说当RI或者TI哪一个为1的话,它就会发送串口中断的请求。

如果是发送,我们会通过SBUF把这个数据传输到控制门,由发送控制器控制它(发送控制器也会控制中断),然后通过TXD引脚发送出去。要准备发送时会通过TI控制置1,然后发送中断请求,将我们的SBUF数据发送出去。

串口相关寄存器

我们的芯片手册上有一张比较全的串行口相关寄存器,但是我们主要介绍其中几种重要的寄存器。

串口控制寄存器SCON

PS:控制寄存器在工作流程图中的这一个位置:

SM0和SM1

SCON也有8位SM0和SM1是用来确定串口通信的工作方式,同样它也有四种方式。方式0,方式1,方式2和方式3,通过SM0和SM1的不同四种组合。

我们常用的通信使用的工作方式是方式1,10位异步收发器,8位数据,波特率是可变的,其中两位是指起始位和停止位。

SM2

SM2 是用来多机通信的控制位。

 使用串口通信时,它可以支持多机通信,什么意思?

比如,主设备的串行口TXD和RXD可以连接多个串口设备。比如说设备1设备2,这是主设备,它可以通过SM2这个位来进行控制。

使用了多机通信的话,这个SM2工作方式主要处于方式2和方式3这两种方式。 当SM2=1的时候,可以利用收到的RB8这个位来控制是否激活RI,RI就是接收中断。

如果RB8=0的时候,表示不激活RI,收到信息就丢弃。 如果当RB8=1的时候,收到的信息就会进入到SBUF缓存器当中来,并激活RI,从而接收数据。 比如,如果使用了两个设备通信的话,设备1配置的 RB8是为1的,设备2接收到RB8是0。等于1的话就可以,读取SBUF里面的数据;等于0的话就不读取。那就代表主机发送的数据是在设备1,而不是在设备2。如果设备2配置的是RB8=1,那它的数据同样也会到达设备2上面来。要忽略它的数据就使RB8接收的数据为0。

当这个SM2=0的时候,不论RB8等于0还是等于1,均可以使用收到的数据进入到SBUF。这样的话,我们在使用串口方式1,也就是不进行多机通信的时候,我们可以将SM2等于设置为0。

刚刚说过,如果设置为1的话,我们就工作在多机通信的这种方式,那这样串口通信方式可以设置为方式2和方式3,因为我们这个时候要用到了RB8,所以,数据位是9位。根据我们发送过来的数据来判断这个RB8是1还是0,从而实现是否激活这个RI。 当然在串口通信过程当中实现多机通信也可以不使用这种方式,也可以使用软件层面来实现多机通信。

REN

REN是允许接收位

REN由软件置1,置1就是启动串行口接收数据,如果这个软件设置为0,也就是REN设置为0的时候就禁止接收。当然我们在串口通信的时候肯定是需要发送和接收的,所以这位是设置为1的,也就是允许接收。   

TB8和RB8

TB8和RB8是工作在方式2和方式3的时候,可以用软件来规定作用,用作数据的机校机偶校验位,或者是在多机通信过程当中用作地址帧和数据帧的标志位。 。

在方式0和方式1的时候,TB8和RB8是没有用到的,所以,我们在串口通信的时候,这两个基本上不用管。

TI和RI

TI是发送中断标志位

在方式0的时候,当串行发送第8位数据结束的时候,或者是在其它方式串行发送停止位的时候,开始的时候内部硬件就会使这个TI置1,它就会向CPU发送中断请求,在中断服务程序当中必须用软件来清零,来取消中断申请,等待下一次的中断。

RI是接收中断标志位

在方式0的时候,当串行接收到第8位数据结束的时候,或者在其它方式串行接收停止位的中间时,由内部的硬件置1,然后发送向CPU发送中断申请。也必须在中断服务程序当中用软件将清零,清零的话就取消中断申请,等待下一次的中断申请。

小总结所以,我们在使用这个计算器SCON的时候,主要是配置SM0和SM1来选择串口通信的工作方式,通常我们选择为方式1,所以将SM0配置为SM1配置为1

然后SM2通常设置为0,因为没有使用多机通信,或者是没有使用9位数据,所以设置为0

REN我们通常在串行通信的时候,我们也要接收数据,所以要允许设置为1

TB8和RB8,我们没用到,我们默认就为0。 TI和RI是硬件自动完成。当进入中断的时候,才需要我们软件手动清零。

电源控制寄存器PCON

电源控制寄存器同样也有8位,但是,它只使用到了最高位,也是第7位。

后面的7位都没有用到。

这个寄存器的功能主要是用来对这个波特率的倍频的选择。

也就是在工作流程图的这个位置:

SMOD

SMOD=0的时候,那它是不进行倍频的。

如果是等于1的时候,这个开关是打到上面进行倍频。 在串口方式1,方式2,方式3的时候,波特率与这个SMOD的倍频值有关。

当SMOD=1的时候,波特率提高了一倍。

复位的时候,SMOD是等于0,也就打到下面来。

所以,在串口通信当中,我们使用工作方式1的时候,可以对这个SMOD的值进行配置,如果要倍频,那就设置为1,如果不倍频,那就是设置为0。

串口工作方式

我们知道通过SCON可以控制串口通信的四种工作方式,方式0,方式1,方式2,方式3。要使用哪一种方式,就通过SM0和SM1这两个值来确定。

方式0

方式0,串行口是同步移位寄存器的输入输出方式。 主要用于扩展并行输出输入和输出口。数据是由RXD,也就是P3.0这个引脚进行输入和输出的。同步移位脉冲是由TXD也就是P3.1引脚进行输出。发送和接收,均为8位数据。低位在前,高位在后。波特率固定是fosc除以12。 Fosc就是外部的晶振的频率,比如我们使用12兆,那就除以12就是1兆,就是对应方式0。

我们来看一下方式0和输出和输入格式:

方式0输出:

写入数据到SBUF到里面,然后它的数据发送和接收都是依靠RXD引脚来进行传输的,所以按照先从低位再到高位的规则,按照这个脉冲进行传输,从D0到D7,8位数据传输完成。传输完成之后TI置1,也就是中断标志位置1。

如果我们开启了中断,它会进入到中断,中断进入之后,我们要清除这个中断TI。

方式0输入

方式0输入的话,输入数据也是依靠RXD引脚来进行接收的,所以当我们接收允许的时候(REN=1作为接收允许),并且在TXD一位脉冲的情况下,数据就会一位一位的进行接收。接收同样是从低到高进行接收,接收完成之后RI置1,然后发送中断请求,接收完成之后在中断服务函数里面,我们手动给它清零,等待下一次的接收。 这是方式0,它的输出和输入的情况。

方式1

工作方式1是10位的异步通信口,TXD是发送引脚,RXD是接收引脚。 传送一帧数据的格式是这样格式:

检验位:用于数据验证(奇偶校验/无检验)

停止位:用于数据帧间隔

其中第一位是起始位,紧接着是8位的数据位,最后是停止位,一帧下来就是10位。

方式1输出。

把数据写入到SBUF这个缓存器里面后,由于方式1是异步的通信,由TH1产生波特率,在这个波特率的情况下,我们就来发送数据。然后,首先是发送低电平的起始位,然后紧接着发送8位的数据,按照从低位到高位的进行发送,发送完了之后还有高低平的停止位。同样发送完成之后,TI也会由硬件置1,代表中断。发送中断的完成,然后向CPU提出中断的请求。进入中断服务函数的时候,我们可以手动将TI清零,等待下一次的中断。

方式1输入

数据是通过RXD来进行接收的,同样它是在波段率的脉冲采样的时序上面进行接收,然后,首先它接收低电平的起始位,然后,以此类推,8位的数据位,从D0到D8,低位到高位,最后是高低平的停止位。然后接收完了之后,它会有高电平RI,表明接收完成中断,然后,开启的中断后它会进入中断服务程序,我们要手动对它进行清零。

这个位采样脉冲就是波特率,波特率的值是通过TH1和TL1的值来进行设置的,后续我们会介绍波特率的计算工具学习如何来计算它的波特率。

对于方式1,我们要对数据进行接收的话,我们还要注意要将这个REN这个中断接收使能位设置为1,接收器就会选择波特率的16倍的采样

16倍的采样是怎么来的?根据我们前面的结构图可以看得到,

这是根据生成的波特率之后,这里是除以16,也就是16分频的采样,

那它就会根据这个采样时序在RXD引角检测电平,检测到了RXD引角输入电平发生负跳变的时候,就说明起始位是有效,也就是来了下降沿的时候就有接收的这个起始位是有效的,并将其移入到输入移位寄存器当中,开始接收一帧信息,一帧信息其他的位就是我们8位的数据:

检验位:用于数据验证(奇偶校验/无检验)

停止位:用于数据帧间隔

接收了这些数据之后,数据都是从这个输入移位寄存器右边进行输入的。 移位寄存器输入的话,起始位移到这个输入移位寄存器的最左边控制电路进行最后一次移位。当这个RI等于0的时候,并且SM2=0的时候,将接收到的9位数据的前8位(不要起始位)装入到SBUF当中,这个过程是单片机内部串口进行自动完成的,而不需要我们对这个接收的数据进行去掉最高位,去掉最低位这样子的操作,这个是由串口的内部结构自动去完成。然后我们只要读取SBUF里面的数据,就可以读取到实际发送的数据了。 当接收完这个8位数据之后,紧接着是停止位,停止位是进入到RB8,并由硬件自动完成设置RI为1,也就是向中断发出请求。

如果串口的工作使用的是9位的话,它第8位数据还会继续接收。方式1是8位数据的,所以后面我们再来介绍9位的数据的情况。

方式2和方式3

方式2和方式3工作的时候是处于11位数据的异步通信。  TXD是发送引脚,RXD是接收引脚,和方式1不同的是,它是11位的,也就是它有9位数据,那我们来看一下它一帧数据的格式,它一帧是11位:起始位、9位数据、停止位,总共加起来11位。

其中起始位和停止位和方式1是类似的,不同的区别就是数据位,它是9位,增加了一个位,即RB8或TB8。

方式2和方式3输出:

发送开始的时候,起始位为0,输出到这个TXD引脚,然后输出移位寄存器的输出位从D0到TXD引脚,然后每一个移位脉冲都使输出移位寄存器的各个位一位。并由TXD引脚输出,也就是说从低位开始移位,一直到高位。 第一次移位的时候,停止位移入到输出移位寄存器的第9位上。以后每移位一次,左边都移入0。当停止位移至输出位的时候,左边其余就全部为0。检测电路检测到这一条件的时候,它就会使控制电路进行最后一次移位,并将TI设置为1,向CPU发出中断请求,这个是由硬件自动完成的。   

方式2和方式3输入:

输入跟输出的过程是类似的。 它由RXD引脚来接收这个数据,同样它是根据位采样脉冲的情况来一位一位的接收。首先是接收下降沿,认为接收开始。然后,以此类推,接收对应的数据。因为方式2和方式3处于11位数据,如果将SM2设置为0,并且RI=0的时候,接收的数据会装入到接收缓存器SBUF当中,和RB8里面。SBUF接收8个位:D0到D7,RB8是保存最后第9位数据。 接收完成之后,RI会置1,向CPU发出中断请求。如果条件不满足则数据丢弃。

数据不满足是指我们前面配置SCON这个特殊寄存器的时候,如果使用了SM2等于0,并且RI等于1的时候,它是直接将数据接收到SBUF里面。如果RB8=0的时候,它是忽略这个数据的 并且不会置位RI=1,继续搜索RXD引脚的负跳变,也就是起始号重复执行。

在串口通信当中,我们使用的主要是方1,一帧数据是10位。对于方式0、方式2和方式3,我们很少使用。

波特率的计算

接下来我们来介绍非常重要的知识点,就是串口的波特率的计算。 下面我们给出了这四种工作方式的波特率的计算公式。

方式0,它的波特率是固定的;

方式2,它的波特率也是固定的;方式1和方式3的波特率是可以更改的。

注意:

SMOD是方

T1是定时器的8位重载的模式。 Fosc是外部晶振的时钟频率,机器周期等于12乘以频率的导数1/12(震荡周期),即是12倍的震荡周期,也就是1微秒。

T1溢出率:方式2是8位的重载模式,那最大值就是256,到达了256它就会溢出,所以用256减掉初值就是实际的计数值,然后再将其倒数乘以机器周期(1微秒)。 

我们也可以不用这么复杂的计算,我们可以使用小工具来完成这个波利的换算。

默认打开这个软件都会直接定位到这个方式2。这个方式2是指定时器的方式,不是串口通信的工作方式。

串口通信的工作方式,我们使用的是方式1,从这个小工具上面也可以看到方式1和方式3,它的波动率才能更改的。我们使用的是方式1。 我们开发板的晶振频率是12兆,在串口通信当中我们一般都要使用11.0592兆晶振

波特率一般使用9600就可以了,SMOD是用来倍频的,如果将这个SMOD设置为1的话。是不是就是9600*2?不是哈,波动率依然是9600,只不过使用了SMOD=1之后,等一下计算的TH1的初值会进行变化,就相当于加倍了。

假设一开始使用不倍频,

点确定是0%误差,比较精确。

然后使用倍频看一下,现在变成了FAH,初值改变了。

为什么要使用11.0592兆的晶振?因为它的误差是零的,假设现在改成12兆,点一下确定看到误差就有了6.98%的误差,这个误差是比较大的,在串口通信过程当中,有可能会出现数据的错误,或者是乱码之类的,这个乱码的产生就是因为通信它有误差。

所以我们在串口通信,我们强烈建议使用11.0592兆的晶振,误差是为零的。

串口配置步骤

下面我们来看继续看一下串口的初始化步骤。

如图中罗列的顺序:

这个顺序的话可以不用按照这个顺序严格一步一步的来,次序可以任意。

我们首先按照这个顺序来讲解。

1.确定T1的工作方式

这个工作方式的确定是通过TMOD这个寄存器来进行设置,这个在定时器的章节当中我们也给大家讲解了,如果你不了解的话,可以回过头看一下我们定时器那一节。我们在使用串口通信的时候,我们是要使用定时器1,并且工作方式是2,也就是8位的自动重装载的模式。

2.确定串口的工作方式

有很多初学者把定时器的工作方式和串口的工作方式很容易混淆,所以在这一块一定要理解好。

定时器的工作方式是用来确定波特率的产生,我们根据串口内部结构图可以知道它只能通过TH1或者TL1,也就是定时器1产生。所以TMOD肯定是要配置定时器1的。

串口的工作方式有四种,通过SM0和SM1这两位来设置,串口通讯方式通常是使用方式1。

确定了工作方式,并且通过SCON可以使能允许接收位SMOD,允许接收位通过这个REN来进行设置。

3.计算我们T1的初值(设定波特率)

通过TH1和TL1这两个8位的寄存器的TL1进行计数,计数溢出之后,由TH1自动装载到TL1当中。所以我们要将计算的初值传入到TH1和TL1当中。 比如我们刚才使用的波特利的计算工具,

就算出来的初值等于0XFA。

那这个初值如何放入TH1和TL1当中?直接就是TH1=0XFA,TL1=0XFA。因为它是8位自动重装载,通过TL1进行开始计数,然后是重装载这个值,它要溢出之后自动装到这里TL1中,所以我们TH1TL1都要装载这个值,这就是波特率的初值的设置。   

4.启动T1(TCON中的TR1位)

5.如果使用中断,需要开启串口中断控制位

IE寄存器中ES位设置为1开启,并且要开启总中断EA。

通过这么几步,那就可以使用串口中断了。

那我们来看一下串口初始化的配置的实际代码。

这是我们自己定义的函数,没有返回值,入口参数是u8类型。

这个入口参数是用来设置波特率,方便我们在调用这个函数的时候,可以传入对应的波特率的值,这个波特率的值自然就是传到TH1和TL1当中的。

TOMD是用来设置定时器1的工作方式。它要工作在方式2,所以通过或运算不干扰到其他的位。TOMD=0010 0000

  

SCON用来设置串口通信的工作方式,那要工作方式1,并且开启了接收,允许接收为REN,那就是0X50。 SCON=0101 0000

然后PCON是对波特率的加倍设置。因为SMOD是PCON的最高位,所以PCON=1000 0000,这个1就对应到了SOMD。

然后TH1和TL1是用来设置波特率的重装载值,通过函数的入口参数传递进来。

 然后ES是开启串口的中断。

EA是总中断。

定时器需要开启所以要打开TR1=1

以上就是串口的初始化。

如果你使用中断,要更改的就是TH1和TL1的初值波特率,这个值可以通过前面介绍的这个波动率的自动计算工具,更改这个值可以改变波动率。

波特率是不是可以说任意的大小?

我们来演示一下,假设波特率现在设置为15200,我们看一下能不能到达。

点击确定,您所输入的晶振频率不能使用这个波特率,所以说不是说你想使用多大的波特率都可以的。

我们设置的11.0592兆这个晶振,它所配置的波动率的大小应该最大就是38400,而且它的误差很大,基本上这个波特率不能用。19200还是可以用的。 所以,你要使用哪个波特率可以根据你的实际的要求来使用,我们使用的是9600就可以了。 以上就是串口初始化的步骤。

下一节开始代码演示。

猜你喜欢

转载自blog.csdn.net/xiaobaivera/article/details/136062119