单片机——串口通信

实验内容】

1、单片机先通过UART 口接收来自 PC 机发送的一个ASCII 码字符,

收到后再把这个字符原样发送给 PC 机。

步骤:

(1)通信波特率选择 9600,8 位数据位,1 位停止位,无奇偶校验位;

(2)查看实验箱的电路图,可看到单片机串口的 TTL 电平通过芯片

MAX232 转换成为 PC 机的 RS232 电平,以实现电平匹配,利用串口通信电缆连接好实验箱和 PC 机;

(3)使用 UART 口需要对行列特殊功能寄存器 SCON 进行设置,该寄存器的位结构,其中 SM0、SM1 两位决定了串口的工作方式,本例选择工作方式 1,赋值 SM0=0、SM1=1;REN 为接收控制位, 置 1 时允许接收,置 0 时禁止,在本例中置 1;TI、RI 为发送、接收中断标志位,因 51 单片机的串口为共享中断,所以需要判断这两位来区分具体是发送中断还是接收中断,本例中接收采用中断方式,发送采用程序查询方式

(4)由于接收采用中断方式,所以还要使能串口中断及总中断,需要对特殊功能寄存器 IE 进行设置,该寄存器的位结构见实验五中的表 5-2, 其中 ES 位置 1 可 使能串口中断,置 0 则禁止;EA 位控制总中断,置1 使能,置 0 禁止;本例中需要赋值 ES=1、EA=1;

(6)本例在 PC 机端通过“超级终端”或相关串口调试软件进行实验。打开串口调试程序,将波特率设置为9600,无奇偶校验,晶振11.0592MHz,发送和接收使用的格式相同,如都使用,字符型格式,在发送框输入 “hello”,在接收框中同样可以看到相同字符,说明设置和通信正确。

#include <reg51.h>
#include "lcd.h"
unsigned char gotData[32],i=0x00,j=0x00;
bit ready=0;
void main (void)
	{
		SCON = 0x50; //设定串口工作方式 1,接收使能PCON &=
		//~0x80; //波特率不倍增
		//TMOD &= ~0x30;
		TMOD |= 0x21; //定时器 1 工作于 8 位自动重载模式
		TL1 = 0xfd;
		TH1 = 0xfd; //波特率 9600
		IE |= 0x92; //打开串口中断及总中断TCON
	//	|= 0x40; //开启定时器 T1 while(1)
		TR1=1;
		LcdInit(DOUBLE,INC,NOSHIFT,OPEN,NOSHOW,BLINK);
		while(1)
		{
		  if(ready)
		  {
		  	LcdWriteCommand(0x01,1);
			ePutstr(0,0,gotData);
			do
			{
			   gotData[j]=0;
			}while(j--);
			ready=0;
		  }
		}
	}
void uart_ren(void) interrupt 4 //串口中断子函数
{
   if(RI)
	{
		//unsigned char temp;
		//EA &= ~0x10; //关闭串口中断if(RI) //判断是
		//temp = SBUF; //读取接收数据
		RI = 0; //清零接收中断标志SBUF
		TH0=0xec;
		TL0=0x77;
		TR0=1;
		gotData[i++]=SBUF;
		//= temp; //回送数据while(!TI); //
		//TI = 0; //清零发送中断标志
	}
	//else {
	//	TI = 0;
	//	EA |= 0x10; //开启串口中断
}

void timero (void) interrupt 1
	{
		TR0=0;
		j=1;
		i=0x00;
		ready=1;
	}

#include "lcd.h"
//==========显示指定座标的一串字符子函数=============
void ePutstr(uchar x, uchar y, uchar const *ptr)//在 x 列 y 行处显示 ptr 指向的字符串
	{
		uchar i,j = 0;
		while(ptr[j] > 31)
		j++; //ptr[j]>31 时为ASCII 码,j 累加,计算出字符串长度
			for(i = 0; i < j; i++)
			{
				DisplayOneChar(x++, y, ptr[i]); //显示单个字符,同时x 坐标递增
				if(x == 16)
					{
					x = 0;
					y ^= 1; //当每行显示超过 16 个字符时换行继续显示
					}
			}
	}

//===============显示光标定位子函数==================
void LocateXY(char posx, char posy) //定位位置到地址x 列 y 行
{
	uchar temp;
	temp = posx & 0x0f; //屏蔽高 4 位,限定 x 坐标的范围为 0~15
	posy &= 0x01; //屏蔽高 7 位,限定 y 坐标的范围为 0~1
	if(posy)
	temp |= 0x40;//若要显示的是第二行,则地址码+0x40,因为第二行起始地址为 0x40
	temp |= 0x80;//指令码为地址码+0x80,因为写 DDRAM 时 DB7 恒为 1(即 0x80)
	LcdWriteCommand(temp, 1); //把 temp 写入 LCD 中,检测忙信号
}

//===========显示指定座标的一个字符子函数===============
void DisplayOneChar(uchar x, uchar y, uchar Data)//在 x 列 y 行处显示变量 Wdata 中的一个字符
{
	LocateXY(x, y); //定位要显示的位置
	LcdWriteData(Data); //将要显示的数据 Wdata 写入 LCD
}

//=================LCD 初始化子函数=====================
void LcdInit(bit N,bit ID,bit S,bit D,bit C,bit B)
{
	uchar cmd =0x30;
	LcdWriteCommand(cmd, 0);//8 位数据方式,双行显示,5×7 字形,不检测忙信号
	Delay_nms(5); //延时 5ms
	LcdWriteCommand(cmd, 0);
	Delay_nms(1);
	LcdWriteCommand(cmd, 0); //重复三次
	if(N)
	cmd|=0x08;
	else{
		cmd&=~0x08;}
		if(N)
		cmd|=0x04;
	else{
		cmd&=~0x04;
	}
	LcdWriteCommand(cmd, 1); //确定显示行数及大小,检测忙信号
	LcdWriteCommand(cmd, 1); //关闭显示,检测忙信号
	LcdWriteCommand(cmd, 1); //清屏,检测忙信号
	cmd=0x04;
	if(ID)
	 cmd|=0x02;
	else
		cmd&=~0x02;
	if(S)
	 cmd|=0x01;
	else
		cmd&=~0x01;
	LcdWriteCommand(cmd, 1);
	cmd=0x08;
	if(D)
	 cmd|=0x04;
	else
		cmd&=~0x04;
	if(C)
	 cmd|=0x02;
	else
		cmd&=~0x02;
	if(B)
	 cmd|=0x01;
	else
		cmd&=~0x01;
	LcdWriteCommand(cmd, 1);
	LcdWriteCommand(0X02, 1);
}

//================写命令到 LCD 子函数===================
void LcdWriteCommand(uchar CMD, uchar Attribc)//写命令 CMD 到 LCD 中,Attribc 为 1 时检测忙信号,否则不检测
{
	if(Attribc)
	WaitForEnable(); //检测忙信号
	LCD_RS=0; //选择指令寄存器
	LCD_RW=0; //选择写方式
	_nop_(); //调用汇编指令延时一个空指令周期,等待稳定
	DataPort =CMD; //把命令数据送到数据线上
	_nop_();
	LCD_EN=1;
	_nop_();
	LCD_EN=0;
}

//===============写数据到 LCD 子函数=====================
void LcdWriteData(uchar Data) //写数据dataW 到 LCD 
{
	WaitForEnable(); //检测忙信号
	LCD_RS=1; //选择数据寄存器
	LCD_RW=0; //选择读方式
	_nop_(); //调用汇编指令延时一个空指令周期,等待稳
	DataPort = Data; //把显示数据送到数据线上
	_nop_();
	LCD_EN=1;
	_nop_();
	LCD_EN=0;
}

//===============从 LCD读出数据子函数=====================
uchar LcdReadData(void) 
{
	uchar tmp;
	WaitForEnable(); 
	DataPort = 0xff;
	LCD_RS=1; 
	LCD_RW=1; 
	_nop_();
	LCD_EN=1;
	_nop_();
	tmp=DataPort ;
	LCD_EN=0;
	return tmp;
}

//===============从 LCD读出地址指针函数=====================
uchar LcdReadAC(void) 
{
	uchar tmp;
	WaitForEnable(); 
	DataPort = 0xff;
	LCD_RS=0; 
	LCD_RW=1; 
	_nop_();
	LCD_EN=1;
	_nop_();
	tmp=DataPort ;
	LCD_EN=0;
	return (tmp & 0x7f);
}

//================检测 LCD 忙信号子函数==================
void WaitForEnable(void)
{
	uchar val;
	DataPort = 0xff; //数据线电平拉高
	LCD_RS=0; //选择指令寄存器
	LCD_RW=1; //选择写方式
	_nop_(); //调用汇编指令延时一个空指令周期,等待稳定
	LCD_EN=1; //使能端拉高电平
	_nop_(); //调用汇编指令延时两个空指令周期,等待稳定
	val = DataPort;
	while(val & BUSY)
	val = DataPort;
	LCD_EN=0;
}

//=================光标移动子函数 =====================
void CursorMove(bit Dir)
{
	if(Dir)
	LcdWriteCommand(0x14, 1);
	else
	LcdWriteCommand(0x10, 1);
}

//=================屏幕移动子函数 =====================
void ImageMove(bit Dir)
{
	if(Dir)
	LcdWriteCommand(0x1c, 1);
	else
	LcdWriteCommand(0x18, 1);
}

//=================n*1mS 延时子函数 =====================
void Delay_nms(uint xms)
{
uint x,y;
for(x = xms ; x > 0 ; x--)
for(y = 110 ; y > 0 ; y--);
}


#include <reg51.h>
#include <intrins.h>
//================变量类型的宏定义===================
#define uchar unsigned char
#define uint unsigned int
//================引脚电平的宏定义==================
sbit LCD_RS =P1^0; 
sbit LCD_RW =P1^1;
sbit LCD_EN =P2^5;
//================端口及晶振宏定义==================
#define DataPort P0
#define BUSY 0x80
#define SINGLE 0
#define DOUBLE 1
#define NORMAL 0
#define LARGE 1
#define INC 1
#define DEC 0
#define SHIFT 1
#define NOSHIFT 0
#define OPEN 1
#define CLOSE 0
#define SHOW 1
#define NOSHOW 0
#define BLINK 1
#define NOBLINK 1
#define LEFT 0
#define RIGHT 1
//================函数声明==================
void Delay_nms(uint n);
void WaitForEnable(void);
void LcdWriteData(uchar W);
uchar LcdReadData(void);
void LcdWriteCommand(uchar CMD, uchar Attribc);
uchar LcdReadAC(void);
void LcdInit(bit N,bit ID,bit S,bit D,bit C,bit B);
void LocateXY(char posx,char posy);
void DisplayOneChar(uchar x, uchar y, uchar Wdata);
void ePutstr(uchar x, uchar y, uchar const *ptr);
void CursorMove(bit Dir);
void ImageMove(bit Dir);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值