【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 = -(/)/baud; //baud代表波特率 TL0 = TH1; ET1 = ; //使用T1来设定波特率,配置T1的工作方式 为 8位自动重装模式,这样就省了再次为TH1 TL1重新赋值的代码了,因此T1的中断也是用不到的,所以设置ET1 = 0。
开启中断
ES = ; //串口中断使能 EA = ; //总中断使能
启动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 = ; //串口接受成功标志 bit serial_send_ok = ; //串口发送成功标志 void serial_init(unsigned int baud) { SCON = 0x50; TMOD &= 0x0F; TMOD |= 0x20; TH1 = -()/baud; //28800 =11059200L/12/32 TL0 = TH1; ET1 = ; //显式关闭T1中断,因为T1使用的是重装模式,所以无需中断函数来重新给TH1 TL1赋值。 ES = ; //使能串口中断 TR1 = ; //开启TI定时器 } { if(RI) //发生接收完成 中断 { RI = ; recData = SBUF; serial_rec_ok = ; //全局标志,告知主函数已经收到1帧数据 } else //if(TI) { TI =; serial_send_ok =; //全局标志,告知主函数已经发送1帧数据 } } /*************************************** 作用:从串口中读取1个字节的数据返回 返回:读取的 unsigned char 类型数据 *****************************************/ unsigned char serial_read() //在读取之前必须使用 serial_rec_ok 判断单片机是否接收到了数据 { serial_rec_ok = ; return recData; //recData 已经在中断函数中获得了SBUF中的串行数据,直接返回 }
/*************************************** 作用:写1个字节的数据到串口,也就是发送1个字节的数据到串口 参数d:发送的 unsigned char 类型的数据 *****************************************/ void serial_write(unsigned char d) { serial_send_ok =; 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
为了获得更好的阅读体验,请访问原博客地址。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
代码钢琴家
【C51】UART串口通信的更多相关文章
- Win10 IoT C#开发 4 - UART 串口通信
Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,既可以开发设备UI与用户交互式操作,又可以控制GPIO等接口,使得原来嵌入式繁琐的开发变得简单.通过Remote Debug ...
- Arduino和C51之串口通信
技术:51单片机.Arduino.串口通信 概述 本文主要讲解串口通信技术的使用方法,并通过串口点灯实验介绍了51单片机和Arduino串口的使用,为初学者学习串口知识提供帮助 详细 代码下载:h ...
- 【ARM】2410裸机系列-uart串口通信
开发环境 (1)硬件平台:FS2410 (2)主机:Ubuntu 12.04 FS2410串口的原理图 串口UART寄存器配置 配置TXD0与RXD0(GPH2.GPH3) 设置波特率(UBRDI ...
- UART串口通信
#include "sys.h" #include "delay.h" #include "usart.h" u8 rdata[]; UAR ...
- 【iCore3 双核心板_FPGA】实验二十五:NIOS II之UART串口通信实验
实验指导书及代码包下载: http://pan.baidu.com/s/1eRMZq18 iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...
- 【iCore4 双核心板_FPGA】实验二十:NIOS II之UART串口通信实验
实验指导书及源代码下载地址: 链接:https://pan.baidu.com/s/1g_tWYYJxh4EgiGvlfkVu1Q 提取码:dwwa 复制这段内容后打开百度网盘手机App,操作更方便哦 ...
- FPGA nios通过驱动LCD12864实现菜单界面和uart串口通信
因为csdn无法插入视频,无法展示我这个实现的效果,这里我截了一些图,应该基本上也能明白了: 基本功能就是如图片所示,里面采用了菜单结构(这里编程需要一定得c语言编程技巧与数据结构知识),gpa是什么 ...
- Stm32串口通信(USART)
Stm32串口通信(UART) 串口通信的分类 串口通信三种传递方式 串口通信的通信方式 串行通信的方式: 异步通信:它用一个起始位表示字符的开始,用停止位表示字符的结束.其每帧的格式如下: 在一帧格 ...
- STM32串口通信UART使用
STM32串口通信UART使用 uart使用的过程为: 1. 使能GPIO口和UART对应的总线时钟 2. 配置GPIO口的输出模式 3. 配置uart口相关的基本信息 4. 使能uart口的相关的中 ...
随机推荐
- [转]HDFS客户端的权限错误:Permission denied
搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误. 错误的详 ...
- ACM 国王的魔镜
国王的魔镜 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描述 国王有一个魔镜,可以把任何接触镜面的东西变成原来的两倍——只是,因为是镜子嘛,增加的那部分是反的. 比如一 ...
- ACM 荷兰国旗问题
荷兰国旗问题 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描述 荷兰国旗有三横条块构成,自上到下的三条块颜色依次为红.白.蓝.现有若干由红.白.蓝三种颜色的条块序列,要 ...
- 关于禁止ipad的home键解决方法
参考http://www.toolsandapplications.com/guided-access-how-to-disable-the-home-button-on-ipad/
- [深入浅出WP8.1(Runtime)]网络编程之HttpClient类
12.2 网络编程之HttpClient类 除了可以使用HttpWebRequest类来实现HTTP网络请求之外,我们还可以使用HttpClient类来实现.对于基本的请求操作,HttpClient类 ...
- 【POJ】3648 Wedding
http://poj.org/problem?id=3648 题意:n对人(编号0-n-1,'w'表示第一个人,'h'表示第二个人),每对两个,人坐在桌子两侧.满足:1.每对人中的两个人不能坐在同一侧 ...
- URAL 1303. Minimal Coverage(DP)
题目链接 又是输出路径...这题完全受上题影响,感觉两个题差不多..用了基本上一样的算法写了,这题比较纠结,就是卡内存啊...5000*5000的数组开不了..然后没办法,水了好几次MLE,看了一下虎 ...
- Redis_Spring与Jedis的集成
首先不得不服Spring这个宇宙无敌的开源框架,几乎整合了所有流行的其它框架,http://projects.spring.io/spring-data/从这上面看,当下流行的redis.solr.h ...
- C#后台如何获取客户端访问系统型号
ASP.NET获取客户端.服务器端基础信息 . 在ASP.NET中专用属性: 获取服务器电脑名:Page.Server.ManchineName 获取用户信息:Page.User 获取客户端电脑名:P ...
- Windows 下安装使用docker swarm machine docker toolbox
下载docker 集成安装环境 http://get.daocloud.io/#install-toolbox 这个网站很不错,下载 这个集成了 docker docker-machine ,还有gi ...