C51的UART 串口通信

  • 1.串口通信简介
  • 2.串口调试助手
  • 3.串口通信的实现
  • 4.UART模块
  • 5.总结
  • 6.实例

1.串口通信简介

UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。串行通信,就如同一条车道,一次只能发送一个字节。
STC89C52 有两个引脚是专门用来做 UART 串行通信的,一个是 P3.0 一个是 P3.1,它们还分别有另外的名字叫做 RXD 和 TXD,由它们组成的通信接口就叫做串行接口,简称串口。

在 UART 通信过程中,是低位先发,高位后发的原则。一个高低电平的持续时间由波特率(比特率)表示,数据位的切换时间就是波特率分之一秒。波特率就是发送二进制数据位的速率,必须保持一致,收发双方才能正常实现通信。本来要发送一个字节的 8 位数据,而实际上我们一共发送了 10 位,多出来的两位是起始位与停止位。

2.串口调试助手


串口调试助手的实质就是利用电脑上的 UART 通信接口,发送数据给我们的单片机,也
可以把我们的单片机发送的数据接收到这个调试助手界面上。
配置波特率的时候,我们用的是定时器 T0 的模式 2,这样我们就可以把想要的定时器初值提前存在 TH0 中。

3.串口通信的实现

波特率设置好以后,打开中断,然后等待接收串口调试助手下发的数据。接收数据的时
候,首先要进行低电平检测 while (PIN_RXD),若没有低电平则说明没有数据,一旦检测到低电平,就进入启动接收函数 StartRXD()。
一旦读到了起始信号,我们就把当前状态设定成接收状态,打开定时器中断,第一次是半个周期进入中断后,对起始位进行二次判断,确认起始位是低电平,而不是干扰信号。以后每经过 1/9600 秒进入一次中断,并且把这个引脚的状态读到 RxdBuf 里边。等待接收完毕之后,我们再把这个 RxdBuf 加 1,再通过 TXD 引脚发送出去,同样需要先发一位起始位,然后发 8 个数据位,再发结束位,发送完毕后,程序运行到 while (PIN_RXD),等待第二轮信号接收的开始。

#include <reg52.h>
sbit PIN_RXD = P3^0; //接收引脚定义
sbit PIN_TXD = P3^1; //发送引脚定义
bit RxdOrTxd = 0; //指示当前状态为接收还是发送
bit RxdEnd = 0; //接收结束标志
bit TxdEnd = 0; //发送结束标志
unsigned char RxdBuf = 0; //接收缓冲器
unsigned char TxdBuf = 0; //发送缓冲器
void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();
void main()
{EA = 1; //开总中断ConfigUART(9600); //配置波特率为 9600while (1){while (PIN_RXD); //等待接收引脚出现低电平,即起始位StartRXD(); //启动接收while (!RxdEnd); //等待接收完成StartTXD(RxdBuf+1); //接收到的数据+1 后,发送回去while (!TxdEnd); //等待发送完成} }
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{TMOD &= 0xF0; //清零 T0 的控制位TMOD |= 0x02; //配置 T0 为模式 2TH0 = 256 - (11059200/12)/baud; //计算 T0 重载值
}
/* 启动串行接收 */
void StartRXD()
{TL0 = 256 - ((256-TH0)>>1); //接收启动时的 T0 定时为半个波特率周期ET0 = 1; //使能 T0 中断TR0 = 1; //启动 T0RxdEnd = 0; //清零接收结束标志RxdOrTxd = 0; //设置当前状态为接收
}
/* 启动串行发送,dat-待发送字节数据 */
void StartTXD(unsigned char dat)
{TxdBuf = dat; //待发送数据保存到发送缓冲器TL0 = TH0; //T0 计数初值为重载值ET0 = 1; //使能 T0 中断TR0 = 1; //启动 T0PIN_TXD = 0; //发送起始位TxdEnd = 0; //清零发送结束标志RxdOrTxd = 1; //设置当前状态为发送
}
/* T0 中断服务函数,处理串行发送和接收 */
void InterruptTimer0() interrupt 1
{static unsigned char cnt = 0; //位接收或发送计数if (RxdOrTxd) //串行发送处理{cnt++;if (cnt <= 8) //低位在先依次发送 8bit 数据位{PIN_TXD = TxdBuf & 0x01;TxdBuf >>= 1;}else if (cnt == 9) //发送停止位{PIN_TXD = 1;}else //发送结束{cnt = 0; //复位 bit 计数器TR0 = 0; //关闭 T0TxdEnd = 1; //置发送结束标志}}else //串行接收处理if (cnt == 0) //处理起始位{if (!PIN_RXD) //起始位为 0 时,清零接收缓冲器,准备接收数据位{RxdBuf = 0;cnt++;}else //起始位不为 0 时,中止接收{TR0 = 0; //关闭 T0}}else if (cnt <= 8) //处理 8 位数据位{RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移if (PIN_RXD) //接收脚为 1 时,缓冲器最高位置 1,{ //而为 0 时不处理即仍保持移位后的 0RxdBuf |= 0x80;}cnt++;}else //停止位处理{cnt = 0; //复位 bit 计数器TR0 = 0; //关闭 T0if (PIN_RXD) //停止位为 1 时,方能认为数据有效{RxdEnd = 1; //置接收结束标志}}} }

一旦读到了起始信号,我们就把当前状态设定成接收状态,并且打开定时器中断,第一
次是半个周期进入中断后,对起始位进行二次判断一下,确认一下起始位是低电平,而不是一个干扰信号。以后每经过 1/9600 秒进入一次中断,并且把这个引脚的状态读到RxdBuf 里边。等待接收完毕之后,我们再把这个 RxdBuf 加 1,再通过 TXD 引脚发送出去,同样需要先发一位起始位,然后发 8 个数据位,再发结束位,发送完毕后,程序运行到 while (PIN_RXD),等待第二轮信号接收的开始。

4.UART模块

可以在单片机内部做一个硬件模块,让它自动接收数据,接收完了,通知我们就可以了。51 单片机内部就存在这样一个 UART 模块,要正确使用它,先把对应的特殊功能寄存器(串行控制寄存器)配置好。
51单片机的UART 串口的结构由串行口控制寄存器SCON、发送和接收电路三部分构成。

对于串口的四种模式,模式 1 是最常用的,就是我们前边提到的 1 位起始位,8 位数据位和 1 位停止位。对于STC89C52 单片机来讲,波特率发生器只能由定时器 T1 或定时器 T2 产生。

5.总结

一般情况下,我们编写串口通信程序的基本步骤如下所示:
1、配置串口为模式 1。 2、配置定时器 T1 为模式 2,即自动重装模式。
3、根据波特率计算 TH1 和 TL1 的初值,如果有需要可以使用 PCON 进行波特率加倍。
4、打开定时器控制寄存器 TR1,让定时器跑起来。
这里还要特别注意一下,就是在使用 T1 做波特率发生器的时候,千万不要再使能 T1 的
中断了。

#include <reg52.h>
void ConfigUART(unsigned int baud);
void main()
{EA = 1; //使能总中断ConfigUART(9600); //配置波特率为 9600while (1);
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{SCON = 0x50; //配置串口为模式 1TMOD &= 0x0F; //清零 T1 的控制位TMOD |= 0x20; //配置 T1 为模式 2TH1 = 256 - (11059200/12/32)/baud; //计算 T1 重载值TL1 = TH1; //初值等于重载值ET1 = 0; //禁止 T1 中断ES = 1; //使能串口中断TR1 = 1; //启动 T1
}
/* UART 中断服务函数 */
void InterruptUART() interrupt 4
{if (RI) //接收到字节{RI = 0; //手动清零接收中断标志位SBUF = SBUF + 1; //接收的数据+1 后发回,左边是发送 SBUF,右边是接收 SBUF}if (TI) //字节发送完毕{TI = 0; //手动清零发送中断标志位} }

因为接收和发送触发的是同一个串口中断,所以在串口中断函数中就必须先判断是哪种中断,然后再作出相应的处理。

6.实例

单片机串口调试助手发送的数据,开发板上的数码管上显示出来

#include <reg52.h>
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code LedChar[] = { //数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[7] = { //数码管+独立 LED 显示缓冲区0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char T0RH = 0; //T0 重载值的高字节
unsigned char T0RL = 0; //T0 重载值的低字节
unsigned char RxdByte = 0; //串口接收到的字节
void ConfigTimer0(unsigned int ms);
void ConfigUART(unsigned int baud);
void main()
{EA = 1; //使能总中断ENLED = 0; //选择数码管和独立 LEDADDR3 = 1;ConfigTimer0(1); //配置 T0 定时 1msConfigUART(9600); //配置波特率为 9600while (1){ //将接收字节在数码管上以十六进制形式显示出来LedBuff[0] = LedChar[RxdByte & 0x0F];LedBuff[1] = LedChar[RxdByte >> 4];} }
/* 配置并启动 T0,ms-T0 定时时间 */
void ConfigTimer0(unsigned int ms)
{unsigned long tmp; //临时变量tmp = 11059200 / 12; //定时器计数频率tmp = (tmp * ms) / 1000; //计算所需的计数值tmp = 65536 - tmp; //计算定时器重载值tmp = tmp + 13; //补偿中断响应延时造成的误差T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节T0RL = (unsigned char)tmp;TMOD &= 0xF0; //清零 T0 的控制位TMOD |= 0x01; //配置 T0 为模式 1TH0 = T0RH; //加载 T0 重载值TL0 = T0RL;ET0 = 1; //使能 T0 中断TR0 = 1; //启动 T0
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{SCON = 0x50; //配置串口为模式 1TMOD &= 0x0F; //清零 T1 的控制位TMOD |= 0x20; //配置 T1 为模式 2TH1 = 256 - (11059200/12/32)/baud; //计算 T1 重载值TL1 = TH1; //初值等于重载值ET1 = 0; //禁止 T1 中断ES = 1; //使能串口中断TR1 = 1; //启动 T1
}
/* LED 动态扫描刷新函数,需在定时中断中调用 */
void LedScan()
{static unsigned char i = 0; //动态扫描索引P0 = 0xFF; //关闭所有段选位,显示消隐P1 = (P1 & 0xF8) | i; //位选索引值赋值到 P1 口低 3 位P0 = LedBuff[i]; //缓冲区中索引位置的数据送到 P0 口if (i < 6) //索引递增循环,遍历整个缓冲区i++;elsei = 0;
}
/* T0 中断服务函数,完成 LED 扫描 */
void InterruptTimer0() interrupt 1
{TH0 = T0RH; //重新加载重载值TL0 = T0RL;LedScan(); //LED 扫描显示
}
/* UART 中断服务函数 */
void InterruptUART() interrupt 4
{if (RI) //接收到字节{RI = 0; //手动清零接收中断标志位RxdByte = SBUF; //接收到的数据保存到接收字节变量中SBUF = RxdByte; //接收到的数据又直接发回,叫作-"echo",//用以提示用户输入的信息是否已正确接收}if (TI) //字节发送完毕{TI = 0; //手动清零发送中断标志位} }

C51的UART 串口通信相关推荐

  1. Android 模拟Uart 串口通信

    下载串口工具 1.下载模拟串口工具:模拟串口工具 模拟串口工具用于生成模拟的两个串口,而不需要真实的物理串口. 2.下载串口调试工具:串口调试工具 串口调试工具用于直接通过串口发送数据 我这里有整合过 ...

  2. UART串口通信浅谈之(一)--基础概述

    通信按照传统的理解就是信息的传输与交换.UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用 ...

  3. NXP(I.MX6uLL) UART串口通信原理————这个未复习

    参考:Linux NXP (I.MX6uLL) UART串口通信原理 作者:一只青木呀 发布时间: 2020-09-20 16:48:33 网址:https://blog.csdn.net/weixi ...

  4. 【蓝桥杯】单片机学习(7)——UART串口通信

    UART串口通信 一.基础知识介绍 1.通信方式的分类 2.RS232通信接口 3.UART模块介绍 (1)串口控制寄存器SCON(可位寻址) (2)电源控制寄存器PCON(不可位寻址) (3)辅助寄 ...

  5. 基于FPGA的UART串口通信实验(VHDL语言实现)

    一.前言: 最近在做UART串口通信的相关实验时,在网上查了很多资料,发现网上的大部分文章只注重理论,不注重代码,很多代码有错误不说,而且难以理解.故在完成此实验后,起了写一篇博客的心思,以供有想做相 ...

  6. zigbee基础应用(五)uart串口通信

    zigbee基础应用(五)uart串口通信 1.硬件篇 P0.2为RX P0.3为TX 2.芯片篇 用到的芯片的概况 3.计算篇 波特率的计算公式,通过对UxBAUD.BAUD_M和UxGCR.BAU ...

  7. 【自学51单片机】11 -- UART串口通信

    文章目录 1.串行通信的初步认识 2.USB转串口通信 3.UART串口通信的基本应用 3.1 通信的三种基本类型 3.2 UARM模块介绍 3.3编写UART串口步骤及程序 4.串口调试助手 5.通 ...

  8. 【正点原子MP157连载】 第十六章 UART串口通信实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  9. 单片机:11.UART串口通信

    原文地址:https://blog.csdn.net/Qingzhusshuiyun/article/details/78236798 通信按照传统的理解就是信息的传输与交换.对于单片机来说,通信则与 ...

最新文章

  1. linux转换二进制命令,Linux--二进制,十进制,十六进制如何转换,单位换算
  2. 多进程同时写一个文件会怎样?分别用write和fwrite去观察现象
  3. MySQL—【加餐1】高效查询方法
  4. [导入]基类的复制控制函数
  5. 如何检测 SAP 电商云 Spartacus UI 当前正处于导航状态
  6. 为什么男性比女性死得更早,心疼一秒钟!
  7. c++ 写x64汇编 5参数_怀念9年前用纯C和汇编写的入侵检测软件
  8. 03MyBatis动态sql
  9. caffe模型文件解析_「机器学习」截取caffe模型中的某层
  10. 【Vue】—动态绑定v-bind
  11. Nginx 的 server_names_hash_bucket_size 问题
  12. 给定三角形三个顶点的坐标,如何求三角形的外心的坐标呢?
  13. TTL(UART)信号和RS232信号 对比
  14. 任正非讲话稿400篇_重磅干货丨任正非讲稿400篇(1994—2018)
  15. c语言解除键盘锁定,笔记本键盘锁定,教您笔记本解除键盘锁定
  16. Ruby ERB模板注入检测
  17. win7重装系统后计算机打不开,win7系统重装后进不了系统怎么办
  18. 【图像生成Metrics】快速计算FID、KID、IS、PPL
  19. 微软中国正式宣布Win10政府版:专属定制安全功能
  20. 国内各大银行数据汇总

热门文章

  1. DeepMind巨亏42亿、独角兽惨遭3折贱卖,AI公司为何难有“好下场”?
  2. 什么是WebGL,它有什么优点
  3. 经验分享丨如何准备三维视觉、SLAM相关职位的面试
  4. h5短信匿名信源码一封来信你的Ta的一封来信表白祝福道告白信
  5. 1008: 美元和人民币 Python
  6. mysql数据库物理结构设计_通俗数据库设计(4)物理结构设计
  7. 近期汇总:锁定任务栏 - 托盘图标重载 - 获取win10系统版本号
  8. Unity——lua文件(.lua后缀的文件)无法被Unity识别问题
  9. 到底要不要拥抱 Spring Boot 3.0
  10. 数据结构和算法_零基础入门01