51单片机串口教程(原理+实例教学)

阅读: 评论:0

51单片机串口教程(原理+实例教学)

51单片机串口教程(原理+实例教学)

本文主要参考资料:

马淑华、高 军、蔡凌.单片机原理与接口技术(第三版).北京:北京邮电大学出版社,2018.6

一、串行通信的基本知识

1.串行通信的基本方式

全双工通信

        通信双方可同时进行数据收发的工作方式。51单片机的串行口是全双工传输方式。

②半双工通信

        通信双方交替进行双向数据传输,但两个方向的传输不能同时进行。

③单工通信

        数据只能单方向传输。

2.串行通信相关寄存器

①串行数据缓冲器——SBUF

        SBUF物理地址为99H,但实际是对应两个缓冲器(一收一发)

  • 发送内容:CPU写入SBUF
  • 接收内容:CPU读取SBUF

②串口控制寄存器——SCON(98H)

SM0和SM1:工作方式选择位,模式选择如下表            

SM2:多机通信选择。当SM2=0时,单机对单机通信;当SM2=1时,多机对多机通信。

REN:串行接收允许位,REN=1 允许接收数据,手动控制;

RB8 :在模式 2、3 时为第 9 个接收位;

TB8:在模式 2、3 时为第 9 个发送位;

RI:串口接收完成中断标志位(即RI=1),需要手动清0;

TI:串口发送完成中断标志位(即TI=1),需要手动清0;

③波特率与电源控制寄存器——PCON(不可位寻址,87H)

SMOD:波特率加倍控制位。在模式1、2、3下,当SMOD=0时,波特率不加倍;当SMOD=1时,波特率加倍。

其他位暂不做详解

④与串行口通信相关的中断寄存器——IE(中断允许寄存器,可位寻址,A8H)

 与串行中断相关的两个位:

EA:总中断控制位,EA=1时允许中断,EA=0时禁止中断

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

 3、串行通信工作模式详解

波特率的计算方法:

1 .模式 0 的波特率

   波特率固定:每个机器周期产生一个移位时钟,可发送或接收一位数据。且不受SMOD位的影响。即

           模式0的波特率=/12 

2 .模式 2 的波特率

   由系统的振荡频率fosc和SMOD共同确定,即

          模式2的波特率=·/64 

3 .模式 1 和模式 3 的波特率

    模式1和模式3的移位时钟由定时器T1的溢出率决定,故波特率由T1的溢出率与SMOD值共同决定,即

       模式1和模式3的波特率= ·T1的溢出率/32

4. 波特率设计
        当定时器T1做波特率发生器使用时,最典型的用法是使T1工作在模式2(初值自动加载),若计数初值为X,则每经过“256-X”个机器周期。定时器T1就会产生一次溢出,溢出周期为:

        

溢出率为溢出周期的倒数,所以波特率为:

从上式解出定时器的初值X:

①模式0:同步移位寄存器

(1)设置方式

 当SM0=0,SM1=0,SM2=0时使用模式0

(2)模式特点

  • 波特率固定,波特率等于/12(即晶振频率的十二分之一),波特率不受SMOD的影响。
  • 数据        由RXD端发送或接收
  • 同步脉冲 由TXD端输出
  • 发送接收的是8位数据,低位在先

(3) 数据传输过程

发送过程:

        将数据写入SBUF时启动发送,串行口即将8位数据以/ 12的波特率从RxD输出(从低位到高位),发送完中断标志TI置"1”,TxD管脚输出同步移位脉冲。

        在再次发送数据前,必须用软件将TI清0。.

接收过程:

        接收时,将接收中断标志RI=0, 设置REN=1允许接收,启动串接收过程。启动接收过程后,RxD为串行输入端,TxD为同步脉冲输出端。串行接收的波特率为/12。

        当接收完成数据(8位)后,控制信号复位,中断标志RI被置”1”,呈中断申请状态。

        当再次接收时,必须通过软件将RI清0。

②模式1:8位UART,波特率可变(最常用)

(1)设置方式

当SM0=0,SM1=1时,使用模式1

(2)模式特点

  • 波特率可变,由定时器的溢出率和SMOD决定。
  • 数据通过TXD发送,RXD接收。
  • 发送10位数据,1位起始位(0),8位数据位,1位停止位。

(3)数据传输过程

     发送过程:

        数据由串行发送端TXD输出。将数据写入SBUF时启动发送,写“SBUF”信号还把“1”装入发送移位寄存器的第9位,并通知TX控制单元开始发送。

        发送完成后,硬件置位中断请求位Tl,即TI=1,向主机请求中断处理。

        再次发送需要将TI置0。

接收过程

        当允许接收位REN=1时,启动接收。

        接收完成之后,置位中断请求位RI,即RI=1,向主机请求中断处理。

        再次接收需要手动将RI置0。

③模式2和模式3

模式2:    9位UART,波特率固定

模式3: 9位UART,波特率可变

(1)设置方式

 SM0=1,SM1=0设置为模式2;

 SM0=1,SM1=1设置为模式3;

(2)模式特点

  • 方式2和方式3都为11位数据的异步通信口,他们唯一的区别是传输速率不同。
  • 数据通过TXD发送,RXD接收。
  • 发送11位数据,1位起始位(0),9位数据位,1位停止位。
  • 第9位的数据位发送时在SCON的TB8,接收时在RB8。

(3)数据传输过程

        发送过程:

                将数据写入SBUF后立即启动发送。

                发送完成后,硬件置位中断请求位Tl,即TI=1,向主机请求中断处理。

                再次发送需要手动将TI置0。

        接收过程:

                当允许接收位REN=1时,启动接收。

                接收完成之后,置位中断请求位RI,即RI=1,向主机请求中断处理。

                再次接收需要手动将RI置0。

二、串行通信的应用(实例分析)

模式1是串口最常用的方式,所以重点讲模式1的应用。

实例所使用的单片机是 亚博智能mini51开发板,编程开发环境为keil5

1.模式1的应用

①通过串口发送一个字符给计算机

步骤:

  • 初始化串口(设置工作模式、波特率等)
  • 编写发送字符的函数

1、初始化串口

设置工作模式:

        由于我们使用的是模式1,所以设置SM0=0,SM1=0,直接赋值SCON=0x40;

配置波特率:

        配置波特率要设置定时器的工作模式及计算定时器的初值。这里选择定时器T1模式2,8位自动重装方式,然后计算初值。波特率选择不加倍。

初值X的计算公式已经给出。

为了省事,可以直接使用下表经过计算后的值:

查表可知,9600波特率的TH1初值X为0XFD,波特率不加倍。

代码如下:

//串口初始化函数
void UartInit()		//9600bps@11.0592MHz
{SCON = 0x40;		//0100 0000 串口工作模式1TMOD &= 0x0F;		//清空TMOD中定时器1相关TMOD |= 0X20;       //设置定时器1工作模式2:8位自动重载TH1 = 0xFD;		//设定定时初值TL1 = 0XFD;TR1 = 1;		//启动定时器1
}

2、编写发送字符的函数

当寄存器SBUF被赋值时,启动发送。在这个发送字符的函数中,只需要写出被赋值语句即可。

void send_char(unsigned char m)
{SBUF=m;
}

   完整代码:

#include <REGX52.H>
//串口初始化函数
void UartInit()		//9600bps@11.0592MHz
{SCON = 0x40;		//0100 0000 串口工作模式1TMOD &= 0x0F;		//清空TMOD中定时器1相关TMOD |= 0X20;       //设置定时器1工作模式2:8位自动重载TH1 = 0xFD;		//设定定时初值TL1 = 0XFD;TR1 = 1;		//启动定时器1
}//字符发送函数
void send_char(unsigned char m)
{SBUF=m;
}
//延时约1s的程序
void delay()
{unsigned char i, j, k;i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}	
//主函数
void main()
{UartInit();//调用串口初始化函数while(1){send_char('p');//调用发送一个字符的函数delay();//调用延时1S的函数}	
}

将程序烧录到单片机后,打开串口助手即可查看串口收到的单片机信息。

(串口调试助手操作)

 (串口接受到了字符)

②通过串口发送字符串给计算机

类似于发送单个字符的步骤

步骤:

  • 初始化串口(设置工作模式、波特率等)
  • 编写发送字符串的函数

第一步已经介绍过,下面介绍编写发送字符串的函数。

编写发送字符串的函数:

void send_string(unsigned char str[])
{unsigned char i=0;while(str[i]!='')//判断是否到字符串尾{SBUF = str[i];while(TI==0);//等待发送完成TI=0;//下次发送前,要手动将TI置0i++;//下次发送}	
}

 完整代码:

#include <REGX52.H>
//串口初始化函数
void UartInit()		//9600bps@11.0592MHz
{SCON = 0x40;		//0100 0000 串口工作模式1TMOD &= 0x0F;		//清空TMOD中定时器1相关TMOD |= 0X20;       //设置定时器1工作模式2:8位自动重载TH1 = 0xFD;		//设定定时初值TL1 = 0XFD;TR1 = 1;		//启动定时器1
}
void send_string(unsigned char str[])
{unsigned char i=0;while(str[i]!='')//判断是否到字符串尾{SBUF = str[i];while(TI==0);//等待发送完成TI=0;//下次发送前,要手动将TI置0i++;//下次发送}	
}
//延时1sd函数
void delay()
{unsigned char i, j, k;i = 8;j = 1;k = 243;	do{do{while (--k);} while (--j);} while (--i);
}void main()
{UartInit();while(1){send_string("Hello World!nr");delay();}
}

打开串口助手即可看到效果(每隔1s发送“Hello World!”):

③单片机接收一个字符

        当SCON寄存器接收位REN=1时,启动接收。

        步骤:

  • 编写串口初始化函数(配置寄存器模式)
  • 编写接收函数

根据串口接收的原理:

        当串口接收到数据时,RI自动硬件置1,所以我们判断RI是否是1即可判断串口是否接受到数据,再将SBUF的内容读出即可获得数据。

        为了验证串口收到的数据是否是我们所发送的数据,可以对单片机定义一些操作来进行确认。

        比如我们把串口接受到的数据在数码管/LCD等显示模块显示出来进行验证,当然也可以采用比较简单的方法,比如点灯验证法。

点灯验证法:

         比如我们要发送一个字符‘O’,规定字符‘O’可以点亮LED1。我们只需观察发送后LED1是否点亮即可判断我们串口接收到了正确的字符。

        同理,我们也可以发送一个字符'C',规定字符C可以熄灭LED1,我们只需观察发送后LED是否熄灭即可判断我们串口接收到了正确的字符。

完整代码(扫描判断法):

#include <REGX52.H>
sbit led=P1^0;//串口初始化函数
void UartInit()		//9600bps@11.0592MHz
{SCON = 0x50;		//0101 0000 串口工作模式1TMOD &= 0x0F;		//清空TMOD中定时器1相关TMOD |= 0X20;       //设置定时器1工作模式2:8位自动重载TH1 = 0xFD;		//设定定时初值TL1 = 0XFD;TR1 = 1;		//启动定时器1
}void main()
{char receive;//用于接收串口数据的变量led=1;UartInit();while(1){if(RI==1)//RI=1说明串口接收到了数据{RI=0;//RI置0保证下次接收receive=SBUF;//将从串口接收到的数据报存到变量中//判断接收的数据,作出相应的操作if(receive=='O')led=0;if(receive=='C')led=1;	}}
}

中断判断法:   

#include <REGX52.H>
sbit led=P1^0;//串口初始化函数
void UartInit()		//9600bps@11.0592MHz
{SCON = 0x50;		//0101 0000 串口工作模式1TMOD &= 0x0F;		//清空TMOD中定时器1相关TMOD |= 0X20;       //设置定时器1工作模式2:8位自动重载TH1 = 0xFD;		//设定定时初值TL1 = 0XFD;TR1 = 1;		//启动定时器1ES=1;//打开串行通信中断EA=1;//打开总中断
}
//串行中断函数
void Uart_receive() interrupt 4
{if(RI==1)//RI=1说明串口接收到了数据{		char receive;RI=0;//RI置0保证下次接收receive=SBUF;//将从串口接收到的数据报存到变量中//判断接收的数据,作出相应的操作if(receive=='O')led=0;if(receive=='C')led=1;	}
}
//主函数
void main()
{led=1;UartInit();while(1){//do any other things what you want;}}

打开串口助手,按照步骤操作给单片机发送数据:

本文发布于:2024-02-04 18:32:00,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170713733058374.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:串口   单片机   实例   原理   教程
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23