51 单片机串口通信 | 原理 / 实验

注:本文为 “51 单片机串口通信” 相关合辑。
图片清晰度受引文原图所限。
略作重排,如有内容异常,请看原文。


单片机与 PC 机串口通信实验

Lzjusc2017 于 2019-01-22 17:57:24 发布

实验原理

51 单片机的串行口是一个可编程的全双工通信接口,具备 UART(通用异步收发器)的全部功能,能够同时进行数据的发送和接收,也可作为同步移位寄存器使用。51 单片机的串行口主要由两个独立的串行数据缓冲寄存器 SBUF(一个发送缓冲寄存器,一个接收缓冲寄存器)、发送控制器、接收控制器、输入移位寄存器及若干控制电路组成。串行口方式 1 是最常用的通信方式,传输的数据共 10 位,包括 1 位起始位、8 位数据位(最低位在前,最高位在后)和 1 位停止位,帧与帧之间可以有空闲,也可以无空闲。

发送方式

当数据被写入 SBUF 寄存器后,单片机自动从起始位开始发送数据。发送到停止位的开始时,内部硬件将 TI 置 1,向 CPU 申请中断。此时,可以在中断程序中进行相应处理,也可以选择不进入中断。

接收方式

通过软件将 REN 置 1 时,接收器以选择波特率的 16 倍速率采样 RXD 引脚电平。检测到 RXD 引脚输入电平发生负跳变时,说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器的右侧移入。当起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。若 RI = 0 且 SM2 = 0(或接收到的停止位为 1),则将接收到的 9 位数据的前 8 位装入接收 SBUF,第 9 位(停止位)进入 RB9,并置 RI = 1,向 CPU 请求中断。

在具体操作串行口之前,需要对单片机的一些与串口有关的特殊功能寄存器进行初始化设置,主要设置产生波特率的定时器 1、串行口控制和中断控制,具体步骤如下:

  1. 确定 T1 的工作方式(编程 TMOD 寄存器);
  2. 计算 TI 的初值,装载 TH1 和 TL1;
  3. 确定串行口工作方式(编程 SCON 寄存器);
  4. 若串行口工作在中断方式,需进行中断设置(编程 IE 和 IP 寄存器)。

相关寄存器的选择说明

寄存器选择说明

寄存器选择说明

寄存器选择说明

实验代码

#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar num, a; // 定义变量

void main()
{
    TMOD = 0x20; // 定时器设置
    TH1 = 0xFD;  // 设置初值 9600 = (2^SMOD / 32) * (TI 溢出率) = (1/32) * 11059200 / (256 - X) * 12
    TL1 = 0xFD;
    TR1 = 1; // 开启定时器 1
    SM0 = 0; // 设置串行口工作方式
    SM1 = 1;
    REN = 1; // 允许串行接收位
    EA = 1;  // 开启总中断
    ES = 1;  // 开启串口中断
    while (1)
    {
        if (num == 1) // 判断是否有串口数据的传送
        {
            ES = 0; // 关闭串口中断
            num = 0;
            SBUF = a; // 发送数据 a 到 SBUF,即将单片机的数据发送到计算机
            while (!TI); // 发送数据后,TI 自动置 1
            TI = 0; // TI 置 0,才能进行下次发送
            ES = 1; // 打开中断
        }
    }
}

void ser() interrupt 4
{
    RI = 0; // 接收到数据后,将 RI 置 0
    a = SBUF; // 接收数据
    num = 1; // 标志位
}

串口通信的特征

串口通信具有以下六个特征:

  1. 物理连接:至少需要 3 根线,分别是 Tx(数据发送线)、Rx(数据接收线)和 GND(共用地线)。
  2. 电平约定
    • RS232 电平:约定 -5V 至 -25V 之间的电压信号为 1,+5V 至 +25V 之间的电压信号为 0。
    • TTL 电平:约定 5V 的电压信号为 1,0V 电压信号为 0。
    • CMOS 电平:约定 3.3V 的电压信号为 1,0V 电压信号为 0(常用于 ARM 芯片)。
  3. 发送顺序:低位先发。
  4. 波特率:收发双方共同约定的一个数据位(0 或 1)在数据传输线上维持的时间,也可理解为每秒可以传输的位数。常用的波特率有 300 bit/s、600 bit/s、2400 bit/s、4800 bit/s、9600 bit/s。
  5. 起始信号:发送方在没有发送数据时,应将 Tx 置 1。当需发送时,先将 Tx 置 0,并保持 1 位的时间。接收方不断侦测 Rx,若发现 Rx 从高电平突然变为低电平,则视为发送方将要发送数据,迅速启动自己的定时器,从而保证收发双方定时器同步。
  6. 停止信号:发送方发送完最后一个有效位后,必须再将 Tx 保持 1 位的时间,即为停止位。

注意事项

读取 SBUF 数据或接收 SBUF 数据均采用 ASCII 码,数据类型为 unsigned char,以二进制形式处理。

实验:从串口中输入 0-999,数码管显示 0-999

#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit wela1 = P1^0; // 第一位
sbit wela2 = P1^1; // 第二位
sbit wela3 = P1^2; // 第三位
uint a;
uchar num, ge, shi, bai;

uchar code table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; // 不带小数点的共阴数码管段值 0-9
uchar code tablewe[] = {0x04, 0x02, 0x01};

uchar table1[2];
uchar k = 0;

void delay(uchar x) // 延时
{
    uchar i, j;
    for (j = x; j > 0; j--)
    {
        for (i = 113; i > 0; i--){}
    }
}

void main()
{
    TMOD = 0x20; // 用定时器设置串口波特率 9600
    TH1 = 0xFD;  // 赋初值 9600 = (2^SMOD / 32) * (TI 的溢出率) = (1/32) * 11059200 / (256 - X) * 12, X = 253
    TL1 = 0xFD;  // 赋初值
    TR1 = 1;     // 开启定时器 1
    SM0 = 0;     // 模式选择
    SM1 = 1;
    REN = 1;     // 串口初始化
    EA = 1;      // 开启总中断
    ES = 1;      // 开启串口中断
    P1 = 0x00;
    while (1)
    {
        if (num == 1) // 判断是否有串口数据的传送
        {
            num = 0;
            if (table1[1] == 0x00)
            {
                bai = table1[1];
                shi = (table1[0] >> 4) & 0xf;
                ge = table1[0] & 0xf;
            }
            else
            {
                bai = (table1[0] >> 4) & 0xf;
                shi = table1[0] & 0xf;
                ge = table1[1];
            }
        }
        if (bai != 0x00)
        {
            P1 = 0x04;
            P0 = table[bai];
            delay(5);
        }
        if (shi != 0x00)
        {
            P1 = 0x02;
            P0 = table[shi];
            delay(5);
        }
        P1 = 0x01;
        P0 = table[ge];
        delay(5);
    }
}

void ser() interrupt 4 // 串口中断号 4
{
    table1[0] = 0;
    table1[1] = 0; // 清零
    if (RI)
    {
        for (k = 0; k < 2; k++)
        {
            while (!RI); // 查询接收标志
            RI = 0;
            table1[k] = SBUF; // 一次读 8 位
            delay(10);
            if (RI == 0) break; // 表示只发一位
        }
    }
    num = 1; // 表示有接收
}

51 单片机之——串口通信(含实现部分)

Patarw_Li 已于 2024-01-30 17:10:26 修改

一 串口通信简介

串口通信简介

本篇文章将实现两个部分:第一部分为 单片机通过串口向电脑发送数据;第二部分为 电脑通过串口控制单片机 LED 灯

二 前置知识

简单的串口通信需要两根通信线:发送端 TXD(transmit exchange data) 和接收端 RXD(receive exchange data),并且它们是交叉连接的。

串口通信连接

如下图所示,RXD 和 TXD 即为单片机芯片上串口通信的两个引脚(注意它们与 P3.0 和 P3.1 引脚是复用的)。

单片机串口引脚

上图中的两个引脚连接至单片机 USB 转 TTL 下载模块的 RXD-U 和 TXD-U 引脚(如下图所示,TXD 为发送端,RXD 为接收端,并且可以看到它们与 RXD-U 和 TXD-U 交叉连接)。

串口连接示意图

以下是一些术语的简单介绍:

串口通信术语

接下来介绍需要用到的寄存器:

寄存器介绍

1. SCON:串行控制寄存器(可位寻址),用于选择串行通信的工作方式和一些控制功能

SCON寄存器

  • SM0 和 SM1:用来确定串行口的工作方式。常用的模式为模式 1,因此初始化为 SM0 = 0 和 SM1 = 1。
  • SM2:控制模式 2 和模式 3 的多机通信。由于使用模式 1,因此初始化为 0。
  • REN:控制是否允许串行接收。REN = 1 表示允许串行接收,可以启动串行接收器 RXD;REN = 0 表示禁止接收。若仅使用发送功能,则初始化为 0;若需要接收功能,则初始化为 1。
  • TB8 和 RB8:用于模式 2 和模式 3,此处初始化为 0。
  • TI:发送中断请求标志位。在模式 1 中,停止位开始发送时由内部硬件置 1,表示向主机请求中断;中断响应后需要软件复位,即 TI = 0。初始化为 0。
  • RI:接收中断请求标志位。在模式 1 中,接收到停止位时由内部硬件置 1;中断响应后由软件复位 0。初始化为 0。

因此,在代码中,可以将 SCON 寄存器初始化为 0x40(单片机通过串口向电脑发送数据)或 0x50(单片机通过串口接收电脑发送的数据)。

2. PCON:电源控制寄存器(不可位寻址)

PCON寄存器

  • SMOD:波特率选择位,控制波特率是否加倍。
  • SMOD0:帧错误检测有效位,控制是否启用帧错误检测。

3. SBUF:串口数据缓存寄存器,用于存放待发送数据

此外,还需要配置定时器相关寄存器,具体配置方法将在后续文章中详细介绍。此处只需按照示例进行配置,其他未提及的寄存器均无需配置。

三 前置准备

硬件准备

  • STC89C52RC 单片机 一块(要操作的 LED 灯为划红线部分)
  • 电脑 一台

硬件准备

软件准备

  • Keil5:用于编写程序代码,生成 .hex 文件。
  • STC-ISP:用于将生成的 .hex 文件烧录到单片机中,同时使用其附带的串口助手工具。

软件准备

四 实现单片机通过串口向电脑发送数据

首先新建工程,选择芯片型号为 AT89C52。

新建工程

创建项目后,确保勾选生成 .hex 文件的选项,以便后续将该文件烧录到单片机中。

生成hex文件

首先编写一个函数用于初始化各个寄存器的参数。可以使用 STC-ISP 软件的波特率计算器生成初始化函数,但需根据单片机的具体参数进行配置,否则可能会出现接收错误字节。此处波特率设置为 4800(可根据实际需求调整)。

波特率计算器

以下是初始化函数:

void UART_Init()
{
    /**串口寄存器配置**/
    SCON = 0x40; // 初始化串行口控制寄存器
    PCON |= 0x80; // 使能波特率倍速位 SMOD

    /**定时器寄存器配置**/
    TMOD &= 0x0f; // TMOD 高四位清 0,低四位保持不变
    TMOD |= 0x20; // 设定定时器 1 为 8 位自动重装方式
    TL1 = 0xf4;   // 设定定时初值
    TH1 = 0xf4;   // 设定定时器重装值
    ET1 = 0;      // 禁止定时器 1 中断
    TR1 = 1;      // 启动定时器 1
}

接下来创建一个函数,用于将一个字节的数据写入 SBUF(串口数据缓冲寄存器) 中。写入后,硬件将自动完成发送,发送完成后硬件会将 TI(发送中断请求标志位)置 1。

void UART_SendByte(unsigned char Byte)
{
    SBUF = Byte; // 将数据写入串口数据缓存寄存器
    while (TI == 0); // 等待 TI 置 1,即发送完成前一直等待
    TI = 0; // 发送完成后,需要软件复位
}

main 函数中调用这两个函数:

void main()
{
    UART_Init(); // 初始化寄存器
    while (1)
    {
        UART_SendByte(0x66); // 发送 0x66 字节
    }
}

编译该代码后,使用 STC-ISP 将编译好的 .hex 文件烧录到单片机中。

打开 STC-ISP 内置的串口助手,设置好波特率(此处波特率设置为 4800,若未正确配置可能会出现接收错误字节),然后打开串口助手。此时,可在接收缓冲区中看到单片机发送的字节,表示单片机通过串口向电脑发送数据的实验成功。

串口助手

五 实现单片机通过串口接收电脑发送的数据

接收串口信息需要将串口控制寄存器中的 REN 位置为 1,即允许单片机通过串口接收信息。因此,SCON 寄存器应从原来的 0x40 变为 0x50。由于接收信息是被动的,串口通过中断提醒单片机有信息要接收,因此需要打开串口中断(EA = 1, ES = 1)。

串口接收配置

以下是初始化函数:

void UART_Init()
{
    /**串口寄存器配置**/
    SCON = 0x50; // 初始化串行口控制寄存器,REN 位为 1
    PCON |= 0x80; // 使能波特率倍速位 SMOD

    /**定时器寄存器配置**/
    TMOD &= 0x0f; // TMOD 高四位清 0,低四位保持不变
    TMOD |= 0x20; // 设定定时器 1 为 8 位自动重装方式
    TL1 = 0xf4;   // 设定定时初值
    TH1 = 0xf4;   // 设定定时器重装值
    ET1 = 0;      // 禁止定时器 1 中断
    TR1 = 1;      // 启动定时器 1

    EA = 1; // 启动所有中断
    ES = 1; // 启动串口中断
}

查询单片机手册可知,串口的中断号为 4。因此,可以编写串口中断子函数(在函数圆括号后加上 interrupt 4),无需调用,当串口中断产生时,将自动执行函数中的内容。

void UART_Routine() interrupt 4
{
    if (RI == 1)
    {
        // 当接收到数据时,让控制 LED 的 P2 端口等于串口数据缓冲寄存器中的值,从而实现串口控制 LED 灯
        P2 = ~SBUF; // 因为 0 为灯亮,所以要取反
        RI = 0; // 软件复位
    }
}

注意,由于串口发送和接收都会引起这个中断,因此需要通过 RI 位(接收中断请求标志位)来判断是否接收到数据。接收到数据后,对单片机 LED 进行操作,并将 RI 位清零。

此实验中,main 函数只需调用初始化函数即可,无需调用中断函数。

void main()
{
    UART_Init();
    while (1)
    {
        // 主循环为空,所有操作在中断中完成
    }
}

编译该代码后,使用 STC-ISP 将编译好的 .hex 文件烧录到单片机中。

打开串口助手,若希望 LED 的高四位亮起,可发送十六进制数 0xF0(二进制为 1111 0000),点击发送数据即可。

发送数据

此时,单片机的高四位 LED 灯将亮起。

LED亮起

至此,关于单片机串口通信的两个简单实验已经完成。可以根据这些基本的实验拓展出更高级的功能。


via:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值