单片机串行通信实验报告实验要求原理仿真图及例程.docx
《单片机串行通信实验报告实验要求原理仿真图及例程.docx》由会员分享,可在线阅读,更多相关《单片机串行通信实验报告实验要求原理仿真图及例程.docx(37页珍藏版)》请在冰豆网上搜索。
单片机串行通信实验报告实验要求原理仿真图及例程
《嵌入式系统原理与实验》实验指导
实验三调度器设计基础
一、实验目的和要求
1.熟练使用KeilC51IDE集成开发环境,熟练使用Proteus软件。
2.掌握Keil与Proteus的联调技巧。
3.掌握串行通信在单片机系统中的使用。
4.掌握调度器设计的基础知识:
函数指针。
二、实验设备
1.PC机一套
2.KeilC51开发系统一套
3.Proteus仿真系统一套
三、实验内容
1.甲机通过串口控制乙机LED闪烁
(1)要求
a.甲单片机的K1按键可通过串口分别控制乙单片机的LED1闪烁,LED2闪烁,LED1和LED2同时闪烁,关闭所有的LED。
b.两片8051的串口都工作在模式1,甲机对乙机完成以下4项控制。
i.甲机发送“A”,控制乙机LED1闪烁。
ii.甲机发送“B”,控制乙机LED2闪烁。
iii.甲机发送“C”,控制乙机LED1,LED2闪烁。
iv.甲机发送“C”,控制乙机LED1,LED2停止闪烁。
c.甲机负责发送和停止控制命令,乙机负责接收控制命令并完成控制LED的动作。
两机的程序要分别编写。
d.两个单片机都工作在串口模式1下,程序要先进行初始化,具体步骤如下:
i.设置串口模式(SCON)
ii.设置定时器1的工作模式(TMOD)
iii.计算定时器1的初值
iv.启动定时器
v.如果串口工作在中断方式,还必须设置IE和ES,并编写中断服务程序。
(2)电路原理图
Figure1甲机通过串口控制乙机LED闪烁的原理图
(3)程序设计提示
a.模式1下波特率由定时器控制,波特率计算公式参考:
b.可以不用使用中断方式,使用查询方式实现发送与接收,通过查询TI和RI标志位完成。
2.单片机与PC串口通讯及函数指针的使用
(1)要求:
a.编写用单片机求取整数平方的函数。
b.单片机把计算结果向PC机发送字符串。
c.PC机接收计算结果并显示出来。
d.可以调用KeilC51stdio.h中的printf来实现字符串的发送。
e.单片机的数码港显示发送的次数,每9次清零。
(2)参考电路原理图
Figure2单片机与PC串口通讯及函数指针的使用原理图
(3)程序设计要求
a.编写求平方函数时,采用函数指针来编写。
b.参考头文件模式,完善设计项目文件结构。
四、思考题
1.如果实验1如何使用实验2的成果来改写?
2.请结合实例说明什么是函数指针及如何使用函数指针。
五、实验报告要求
1.简述编写C程序,并联合调试程序的过程。
2.解释编写的实验程序的代码,描述实验结果。
3.解答思考题。
4.简述实验的心得。
《嵌入式系统原理及实验》实验报告
Lab3调度器设计基础
一、甲机通过串口控制乙机LED闪烁
(一)实现原理
1.总体思路
通过发送缓冲寄存器SBUF,以及接收缓冲寄存器SBUF,将在甲机上初始化的要发送的数据'A','B','C','D'存入一个数组,通过超级循环内设定的一个按键控制函数,依次发送给乙机,由乙机接收并让相应的LED灯闪烁。
2.硬件设计
上图所示的是单击Play
以后开始仿真,此时没有按键按下,甲机乙机均处于等待状态之下。
*******************************************************************
上图所示按键第一次按下,甲机发送字符'A',D1灯闪烁,乙机接收字符'A',并显示相应与甲机D1灯位置对应的D2灯闪烁。
*******************************************************************
以上两幅图是在一起的,也许是LED灯启动以及延迟还有甲、乙机发送接收数据时间差等各方面的差异,甲机的D3灯和乙机的D4灯亮不到一块去,它们交替着闪烁,此闪彼灭。
总之,以上两幅图所呈现的,是当按键第二次按下,甲机发送字符'B',并闪烁D3灯,乙机接收字符'B',并闪烁相应的D4灯。
*******************************************************************
上图所示按键第三次按下,控制甲机发送字符'C',并同时闪烁D1和D3灯,与此同时,乙机接收甲机发来的字符'C',并同时闪烁D2、D4灯。
图中所示的是LED灯一闪一灭时的亮状态,灭状态的截图此处省去。
*******************************************************************
上图所示按键第四次按下,甲机向乙机发送字符'D',同时使得D1、D3灯灭掉,乙机接收完字符'D'之后,也使得其控制的D2、D4灯停止闪烁。
3.软件设计
流程图:
开始
↓←←←←←←↑
是否有按键按下?
否→↑
是↓
第几次按下按键?
↓
1
2
3
4
↓↓↓↓
↓甲机发送字符:
'A''B''C''D'
↓↓↓↓
LED1LED3LED1LED1&LED3全灭
闪烁闪烁&LED3
都闪烁
↓
乙机接收相应字符
↓
'A''B''C''D'
↓↓↓↓
LED2LED4LED2LED2&LED4全灭
闪烁闪烁&LED4
都闪烁
关键代码段+解释:
甲机代码段·································································
/*******************************
//按键控制函数
voidbutton(void)//按键控制函数
{
debouncing();//调用消抖函数
if(n==1)
{
SBUF=send[i];//发送第i个数据
while(TI==0);//查询等待发送是否完成
TI=0;//发送完成,TI由软件清0
n=0;
switch(i)
{
case0:
while(debouncing()==0){D1=~D1;delay_ms(150);}break;//甲机D3灯灭状态,D1灯不断闪烁,直到有新的按键按下为止
case1:
D1=1;while
(1){D3=~D3;delay_ms(150);if(debouncing()){break;}}break;//甲机D1灯灭状态,D3灯不断闪烁,直到有新的按键按下为止
case2:
D3=1;while
(1){D1=~D1;D3=~D3;delay_ms(150);if(debouncing()){break;}}break;//甲机D1、D3灯一起不断闪烁,直到有新的按键按下为止
case3:
D1=1;D3=1;break;//甲机D1、D3灯均处于灭状态
default:
;
}
i++;
if(i==4)//使控制功能能循环反复地执行
{
i=0;//使控制功能能循环反复地执行
}
}
}
*******************************/
/*******************************
//甲机相关初始化
TMOD=0x20;//定时器T1工作于方式2
TL1=0xf4;//波特率为2400bps
TH1=0xf4;
TR1=1;
SCON=0x40;//定义串行口工作于方式1
*******************************/
乙机代码段·································································
/*******************************
//乙机接收显示函数
voiddisp(void)//乙机接收显示函数
{
REN=1;//允许接收
while(RI==0);//查询等待接收标志为1,表示接收到数据
buffer[i]=SBUF;//接收数据
RI=0;//RI由软件清0
switch(i)
{
case0:
while(!
RI){D2=~D2;delay_ms(150);}break;//乙机D4灯灭状态,D2灯不断闪烁,直到乙机接收到新传来的数据为止
case1:
D2=1;while
(1){D4=~D4;delay_ms(150);if(RI){break;}}break;//乙机D2灯灭状态,D4灯不断闪烁,直到乙机接收到新传来的数据为止
case2:
D4=1;while
(1){D2=~D2;D4=~D4;delay_ms(150);if(RI){break;}}break;//甲机D2、D4灯一起不断闪烁,直到乙机接收到新传来的数据为止
case3:
D2=1;D4=1;break;//乙机D2、D4灯均处于灭状态
default:
;
}
i++;
if(i==4)//使控制功能能循环反复地执行
{
i=0;//使控制功能能循环反复地执行
}
}
*******************************/
/*******************************
//乙机相关初始化
TMOD=0x20;//定时器T1工作于方式2
TL1=0xf4;//波特率为2400bps
TH1=0xf4;
TR1=1;
SCON=0x40;//定义串行口工作于方式1
*******************************/
(二)调试
1.调试的方式
软件仿真
调试现象:
1单击Play
以后开始仿真,此时没有按键按下,甲机乙机均处于等待状态之下。
2P1.0口按键第一次按下以后,甲机D1灯闪烁,同时乙机D2灯也闪烁。
3当按键第二次按下,甲机闪烁D3灯,乙机闪烁D4灯。
4按键第三次按下时,甲机同时闪烁D1和D3灯,与此同时,乙机同时闪烁D2、D4灯。
5按键第四次按下,甲机的D1、D3灯同时灭掉,乙机控制的D2、D4灯也都停止闪烁。
6若接下来还有按键按下,那将回到②,如此循环执行下去。
(三)实验再思考
1.进一步改进的设想
可以用串行口中断服务程序来实现。
2.实验的收获
学会了双机串行口通信
3.实验中尚不能解决的疑问
的确有个疑问:
若是我把程序中的任何一个switch语句改成如下形式:
switch(SBUF)
{
case'A':
……;break;
case'B':
……;break;
case'C':
……;break;
case'D':
……;break;
default:
;
}
这样的switch语句无论出现在甲机还是乙机的程序里面,都无法实现相应的任何控制功能了。
SBUF存储数据的情况具体是怎样的呢?
switch语句不能够引用SBUF吗?
二、单片机与PC串口通讯及函数指针的使用
(一)实现原理
1.总体思路
按键接的是P3.2复用口,于是就想到用外部中断0控制。
所以,将数码管显示程序以及串口通讯程序都一起放入外部中断INT0服务程序当中,就可以实现实验要求。
另外,在C51程序编写当中还应当特别注意以下几点:
①TH1=0xf3;
TL1=0xf3;//设置串行口波特率为2400bps,定时器初值,波特率设置非常严格
//要是设置错了,在发送和接收的时候,就会出现莫名其妙的符号,比如说:
x▋xxx▋▋xx▋x诸如此类...O__O"…
②调用printf之前应该关闭串口中断使能
ES=0;//禁止串行口中断
TI=1;//必须置高TI,RI
RI=1;
printf("%d*%d=%d",n,n,c);
putchar('\n');
while(!
TI);//等待printf语句执行完毕
while(!
RI);//等待printf语句执行完毕
2.硬件设计
上图所示有关串口COMPIM的相关参数设置应该注意的地方
****************************************************************
上图所示虚拟终端相关参数设置应该注意的地方,虚拟终端相关参数设置应该与串口的相关参数设置一致,也应该与C51编程中串口初始化时设定的波特率的数值一致,即都应该是2400bps。
注意,虚拟终端的RXD应当与串口第3脚TXD(即发送端)连接,否则仿真时无法虚拟终端调试窗口无法显示printf语句内容。
****************************************************************
上图所示的是单击Play
以后开始仿真,此时没有按键按下,数码管静止在显示0的状态当中,此时没有任何的数据发送和接收。
****************************************************************
上图所示当第一次按下按键时,触发外部中断,单片机调用函数指针指向的求取整数平方的函数,并将计算结果发送给PC机,此时虚拟终端显示:
1^2=1;即1
=1;(似乎虚拟终端显示框要显示的文字在这个截图里面有点小,看不太清楚),数码管此时显示发送次数为1。
****************************************************************
上图所示当第5次按键按下,数码管显示发送次数为5,此时也可以清楚地观察到虚拟终端调试窗口的显示:
1*1=1
2*2=4
3*3=9
4*4=16
5*5=25
****************************************************************
数码管显示每9次清零,求整数平方数也是0~9循环,上图所示虚拟终端显示结果有异常情况。
到目前为止,我改写过多种printf语句形式,可是还是解决不了上图所示的异常显示问题。
为什么会显示成:
$6^2=36;
17^2=49;
@8^2=64;
Q9^2=81;
(⊙o⊙)呢?
好奇怪!
?
****************************************************************
如上图所示,就算我改了printf语句形式,也还是会有同样的问题出现。
****************************************************************
上图所示是数码管每9次清零,然后再执行到3的情况,从虚拟终端调试窗口可见0~9求平方已经循环执行到了第二轮的3。
3.软件设计
流程图:
开始
↓
初始化定时器1、串口、外部中断0
↓
等待中断←←←←←←←↑
↓↑
是否有外部中断?
否→→→→↑
是↓↑
转入外部中断0中断服务程序↑
↓↑
按键消抖↑
↓↑
函数指针调用求整数平方函数↑
↓↑
在数码管上显示发送次数↑
↓↑
发送求取结果↑
↓↑
查询等待发送是否完成↑
↓↑
发送完成,TI由软件清0↑
↓↑
在虚拟终端上显示求平方结果↑
↓↑
中断返回↑
↓→→→→→→→→↑
关键代码段+解释:
/*******************************
//串口初始化
TH1=0xf3;
TL1=0xf3;//设置串行口波特率为2400bps,定时器初值,波特率设置非常严格
//要是设置错了,在发送和接收的时候,就会出现莫名其妙的符号,比如说:
x▋xxx▋▋xx▋x诸如此类...O__O"…
SCON=0x50;//0101,0000:
串行口方式1EN=1允许接收,8位异步通信方式,8-bitUART,TI=0;RI=0
PCON=0x00;//SMOD=0
EA=1;//开总中断允许位
ES=1;//开串行口中断
*******************************/
/*******************************
//求取整数平方函数
uintpow2(uintx)//求取整数平方函数
{
uintq;
q=x*x;
returnq;//return返回平方数结果
}
*******************************/
/*******************************
//虚拟终端显示
voidvir_ter(uintn,uintc)//虚拟终端显示
{
ES=0;//禁止串行口中断
TI=1;//必须置高TI,RI,TI=1发送填充字节,中断“不”使能
RI=1;
printf("%d*%d=%d",n,n,c);//*.调用printf之前应该关闭串口中断使能
putchar('\n');
while(!
TI);//等待printf语句执行完毕
while(!
RI);//等待printf语句执行完毕
ES=1;
TI=0;
RI=0;
}
*******************************/
/*******************************
//外部中断INT0中断服务程序
voidintsvr0(void)interrupt0//外部中断INT0
{
debouncing();//调用消抖函数
c=(*p)(n);//用函数指针形式调用求取整数平方函数
disp(n);//在数码管上显示发送次数
SBUF=c;//发送求取结果
while(TI==0);//查询等待发送是否完成
TI=0;//发送完成,TI由软件清0
vir_ter(n,c);//在虚拟终端上显示求平方结果
}
*******************************/
(二)调试
1.调试的方式
软件仿真
调试现象:
1单击Play
以后开始仿真,此时没有按键按下,数码管静止在显示0的状态当中,此时没有任何的数据发送和接收。
2P3.2口按键第一次按下以后,触发外部中断,单片机调用函数指针指向的求取整数平方的函数,并将计算结果发送给PC机,此时虚拟终端显示:
1^2=1;即1
=1;
3不端按下按键触发外部中断,当外部中断一到来,单片机就执行调用函数指针指向的求取整数平方数的函数,并将求取结果发送给串口。
单片机0~9不断循环求取整数平方数,并也循环显示在虚拟终端调试窗口上,数码管显示求取整数平方数结果发送次数,每9次清零。
2.遇到问题的处理
①虚拟终端的RXD应当与串口第3脚TXD(即发送端)连接,否则仿真时无法虚拟终端调试窗口无法显示printf语句内容。
②虚拟终端相关参数设置应该与串口的相关参数设置一致,也应该与C51编程中串口初始化时设定的波特率的数值一致,在此次实验报告中即都应该是2400bps。
在编写C51程序时,TH1=0xf3;TL1=0xf3;//设置串行口波特率为2400bps。
波特率的设置非常严格,要是设置错了,在发送和接收的时候,就会出现莫名其妙的符号,比如说:
x▋xxx▋▋xx▋x诸如此类...O__O"…
(三)实验再思考
1.进一步改进的设想
目前还没有设计得出外部中断服务程序和串行口中断服务程序同时一起用的C51程序,遇到很多问题。
希望老师今后能指导我们关于双重中断程序的编写,我自己捣鼓了好久还没捣鼓出来。
2.实验的收获
收获当然很多,诸如:
虚拟终端的RXD应当与串口第3脚TXD(即发送端)连接等等都是我对单片机新的认识,新的收获。
还有:
SBUF=c;//发送求取结果
while(TI==0);//查询等待发送是否完成
TI=0;//发送完成,TI由软件清0
ES=0;//禁止串行口中断
TI=1;//必须置高TI,RI,TI=1发送填充字节,中断“不”使能
RI=1;
printf("%d*%d=%d",n,n,c);//调用printf之前应该关闭串口中断使能
putchar('\n');
while(!
TI);//等待printf语句执行完毕
while(!
RI);//等待printf语句执行完毕
以上语句应该熟记,是使能虚拟终端的常用语句。
3.实验中尚不能解决的疑问
上图所示便是最大的疑问
(四)附录(粘贴完整代码)
甲机通过串口控制乙机LED闪烁
甲机完整代码·······························································
-Target1
-SourceGroup
+F.c
F.h
+main.c
//F.h/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitD1=P0^0;
sbitD3=P0^3;
sbitP1_0=P1^0;
uintdebouncing(void);
voidbutton(void);
voiddelay_ms(uintxms);
//F.c//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include"F.h"
uintn=0;
uchari=0;
externucharsend[4];//声明全局变量
voiddelay_ms(uintxms)//ms级延时函数
{
uintx,y;
for(x=xms;x>0;x--)
{
for(y=130;y>0;y--);
}
}
uintdebouncing(void)//debouncing:
消除抖动的意思,按键消抖函数:
若确实有按键按下,函数返回值为1;否则返回值为0
{
if(P1_0==0)//有键按下吗?
{
delay