自学内容网 自学内容网

51 单片机[8]:串口通信

一、目标

  1. 单片机通过串口向电脑发送数据(数字递增)
  2. 电脑通过串口控制单片机上的LED

二、基本概念

1. 串口

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

2. 硬件电路

简单双向串口通信有两根通信线:发送端(Transmit Exchange Data, TXD)和接收端(Revieve Exchange Data, RXD)
TXD与RXD要交叉连接
当只需单向的数据传输时,可以直接一根通信线
当电平标准不一致时,需要加电平转换芯片

img

3. 点评标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

TTL电平:+5V表示1,0V表示0
RS232电平:-3~-15V表示1,+3~+15V表示0
RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

4. 引脚接口及定义(DB9)

img

现在笔记本电脑上都没有这个接口了,都用USB接口。

5. 常见通信接口比较

名称引脚定义通信方式特点
UARTTXD、RXD全双工、异步点对点通信
I²CSCL、SDA半双工、同步可挂载多个设备
SPISCLK、MOSI、MISO、CS全双工、同步可挂载多个设备
1-WireDQ半双工、异步可挂载多个设备

此外还有:CAN、USB等

  • 全双工:通信双方可以在同一时刻互相传输数据

  • 半双工:通信双方可以互相传输数据,但必须分时复用一根数据线

  • 单工:通信只能有一方发送到另一方,不能反向传输

  • 异步:通信双方各自约定通信速率

  • 同步:通信双方靠一根时钟线来约定通信速率

  • 总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)

6. 51单片机的UART

STC89C52有1个UART

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

img

img

TXD接RXD,RXD接TXD

img

7. 串口参数及时序图

  • 波特率:串口通信的速率(发送和接收各数据位的间隔时间)
  • 检验位:用于数据验证
  • 停止位:用于数据帧间隔

img

8. 串口模式图

img

SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器

9. 串口和中断系统

img

在简单情况下,控制ES、EA即可控制中断。

10. 串口相关寄存器

img

三、单片机通过串口向电脑发送数据

新建项目“8-1 串口向电脑发送数据”,新建main.c。
把之前的Delay.c和Delay.h复制到本项目文件夹中。

SCON:串行控制寄存器(可位寻址)
img

其中SM0、SM1按下列组合确定串行口的工作方式:
img

REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。

TI:发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位。初始化一般置0

RI:接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI1,向主机请求中断,响应中断后必须用软件复位,即RI0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1(例外情况见SM2说明),必须由软件复位,即RI=0。初始化一般置0

1. 串口初始化

我们选择工作方式1,所以SM0=0, SM1=1,其余的置零,0100 0000,即SCON=0x40

电源控制寄存器PCON(不可位寻址)
img

SMOD:波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、3的波特率加倍;SMOD=0,则各工作方式的波特率加倍。复位时SMOD=0。

SMOD0:帧错误检测有效控制位。当SMOD0=1,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能;当SMOD0=0,SCON寄存器中的SM0/FE位用于SM0功能,和SM1一起指定串行口的工作方式。复位时SMOD0=0。

我们需要让波特率加倍,所以SMOD=1,寄存器赋值应该为1000 0000所以PCON=0x80

void Uart_Init(void)//4800bps@11.0592MHz
{
PCON &= 0x80;//使能波特率倍速位SMOD
SCON = 0x50;//8位数据,可变波特率
TMOD &= 0x0F;//清除定时器1模式位
TMOD |= 0x20;//设定定时器1为8位自动重装方式
TL1 = 0xFA;//设定定时初值
TH1 = 0xFA;//设定定时器重装值
ET1 = 0;//禁止定时器1中断
TR1 = 1;//启动定时器1
}

上述代码可以从STC-ISP中的波特率计算器获得
img
要注意误差为0%

2. 串口写入

void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;//写入
while(TI==0);
TI=0;//响应中断后,软件复位
}

主函数为

void main()
{
Uart_Init();
UART_SendByte(0x66);
while(1)
{

}
}

编译一下,发现按一下开发板的重置键,STC-ISP的串口助手就出现一次"66"

img

img

如果串口助手的波特率改为其他数字了,按下充值键出现的就不是66了,数据就出错了,因为采样的时间不一样。

3. 发送秒数

定义一个unsigned char Sec1;用来记秒数,把UART_SendByte(Sec1);放入while(1)循环中。
发送完Sec1后,要自增Sec1++;,然后延时1秒Delay(1000);

void main()
{
Uart_Init();

while(1)
{
UART_SendByte(Sec1);
Sec1++;
Delay(1000);
}
}

4. 模块化

新建UART.c和UART.h文件,把串口初始化程序和串口写入程序放到YART.c中,在UART.h中声明一下,在main.c中#include "UART.h"

UART.c:

#include <REGX52.H>

/**
  * @brief串口初始化,4800bps@11.0592MHz
  * @param无
  * @retval无
  */
void Uart_Init(void)//4800bps@11.0592MHz
{
PCON &= 0x80;//使能波特率倍速位SMOD
SCON = 0x50;//8位数据,可变波特率
TMOD &= 0x0F;//清除定时器1模式位
TMOD |= 0x20;//设定定时器1为8位自动重装方式
TL1 = 0xFA;//设定定时初值
TH1 = 0xFA;//设定定时器重装值
ET1 = 0;//禁止定时器1中断
TR1 = 1;//启动定时器1
}

/**
  * @brief串口发送一个字节数据
  * @paramByte 要发送的一个字节数据
  * @retval无
  */
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;//写入
while(TI==0);
TI=0;//响应中断后,软件复位
}

UART.h:

#ifndef __UART__H__
#define __UART__H__

void Uart_Init(void);
void UART_SendByte(unsigned char Byte);

#endif

main.c:

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

unsigned char Sec1;

void main()
{
Uart_Init();

while(1)
{
UART_SendByte(Sec1);
Sec1++;
Delay(1000);
}
}

四、电脑通过串口控制LED

因为单片机不知道电脑什么时候发信息,所以需要一个中断程序,电脑发过来信息后,触发中断,在中断函数中处理数据。

所以在初始化的时候要把中断程序接上,即EA=1;ES=1;
SCON的REN之前置0,现在要置1,允许串行口接收信息。也就是说,SCON = 0x50;
img

void Uart_Init(void)//4800bps@11.0592MHz
{
PCON &= 0x80;//使能波特率倍速位SMOD
SCON = 0x50;//8位数据,可变波特率
TMOD &= 0x0F;//清除定时器1模式位
TMOD |= 0x20;//设定定时器1为8位自动重装方式
TL1 = 0xFA;//设定定时初值
TH1 = 0xFA;//设定定时器重装值
ET1 = 0;//禁止定时器1中断
TR1 = 1;//启动定时器1
EA = 1;
ES = 1;
}

img
在main.c中,定义一个中断服务子函数

void UART_Routine() interrupt 4
{
P2=0x00;
}

当中断号 4 产生时,程序就会跳转到UART_Rountine(),点亮所有LED

编译一下,打开串口助手,随便发一个数据,可以看到,8个LED全亮了。

把程序升级一下,让LED根据发送的数据亮对应的灯。

修改一下中断子函数:

void UART_Routine() interrupt 4
{
if(RI=1)
{
P2=~SBUF;
RI=0;
}
}

编译一下,在串口助手中输入f0,点击发送数据
img
可以看到D5~D8亮了。

发送aa,D2 D4 D6 D8亮了。

下面再把接收到的数据发回给电脑

void UART_Routine() interrupt 4
{
if(RI=1)
{
P2=~SBUF;
UART_SendByte(SBUF);
RI=0;
}
}

五、数据集显示模式

HEX模式/十六进制模式/二进制模式:以原始数据的形式显示

文本模式/字符模式:以原始数据编码后的形式显示


原文地址:https://blog.csdn.net/m0_55642878/article/details/140587717

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!