51单片机——串口

概述

串行接口(Serial Interface)简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口,串行是指数据一位一位地顺序传送,特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本,特别适用于远距离通信,但传送速度较慢

关键词:

1、是设备之间接线互相传输数据的一种方式

2、数据传输时是一位一位顺序传输

3、双向通信,全双工通信

4、传送速度相对较慢

标准和协议

串口之间按照电气标准和协议的不同来分包括:RS-232-C串口,RS-422串口,RS-485串口

RS-232-C

RS-232-C是标准串口协议,最常用的一种协议,比如台式电脑的九针串口,最高传输速率为20kb/s,最大传输距离为15m,适用于本地设备之间通信。该协议为点对点协议,即1对1收发数据,不可以一台设备对多台设备发送数据

RS-422

RS-422由于接收器采用高输入阻抗和发送驱动器比RS232具有更强的驱动能力,故支持点对多的双向通信。即一个主设备,其余为从设备,各从设备可以和主设备之间收发数据,但从设备之间不能通信。

RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比

RS-485

RS-485是从RS-422基础上发展而来的,无论四线还是二线连接方式总线上可多接到32个设备。

串口电平

经常用的串口是UART-异步串口,即运行速度不同的设备的串行数据传输,传输数据时,快速度的设备减速和慢速度的设备的速度匹配,再传输数据

UART包含用RS-232电平的串口和TTL电平的串口

RS-232电平

RS-232电平,逻辑1是-15到-3v的电压,逻辑0是3到15v的电压

某些单片机用的是RS-232电平,若要和笔记本之间串口通信,那么所用的串口则需要是RS-232串口,矩形设备接入到笔记本,9针串口接入到单片机,如图

TTL电平

TTL电平信号应用广泛,TTL(Transistor-Transistor Logic)即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备内部各部分之间通信的标准技术。

TTL电平,逻辑1是+5v的电压,逻辑0是0v的电压。

数字电路中由TTL电子元器件组成电路的电平是个电压范围,规定:

输出高电平>=2.4V,输出低电平<=0.4V;

输入高电平>=2.0V,输入低电平<=0.8V

也有某些单片机用的是TTL电平,那么这些单片机会引出两个引脚用来接线,TX端口作为发送端口,RX端口作为接受端口。若要和笔记本之间串口通信,那么需要用到usb转TTL设备,矩形接口接入到笔记本,TX针脚和RX针脚通过杜邦线连接到单片机的RX针脚和TX针脚,这样实现串口通信。如图

上官1号单片机,集成了转TTL的ch340芯片,所以不需要使用usb转TTL设备进行数据传输,可以直接用Type-c数据线连接电脑和单片机,数据到单片机后,经过转ch340芯片,实现串口通信。而且上官1号单片机有单独引出TX和RX针脚(TX为P3^1,RX为P3^0),可以让该单片机和其他串口通信设备进行通信,即电脑和单片机可以在ch340的作用下通过Type-c数据线将二者的TX和RX连接上进行数据传输,且单片机也可以和其他设备通过杜邦线连接单片机和设备之间的TX和RX针脚再在ch340的作用下进行数据传输

不同的串口电平,对于软件层面无影响,相当于软件里面编程的0和1,接不同的串口,对应出的电压大小不同

串口通信

接线

设备与设备之间串口通信,接线时TX口接到RX口,RX口接到TX口才能相互通信

电脑和上官一号的串口数据传输时,电脑的TX口和RX口连接到Type-c线中的TX口和RX口,Type-c的TX口和RX口连接到上官一号的ch340,ch340接收到电脑的TX口和RX口,再在内部将TX口连接到上官一号的RX口,RX口连接到TX口,如此实现数据传输,相当于ch340模块作为中间人将二者的TXRX口连接上了

收发缓冲器SBUF

51单片机设立有两个互相独立的接收发送缓冲器,可以同时接收和发送数据,并且这两个缓冲器共用一个地址码99H,都叫做SBUF,即这两个缓冲器实际情况是一个寄存器在控制,当计算机发送数据时,这个寄存器作为发送缓冲器,只能向缓冲器写入数据,当外部模块给计算机发送数据时,计算机接收数据,这个寄存器作为接收缓冲器,只能向缓冲器读出数据

发送数据时单片机往SBUF写东西,写完后,会发送给外部模块SBUF=data,接收数据时外部设备的值写入到了SBUF中,单片机从SBUF中读出来存到变量里,char data=SBUF,总之向这个寄存器写入数据时,就是作为发送缓冲器,从这个寄存器读出数据时,就是作为接收缓冲器,两个寄存器互不干扰

外部模块通过TX串行输入数据到单片机的RX,RX接到串行输入移位寄存器将数据存入到SBUF,单片机cpu直接从SBUF里面取得外部发送的数据;发送给外部模块时同理

接收数据的注意:首先要及时RI置0,其次移位寄存器如果成功将数据放入SBUF后,单片机要及时取取走这个数据,间隔时间太长,移位寄存器会覆盖SBUF的数据

具体原理:

及时取走SBUF

单片机接收数据时,如果外部模块一次性发送了很多数据,数据串行发送到移位寄存器,移位寄存器接收这些数据,然后存入到SBUF中,当一帧数据成功放入到SBUF里,移位寄存器就会立刻接收下一帧数据,我们需要在移位寄存器接收到下一帧数据再次放入SBUF之前,让单片机取走本次这帧数据(用变量存起来),如果没来得及取走,SBUF的数据会被下一帧的数据覆盖,所以这帧数据将不会被接收而丢失。要避免这种情况,可以让外部模块一次一次的发送数据,可以等SBUF值完全被取走后,再次发送数据,相当于手动降低发送频率

及时RI置0

接收数据时,若移位寄存已经接收到了数据,但是想要让移位寄存器将数据存入SBUF中需要满足的条件是:此时RI=0而且接收到的停止位为1,只有满足这两种条件才能把数据装入SBUF中,不满足条件则数据会丢弃而不存入SBUF中;接收到数据之后,会立刻判断一次能否装入SBUF,结果有效则进入中断,结果无效则丢弃数据,但是结果无论如何,移位寄存器又会再次接收数据,所以进入中断后要及时的将RI置0,如果不及时置0,那么主机在处理中断程序时,可能移位寄存器已经接收到了数据,之后检测RI,因为没有RI置0,则这个数据就丢失了,等到RI置0时,可能已经丢弃了很多数据了,然后再次检测RI,满足条件了,装数据入SBUF,进入中断,如此反复便会损失很多数据

//测试显示:

如果用变量接受SBUF的字符后,再把这个字符回传给PC,之后不延时,相当于单片机接收完SBUF的字符后就结束了,等待着移位寄存器更新SBUF的值,然后又中断取走SBUF,一次性发送600个字符都能完全接收到,超过600个字符可能有数据损失;如果延时100us,一次性发送13个数据以上就会产生数据损失;如果延时1000us,一次性发送4个数据以上就会产生数据损失;如果延时10ms以上,一次性发送3个数据以上就会产生数据损失;

波特率

对于UART异步串口通信,由于设备与设备之间时钟频率不同,双方需要约定一个通信速度,就是波特率

51单片机需要自己在代码中配置波特率,波特率由定时器1控制产生

计算方式:

举例定时器1是8位自动重载定时器,12T模式,SMOD波特率不加倍,要9600的波特率,求THTL1的值

9600=(1/32)*(11059200/(12*(256-TH1))) 计算出TH1=253=0xFD 

串口相关寄存器

PCON寄存器

不可位寻址

最高位SMOD位,当SMOD置1串口123波特率加倍,SMOD置0串口123波特率不加倍,默认置0

第6位SMOD0位,当SMOD0置1时,让SCON寄存器的SM0/FE位运行FE功能,检测帧错误,确保数据传输正确,当检测到帧错误时,FE位由UART置1,软件能够检测到此位,而且FE位必须软件置0;当SMOD0置0时,让SCON寄存器的SM0/FE位运行SM0功能,和SM1共同指定串口工作方式,默认置0

SCON寄存器

可位寻址

复位时全0

最高位SM0/FE位,由PCON寄存器选择此位的作用是SM0还是FE,FE检测帧错误,SM0配合SM1决定串口工作方式

第6位SM1位,与SM0配合,SM0与SM1,00为同步移位串行方式,波特率固定;01为8位UART波特率可变,通过设置定时器1的模式和TH1TL1初值和12T/6T模式来改变波特率;10为9位UART,波特率固定;11为9位UART,波特率可变,设置方式如01

实际应用中工作方式多半选择方式1和方式3,即可调波特率8位或9位UART

第5位SM2位,允许方式2或者方式3多机通信控制位。

第4位REN位,REN位置1允许串口接收数据RX口打开,置0不允许,用于接收其他设备向单片机发送数据

第3位第2位为TB8和RB8,在方式2和3才有效,是串口发送或接收的第9位数据,TB8可以用作数据校验位或多机通讯的地址帧标记位,RB8在非多机通讯时是接收到的停止位,方式0不用RB8

第1位为TI发送中断请求标志位,置1请求中断,响应中断后必须软件置0

第0位为RI接收中断请求标志位,同TI,是在接收到数据后硬件置1,没有接收到数据之前RI仍为0 

注意:如果要使用中断服务函数,需要打开总中断开关EA,和UART中断开关ES

         TI和RI中断时都会进入中断服务函数,但是系统不知道是TI还是RI的中断,所以要在中断服务函数中对TI和RI中断分开处理

案例

案例1 51与PC互相发送数据

代码1 51向PC发送数据-延时方式

#include "reg52.h"
#include <intrins.h>
sfr AUXR=0x8E;
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//??????
	SCON = 0x50;		//8???,?????
	AUXR &= 0xBF;		//???1???Fosc/12,?12T
	AUXR &= 0xFE;		//??1?????1???????
	TMOD &= 0x0F;		//?????1???
	TMOD |= 0x20;		//?????1?8???????
	TL1 = 0xFD;		//??????
	TH1 = 0xFD;		//????????
	ET1 = 0;		//?????1??
	TR1 = 1;		//?????1
}


void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main(){
	 char msg='a';
	 char kongge=' ';
	 int cnt=0;
	 UartInit();
     while(1){
	 if(cnt==26){
       cnt=0;
	   msg='a';
     }	 
	 SBUF=msg;
	 Delay1000ms();
	 SBUF=kongge;
     Delay1000ms();
	 msg++;
	 cnt++;
	 }

}

注意:

往SBUF存数据了之后,会通过移位寄存器读出这个数据发送出去,需要消耗时间,我们需要保证这个数据发送出去之后再往SBUF里存数据,所以往SBUF存数据之后,需要延时一会,再存数据

对于这个问题的解决可以用到串口中断,发送完一个8位数据就发出中断请求中断位由硬件置1,以!TI作为循环的检测标志,发送数据时TI0,循环为死循环,发送结束产生中断跳出循环,再将TI置0,代表可以发送下一个数据,再往SBUF存数据,以!TI来等待,不断循环

代码 51和PC互不影响互发数据

#include "reg52.h"
#include <intrins.h>
sfr AUXR=0x8E;
sbit led=P3^7;
char getflag;
void UartInit(void)		//9600bps@11.0592MHz
{   //½µµÍϵͳ¶ÔÍâ½çµÄµç´Å·øÉä
	  AUXR=0x01;
	  //SCONÅäÖÃ
    SM0=0;
	  SM1=1;
	  REN=1;
	 //PCONÅäÖÃ
	  PCON=0x10;//²¨ÌØÂʲ»¼Ó±¶×î¸ßλSMOD=0,½øÐд®¿ÚģʽѡÔñµÚ6λSMOD0=0;
	 //²¨ÌØÂÊÅäÖÃ
	 //1¡¢¶¨Ê±Æ÷1ģʽΪ8λ×Ô¶¯ÖØÔØ 
	  TMOD &=0x0F;
		TMOD |=0x20; 
   //9600²¨ÌØÂʵijõÖµ	
	  TH1=0xFD;
	  TL1=0xFD; 
	  TR1=1;
	  EA=1;
	  ES=1;
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void huanhang(char*p){
	while(*p!='\0'){
	SBUF=*p;
	while(!TI);
	TI=0;
	p++;
	}

}
void send(char p,char h){
	 int cnt=26;
   while(cnt--){
	 SBUF=p;
	 while(!TI); 
	 TI=0;		 
	 SBUF=h;
	 while(!TI);
	 TI=0;	 
	 p++;
   }

}
void main(){

	 char msg='a';
	 char* huan="\r\n";
	 char h=' ';
	 UartInit();
     while(1){	 
         send(msg,h);
		 Delay1000ms();
		 huanhang(huan);
	 }

}
void light() interrupt 4
{
	getflag=SBUF;
	RI=0;
	if(getflag=='o')led=0;
	if(getflag=='c')led=1;
}

注意ASCII码的坑:对于发送的char型数据,在计算机内部存在的形式是二进制数字,表示的大小和ASCII码的数字大小相同,如果你发送的是字符,实际单片机接收到的是字符通过ASCII码表转译过来的16进制hex数字,接收时如果选择文本模式,系统会把hex数字转回字符,这样就双方数据匹配了;如果发送的是8位的数字,接收的时候就要选择hex模式

案例2 手机通过蓝牙与51互相通信

蓝牙模块

蓝牙模块的使用很简单,不需要做额外配置。模块上电,手机与蓝牙模块连接成功后,就可以正常通信了,如果想修改蓝牙模块的相关信息,才需要发AT指令来配置。以后的WIFI模块连接后如果要正常使用,让WIFI入网,就需要发一些AT指令来配置

HC-08蓝牙模块,可以让手机软件通过蓝牙连接到模块,连接成功后,手机发送信息到模块,模块接受到信息后,通过串口发送到其他模块,实现信息传递,由于该蓝牙模块所用的串口电平为TTL电平,如果其他模块电平不匹配需要用转TTL设备来转换

AT指令

AT指令是用于终端设备(主机发指令)向终端适配器(从机干活)发送的指令,PC与蓝牙模块连接后,我们可以让PC通过软件向蓝牙模块发送AT指令,来改变蓝牙模块的各种属性

注意:每个AT命令行中只能包含一条AT指令,不能一次性发多条指令,AT指令要以回车来结尾以免出错,一条AT指令除AT外还能接收1056个字符

当蓝牙模块上电后如果没有连接默认进入的是AT状态,此时指示灯闪烁代表进入AT指令模式,连接后指示灯常亮

各AT指令比如:

代码

#include "reg52.h"
#include <intrins.h>
#include <string.h>
sfr AUXR=0x8E;
sbit led=P3^7;
sbit ledy=P3^6;
char getflag[5];
char ms;
void UartInit(void)		//9600bps@11.0592MHz
{   //½µµÍϵͳ¶ÔÍâ½çµÄµç´Å·øÉä
	  AUXR=0x01;
	  //SCONÅäÖÃ
    SM0=0;
	  SM1=1;
	  REN=1;
	 //PCONÅäÖÃ
	  PCON=0x10;//²¨ÌØÂʲ»¼Ó±¶×î¸ßλSMOD=0,½øÐд®¿ÚģʽѡÔñµÚ6λSMOD0=0;
	 //²¨ÌØÂÊÅäÖÃ
	 //1¡¢¶¨Ê±Æ÷1ģʽΪ8λ×Ô¶¯ÖØÔØ 
	  TMOD &=0x0F;
		TMOD |=0x20; 
   //9600²¨ÌØÂʵijõÖµ	
	  TH1=0xFD;
	  TL1=0xFD; 
	  TR1=1;
	  EA=1;
	  ES=1;
}


void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void huanhang(char*p){
	while(*p!='\0'){
	SBUF=*p;
	while(!TI);
	TI=0;
	p++;
	}

}
void send(char p,char h){
	 int cnt=26;
   while(cnt--){
	 SBUF=p;
	 while(!TI); 
	 TI=0;		 
	 SBUF=h;
	 while(!TI);
	 TI=0;	 
	 p++;
   }

}
void main(){

	 char msg='a';
	 char* huan="\r\n";
	 char h=' ';
	 int cnt=0;
	 UartInit();
   while(1){	 
     send(msg,h);
		 Delay1000ms();
		 huanhang(huan);
	 }
}
void light() interrupt 4
{
	if(RI==1){
	static int i=0;
	int j=0;	
	getflag[i]=SBUF;
	RI=0; 
	i++;
 if(i==4){
		for(j=0;j<4;j++){
        SBUF=getflag[j];
		while(!TI);
		TI=0;
        }
        if(!strcmp(getflag,"open")){
		   led=0;
		   ledy=0;
		   i=0;
		memset(getflag,'\0',sizeof(getflag));
	   }
   }
  else if(i==5){
	 ledy=0;
     i=0;
	 j=4;
     SBUF=getflag[j];
		while(!TI);
		TI=0;
	    if(!strcmp(getflag,"close")){
		  led=0;
		  ledy=1;
		  i=0;
         }
	    memset(getflag,'\0',sizeof(getflag));
 }
 else{
      led=1;
      ledy=1;
  }
}
  if(TI==1){
 }
}

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做台无人机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值