51单片机学习笔记-6串口通信

news2024/11/16 21:54:26

6 串口通信

[toc]

注:笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。


6.1 串口通信原理

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。

图6-1 串口通信接口示意图

上图所示的简单双向串口通信,有两根交叉连接的通信线(发送端TXD和接收端RXD)。当只需单向的数据传输时,可以只接一根通信线。当电平标准不一致时,需要加电平转换芯片。电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

  1. TTL电平:+5V表示1,0V表示0。
  2. RS232电平:(-3V,-15V)表示1,(+3V,+15V)表示0。
  3. RS485电平:两线压差(+2V,+6V)表示1,(-2V,-6V)表示0(差分信号)。
图6-2 DB9接口示意图
图6-3 现代串口应用案例

图6-2是串口通信最经典的DB9接口(单片机不支持流控信号),使用RS232电平标准,但是由于其体积大、速率慢等原因,逐渐的被笔记本电脑领域所淘汰。而为了完成与电脑的串口通信,现代通常使用USB转串口的模块(如上图6-3左)。同时也可以看出,由于51单片机最常用的还是串口通信,所以为了配合51单片机,有许许多多的模块开始与串口通信结合起来。

表6-1 常见通信接口比较
名称引脚定义通信方式特点
UARTTXD:发送端
RXD:接收端
GND:公共(参考)地
全双工、异步点对点通信
I²CSCL:同步时钟
SDA:数据输入/输出端
半双工、同步可挂载多个设备
SPISCLK:同步时钟
MISO:主机输入,从机输出
MOSI:主机输出,从机输入
CS:从设备使能信号,由主设备控制。
全双工、同步可挂载多个设备
1-WireDQ:发送/接收端半双工、异步可挂载多个设备
此外还有CAN(差分传输)、USB等

对于上表的注释:

  • 全双工:通信双方可以在同一时刻互相传输数据
    半双工:通信双方可以互相传输数据,但必须分时复用一根数据线
    单工:通信只能有一方发送到另一方,不能反向传输
  • 异步:通信双方各自约定通信速率
    同步:通信双方靠一根时钟线来约定通信速率
  • 总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)
  • TXD全称:transmit external data。

在开发板上,I²C用于与EEPROM(AIM23A10)通信,SPI改编后与RTC芯片(DS1302通信),1-Wire用于与温度传感器(DS18B20)通信。CAN总线常用语汽车控制领域,USB协议则在日常生活中最常见。STC89C52只有1个UART(如下图P3.0/P3.1),这个UART有四种工作模式:

模式0:同步移位寄存器
模式1:8位UART,波特率可变(常用)
模式2:9位UART,波特率固定
模式3:9位UART,波特率可变

图6-4 STC89C52上的串口示意图

下面图6-5给出串口通信在单个通信线上的时序图,上面发送和接收各数据位的间隔时间就是 波特率,表明了串口通信的速率。可以看到主要包含 4个部分

  1. 起始位:拉低信号,表明开始传输8bit的数据。
  2. 数据位:每次传输8bit的数据,注意先传输低位LSB。
  3. 检验位(选填):只出现在9位UART的最后一位,用于数据验证。
  4. 停止位:拉高信号,用于数据帧间隔。

注意波特率只能为:4800、9600、115200等约定好的值。

图6-5 串口时序图

由于器件手册中给出的串口模式图过于复杂,包含了许多不利于学习理解的信号。所以下图给出了单片机内部的串口简化模式图。可以看到,最关键就是SBUF(存储发送和接收的数据)、RI(接收完毕中断)、TI(发送完毕的中断)这三个信号,甚至于RXDTXD都不用我们手动配置,只需要关心那两个中断请求就好。

图6-6 串口模式图

  • SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。对于MCU来说,发送缓冲器只能写入,接收缓冲器只能读出,所以 可以同时操作
  • 根据上面的图可以发现,串口发送/接收所需要的 波特率都只能由定时器T1来提供!!且T1工作在模式3(8位自动重装)。
  • T1溢出率意思为定时器T1的溢出速率,可以SBUF的1bit数据保持时间与波特率一致。

图6-7 串口相关寄存器

  • 串行控制寄存器SCON(可位寻址):选择串行通信的工作方式和某些控制功能。
    SM0/FE:PCON中的SMOD0选择其为SM0时,与下面的SM1共同选择串口工作模式([SM0,SM1]=[0,1]模式1);PCON中的SMOD0选择其为FE时,检测到帧错误则拉高,且必须由软件归零。
    SM2:允许方式2/3多机通信。方式1中,SM2=1则接收到有效的停止位RI才拉高。
    REN:允许/禁止串行接收控制位(1/0)。默认禁止。
    TB8:方式2/3中发送的第9位数据,软件控制。
    RB8:方式2/3要接收的第9位数据。方式
    TI:表明发送完毕的中断请求,停止位开始的发送时拉高,必须软件复位。
    RI:表明接收完毕的中断请求。只有模式0需要软件置位。
  • 波特率选择特殊功能寄存器PCON(不可位寻址):
    SMOD:波特率加倍控制位,软件置位。SMOD=1,工作模式1、2、3波特率加倍;SMOD=0,波特率不加倍。
    SMOD0:帧错误检测有效控制位。决定了SCON 中的SM0/FE被选为FE(帧错误检测)还是SM0(0/1)。
  • IEIPHIP
    由于单片机串口通信用到了RI、TI两个中断,所以还需要配置 串口通信中断源 中断寄存器。可以参考上一节。

6.2 实验:串口向电脑发送数据

需求:单片机不断每秒向电脑发送一个8位递增数字(也可以直接发送单个字符,如’A’)。

图6-8 “串口发送连续数字”代码调用关系

代码展示:
- main.c

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"

void main(){
  unsigned char num = 0x00; // 要发送的变量
  UART_Init(); // 串口初始化
  while(1){
    UART_SendByte(num);
    Delay(1000); // 软件延时,防止打乱定时器的操作
    num += 1;
  }
}

- UART.h

#ifndef __UART_H__
#define __UART_H__

void UART_Init(); // 串口初始化
void UART_SendByte(unsigned char Byte); // 串口发送1Byte数据

#endif

- UART.c

#include <REGX52.H>

/**
  * @brief :串口通信初始化,4800bps@11.0592MHz
  * @param :无
  * @retval :无
 */
void UART_Init(){
  SCON = 0x40; // 串口控制寄存器,暂时接收不使能
  PCON &= 0x7f; // 波特率选择特殊功能寄存器
  
  // 发送数据不需要开启中断,接收数据才需要
  
  // 下面配置定时器,用于波特率设置
  // 注:串口只能用定时器T1(8位自动重装模式)
  TMOD&=0x0F;TMOD|=0x20; //设置定时器模式
	TL1 = 0x66;  //设置定时初始值
	TH1 = 0xFA;  //设置定时初始值
	ET1 = 0;		 //禁止定时器中断,只要有溢出就可以生成波特率
	TR1 = 1;		 //定时器1开始计时
}

/**
  * @brief :通过串口发送8位数据
  * @param :需要发送的8位数据
  * @retval :无。但函数会直到该字节发送完成才返回。
 */
void UART_SendByte(unsigned char Byte){
  SBUF = Byte;
  while(TI==0); // 等待发送完毕
  TI = 0; // 软件复位
}

- Delay.h

#ifndef __DEALY_H_
#define __DEALY_H_

// 延时cycles ms,晶振@11.0592MHz
void Delay(unsigned int cycles){
  unsigned char i, j;
  do{
    i = 2;
    j = 199;
    do{
      while (--j);
    }while (--i);
  }while(--cycles);
}

#endif

6.3 实验:电脑通过串口控制LED

需求:电脑向单片机发送一个8位数字,用于控制8个LED的点亮情况,同时单片机将接收到的数据返回给电脑。

本节实验与上一个实验最大的区别就是,串口初始化的过程中添加了允许串口中断。下面是代码展示:
- main.c

#include <REGX52.H>
#include "UART.h"

void main(){
  UART_Init(); // 串口初始化
  while(1){}
}

// 串口接收中断子函数
// 注意发送和接收两种中断都会进入到这个子函数中来
void UART_Routine() interrupt 4{
  if(RI==1){
    P2 = ~SBUF; // 存储接收到的字节
    RI = 0; // 软件清空接收完成标志
    UART_SendByte(SBUF);
  }
}

- UART.h

#ifndef __UART_H__
#define __UART_H__

void UART_Init(); // 串口初始化
void UART_SendByte(unsigned char Byte); // 串口发送1Byte数据

#endif

- UART.c

#include <REGX52.H>

/**
  * @brief :串口通信初始化,4800bps@11.0592MHz
  * @param :无
  * @retval :无
 */
void UART_Init(){
  SCON = 0x50; // 串口控制寄存器,接收使能
  PCON &= 0x7f; // 波特率选择特殊功能寄存器
  
  // 接收数据需要串口中断
  EA = 1; ES = 1; // 允许全局中断、串口中断
  
  // 下面配置定时器,用于波特率设置
  // 注:串口只能用定时器T1(8位自动重装模式)
  TMOD&=0x0F;TMOD|=0x20; //设置定时器模式
  TL1 = 0xFA;  //设置定时初始值
  TH1 = 0xFA;  //设置定时初始值
  ET1 = 0;		 //禁止定时器中断,只要有溢出就可以生成波特率
  TR1 = 1;		 //定时器1开始计时
}

/**
  * @brief :通过串口发送8位数据
  * @param :需要发送的8位数据
  * @retval :无。但函数会直到该字节发送完成才返回。
 */
void UART_SendByte(unsigned char Byte){
  SBUF = Byte;
  while(TI==0); // 等待发送完毕
  TI = 0; // 软件复位
}

/*串口中断函数模板
// 串口接收中断子函数
// 注意发送和接收两种中断都会进入到这个子函数中来
void UART_Routine() interrupt 4{
  if(RI==1){ // 若接收到1Byte数据
    
  }
}
*/

编程感想:

其实好几次现象不对,都是因为对于串口助手的使用不熟练。注意点的是“发送数据”,而不是“发送回车”;另外发送和接收的模式“文本模式”/“HEX模式”要匹配上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

层级选择器

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>层级选择器</title> <style type"text/css"> /*需求&#xff1a;需要选中前三个段落标签*/ /*下面两个选择器之间加…

JavaScript 发布订阅者模式和观察者模式及区别

一、发布订阅模式 发布订阅模式其实是一种对象间一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都将得到状态改变的通知。 多方订阅&#xff0c;一方发布&#xff0c;订阅放会收到通知 举例&#xff1a;教学楼中每个教室都有一个广…

Iterator_fail-fast和Iterator_fail-safe~

初识fail-fast&#xff1a; fail-fast 机制是java集合(Collection)中的一种错误机制&#xff0c;当多个线程对同一个集合的内容进行操作时&#xff0c;就可能会产生fail-fast事件&#xff0c;它只是一种错误检测机制&#xff0c;只能被用来检测错误&#xff0c;因为JDK并不保证…

蓝桥杯2022Python组

蓝桥杯2022Python组 1.排列字母 用一个sorted就好了&#xff0c;没啥好说的 s WHERETHEREISAWILLTHEREISAWAY s sorted(s) # 变成列表形式了 print(.join(s))2.寻找整数 这题我刚开始以为答案只能是11和17的倍数&#xff0c;就在他们的倍数里面找&#xff0c;发现不对&…

STL——STL简介、STL六大组件

一、STL是什么 STL(standard template library)&#xff1a; C标准模板库&#xff0c;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;还是一个包罗数据结构与算法的软件框架。 通俗来讲&#xff1a; STL就是将常见的数据结构&#xff08;顺序表、…

Superset权限管理

文章目录1.Superset角色1&#xff09;Admin2&#xff09;Alpha3&#xff09;Gamma4&#xff09;Sql_lab5&#xff09;Public2.实操自定义授权1&#xff09;权限集2&#xff09;实操1.Superset角色 Superset的默认角色有&#xff1a;Admin、Alpha、Gamma、sql_lab、Public 1&a…

【信息资源建设】

考试分为单选、判断改错、名词解释、简答、综合论述 1.1 如果按价值观念划分&#xff0c;则可将信息分为有用信息和无用信息 信息的特性&#xff1a;普遍性、客观性、时效性、传递性、共享性、变换性、转化性、可伪性。 1.1.2 &#xff08;必考&#xff09;OECD的知识分类…

【docker概念和实践 4】(4) 本地镜像提交到本地仓库

一、说明 registry是一个镜像&#xff0c;该镜像专门生成镜像仓库的容器&#xff0c;registry是基于http协议&#xff0c;那就是说&#xff0c;在单机、局域网、或者互联网上都可以建立registry数据仓库&#xff0c;存放自己构建的镜像。本篇专门介绍如何在本地单机上建立容器仓…

Python中的集合(set and frozenset)语法汇总

集合的基本语法知识目前有两种集合类型&#xff1a;set和frozenset。可变集合&#xff1a;set()set类型是可变的&#xff0c; 其内容可以使用 add() 和 remove() 这样的方法来改变&#xff0c;因为是可变的&#xff0c;所以没有哈希值&#xff0c;且不能被用作字典的键或其它集…

java线上项目排查,Arthas简单上手

Arthas 是Alibaba开源的Java诊断工具。参考&#xff1a;Arthas 用户文档 — Arthas 3.5.4 文档 当你遇到以下类似问题而束手无策时&#xff0c;Arthas可以帮助你解决&#xff1a; 这个类从哪个 jar 包加载的&#xff1f;为什么会报各种类相关的 Exception&#xff1f;我改的代…

一起Talk Android吧(第四百七十九回:集合类视图动画)

文章目录使用方法属性介绍示例代码各位看官们大家好&#xff0c;上一回中咱们说的例子是"旋转类视图动画",这一回中咱们说的例子是"集合类视图动画"。闲话休提&#xff0c;言归正转&#xff0c;让我们一起Talk Android吧&#xff01; 使用方法 集合类动画…

web测试2:嵌入式移植boa

读此篇之前&#xff0c;先读前一篇 1.在源码编译的时候&#xff0c;指定交叉编译工具链 lkmaoubuntu:~$ arm-linux-gnueabi-gcc --version arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 Copyright (C) 2015 Free Software Foundation, Inc.…

C++工程的CMakeLists.txt文件编写

最简单的demo工程如下&#xff1a; #include <iostream> #include <string> int main(int argc,char** argv) {std::cout << "hello world" << std::endl;return 0; } 文件结构如下&#xff0c;其中include可用来自定义接口功能类。 CMake…

IMX Linux 用户手册 --- 1

IMX Linux 用户手册 — 1 第一章 概述 本文档介绍了i.MX LinuxOS BSP (BSP代表Board Support Package)在i.MX平台上的构建和安装方法。它还涵盖了特殊的i.MX功能和如何使用它们。 本文档还提供了运行i.MX平台的步骤&#xff0c;包括单板拨码开关设置、U-Boot引导加载程序的配置…

IP地址是什么

我们知道&#xff0c;网络通讯的本质就是收发数据包。如果说收发数据包就跟收发快递一样。那IP地址就类似于快递上填的收件地址和发件地址一样&#xff0c;有了它&#xff0c;路由器就可以开始充当快递员的角色&#xff0c;在这个纷繁复杂的网络世界里找到该由谁来接收这个数据…

linux上git三板斧的使用

前言 现在在我们的生活当中&#xff0c;用我们程序员的一句玩笑话&#xff0c;来说就是“全球最大的同性交友网站就是githup”。 那么它具有什们功能呢&#xff0c;能让人这么吹捧&#xff0c;用通俗易懂的话来说就是&#xff0c;储存和管理代码&#xff0c;它会记录我们修改甚…

java知识总结(一)

ArrayList和LinkedList的区别1. ArrayList的实现是基于数组,LinkedList的实现是基于双向链表。2. 对于随机访问ArrayList要优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随机访问,而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,查找某个…

【开发工具 - 安装手册】BeyondCompare4 下载与安装+免费使用

1. 官网 Download Beyond Compare Free Trial 2. 下载 阿里云盘 &#xff08;不限速 - 推荐&#xff09;官网下载3. 安装&#xff08;无脑下一步&#xff09; 4.三种方法长期免费使用 方法一 修改初始化文件 C:\Users\Administrator\AppData\Roaming\BCompare\BCompare.ini…

【奇妙的数据结构世界】用图像和代码对队列的使用进行透彻学习 | C++

第十一章 队列 目录 第十一章 队列 ●前言 ●一、队列是什么&#xff1f; 1.简要介绍 2.具体情况 ●二、队列操作的关键代码段 1.类型定义 2.顺序队列的常用操作 3.链式队列的常用操作 ●总结 前言 简单来说&#xff0c;数据结构是一种辅助程序设计并且进行优化的方法论&…

介绍一款2023年新出的mysql管理工具: FlyBird Database Manager

FlyBird Database Manager 介绍 FlyBird Database Manager 是一款mysql 界面化管理工具&#xff0c; 使用go语言编写&#xff0c;天然支持Windows, MacOS, Linux等主流平台。 提供无需安装的命令行版本&#xff0c; 命令行中启动服务&#xff0c;以html支持UI界面,在浏览器中…