趣聊51之串口通信(实现篇)

本文深入讲解了基于STC89C51/52系列单片机的串口通信,包括串口硬件结构、SCON和PCON寄存器的配置、定时器与波特率的关系以及中断服务函数的工作原理。重点阐述了串口工作方式、波特率计算、串行通信寄存器的位操作,并提供了串口初始化及数据发送的代码示例。适合单片机初学者理解和实践。
摘要由CSDN通过智能技术生成

 

             哈哈哈罗各位同学,很高兴又和大家见面了,继上次我们所聊的串口通信的一些概念,今天咱们来聊一下基于STC89C51/52系列单片机的串口硬件结构。

        51单片机的串行口是一个可编程的全双工通信接口,基本结构如下图所示:

        看到此图,切莫慌张,就像学开车不需要先学造车,(当然要是能懂一点汽车的构造是最好的),我先带大家来看看串口通信的典型代码:

void serialinit(void)//串口初始化代码

 {

 SCON=0x50;//配置SCON寄存器,该寄存器控制串口工作的一些参数(此寄存器一定要配置)

 PCON=0x80; //配置PCON电源管理寄存器(此寄存器根据需要配置)

TMOD=0x20;//配置定时器工作方式(设置定时器1工作在方式2)

 TH1=0xF4;//为定时器装初值

 TL1=0xF4;   

 EA=1;//开启总中断

 ES =1;//开启串口中断

 TR1=1;//点火!~~定时器1以工作方式2开始工作

 }

void process() interrupt 4//熟悉的中断服务函数,当发送一帧数据完毕或者接受到数据起始位时被触发

   {

   if(RI==1)//if语句通过判断RI或者TI的值来判断是接收了数据还是发送了

   {  

     RI=0;//此位要通过软件清零

 receivedate[n] = SBUF;//注意赋值的方向,翻译:把SUBF寄存器的数据放到数组receivedate当中。

 n++;

   }



   if(TI==1)

   {

   TI=0;

   }

   }

/***************/

for(i=0;i<8;i++)//把一个数组里的数据发送出去

{

ES = 0;//收数据前先关闭串口中断

SBUF = cmd[i];   //注意赋值方向,翻译:把cmd数组里的数据放到SBUF寄存器里 

 while(TI==0);//等待发送完毕

 ES=1;//再开启串口中断(串口OS:算你还有良心)

}

        独秀同学拿了代码就想跑?大家请先稍安勿躁,学习一定要知其所以然,要不然学完以后还是糊里糊涂的,没有什么实质的改变。无论大家有没有细细看前面三段代码,我现在需要大家做的事就是把上一节咱们讲过的一些通信关键词复述出来:第一个词叫串口(RXD和TXD引脚)。第二个叫异步串行通信的数据帧,第三个叫发送数据的速度,也就是老朋友波特率。咱们配置SCON寄存器和PCON寄存器以及TMOD寄存器的目的就是描述这三个关键词。

        先来解析一下PCON寄存器(全称叫Power Control Register,即功率控制寄存器)

        这个寄存器各位的详细功能介绍大家可以自行从网上查阅,对于我们这节内容,有用的就是一位:SMOD位。当SMOD=0时,串口工作方式1、2、3的波特率正常,当SMOD等于零时,串口方式1、2、3的波特率倍增。值得注意的是,该寄存器不能进行位寻址,字节地址为87H,也就是说,不能出现“SMOD=0/1”这样的语句,只能整体对PCON寄存器赋值,大家可以参考前面的代码进行理解。

        其次一个重要的寄存器就是SCON寄存器,这是一个非常重要的寄存器,这里给各位同学敲敲黑板。

        SCON(Serial Control Register)又叫串行口控制寄存器,主要用于控制串行通信的方式、接收和发送,指示串口的状态。SCON既可以字节寻址,也可以位寻址,其字节地址为98H,地址位为98H~9FH。

                哟西,终于碰到一个可以进行位寻址的寄存器,我们应该感到兴奋,如果你没有这样的感觉的话,请加快你的呼吸,体验一下兴奋的感觉!

                首先,我们来看一下SM0和SM1位

         这两个位又称工作方式选择位,那么你一定好奇,串口有哪些工作方式呢?

        如图所示,串口共有2x2=4种工作方式。不同的工作方式发送的数据,以及传输波特率都是不同的。作为一篇分享型博客,我会把所有的工作方式都进行描述,但对于初学者,掌握工作方式1就足矣。

        说明一栏中,我们可以看到,除了工作方式0,其它的工作方式要不就是10位,要不就是11位,除去起始位和结束位,数据分为8位和9位,8位的数据大家都理解,一个字节的数据,那么9位究竟是多了哪一位呢?聪明的你一定想起来我们在前一节所说的数据帧格式,没错,第九位就是奇偶校验位,但是需要注意,该位并不进入咱们的数据寄存器SBUF,而是被读进SCON寄存器的RB8位。

        解决了数据长度的问题,接下来我们来看波特率的不同之处。很显然,工作方式0和工作方式2的波特率是固定的,我们很容易可以求解,但是不同的场合要使用不同的波特率来传输数据,这就要求串口发送的数据要可以进行人为编程调节,这样就产生了工作方式1和工作方式3。他们的波特率又和什么东西有关呢?

        话不多说,直接上图。从图上我们可以知道,方式0与方式2的波特率相对固定(方式二可以倍增),对于方式1和方式3,波特率的一个重要的影响因素叫T1的溢出率。看到此处我们不由得佩服设计者们的智慧,为了实现波特率可变的用心良苦。

        那么什么叫波特率溢出率呢?我们学过定时器可以知道,定时器的本质是一个计数器,就像一个水缸一样,我们往定时器内装初值就是实现往水缸里装上一定量的水,所谓的TR1=1,就相当于打开水缸的水龙头,让水流进水缸,直到水缸装满水了,就会“溢出”,从开启水龙头到发生溢出的这段时间叫“溢出时间”,所谓溢出率就是溢出时间的倒数

        计算波特率的方法可以通过手工计算,或者查表计算,再或者使用专门软件进行计算。

        讲完了工作方式位,下面我们来看SM2位,此位又叫多机通信位控制位,主要用在工作方式2与工作方式3。(主要还是因为这两种工作方式多出了一位校验位,我们可以把它当成是否接受该条数据的一个标志)。当接收机的SM2=1时开启多机通讯的校验功能,当接收到的RB8=0时,不激活RI(意味着收到的数据被丢弃),当接受到的RB8=1时,激活RI,收到的数据进入SBUF。在工作方式0时,SM2必须为0,在工作方式1时若将SM2位置1,则只有在接收到有效停止位时,RI才置1.

        再往下看,REN位,又叫允许串行接受位,顾名思义,当REN=1时允许串行口接受数据,当REN=0时,禁止串口接受数据,大家在配置串口时一定不要遗漏这一位的设置。

        TB8与RB8位分别是发送数据和接受数据的第九位(工作方式2、3)。前面我们聊过了奇偶校验和多机通信的标志位,这两位便是做这一用途的。值得注意的是TB8需要自己用软件写进去,但是这个肯定是可以自动化完成的,具体实现方法我会再发一篇博客来介绍。在今天的讨论里,咱们暂且不使用此位。

        TI与RI位,又叫发送标志位与接收标志位。

        对于接收标志位(RI),在方式0时,当串行发送第8位数据结束时,由硬件置1,其他方式时,在串口发送停止位开始时,由硬件置1;

        对于发送标志位(TI),在方式0时,当串口接收第8位数据结束时,由硬件置1,其他方式时,串口接收停止位的中间时,由硬件置1;

        需要注意,当开始串口中断后,TI与RI置1时会向CPU发送中断申请,并进入中断服务函数(发送完成或者接收完成时都会),在中断服务函数中我们要完成的工作有:

  1. 将标志位清零(软件清零),以取消中断申请。
  2. 接收串行数据。

        最后一个要讲的寄存器就是SBUF寄存器,大家很好奇为什么发送和接收用的是同一个寄存器,这感觉就像是共用一个名字的双胞胎,不停出现在我们面前。事实上,这个特殊功能寄存器共用一个地址99H,但在物理上却是两个独立的寄存器。发送数据是我们常用“SBUF=x”来给SBUF赋值,接收时用“x=SBUF”来将SBUF内的数据装入x,这种设计的目的在于方便大家的使用,不过却常常引起初学者们的不理解。

        恭喜看到这里的小伙伴们,至此咱们重要的串行通信寄存器就基本讲完了。如果大家看累了,我就在这里打打叉:不同于STM32或者adiuno等等大量使用库的单片机,51单片机的编程主要还是面向寄存器,所以掌握寄存器是咱们必学的一项基本功,一时记不清楚没有关系,感觉难以理解也没有关系,学习不是考试,忘记了就翻翻书,学会了就多写写代码练练手,久了自然而然就熟了,也许这就叫“日久生情”吧?广大单身同志们!可能你心爱的人心里不一定装着你,但单片机里烧录的一定只会是你---写的代码,所以请好好爱护你的单片机!

        得得得,扯到天上去了,言归正传,下面我给大家总结一下配置串口通信方式1的具体步骤:

  • 初始化

配置定时器1,TMOD寄存器;

往定时器1内装初值,TH1,TL1;

配置PCON寄存器(工作方式1,2,3波特率是否翻倍);

配置SCON寄存器(SM0,SM1确定工作方式,REN是否开启串口接收数据);

中断配置(EA=1开启全局中断,ES=1开启串口中断);

打开定时器(TR1=1,点火!!!)

  • 发送数据

SBUF=x

  • 中断服务函数
  1. 标志位清零
  2. 接收数据:x=SBUF

        至此一个配置串口通信的基本骨架搭建完成,更多的细节还需要根据大家自己的要求进行编程。

        51单片机串口通信的内容至此告一段落,希望我的分享能对大家有所帮助。

        路漫漫其修远兮,吾将上下而求索。与君共勉!

图片部分来源网络,侵删。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值