一、实验任务
1.用中断方式串口循环发送学号到PC并用串口助手显示;
2.串口接收PC发送数据(0-F)并发回PC,同时用单个数码管显示接收到的数据。
二、实验目的及原理
1.实验目的:掌握串行口接收、发送数据的原理及编程方法,掌握定时器产生波特率的原理,掌握串行中断服务程序。
2.实验原理:串行通信通过将数据存储在SBUF,再进一步进行发送与接收。发送、接收的速率由波特率控制,其值由定时器产生。当发送、接收完后发送、接收标志位会置1,传输停止,执行串行中断程序,将发送、接收标志位置0,方便下次传输。
三、实验中使用的仪器与材料
Keil、PZ-ISP、普中科技51单片机、串行口、定时器
四、实验方案、步骤及原始记录(数据、图表、计算等)
1.任务一:用中断方式串口循环发送学号到PC并用串口助手显示
(1)用keil编写程序,输出.hex文件
/*-----------------------------------------------
功能: 连接串口到电脑,下载该程序,打开电源
打开串口调试助手,将波特率设置为9600,无奇偶校验
晶振12MHz,发送和接收使用的格式相同,如都使用
字符型格式,设置正确后接受框可以显示出:
The UART test, 请在发送区输入信息
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
/*------------------------------------------------
函数声明
------------------------------------------------*/
void SendStr(unsigned char *s);
/*------------------------------------------------
串口初始化
------------------------------------------------*/
void InitUART (void)
{
SCON = 0x50; // SCON:设定工作方式1, 8-bit, 打开REN(允许串行接收位)
TMOD = 0x20; // TMOD:设定定时器中断方式2, 8-bit 自动重装初值
//定时器T1产生波特率
TH1=0xfa; //存放备用初值,自动重装给TL1
TL1=0xfa; //定时器初值-----11.0592MHZ晶振+4800波特率-->对应应装初值
EA = 1; //打开总中断
ET1=0; // 关闭定时器中断,因为其优先级比串行高,且实际不需要它
TR1=1; // TR1:启动定时器
// ES = 1; //这里暂不打开串行发送中断的原因是,一般在发送数据是不会
//对数据进行处理的,不需要中断
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
int i,j;
InitUART();
while(1) //循环发送
{
SendStr("2022210491 ");
for(i=0;i<200;i++) //延时
for(j=0;j<300;j++);
}
ES = 1; //打开串口中断
while (1)
{}
}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void SendByte(unsigned char dat)
{
SBUF = dat; //将数据写入发送缓冲器SBUF
while(!TI); //TI=1,数据发完,触发中断
TI = 0; //恢复其值,为下一次发送做准备
}
/*------------------------------------------------
发送一个字符串
------------------------------------------------*/
void SendStr(unsigned char *s)
{
//循环将字符串里的数字一个个发出来
while(*s!='\0')// \0 表示字符串结束标志,通过检测是否字符串末尾
{
SendByte(*s);
s++;
}
}
/*------------------------------------------------
串口中断程序
------------------------------------------------*/
void UART_SER (void) interrupt 4 //串行中断服务程序
{
unsigned char Temp; //定义临时变量
if(RI) //判断是接收中断产生
{
RI=0; //标志位清零
Temp=SBUF; //读入缓冲区的值
P1=Temp; //把值输出到P1口,用于观察
SBUF=Temp; //把接收到的值再发回电脑端
}
if(TI) //如果是发送标志位,清零
TI=0;
}
(2)将输出的hex文件烧录到开发板上
2.任务二:串口接收PC发送数据(0-F)并发回PC,同时用单个数码管显示接收到的数据
(1)用keil编写程序,输出.hex文件
#include<reg52.h>
#define uchar unsigned char // 定义无符号字符类型
uchar Char; // 定义字符变量Char
uchar flag; // 定义标志位变量flag
// UART初始化函数
void UART_Init()
{
SCON=0x50; // 设置串口工作方式1 ,8-bit, 打开REN(允许串行接收位)
//PCON=0; // 设置波特率
TMOD=0x20; // 设置定时器工作方式2, 8-bit 自动重装初值
TL1=0xfa; // 设置定时器初值-----11.0592MHZ晶振+4800波特率-->对应应装初值
TH1=0xfa;//存放备用初值,自动重装给TL1
ET1=0; // 关闭定时器中断
ES=1; // 开启串口中断
EA=1; // 开启总中断
TR1=1; // 启动定时器
}
// UART发送一个字节函数
void UART_sendbyte(uchar Byte)
{
SBUF=Byte; // 将数据写入串口缓冲区
while(TI==0); // 等待发送完成
TI=0; // 清除发送标志位
}
// 主函数
void main()
{
uchar Code[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,
0x7c,0x39,0x5e,0x79,0x71}; // 定义数码管显示编码数组
uchar i=0; // 定义计数器变量i
UART_Init(); // 调用UART初始化函数
P2=0xe3; // 选择数码管以输出值
while(1) // 无限循环
{
if('0'<=Char&&Char<='9'&&flag==1) // 如果接收到的数字在0-9之间且标志位为1
{
i=Char-'0'; // 计算数字对应的编码索引
UART_sendbyte(Char); // 发送接收到的数字
P0=Code[i]; // 控制数码管显示对应的编码
flag=0; // 清空标志位
}
if('a'<=Char&&Char<='f'&&flag==1) // 如果接收到的小写字母在a-f之间且标志位为1
{
i=Char-'a'+10; // 计算字母对应的编码索引
UART_sendbyte(Char); // 发送接收到的字母
P0=Code[i]; // 控制数码管显示对应的编码
flag=0; // 清空标志位
}
}
}
// UART接收中断服务函数
void UART_R() interrupt 4
{
if(RI==1) // 如果接收到数据
{
Char=SBUF; // 读取接收到的数据到Char变量
RI=0; // 清除接收标志位
flag=1; // 设置标志位为1,表示接收到数据
}
}
(2)将输出的hex文件烧录到开发板上
五、实验结果及分析、实验过程中遇到问题及处理过程说明
1.任务一结果
2.任务二结果
3.遇到的问题及解决方法
在任务一时打开了定时中断,接收不到信息,分析原因后是因为定时器的中断优先级比串行高,且无需定时器中断,这里仅用定时器来产生波特率。
六、实验总结及心得体会
通过理论与实践相结合,我进一步理解了串行口的结构、工作方式,还有串行口进行数据的发送与接收的原理及编程逻辑。在使用多个中断时注意中断优先级。