实验内容】
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);