单片机蓝桥杯——串口通信

1、什么是串行、并行、单工、全双工、半双工、同步、异步

通讯的方式分类:并行通信  串行通信

并行通信:数据的各位同时在多根数据线上发送或接收。

串行通信:数据的各位在同一根数据线上逐位发送和接收7

并行通信的特点:控制简单,传输速度快;由于传输线较多,适用于短距离通信。

串行通信的特点:控制复杂,传输速度慢;只需要一根数据线,适用于远距离通信。

根据串行通信中对数据流的分界、定时以及同步方案方法不同,可分为和同步和异步。

同步方式:发送端和接收端必须使用同一时钟,是一种连续传送数据的通信方式,一次通讯传送多个字符数据(一帧数据)

异步方式:发送和接收端使用的是各自的时钟,是一种不连续传送数据的通信方式,一次通信只能传输一个字符数据(字符帧)。字符帧之间的间隙可以是任意的

根据串行数据的传输方向,我们可以将通信分为单工,半双工,双工。

单工:信道是单向的,数据只能单方面传输,发送端只能发送数据,不能接收;接收端只能接收数据,不能发送;

半双工:数据可以进行双向传输,但不能在两个方向上同时进行。

全双工:数据可以同时进行双向传输。

---------------------------------------------------------------------------------------------------------------------------------

2、串口通信中需要用到的寄存器SCON——串行通信控制寄存器(一般设置为0x50)

B7 B6 B5 B4 B3 B2 B1 B0
SM0 SM1 SM2 REN TB8 RB8 TI RI

SM0SM1 工作方式:

SM2:多机通信控制位。方式2、方式3的时候才使用。

        工作于方式2和方式3时,当SM2=1时,只有当接收到第9位数据(RB8)为1时,才把接收到的前8位数据送入SBUF,发出中断申请,否则会将接受到的数据放弃。当SM2=0时,就不管第位数据是0还是1,都将数据送入SBUF,并发出中断申请。   

REN=1允许接收;REN=0禁止接收。

TB8:接收数据的第8位

RB8:接收数据的第8位

TI:串口发送完成中断标志位。由硬件自动置1,需要软件清“0”。

RI:串口接收完成中断标志位。由硬件自动置1,需要软件清“0”。

---------------------------------------------------------------------------------------------------------------------------------

3、代码思路

串口初始化设置

(1)设置串口工作方式,一般为异步8位UART并且允许接收(REN=1),即SCON=0x50
(2)设置定时器T1工作在方式2,8位自动重装,可用作波特率发生器
(3)通过给TH1、TL1赋不同值,设置波特率,其数值可查表找到
(4)打开中断总开关 EA=1;    
(5)允许串口中断 ES=1;      
(6)启动T1  TR1=1;      
(7)此外还需要设置AUXR,用于设置T1时钟,为1T还是12T。注意如果用定时器2作为波特率发生器,则有关T2的设置在AUXR寄存器

比赛中,有关AUXR的设置都可以在STC-ISP中自动生成。如用定时器2作为波特率发生器,波特率为4800bps,数据位为8位,无校验位:

中断服务子程序

        通过SBUF寄存器发送接收数据,发送数据时,将所要发送的数据给SBUF;接收数据时,直接从SBUF中读取数据

4、例题

功能1:上位机发送数据到单片机,单片机再将数据传送给上位机

代码实现:

#include"reg51.h"
#include"intrins.h"

sfr AUXR=0x8e;

unsigned char Rdat;
//***************串口初始化设置******************************************
void Init_Uart()
{
	AUXR=0x00;  
	SCON=0x50;  //0101 0000;工作在方式1,异步8位UART并且允许接收 即REN=1
	TMOD=0x20;  //设置定时器T1工作在方式2,8位自动重装,可用作波特率发生器
	TH1=0xfd;   //设置波特率为9600kbps,数值可查表找到
	TL1=0xfd;   //
	EA=1;       //打开中断总开关
	ES=1;       // 允许串口中断
	TR1=1;      //启动T0
}
//***************发送一个字节******************************************
void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);
	TI=0;
}
//***************串口中断服务子程序******************************************
void ServiceUart() interrupt 4
{
	if(RI==1)//如果接收完成
	{
		Rdat=SBUF;//Rdat为从上位机接收到的数据
		RI=0;				
		SendByte(Rdat);//再将收到的数据再发送到上位机
	}
}
//***************主函数**************************************************
void main()
{
	Init_Uart();//调用串口初始化设置函数
	while(1);
		
}

现象:

 功能二:通过上位机发送数据到单片机,进而控制led,低电平点亮

代码实现:

#include"reg51.h"
#include"intrins.h"

sfr AUXR=0x8e;

unsigned char Rdat;

void SelectHc573(unsigned char n)
{
	switch(n)
	{
		case 4://Y4有效,P0直接控制LED
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5://Y5有效,P0控制蜂鸣器、继电器
			P2=(P2 & 0x1f) | 0xa0;
			break;
		case 6://Y6有效,P0控制数码管位选
			P2=(P2 & 0x1f) | 0xc0;
			break;
		case 7://Y7有效,P0控制数码管段选
			P2=(P2 & 0x1f) | 0xe0;
			break;
		case 0:
			P2=(P2 & 0x1f) | 0x00;
			break;
	}
}
//***************初始化系统******************************************
void InitSystem()
{
	SelectHc573(5);//关闭蜂鸣器继电器
	P0=0x00;       
	SelectHc573(4);//设置led初始状态为全灭
	P0=0xff;
}
//***************串口初始化设置******************************************
void Init_Uart()
{
	AUXR=0x00;  
	SCON=0x50;  //0101 0000;工作在方式1,异步8位UART并且允许接收 即REN=1
	TMOD=0x20;  //设置定时器T1工作在方式2,8位自动重装,可用作波特率发生器
	TH1=0xfd;   //设置波特率为9600kbps,数值可查表找到
	TL1=0xfd;   //
	EA=1;       //打开中断总开关
	ES=1;       // 允许串口中断
	TR1=1;      //启动T0
}
//***************发送一个字节******************************************
void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);
	TI=0;
}
//***************发送一个字符串******************************************
void SendString(unsigned char *str)
{
	while(*str !='')		
		SendByte(*str++);
}
//***************串口中断服务子程序******************************************
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		Rdat=SBUF;//从上位机接收到的数据
		RI=0;
		SelectHc573(4);
		P0=Rdat;
		SendByte(Rdat);
	}
}
//***************主函数**************************************************
void main()
{
	InitSystem();
	Init_Uart();	
	SendString("Welcome to Serial port!rn");
	while(1);	
}

现象:

程序开始时先发送一个字符串,注意此时应为文本模式接收:

一个字节的接收应为hex模式,通过电脑发送数据给单片机,去控制led:

第十届国赛例题

代码:

#include"stc15f2k60s2.h"
#include"intrins.h"
#include <stdio.h>
#include <string.h>

unsigned char Recv[8];							//从串口接收的数据
unsigned char order1[8]="STrn";		//命令1:查询数据指令:”STrn"
unsigned char order2[8]="PARArn";	//命令2:查询参数指令:"PARArn"
bit flag=0;								//串口接收完成标志位,若一组数据接收完成 置1			
unsigned int dis=20;			//距离
unsigned int temp1=24;		//温度(整数部分)
unsigned int temp2=32;		//温度(小数部分)
unsigned int disParm=35;	//距离参数
unsigned int tempParm=30;	//温度参数
void SelectHc573(unsigned char val)
{
	switch(val)
	{
		case 4://Y4有效,P0直接控制LED
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5://Y5有效,P0控制蜂鸣器、继电器
			P2=(P2 & 0x1f) | 0xa0;
			break;
		case 6://Y6有效,P0控制数码管位选
			P2=(P2 & 0x1f) | 0xc0;
			break;
		case 7://Y7有效,P0控制数码管段选
			P2=(P2 & 0x1f) | 0xe0;
			break;
		case 0:
			P2=(P2 & 0x1f) | 0x00;
			break;
	}
}
//***************初始化系统******************************************
void InitSystem()
{
	SelectHc573(5);//关闭蜂鸣器继电器
	P0=0x00;       
	SelectHc573(4);//设置led初始状态为全灭
	P0=0xff;
}
//***************串口初始化设置******************************************
void UartInit(void)		//4800bps@12MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器时钟12T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xCC;		//设置定时初始值
	TH1 = 0xFF;		//设置定时初始值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
	EA=1;       //打开中断总开关
	ES=1;       // 允许串口中断
}
//***************发送一个字节******************************************
void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);
	TI=0;
}
//***************发送一个字符串******************************************
void SendString(unsigned char *str)
{
	while(*str !='')		
		SendByte(*str++);
}
//重定向,否则无法使用printf函数
char putchar(char ch)
{	
	SendByte(ch);
  return ch;	
}
//***************串口中断服务子程序******************************************
unsigned char Rdat;
unsigned char Rcnt=0;
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		RI=0;
		Rdat=SBUF;//从上位机接收到的数据
		if(Rdat != 'n')
		{
			Recv[Rcnt] = Rdat;
			Rcnt++;
		}
		else
		{	
			Recv[Rcnt] = Rdat;	
			Rcnt=0;
			flag=1;
		}
	}	
}

//***************主函数**************************************************
void main()
{
	unsigned char ret1,ret2,i;
	InitSystem();
	UartInit();	
	SendString("hellorn");
	while(1)
	{
		if(flag==1)
		{
			flag=0;
			ret1=strcmp(order1,Recv);  //命令1比较的返回值   
			ret2=strcmp(order2,Recv); //命令2比较的返回值 		
			if(ret1==0)
				printf("$%d,%d.%drn",dis,temp1,temp2);
			else if(ret2==0)
				printf("#%d,%drn",disParm,tempParm);
			else
				printf("ERRORrn");	
			for(i=0;i<8;i++)          //清空接收数组
			{
				Recv[i]='';
			}	
		}
	}	
}

结果:

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>