【C51】UART串口通信

我们常需要单片机和其他模块进行通信,数据传输,常用的方式就是串口通信技术。

常用来 单片机<-->电脑,  单片机<-->单片机之间通信。

串行通信 versus 并行通信

并行传输:将字节的各个 bit 用多条传输线路同时发送出去。每个bit使用一条线路。

优点:速度相对快,控制简单。

缺点:控制线路多,耗费的硬件资源多。

串行传输:将一个字节的数据的各个 bit 在一条线路上 分时发送。一个字节8位,则至少需要分8次发送完。

优点:需要的线路少,成本低。

缺点:控制复杂,因为它要遵循一定的传输协议。

                     

通信的工种

单工       :A,B中只有一个发送数据另一个只能接受数据 ,如广播。
半双工    :A 和B既可以发送数据,也可以接受数据,但是当其中一方在发送数据时,另一方就只能接受数据 ,如对讲机。
全双工    :通信双方双方可以同时发送 和 接受数据。如电话 ,单片机的串口通信。

单片机的串口通信是一种全双工通信。

前面提到,使用串行方式发送数据只需一条线,然而,由于串口通信是全双工的,通信的任何一方都必须 既能发送数据,又接受数据,所以需要2根数据线,分别用于接受串行数据和发送串行数据。

对于51单片机,就是P3.0 和 P3.1  两个引脚控制的。

P3.0:   RXD, 串行数据接收端

P3.1:   TXD,串行数据发送端

UART串口通信原理与数据帧格式

MCS-51单片机具有一个全双工的串行通信接口,能同时进行发送和接收。它可以作为UART(通用异步接收和发送器)使用。

在任何一根数据线上,空闲状态下,即无数据传输时,线上一直持续逻辑电平1。当接收方突然接收到逻辑电平0时,表示对方发送数据来啦,要做好准备接收了。这个0就是数据帧的起始位,它只是标记了数据的开始,不构成真正发送的数据。接受方检测到这个下降沿跳变后,就开始准备接收后面的数据了。

随后,发送方会连续发送8 个 bit,代表发送的目标数据,(先发送地位,后发送高位,比如发送 二进制数据 0000 0001 ,则第一个发送的bit数据是1)。8位数据发送完了后,发送方再发送一个逻辑1(不考虑使用奇偶校验位,后面会提到),表示这帧数据发送结束。 此后数据线上可能再次恢复到空闲状态,也可能紧接着传输下一个帧。

同时,接受方会在发送的期间,利用自己的串口电路,以16倍的波特率速度采集RXD引脚信号,也就是一帧要重复采集16次(减少误差),然后过滤出8位数据,送给自己的SBUF。

波特率

通信双方统一的约定:一个bit 的信号要持续多久???

数据帧中的bit会先后在数据线上传输,而且一个帧中的每一个bit持续的时间是一定的。假如(只是假如)每个bit 信号持续1ms ,发送方的串口电路将使发送线路的每个bit 的逻辑电平持续1ms,然后发送下一个bit信号。同理,接受方的串口电路持续探测数据线1ms后,然后继续探测下一个bit信号。上图中,蓝色线条的宽度,就代表每个bit持续的时间。

这里假定1ms,如果每个bit发送的时间越短,那么可以让数据发送的速度越快,我们一般用波特率表示。

波特率的单位是 bps(bit per secons),意思是 每秒钟发送的 bit数。常用的波特率:1200bps,2400,4800,9600,14400,19200,28800,38400,57600...

如果 每个bit传输的时间为T s,则波特率  baud = 1/T bps 。

串口通信双方波特率一定要一样!

为什么叫异步收发器

收发双方各自使用自己的时钟,无需用同一个时钟信号同步。它以数据帧的方式传输数据,为了能让接受方正确接受一个帧,需要在帧首 加上起始位,同时,为了让接收方正确识别一个完整的帧,需要在帧尾加上停止位,代表一帧的结束。因此,只要双方遵守这个协议,他们就可以在任意时刻发送和接收一个帧,发送方可以在发送完第一个帧后,等1个小时再发送第二个帧,而接受方会不断采集线路(接受方的RXD引脚)上的电平,如果突然采集到下降沿,由1变为 0 ,则认为有新的数据要传输了,于是开始以16倍波特率速度采集帧。

帧与帧之间的间隔是任意的,但是一帧中的各个bit之间的间隔是固定的。

51单片机的串口通信

会用到的寄存器 和位 :SBUF  , SCON,  TMOD,PCON,TR1  EA ,ES

SCON 用于控制单片机串口的工作方式。

SM1 SM0 方式 用法 波特率
0  0 0 同步移位寄存器传输方式,并不符合常规的串口通信。 波特率固定,为:Fosc/12
1 0 1 10位数据帧传输方式,1位起始位,8位数据,1位终止位。 波特率可变,为:T1溢出率/n    n=16, 32
0 1 2 11位数据帧传输方式。 波特率固定,为:Fosc/n
1 1 3 11位数据帧传输方式。 波特率可变,为:T1溢出率/n    n=16, 32

SM2:多机通信控制

= 0 双机

=1  多机

TB8:用于方式2,3中。存储发送出的数据的第9位

RB8:用于方式2,3中。存储接收到的数据帧的第9位。

REN = 1 :允许串口接收外部串口数据

= 0:不接受外部的串口数据

TI:发送中断标识位。当一帧数据发送到停止位时(发送完成),TI变为1,并请求中断。与其它51中断不同,TI必须由代码软件归 0。

RI:接收中断标识位。当一帧数据接收到停止位时(接收完成),RI变为1,并请求中断。与其它51中断不同,RI必须由代码软件归 0。

还有个很特殊的是,TI 和 RI 的中断入口地址是一样的,也就是这2个中断是同一个中断函数处理的,所以必须在中断函数中做出判断,来进行不同的处理。

SBUF

串行口缓冲寄存器,它用于 管理 发出去 或者 接受到的 数据。也就说,我们需要让单片机向外发送数据,就把这个字节数据赋值给SBUF,想接收发送给单片机的数据,则从SBUF中读取数据。在逻辑上,SBUF只有1个,我们在编程时只会操作这一个寄存器,但是实质上SBUF是指 2个独立的寄存器,一个只存储接收的数据,一个用于暂存发送出去的数据。正是因为有2个SBUF,我们的单片机才支持全双工模式。

方式1

10位数据帧传输格式:1个起始位 ,8个数据位,1个结束位。

TI = 0  的前提下,向SBUF写入数据,单片机的硬件自动封装成帧,发送出去,当发送到停止位时,自动将TI置1。表示这帧发送完毕,申请中断

RI = 0,且REN =1,SM2=0的前提下, 单片机串口以波特率的16倍速度采样RXD引脚,将接受到的数据存放到SBUF中,并自动将RI置1。表示受到数据,申请中断。

模式盘配置:

SCON = 0x50;  //二进制(0101 0000)即:REN=1,允许接受,SM2,TB8 RB8用不到,都是0,TI RI 中断标识为0。

波特率的配置

TMOD &= 0x0F;
TMOD |= 0x20;     //非破坏性赋值

TH1 =256 -(11059200L/12/32)/baud;     //baud代表波特率
TL0 = TH1;
ET1  =0 ;       //使用T1来设定波特率,配置T1的工作方式 为 8位自动重装模式,这样就省了再次为TH1 TL1重新赋值的代码了,因此T1的中断也是用不到的,所以设置ET1 = 0。

开启中断

ES = 1;   //串口中断使能

EA = 1;   //总中断使能

启动T1

TR1  =1;

方式1是用的最多的,也能满足绝大多数的UART通信场合,下面是我自己写的一个库,可以直接拿去使用。

#include"serial.h"
/*
author:         代码钢琴家

file:           serial.c

description:    51单片机URAT串口库

date:          2016/10/26

attention:

1、在使用serial_read()前,必须使用标志 serial_rec_ok 判断单片机是否接收到了数据

2、不要在程序中使用T1,因为使用T1配置波特率了。且应做到对TMOD无破坏性赋值

3、在使用serial_init前需要使能EA !,我没有在serial_init中打开中断总开关EA,你需要自己先打开EA。

4、不要在没有发送任何数据前,就读取serial_send_ok的值,因为我故意初始化位1(本应该是0),这是为了减少serial_write_str中的代码。5、不要手动修改serial_rec_ok  和 serial_send_ok的值。

6、无奇偶校验,允许接受(REN=1),没有使用PCON加倍波特率,使用T1配置波特率。

*/

static unsigned char recData = ‘\0‘;    //接受SBUF存储的数据,内部使用
bit serial_rec_ok  = 0;                 //串口接受成功标志
bit serial_send_ok = 1;                    //串口发送成功标志

void serial_init(unsigned int baud)
{
    SCON = 0x50;

    TMOD &= 0x0F;
    TMOD |= 0x20;

    TH1 =256 -(28800)/baud;     //28800 =11059200L/12/32
    TL0 = TH1;
    ET1  =0 ;               //显式关闭T1中断,因为T1使用的是重装模式,所以无需中断函数来重新给TH1 TL1赋值。

    ES = 1;                 //使能串口中断
    TR1 = 1;                //开启TI定时器
}

void serial_interrupt(void) interrupt 4
{

     if(RI)                        //发生接收完成 中断
     {
        RI = 0;
         recData = SBUF;
        serial_rec_ok = 1;       //全局标志,告知主函数已经收到1帧数据
     }

     else        //if(TI)
     {
         TI =0;
        serial_send_ok  =1;   //全局标志,告知主函数已经发送1帧数据
     }
}

/***************************************
作用:从串口中读取1个字节的数据返回

返回:读取的 unsigned char 类型数据

*****************************************/
unsigned char serial_read()      //在读取之前必须使用      serial_rec_ok 判断单片机是否接收到了数据
{
    serial_rec_ok = 0;
    return recData;             //recData 已经在中断函数中获得了SBUF中的串行数据,直接返回
}

/***************************************
作用:写1个字节的数据到串口,也就是发送1个字节的数据到串口

参数d:发送的 unsigned char 类型的数据

*****************************************/
void serial_write(unsigned char d)
{
    serial_send_ok =0;
    SBUF = d;
}

/***************************************
作用:写1个字符串到串口,也就是发送1个字符串

参数str:字符串的地址。请确保字符串末尾有‘\0‘

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

void serial_write_str(unsigned char*str)
{
     while(*str)                       //请确保字符串末尾有‘\0‘
     {
        while(!serial_send_ok)
        ;                       //等待前一个字符发送完毕,才能继续发送下一个字符。
                                //异步串口通信,不对帧与帧之间的间隔做要求,因此这里的循环等待问题不大。
        serial_write(*str++);
     }
}
/*****
file: serial.h
******/
#ifndef _SERIAL_H__
#define _SERIAL_H__

#include<reg52.h>            //根据具体使用的单片机修改 reg52.h   or   reg51.h

extern bit serial_rec_ok ;
extern bit serial_send_ok;

void serial_init(unsigned int baud);
unsigned char serial_read();
void serial_write(unsigned char d);
void serial_write_str(unsigned char*str );

#endif

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

欢迎转载,请注明出处:www.cnblogs.com/lulipro

为了获得更好的阅读体验,请访问原博客地址。

代码钢琴家

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

时间: 2024-10-08 02:16:16

【C51】UART串口通信的相关文章

嵌入式Linux裸机开发(七)——UART串口通信

嵌入式Linux裸机开发(七)--UART串口通信 一.UART串口通信简介 通用异步收发器简称UART,即UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER, 它用来传输串行数据.发送数据时, CPU 将并行数据写入UART,UAR按照一定的格式在一根电线上串 行发出:接收数据时, UART检测另一根电线的信号,将串行收集在缓冲区中, CPU 即可读取 UART 获得这些数据. 在 S5PV210中, UART提供了 4 对独立的异步串口I/O端口,

Win10 IoT C#开发 4 - UART 串口通信

原文:Win10 IoT C#开发 4 - UART 串口通信 Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,既可以开发设备UI与用户交互式操作,又可以控制GPIO等接口,使得原来嵌入式繁琐的开发变得简单.通过Remote Debug功能可以进行断点追踪调试.C#语言本身也有很好的用户基础,相信Win10 IoT 不远的将来会火起来.上个月帮朋友解决了关于Win10 IoT 的一些技术问题,当前也有很多公司在尝试采用Win10 IoT进行开发,可能也会遇到这些问题,

奶爸业余单片机学习之:UART串口通信学习笔记(一)

UART串口通信,全名:异步串口通信 UART的四种工作模式:(0,1,2,3) 模式1:SM0 = 0; SM1 = 1;REN = 1  //由SCON(串行口控制寄存器)控制,可位寻址.10位异步收发(8位数据),波特率可变(由定时器1的溢出率控制) 模式1功能:以TXD为例,平时没数据时,TXD为高电平,需要发送数据时,先发送一个起始位0,然后发送八位数据位(一个字节),最后发送一位停止位1: REN位为允许串行接收位:REN = 1:允许串行口接收数据:REN = 0:禁止串行口接收数

Win10 IoT C#开发 3 - UART 串口通信

Windows 10 IoT Core 是微软针对物联网上市场的一个重要产品,既可以开发设备UI与用户交互式操作,又可以控制GPIO等接口,使得原来嵌入式繁琐的开发变得简单.通过Remote Debug功能可以进行断点追踪调试.C#语言本身也有很好的用户基础,相信Win10 IoT 不远的将来会火起来.上个月帮朋友解决了关于Win10 IoT 的一些技术问题,当前也有很多公司在尝试采用Win10 IoT进行开发,可能也会遇到这些问题,相关文档现在还非常少,这里写出来供大家参考.因为要做一个Jav

奶爸业余单片机学习之:UART串口通信学习笔记(二)

/************************************** 串口通信实验* 晶振11.0592MHz* 波特率9600bps* 中断方式实现:单片机接收电脑数据,加1后发送回电脑***************************************/ #include<reg52.h> unsigned char dat; /**********串口通信配置*******************/void UART_CONFIG(unsigned long baud

Arduino和C51之串口通信

技术:51单片机.Arduino.串口通信 概述 本文主要讲解串口通信技术的使用方法,并通过串口点灯实验介绍了51单片机和Arduino串口的使用,为初学者学习串口知识提供帮助 详细 代码下载:http://www.demodashi.com/demo/14691.html 一.串口通信 串口通信(Serial CommunicaTIons)的概念非常简单,串口按位(bit)发送和接收字节.串口用于ASCII码字符的传输,通信使用3根线完成,分别是地线.发送线.接收线.由于串口通信是异步的,端口

进阶项目(3)UART串口通信程序设计讲解

写在前面的话 UART串行接口简称串口,是我们各类芯片最常用的一种异步通信接口,通过串口我们就可以建立起计算机和我们实验板之间的通信和控制关系,也就是我们通常所说的上下位机通信.串口可以说是不同平台互相通信.控制的一个最基本的接口. 项目需求 设计一个UART控制器,当控制器从上位机接收到数据以后,马上将数据输出,发送回上位机,完成“回环测试”.  UART的原理分析 要实现UART通信,首先我们需要用到一个外部的电平转换芯片MAX232,其具体配置电路如下: 注解: MAX232芯片是美信(M

51单片机IO口模拟UART串口通信

#include <reg52.h>#include "main.h"#include "smartcard.h"#include "stdio.h" typedef enum { false, true }bool; #if 0sbit PIN_RXD = P1^0; //接收发送同一个引脚定义sbit PIN_TXD = P1^0; //接收发送同一个发送引脚定义sbit PIN_CLK = P3^1; //智能卡时钟引脚定义sb

深入理解51单片机串口通信

串口通信的基本认识 通信分为并行通信和串行通信,并行通信时的数据各个位同时传送,可以实现字节为单位通信,但通信线多占用资源,成本高.以前用到的的P1=0x55,一次给P1口的8个管脚分别赋值,同时进行信号输出,类似于8个车道可以过去8辆车,这样的形式是并行的,一般称P0,P1,P2,P3为51单片机的4组并行总线. 串行通信,就是一个车道,一个只能通过一辆车,如果一个0x55这样一个字节的数据要传输过去的话,假如低位在前,高位在后的话,那发送方式是:0-1-0-1-0-1-0-1,一位一位的进行