这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 坤创E-Geek/天科大新电社 » 第十一届蓝桥杯信息技术人才大赛-单片机竞赛备赛分享十——串口通信基础知识讲解(二

共5条 1/1 1 跳转至

第十一届蓝桥杯信息技术人才大赛-单片机竞赛备赛分享十——串口通信基础知识讲解(二)

工程师
2020-03-16 19:26:48     打赏

哈喽哈喽大家好,我是阿飞的小蝴蝶,大家可以叫我阿飞或者小飞,我又回来啦!

我们接着上节的内容来给讲一下51单片机串口的使用方法,好的,直接开始我们今天的内容。


串行口的结构:

image.png

这里有两个物理上独立的接收、发送寄存器SBUF,它们占用同一内存(99H)。

在程序逻辑上,SBUF只有一个,既代表发送寄存器,又代表接收寄存器,具有同一单元地址,但在物理结构上,则有两个完全独立的SBUF,一个发送寄存器SBUF和一个接收寄存器SBUF。如果CPU写SBUF,数据会被存入发送寄存器准备发送;如果CPU读SBUF,则读入的数据一定来自接收寄存器SBUF。(a=SBUF;SBUF=a;)。

 

接下来讲一下与串口有关的寄存器:

首先是SCON寄存器:

image.png

这里我简单说一声每一位的功能:

 

SM0:当PCON寄存器中SMOD0位为1时,该为用于帧错误检测。为0时,该位与SM1一起控制串口通信的工作方式。(这里一般用于控制工作方式)

 

SM0、SM1控制串口通信工作方式:

image.png

这里的SYSclk是晶振频率,方式0和方式2是比波特率固定的,具体大家可以自己算一下。方式1和方式3通过配置定时器1来改变波特率,SMOD是PCON寄存器中可以配置的,配置为1时可以将波特率提升1倍,后边会再介绍。

我们一般使用方式1,发送/接收8位数据,波特率可变。

 

SM2:多机通信控制位,主要用在方式2和方式3,为0时双机通信,为1时多机通信。

 

REN:串行接收允许位,REN=0时禁止接收,REN=1时允许接收

 

TB8/TR8:在方式2和方式3时分别用于存放发送/接收的第9位数据。

 

TI:发送中断请求标志位,数据发送结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。

 

RI:接收中断请求标志位,数据接收结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。

 

接下来是PCON寄存器:

image.png

SMOD:波特率选择位:SMOD=1时,工作方式1、2、3中波特率加倍。

 

最后还是我们熟悉的IE寄存器:

image.png

这里与串口有关的为:

EA:CPU总中断允许控制位,前边多次介绍过的,不多说了

ES:串行口中断允许位,ES=1,允许串行口中断;ES=0,禁止串行口中断。

我们配置好串口工作模式、打开串口中断后,CPU接收到串口的中断请求时就会相应串口中断执行串口中断服务函数。

 

波特率计算:

当串口工作在方式1时,波特率由定时器1的溢出率决定,此时定时器1通常选用定时器初值自动重装的工作模式(工作模式2,TMOD=0x20;)此时仅用低8位来计数,溢出以后8位的存放的数据会放入低8位中重新计时,无需再通过程序重放初值

因此,波特率=(2^SMOD/32)*(单片机时钟频率/(256-X)),X是初值。

在实际应用中,通常是选确定波特率,再根据波特率算出TI的定时初值,因此:X=256-(2^SMOD/32)*(单片机时钟频率/波特率)

我举个栗子:波特率为9600时,T1存放的初值(晶振频率为11.0592MHZ)。

SMOD=0,(2^SMOD/32)=1/32,(单片机时钟频率/波特率)=((11.0592MHZ/12)/9600)=96。X=253,因此T1存放初值为253(TH1=0xfd;TL1=0xfd;)。


再使用串口前,我们要把上边讲到的寄存器进行配置,设定好工作方式。

1、设置T1工作方式(编程TMOD寄存器);

2、计算T1的初值,装载TH1、TL1;

3、启动T1(编程TCON中的TR1位);

4、确定串行口控制(编程SCON寄存器);

5、如需串口在中断方式工作时,要进行中断设置编程IE寄存器


好的,现在用代码来对串口进行初始化:

void uart_init()

{

    TMOD = 0x20;   //T1工作模式2  8位自动重装

    TH1 = 0xfd;
    TL1 = 0xfd;  //比特率9600
    TR1 = 1;  //启动T1定时器
    SM0 = 0;
    SM1 = 1;   //串口工作方式1 10位异步
    REN = 1;  //串口允许接收
    EA  = 1;  //开总中断
    ES  = 1;  //串口中断打开

}

 

下边用一个例子来带大家了解一下:

串口收发数据,设置波特率为9600,把接收到的数据用P1端口的LED灯以二进制的形式显示(灭为0,亮为1),在把接收到的数据加1并发出。

#include <reg52.h>

#define u8 unsigned char
#define u16  unsigned int

u8 num;    //用于存放接收/发送数据
void delay(u16 z)
{
 u16 x,y;
 for(x = z; x > 0; x--)
  for(y = 114; y > 0 ; y--);
} 
void UART_init()
{
 TMOD = 0x20;    //T1工作模式2  8位自动重装
 TH1 = 0xfd;
 TL1 = 0xfd;    //比特率9600
 TR1 = 1;    //启动T1定时器
 SM0 = 0;
 SM1 = 1;    //串口工作方式1 10位异步
 REN = 1;    //串口允许接收
 EA  = 1;    //开总中断
 ES  = 1;    //串口中断打开
}
void main()
{
 UART_init(); //串口初始化
 while(1); 
}

void UART() interrupt 4
{
 if(RI)    //检测是否接收完成
 {
  num = SBUF;    //采集接收到的数据
  P1 = SBUF;
  num++;    //把接收的数据加1并发送
  RI = 0;
  SBUF = num; 
  while(!TI);    //等待发送完成
  TI = 0;
 }
}


当我们使用串口发送字符串时,可以直接添加头文件“#include <stdio.h>”,这个就是我们学习C语言时常用到了,我们可以直接调用其中的“printf”、“putchar”等函数来通过串口发送数据,这里要注意的是:在发送前要通过程序来把“TI”置1,因为在这些函数开头就会通过“while(!TI);”来判断数据是否发送完成。

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

void putchar (unsigned char sbyte)

{

    while(!TI);    //等待数据发送完成

    //如果没有置1,程序会卡在这里

    SBUF = sbyte;

}

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


好的,现在用程序来实现一下:

#include <reg52.h>

#define u8 unsigned char
#define u16  unsigned int

u8 num;    //用于存放接收/发送数据

void Delay(u16 n)
{
 u8 j;
 while(n--)
  for(j=113;j>0;j--);
} 
void UART_init()
{
 TMOD = 0x20;    //T1工作模式2  8位自动重装
 TH1 = 0xfd;
 TL1 = 0xfd;    //比特率9600
 TR1 = 1;    //启动T1定时器
 SM0 = 0;
 SM1 = 1;    //串口工作方式1 10位异步
}//这里没有使用中断和接收功能,可以不配置

void main()
{
 UART_init();    //串口初始化
 while(1)
 {
  TI = 1;
  printf("欢迎大家使用串口通信!\n");
  while(!TI);    //等待发送完成
  TI = 0;
  Delay(1000);    //每隔1S发送一次
 }
}


调试串口时,可以使用“STC-ISP(V6.85)”(其它版本应该也可以)

}~KMUCB}}%H%NSQBRFM1L]R.png


好的,本节内容就先到这里啦,这节没有小练习啦,我会找个时间来更新一篇“备赛番外篇”来带大家使用一些串口(保证是大家都想看到的哦~)






工程师
2020-03-16 21:56:55     打赏
2楼

多谢分享哦


工程师
2020-03-19 16:15:38     打赏
3楼

感谢分享


工程师
2020-03-19 16:16:14     打赏
4楼

感谢分享,楼主辛苦了


菜鸟
2020-04-10 11:03:49     打赏
5楼

感谢楼主,,,实属有大收获


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]