文档详情

单片机软件仿真实验

沈***
实名认证
店铺
DOC
358KB
约12页
文档ID:157945253
单片机软件仿真实验_第1页
1/12

单片机软件仿真实验一、使用Keil C51软件仿真的意义调试、运行汇编或C语言程序后,我们会觉得单片机并不很复杂,学起来也并不枯燥特别是Keil C51提供了 I/O端口、定时/计数器、中断结构和串行通信部件窗口,可观察到程序运行或单步调试时各端线、寄存器、标志位等电平的变化情况,对清晰把握流程及理解工作原理起到良好的促进作用当输出端电平按自己的要求变化时,愉悦随之而来!软件仿真不仅在学习探究阶段是好方法,实际应用中也是重要的环节二、由浅入深安排的实验项目[实验1 ] Keil C51软件仿真步骤输入、编译一个短小程序,调试运行观察P1.0端的电平变化规律,并对程序作适当修改,让P1端口各位依次出高电平点亮LED发光管(左移)[实验2] 十进制数转BCD码(汇编程序、C语言) 了解数据在累加器、存储单元内的存储形式及如何控制端口Port各位电平的高低、SWAP命令的功能 开始尝试调试或了解C语言程序[实验3] 定时器/计数器(汇编程序、C语言) 要点:定时器延时方法、程序查询溢出、定时器程序调试技巧 [实验4] 中断(汇编程序、C语言)1.定时器硬件中断 2.外部中断 要求:把握汇编程序的转跳流程、C51程序的中断服务函数定义格式,学会软件仿真调试时怎样实现外部中断。

[实验5] 航标灯(汇编程序) 白天灯灭,天黑闪亮,快慢可调,电路简单,流程清晰,调试、运行成功多有趣![实验6] 步进电机(C语言) 步进电机也称为脉冲电机,它可以接收单片机I/O端口的数字脉冲(高低电平的变化),使电机旋转过相应的角度,在要求快速启停、精确定位的场合广泛应用[实验7] 串行通信奇偶校验(汇编程序) 调试一个程序了解奇偶校验技术、方式2一帧数据组成、振荡周期、波特率周期,观察TB8(“第九位数据”)、P(PSW.0)、CY(位累加器C)、TI(中断申请)位[实验8] 转速自动稳定程序(C语言)三、实验内容实验1 Keil C51软件仿真步骤1.进入Keil uVision2集成开发环境2.建立项目 选“Project”—“New Project…”,在对话框中输入项目名:led注意:路径是E:\CJY\实验1\led,需先建个人文件夹及子文件夹“实验1”3.选芯片 项目建立完毕自动弹出器件选择对话框,选择“Inter”中的8051AH4.输入程序 选“File”—“New…”,在文本框中编辑源文件,保存汇编程序路径及文件名为: E:\CJY\实验1\ led.asm5.添加 将汇编程序添加到项目中,方法是在左边文件栏中用鼠标右键点击 弹出快捷菜单,选“Add Files to Group ‘Source Group 1’” ,在对话框中选led.asm,点击“Add” 、“Close”按钮。

6.编译 点击图标“ ”(Build Target),进行编译,根据错误提示修改7.调试 点击图标“ ”(Start/Stop Debug…)进行调试,“ ”单步执行,“”跳出循环Peripherals”—“I/O Ports”—“Port 1”显示端口窗口 点击“ ”可运行程序,“Port 1”端口的P1.0应怎样变化?“”停止 如何用左移指令使得P1端口各位依次出高电平点亮LED管?提示:增加、修改的语句有:MOV A,#01H、MOV P1,A 、RL A MOV P1,A8.关闭项目“Project”—“Clouse Project” 程序调试界面 实验2 十进制数转BCD码 借助本程序的调试,可清楚地观察到执行每条语句后各累加器内容的变化情况,了解到十进制数是以何种形式存入累加器的,I/O端口的电平的高低是怎样控制的 汇编语言程序调试界面C51程序:#includevoid main(){ unsigned char a=23,t,b; t=a/10; b=a%10; t<<=4; b+=t; P1=b;}调试、运行C语言程序的方法与汇编语言相同,不妨试一试,自己喜欢哪一种? 实验3 定时器/计数器 延时方法有三种,一是子程序延时(实验1),二由定时器完成(实验3),三是两种方法的结合(试验4)。

当程序调试到下面位置时,应怎样做才能继续? 实验3汇编程序调试界面 C语言: #includesbit P1_0=P1^0; /* 定义P1_0为Port1端口的0位 */void main(){ TMOD=0x01; /* “0x01”的第一个符号是零 */ TR0=1; for(;;){ TH0=0x3D; TL0=0xB0; do{}while(TF0==0); P1_0=!P1_0; TF0=0; }}实验4 中断1.定时器硬件中断 定时器0、6M晶振,定时6秒,中断到来P1.0输出低电平,电亮发光二极管汇编程序:ORG 0000H AJMP MAIN ORG 000BH ; 定时器0溢出中断矢量地址 AJMP ET0P ; 转跳中端服务子程序 ORG 0100HMAIN: SETB P1.0 MOV TMOD,#01H MOV TH0,#0CH ;设置125ms定时 MOV TL0,#0DCH MOV R3,#30 ;延时方法3:定时器与寄存器计数结合增大延时量 SETB EA ;中断总允许 SETB ET0 ;允许定时器0溢出中断 SETB TR0 ;启动定时器WAIT: CJNE R3,#00H,WAIT ;一旦溢出中断即刻执行000BH处的命令:AJMP ET0P CLR P1.0 ;定时结束(R3为0),P1.0变为低电平HERE: SJMP HEREET0P: MOV TH0,#0CH ;定时器中断服务子程序 MOV TL0,#0DCH DEC R3 ;需要48次中断(0.125×46=6) RETI ;返回 WAIT 处 END要求:调试时清晰把握转跳流程,并在上面程序中画线示明。

注意:点击定时器窗口中的TF0使其置1,可强迫溢出中断,并将#30改为#02H快捷C语言: #includechar data flag;sbit P1_0=P1^0;void time0() interrupt 1 using 1 /*“interrupt 1”中的1是中断源自然优先编号:*/{ /* 0:外部中断0 1:定时器0 2:外部中断1 3:定时器1 4:串行口*/ TH0=0x0C;TL0=0xDC;flag++;}void main(){ P1_0=1;TMOD=1;EA=1;ET0=1;TH0=0x0C;TL0=0xDC;TR0=1;flag=0; do{}while(flag<48); P1_0=0; do{}while(1);}2.外部中断 用外部中断INT0 (P3.2)触发P1.0输出低电平,点亮发光二极管汇编程序调试界面:问题:(1)如何继续?(2)IT0置1与清0有和差别?(通过修改、调试、观察来鉴别)C语言: +5v 8051P1.0 P3.2 I NT0#includesbit P1_0=P1^0;void service_int0() interrupt 0 using 2{ P1_0=0;}void main(){ EA=1;EX0=1;IT0=1; P1_0=1; do{}while(P1_0==1); do{}while(P1_0==0);} 实验5 航标灯 下面是航标灯电路示意图和汇编程序,请对其进行调试(打开定时器0、Port1、Port3窗口),观察能否实现天黑灯闪亮的控制。

程序按延时2秒让P1.7电平变化,达到闪亮效果ORG 0000H ;安排程序起点软件仿真时必须有 +Vcc AJMP MAIN ;跳到主程序 ORG 0003H ;外部中断时自动转到此(矢量地址) AJMP WBINT ;跳到中断服务子程序 灯 ORG 000BH ;定时器矢量地址(溢出中断自动转到此) AJMP T0INT ;跳到溢出中断子程序 P1.78051 P3.2 INT0 ORG 0100H ;主程序入口地址MAIN: MOV SP,#30H CLR P1.7 CLR IT0 ;低电平触发方式 CLR PX0 ;优先等级0 SETB EX0 ;外部中断0开 去感光电路 SETB EA (白天高电平,天黑为低电平0) HERE: AJMP HERE ;等待外部中断(天黑) ;WBINT:MOV TMOD,#01H ;设置T0为定时功能 MOV TL0,#0B0H MOV TH0,#3CH SETB PT0 ;定时器优先等级为1 SETB TR0 ;启动定时器计数 SETB ET0 ;定时器硬件中断开 MOV R7,#40 ;辅助延时HERE1:JNB P3.2,HERE1 ;天黑等待定时器溢出中断 CLR ET0 ;天亮... CLR TR0 CLR P1.7 RETI定时器T0延时50ms,模式1,计数初值:X=65536—12×50×1000/12 =3CB0HR7软件计数值:2×1000/50=40调试时还用40吗? ;T0INT:MOV TL0,#0B0H MOV TH0,#3CH DJNZ R7,EXIT ;2秒未到 MOV R7,#40 ;2秒到 CPL P1.7EXIT: RETI ; END 实验6 步进电机 编程控制4相步进电机,4个按钮选择4拍、8拍方式正反转。

include#define uchar unsigned char /* 无符号字符型变量可存放整数*/uchar cwf[4]={0x08, 0x04, 0x02, 0x01}; /* 4拍方式正向转动控制字节 */uchar ccwf[4]={0x01, 0x02, 0x04, 0x08}; /* 4拍方式反向转动控制字节 */uchar cwe[8]={0x08, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09}; /* 8拍正向转动控制字节 */uchar ccwe[8]={0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08}; /* 8拍反向转动控制字节*/uchar key; +Vcc去电机绕组线路P1.4 P1.0P1.5 P1.1P1.6 P1.2P1.7 P1.3void delay(uchar a){ /*延时函数*/ K1 uchar i,j; for(i=0;i

} } } }}实验7 串行通信奇偶校验1.请读程序:ORG 0000HTRAN: MOV SCON,#80H ;串行方式2,一帧数据11位 ;(起始位、?位数据、第九位TB8、停止位) MOV A,#0A8H ;数据存入A中时PSW.0自动跟踪A中1的奇偶性 MOV C,PSW.0 ;将奇偶校验位的值存入位累加器 MOV TB8,C ;再存入"第九位" MOV SBUF,A ;数据送发送缓冲器并启动发送LOOP: JBC TI,TRAN ;TI为1则清零转跳(一帧数据发送结束则硬件置中断位TI为1) SJMP LOOP ;等待一帧发送结束,波特率为振荡频率的1/64,本句执行14次 ;"JBC TI,TRAN"执行了15次,两条指令各需24个震荡周期, ;共耗时24*29=696个震荡周期,波特率周期为64个震荡周期, ;符合"当最后一个数据位(附加位)送完后使TI置1,置TXD=1 END ;作为停止位"(P120),实际上发送10位后便中断2.调试运行(1)单步调试过程中,会发现“LOOP”需要循环15次,能否快一些?能计算振荡频率吗? 解决方法是增加一句“MOV PCON, #80H”,再调试看看会有什么变化,为什么?(2)请观察默认状态是奇校验还是偶校验?将发送数据改为#0AAH会有什么变化?问题:为什么Port3的P3.1(TXD)点电平不随移位发送而变化? 实验8 转速自动稳定程序1.考虑占空比的脉冲发生程序 占空比指高电平占周期的比例,如:周期2.5秒,占空比20%,则高电平时间为0.5秒。

振荡频率12MHz,机器频率1MHz,机器周期1微秒(加1计数1次),定时器T0最大定时量(方式1):65536次×1微秒=65.536毫秒定时器T0定时10毫秒,需要计数10×1000/1=10000次,则得初值X=65536-10000, 满足高电平0.5秒需0.5×1000/10=50次溢出中断,满足2.5秒周期需250次中断 读懂程序,单步调试时可将50和250改成2、3,并点击TF0置1强制溢出main(){ TMOD=0x01; TH0=(65536-10000)/256; TL0=(65536-10000)%256; EA=1;ET0=1;TR0=1; do{}while(1);}#include#define uchar unsigned charuchar time=0,period=250,high=50;sbit P1_0=P1^0;timer0() interrupt 1 using 1{ TH0=(65536-10000)/256; TL0=(65536-10000)%256; if(++time==high) P1_0=0; else if(time==period){ time=0;P1_0=1;}}此程序不是简单地定时溢出将P1.0取反,那样得到的是高、低电平时间相同(占空比为50%)的脉冲,而现在只要改动“50”就能改变高电平的时间,如果用P1.0输出的脉冲驱动电机,转速随即改变。

2.自动稳速程序请读下面程序,看看它是怎样自动稳速的,需要了解C语言中的共用类型unioninclude#define uchar unsigned char#define uint unsigned intuchar time,status,percent,period;uint oldcount,target=500;bit one_round;sbit P1_0=P1^0;void timer0() interrupt 1 using 1{ /*T0溢出中断程序*/ TH0=(65536-1000)/256; TL0=(65536-1000)%256; ET0=1; if(++time==percent) P1_0=0; /*高电平转低电平,percent自动调整,慢则增快则减*/ else if(time==100){ time=0;P1_0=1;} /*周期到输出高电平*/}void tachmeter() interrupt 2 using 2{ /*外部中断1服务程序测一圈T1计数次数*/ union{uint word; /*共用类型含两个成员*/ struct{uchar hi;uchar lo;}byte;}newcount; newcount.byte.hi=TH1; /*取T1计数器的值*/ newcount.byte.lo=TL1; period=newcount.word-oldcount; /*共用型各成员共享同一内存空间*/ oldcount=newcount.word; /*只有一个值,各成员都能取用*/ one_round=1; /*转一圈标志置1*/}main(){ IP=0x04;/*外部中断1为高优先级*/ TMOD=0x11;/*定时器T0、T1以方式1工作,T1用以判断转速变化*/ TCON=0x54;/*01010100启动T0、T1,IT1=1边沿触发*/ TH1=0;TL1=0;/*T1初值为零,用以测量一圈计数次数,不用以定时*/ IE=0x86;/*等效EA=1、ET0=1、EX1=0,不许T1中断*/ for(;;){ /*循环等待T0、INT1中断, 处理各自的中断服务程序*/ if(one_round)/*转一圈,外部中断边沿触发一次,置标志位one_round为1*/ { if(period0)/*如定时器1转一圈计数次数大于100*/ --percent; /*将高电平时间缩短,但不能超过周期长*/ one_round=0; /*一圈标志清零*/ 能计算稳定在什么转速上吗? } } }time0() interrupt 1 { ……}函数关系: 定时器T0溢出中断服务程序 主函数等待两个中断 作用:控制P1.0高、低电平时间,形成main(){ ...... f (;;){ f (one_round){ …… } }} 能稳定转速的脉冲输出驱动电机。

外部中断INT1中断服务程序高优先级tachmeter() interrupt 2 { ……} 作用:取刚转过的一圈中T1计数值。

下载提示
相关文档
正为您匹配相似的精品文档