Bootstrap

串口工作方式

方式0

方式 0 时,串行口为同步移位寄存器的输入输出方式。主要用于扩展并行输 入或输出口。
数据由 RXD(P3.0)引脚输入或输出,同步移位脉冲由 TXD(P3.1) 引脚输出。发送和接收均为 8 位数据,低位在先,高位在后。波特率固定为 fosc/12

方式0输出

在这里插入图片描述

方式0输入

在这里插入图片描述

方式1

方式 1 是 10 位数据的异步通信口。TXD 为数据发送引脚,RXD 为数据接收引 脚,传送一帧数据的格式如下所示。其中 1 位起始位,8 位数据位,1 位停止位。
在这里插入图片描述

方式1输出

在这里插入图片描述

方式1输入

在这里插入图片描述

用软件置 REN 为 1 时,接收器以所选择波特率的 16 倍速率采样 RXD 引脚电 平,检测到 RXD 引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入 移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄 存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移 位。当 RI=0,且 SM2=0(或接收到的停止位为 1)时,将接收到的 9 位数据的前 8 位数据装入接收 SBUF,第 9 位(停止位)进入 RB8,并置 RI=1,向 CPU 请求中断。

方式2或方式3

输出

方式 2 或方式 3 时为 11 位数据的异步通信口。TXD 为数据发送引脚,RXD 为 数据接收引脚。

在这里插入图片描述

发送开始时,先把起始位 0 输出到 TXD 引脚,然后发送移位寄存器的输出位 (D0)到 TXD 引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由 TXD 引脚输出。第一次移位时,停止位“1”移入输出移位寄存器的第 9 位上, 以后每次移位,左边都移入 0。当停止位移至输出位时,左边其余位全为 0,检 测电路检测到这一条件时,使控制电路进行最后一次移位,并置 TI=1,向 CPU 请求中断。

输入

在这里插入图片描述

接收时,数据从右边移入输入移位寄存器,在起始位 0 移到最左边时,控制 电路进行最后一次移位。当 RI=0,且 SM2=0(或接收到的第 9 位数据为 1)时, 接收到的数据装入接收缓冲器 SBUF 和 RB8(接收数据的第 9 位),置 RI=1,向 CPU 请求中断。如果条件不满足,则数据丢失,且不置位 RI,继续搜索 RXD 引脚 的负跳变。

串口使用方法

如何计算波特率

在这里插入图片描述
(256 - TH1) = 11.0592M/12169600,所以TH1=TL1=250;

串口初始化步骤

如何使用串口,大家可以按照以下几个步骤配置。

  • ①确定 T1 的工作方式(TMOD 寄存器);
  • ②确定串口工作方式(SCON 寄存器);
  • ③计算 T1 的初值(设定波特率),装载 TH1、TL1;
  • ④启动 T1(TCON 中的 TR1 位);
  • ⑤如果使用中断,需开启串口中断控制位(IE 寄存器)。

串口回传实验

 //功能:串口回传实验,PC通过串口通讯工具,发送字符a或字符串hello,MCU回复相同内容

#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;

//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						
//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

void Uart1_Init(void);	  //串口1的初始化


void main()
{
	Uart1_Init();

	while(1)	//保持应用程序不退出
	{
	
	}
}


void Uart1_Init(void)//配置串口为工作方式1,定时器1,工作方式为2,8位自重载
{
	//串口模块寄存器
	PCON |= 0x80;			//使能波特率倍速位SMOD
	SCON |= 0x50;			//配置串口工作方式1,允许接收数据
	
	//定时器1相关寄存器
	TMOD &= 0x0F;		//使用定时器1
	TMOD |= 0x20;		//配置工作方式2,8位自重载
	TL1 = 0xFA;			//设置定时计数器的低8位
	TH1 = 0xFA;			//设置定时计数器的高8位
	TR1 = 1;			//开启定时器1
	
	//中断相关寄存器
	ES = 1;			  	//串行口中断允许位
	EA = 1;				//CPU 中断允许(总允许)位
}


void Uart1_Isp(void)	interrupt 4
{
	u8	u8RecData = 0;


	if(RI)	//检测串口接收完成中断
	{
		u8RecData = SBUF;		//将串口模块缓存寄存器中的数据读到用户内存	

		SBUF = 	u8RecData;		//将用户数据传输到串口缓存寄存器中,准备发送
		while(TI==0);			//用户在等待串口发送单元发送完成

		RI = 0;		//用户清除接收数据完成标志
		TI = 0;		//用户清除发送数据完成标志
	}
}

模拟printf实验

 //功能:实现printf的输出重定向

#include "reg52.h"
#include "stdio.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;

//定义LED的引脚
sbit LED1 = P2^0;


//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						
//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

void Uart1_Init(void);	  //串口1的初始化
void Uart1_SendData(u8 u8data);		//串口1的发送数据

void main()
{
	u16 i = 0;
	Uart1_Init();

	while(1)	//保持应用程序不退出
	{
		i++;
		delay_ms(1000);
		printf("i = %03d,hello world!\r\n",i);
	}
}


void Uart1_Init(void)//配置串口为工作方式1,定时器1,工作方式为2,8位自重载
{
	//串口模块寄存器
	PCON |= 0x80;			//使能波特率倍速位SMOD
	SCON |= 0x50;			//配置串口工作方式1,允许接收数据
	
	//定时器1相关寄存器
	TMOD &= 0x0F;		//使用定时器1
	TMOD |= 0x20;		//配置工作方式2,8位自重载
	TL1 = 0xFA;			//设置定时计数器的低8位
	TH1 = 0xFA;			//设置定时计数器的高8位
	TR1 = 1;			//开启定时器1
	
	//中断相关寄存器
	ES = 1;			  	//串行口中断允许位
	EA = 1;				//CPU 中断允许(总允许)位
}


void Uart1_Isp(void)	interrupt 4
{
	u8	u8RecData = 0;

	if(RI)	//检测串口接收完成中断
	{
		u8RecData = SBUF;		//将串口模块缓存寄存器中的数据读到用户内存	

		switch(u8RecData)
		{
			case 0x10:	LED1 = 1;break;
			case 0x11:	LED1 = 0;break;
			default:break;
		}

		RI = 0;		//用户清除接收数据完成标志
		
	}
}

char putchar (char dat)	//标准C的输出重定向
{
	Uart1_SendData(dat);
	return dat;
}

void Uart1_SendData(u8 u8data)
{
	SBUF = u8data;		//串口输出单元开始工作
	while(TI == 0)			//等TI为高电平,输出完成
    {
        
    }
    TI = 0;				//清除发送标志
}

串口接收数据不丢失实验

 //功能:串口接收长字符(50以内)不丢失数据,通过printf发送给PC

#include "reg52.h"
#include "stdio.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;



u8 	u8Uart_Buffer[50]={0};		//串口缓存池
u8	u8Uart_Rx_STA = 0;		//串口接收状态标志
//bit7	0:表示没有接收完成,	1反之
//bit6	0:表示没有接收到'\r',	1反之
//bit5--bit0	表示接收到的有效数据长度


//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						
//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

void Uart1_Init(void);	  //串口1的初始化
void Uart1_SendData(u8 u8data);		//串口1的发送数据
void Uart1_RecvData(void);

void main()
{
	u8 len = 0;
	Uart1_Init();

	while(1)	//保持应用程序不退出
	{
		if(u8Uart_Rx_STA & 0x80)	//串口数据接收完成
		{
			len = 	u8Uart_Rx_STA & 0x3f;
			u8Uart_Buffer[len] = 0;
			printf("%s\r\n",u8Uart_Buffer);
			u8Uart_Rx_STA = 0;		//清除状态标志
		}
	}
}


void Uart1_Init(void)//配置串口为工作方式1,定时器1,工作方式为2,8位自重载
{
	//串口模块寄存器
	PCON |= 0x80;			//使能波特率倍速位SMOD
	SCON |= 0x50;			//配置串口工作方式1,允许接收数据
	
	//定时器1相关寄存器
	TMOD &= 0x0F;		//使用定时器1
	TMOD |= 0x20;		//配置工作方式2,8位自重载
	TL1 = 0xFA;			//设置定时计数器的低8位
	TH1 = 0xFA;			//设置定时计数器的高8位
	TR1 = 1;			//开启定时器1
	
	//中断相关寄存器
	ES = 1;			  	//串行口中断允许位
	EA = 1;				//CPU 中断允许(总允许)位
}


void Uart1_Isp(void)	interrupt 4
{
	u8	u8RecData = 0;

	if(RI)	//检测串口接收完成中断
	{
		Uart1_RecvData();
		RI = 0;		//用户清除接收数据完成标志
		
	}
}

char putchar (char dat)	//标准C的输出重定向
{
	Uart1_SendData(dat);
	return dat;
}

void Uart1_SendData(u8 u8data)
{
	SBUF = u8data;		//串口输出单元开始工作
	while(!TI);			//等TI为高电平,输出完成
	TI = 0;				//清除发送标志
}

void Uart1_RecvData(void)
{
	u8 r = SBUF;

	if((u8Uart_Rx_STA & 0x80) == 0)//没有接收完成
	{
	  	if(u8Uart_Rx_STA & 0x40)
	  	{
			  if(r!='\n')
			  {
			  	 u8Uart_Rx_STA = 0;		//将状态清0
			  }
			  else
			  {
			  	 u8Uart_Rx_STA |= 0x80;	//标记数据接收完成
			  }
		}
		else	//还没有接收过'\r'
		{
			 if(r == '\r')
			 {
			 	  u8Uart_Rx_STA |= 0x40;	//标记数据接收到\r
			 }
			 else
			 {
			 	 if((u8Uart_Rx_STA & 0x3f)<48)
				 {
				 	 u8Uart_Buffer[u8Uart_Rx_STA++] = r;
				 }
				 else
				 {
				 	u8Uart_Rx_STA = 0;
				 }
			 }
		}
	}
}
;