实验一 系统认识实验
实验1 系统认识实验
1.打开KEILC
2.新建工程,Project->New Project,弹出Create New Project
创建工程文件的位置,不允许是桌面,也不允许是根目录,要创建一个自己的目录,且以英文为名,比如p1。工程文件名同样也必须是英文。按保存后,弹出选择CPU对话框
3.选择ATMEL下面的AT89C52单片机,确定
4.弹出一个对话框,问:Copy Standard ...。无条件选NO,如果选了YES,则把项目里面自动添加的STARTUP.A51文件remove
5.接下来新建一个源码,选择File下的new...
6.保存源码,选择File下面的Save,注意保存在和项目文件相同的文件夹下。保存时,如果时汇编语言源码,文件后缀一定是asm,比如p1.asm
7.开始写代码
比如: ORG 0000H
MOV A,#3AH
MOV 20H,A
MOV DPTR,#1000H
MOVX @DPTR,A
END
8.把源码添加进项目中,选中项目的Source Group 1按右键选择Add Files to Group...,找到刚才的源文件,添加进来。注意:在所有的8次实验中,项目下面只允许一个源文件!!!系统是支持多个源文件在一个项目中,但你们不知道该如何协调多个文件的功能区分,所以,只允许一个源文件。如果不小心添加进来,则remove。
9.使用编译按钮,把源码编译成机器码,要看到0 Errors 0 Warning。偶尔有时候会有Warning,大部分情况下Warning是没问题的,但不排除有问题,辩证得看。
10.编译通过后,可以进行仿真了,今天第一次实验,我们不用仿真器,直接在KEILC系统里做虚拟调试
按Debug按钮后出现一个黄色的箭头,指向第一行代码,左边出现了寄存器区(如果看不到,则选择View下面的Project Window打开)。如果想看存储器,则默认在右下角(如果看不到,则选择View下面的Memory Window)。
11.在Memory Window的Address处输入地址,则可以看到对于的存储器中的内容。
如果想看内部存储器,则输入:D:20h,则可以看到内部存储器20h开始的所有内存中的值。如果想修改内存中的值,则在对应的位置按右键,选择Modify...
如果想看外部存储器,则输入:X:1000h,则可以看到外部存储器1000h开始的所有内存中的值,如果想修改,同样按右键。
12.单步运行,同时监测对应寄存器和存储器中内容的变化,看看是否符合程序运行的目标。按单步运行Step Over按钮,可以一条一条指令的运行,同时看寄存器和内存的变化。不要按Run连续运行,啥也看不到
START: CLR C
MOV R0,#41H
MOV R1,#51H
AD1: MOV A,@R0
ADD A,@R1
MOV @R0,A
DEC R0
DEC R1
MOV A,@R0
ADDC A,@R1
MOV @R0,A
RET
实验二 汇编语言跑马灯
实验2 汇编语言跑马灯
1. 第2个板子是主控板+电源板,左下角有一个红色按钮,是交流电源开关,这个开关,做实验时可以保持闭合状态。实验做完后关闭
2. 第2个板子的右下角有一个拨码开关,是直流开关,这个开关,在接线时,不能闭合,保持直流电源无电状态,当接好线,检查无误后,再打开这个开关
3. 第2个板子的下方中间位置就是一系列的电源提供端,有5V,有GND,还有其他电源模块,按需取用,左下方抽屉里有一些线可以用。尽量使用和电源圆角插座相同的颜色的线连接,这样容易排错。
4. 除了第2板子有电,其他板子都是没电。所以如果用到其他板子,用连接线接到其他板子,第一块板子的下方,有红色和黑色圆角插座,必须连接到第2块板子的电源5V和GND。
5. 我们用到的CPU,在仿真器里面,所以大家不要把仿真器拆下来,如果你看到拆下来了,检查一下排线红色端是不是朝上。
6. CPU上面有一些端子引线,上面标识了P0,P1,P2,P3。这四个黑色的排线插座分别对应CPU的四个端口。可以使用灰色的排线进行连接。再往上还有一些圆口插座,上面标识了P0.0~P0.7,.....。也是CPU的端口线,这个线用单股线连接
7. 第一块板子的第4个部分指示灯模块,每个圆角插座对应一个灯,黑色的插座对应着8个灯。
8. 第一块板子的第五部分,对应着8个拨码开关,每个圆角插座对应一个开关。实验要求:
1. 用8个指示灯模块,设计一个跑马灯,先让第一个灯亮,然后让第2个灯亮,。。。。让第8个灯亮,接下来让第一个灯亮,循环往复。
○○○○○○○●
○○○○○○●○
○○○○○●○○
○○○○●○○○
○○○●○○○○
○○●○○○○○
○●○○○○○○
●○○○○○○○
2. 用一个拨码开关输入到单片机,当拨码开关往上拨时,执行循环左移,当拨码开关往下拨时,执行右移,灯亮的次反过来。
拨码开关往上拨:
○○○○○○○●
○○○○○○●○
○○○○○●○○
○○○○●○○○
○○○●○○○○
○○●○○○○○
○●○○○○○○
●○○○○○○○
拨码开关往下拨
●○○○○○○○
○●○○○○○○
○○●○○○○○
○○○●○○○○
○○○○●○○○
○○○○○●○○
○○○○○○●○
○○○○○○○●涉及到技术:
1. 如何把程序下载,连接蓝色的线到计算机USB口,另外一端接到仿真器。在设备管理器的端口处出现一个新的COM。一般是COM3
2. 把工程里的target1的OPTION里的DEBUG切换到USE KEIL-MONITOR51,然后在后面的SETTING处,把端口切换到刚才新出现的端口,比如COM3,波特率切换到115200,而不是11520
3. 此时再按DEBUG按钮,程序会自动下载到仿真器的CPU里。
4. 如何驱动指示灯,假如LED的8个灯接到P0口
这个灯是低电平亮
MOV A, #0FEH; FE(11111110)是最低位为0.所以对应的P0.0口灯会亮
MOV P0, AMOV A, #0FDH; FD(11111101)是次低位为0.所以对应的P0.1口灯会亮
MOV P0, A5. 如何接受按键的状态,假设拨码开关接在P1.0上
;第一种读法,只读一位
MOV C, P1.0;读接在P1.0口的一个状态
JC LED1;第二种读法,读P1口上的全部8位
MOV A, P1;读接在P1口的八个状态6. 如何延时
两重循环,做延时
主程序
CALL DELAY;
子程序
DELAY:
MOV R5, #200
DELAY2: MOV R6, #200
DELAY1: DJNZ R6, DELAY1
DJNZ R5, DELAY2
RET
MOV A,#0FEH ;LED低电平点亮
START:
MOV P0,A ;将A代表的8位数据,点亮相应LED
CALL DELAY
MOV C,P1.0 ;P1.0是位操作,写入进位位C
JC LED1 ;进位为1,则跳转到LED1
RL A ;左移一位
JMP START
LED1:
RR A ;右移一位
JMP START
DELAY:
MOV R3,#200
DELAY2: MOV R4,#200
DELAY1: DJNZ R4, DELAY1
DJNZ R3, DELAY2
RET
END
单片机连线图
实验三 C语言的复杂跑马灯
实验3 C语言的复杂跑马灯
1. 创建一个C语言工程
2. 创建一个源码。用.c作为后缀,源码里必须有一个死循环。因为我们的单片机运行,是要一直跑的,不是跑一会就结束,是要永远跑的,所以必须要有一个死循环,代码永远跑。
#include <reg52.h>main()
{
while(1)
{
}
}
3. 实现一个能用拨码开关控制的复杂跑马灯
(1)拨码开关1往上时,实现最普通的左移跑马灯
○○○○○○○●
○○○○○○●○
○○○○○●○○
○○○○●○○○
○○○●○○○○
○○●○○○○○
○●○○○○○○
●○○○○○○○
(2)拨码开关2往上时,实现
●○○○○○○●
○●○○○○●○
○○●○○●○○
○○○●●○○○
○○●○○●○○
○●○○○○●○
●○○○○○○●
(3)拨码开关3往上时,实现八个灯闪烁
●●●●●●●●
○○○○○○○○
●●●●●●●●
○○○○○○○○涉及的操作
#include <reg52.h>
sbit key1 = P1^0;//拨码开关1
sbit key2 = P1^1;//拨码开关2
sbit key3 = P1^2;//拨码开关3void delay()
{
unsigned char i,j;
for(i = 0; i < 200; i++)
for(j = 0; j < 200; j++)
;
}main()
{
unsigned char led,key;
while(1)
{
//控制灯的显示
led = 0x7e;//01111110
P0 = led; //最高和最低位灯亮,其他不亮
//第一种按键读取方式,一次读八个输入
key = P1;
//判断八个输入中的每一个
if(key&0x01) //拨码开关1,最低位按键判断
{
}
if(key&0x02) //拨码开关2,次低位按键判断
{
}
if(key&0x04) //拨码开关3,次次低位按键判断
{
}//第二种按键读取方式,一次判断一个按键
if(key1) //拨码开关1,最低位按键判断
{
}
if(key2) //拨码开关2,次低位按键判断
{
}
if(key3) //拨码开关3,次次低位按键判断
{
}
delay();
}
}
#include <REGX52.H>
sbit key1 = P1^0; // 拨码开关1
sbit key2 = P1^1; // 拨码开关2
sbit key3 = P1^2; // 拨码开关3
unsigned char LED1[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
unsigned char LED2[] = {0x7e, 0xbd, 0xdb, 0xe7, 0xdb, 0xbd, 0x7e};
void delay()
{
unsigned char i, j;
for (i = 0; i < 200; i++)
for (j = 0; j < 200; j++)
;
}
void main()
{
unsigned char led, key, i;
while (1)
{ //实现循环左移
if (key1)
{
for (i = 0; i < 8; i++)
{
led = LED1[i];
P0 = led;
delay();
key = P1;
}
}
if (key2)
{ //实现双向循环
for (i = 0; i < 7; i++)
{
led = LED2[i];
P0 = led;
delay();
key = P1;
}
}
if (key3)
{
led = 0xff; // 11111111, LED全灭
P0 = led;
delay();
key = P1;
led = 0x00; // 00000000, LED全亮
P0 = led;
delay();
key = P1;
}
}
}
单片机连线图
实验四 C语言的抢答器
实验4 C语言的抢答器
1. 创建一个C语言工程
2. 创建一个源码。用.c作为后缀,源码里必须有一个死循环。因为我们的单片机运行,是要一直跑的,不是跑一会就结束,是要永远跑的,所以必须要有一个死循环,代码永远跑。
#include <reg52.h>main()
{
while(1)
{
}
}
3. 实现一个能用点动开关控制的抢答器,同时按下多个点动开关,找出最先按下的那个开关,并显示在8段数码管上,注意要保持住最先按下键对应的显示结果,不受后面其他人多次点按的影响。
4.读按键
同时读8个点动开关
unsigned char key;
key = ~P1;//实验平台的开关,按下是0,此处对P1的输入取反,按下是1,方便判断
//判断按键的第一种写法
if(key&0x01){
}
else if(key&0x02){
}
//判断按键的第二种写法
switch(key)
{
case 0x01:
break;
case 0x02:
break;
.....
}5. 显示8段数码管
P0 = seg8---a---
| |
| |
f b
| |
| |
---g---
| |
| |
e c
| |
| |
---d--- _dp_gfedcba
为了显示1,要点亮b和c,则送给P0口显示的应该是00000110,seg8=06H
为了显示2,要点亮a,b,d,e和g,则送给P0口显示的应该是01011011,seg8=5BH
#include <reg52.h>
unsigned char seg8[] = {0x06,0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f};
void main()
{
unsigned char x = 1;
while (1)
{
unsigned char key;
key = ~P1;
if (x)
{
if (key & 0x01)
{
P0 = seg8[0];
x = 0;
}
else if (key & 0x02)
{
P0 = seg8[1];
x = 0;
}
else if (key & 0x04)
{
P0 = seg8[2];
x = 0;
}
else if (key & 0x08)
{
P0 = seg8[3];
x = 0;
}
else if (key & 0x10)
{
P0 = seg8[4];
x = 0;
}
else if (key & 0x20)
{
P0 = seg8[5];
x = 0;
}
else if (key & 0x40)
{
P0 = seg8[6];
x = 0;
}
else if (key & 0x80)
{
P0 = seg8[7];
x = 0;
}
}
}
}
单片机连线图
实验五 汇编语言中断
实验5 汇编语言外部中断
1. 创建一个汇编语言的工程。源码后缀asm
2. 中断代码的框架
ORG 0000H;上电后的程序启动地址
JMP STARTORG 0003H;外部中断0的入口地址
JMP EINT0ORG 0013H;外部中断1的入口地址
JMP EINT1START: ;此处写主程序
;主程序中至少包含一个无限循环
EINT0: ;此处写外部中断0的代码
;在中断服务程序里,禁止直接跳转到主程序
;必须通过RETI返回被中断的位置
RETIEINT1: ;此处写外部中断1的代码
;在中断服务程序里,禁止直接跳转到主程序
;必须通过RETI返回被中断的位置RETI
3. 如何初始化中断
SETB IT0;定义外部中断0为边沿触发
SETB EX0;使能外部中断0
SETB IT1;定义外部中断1为边沿触发
SETB EX1;使能外部中断1
SETB EA;使能总中断4. 本次实验的任务
在主程序(网上的代码,跑马灯都是写在中断里的)做一个左移跑马灯和一个右移跑马灯,但不跑,用外部中断0和中断1控制是否跑动,当触发外部中断0时,做左移八次的跑马灯。当触发外部中断1时,做右移八次的跑马灯。5. 怎么触发中断?
外部中断0接P3.2口,外部中断1接P3.3口
使用按键模块中的两个按键,接到P3.2和P3.3口,则按下按键时,会在端口上产生下降沿。则会导致单片机内部触发中断
ORG 0000H;上电后的程序启动地址
JMP START
ORG 0003H;外部中断0的入口地址
JMP EINT0
ORG 0013H;外部中断1的入口地址
JMP EINT1
START: ;此处写主程序
SETB IT0;定义外部中断0为边沿触发
SETB EX0;使能外部中断0
SETB IT1;定义外部中断1为边沿触发
SETB EX1;使能外部中断1
SETB EA;使能总中断
;主程序中至少包含一个无限循环
MOV A, #0FEH
CJNE R7,#0H,LEFT
LEFT:
CJNE R7,#10H,RIGHT
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
CALL DELAY
RL A
MOV P0, A
CALL DELAY
MOV R7,#40H
JMP START
RIGHT:
CJNE R7,#20H,START
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
RR A
MOV P0, A
CALL DELAY
MOV R7,#40H
JMP START
EINT0: ;此处写外部中断0的代码
MOV R7,#10H
RETI
EINT1: ;此处写外部中断1的代码
MOV R7,#20H
RETI
DELAY:
MOV R3,#200
DELAY2: MOV R4,#200
DELAY1: DJNZ R4,DELAY1
DJNZ R3,DELAY2
RET
END
单片机连线图
实验六 C语言的中断
实验6 C语言外部中断
1. 创建一个C语言的工程。源码后缀c
2. C语言的中断代码框架
#include "reg52.h"
void int0() interrupt 0 //INT0中断
{
}
void int1() interrupt 2 //INT1中断
{
}
void main()
{
while(1)
{
}
}3. C语言初始化中断
IT0 = 1;
EX0 = 1; //中断0
IT1 = 1;
EX1 = 1; //中断1
EA = 1;4. 程序需求
(1) 必须在主程序中实现左移跑马灯和8段数码管上0~9循环计数,而不是在中断中实现
(2) 用两个按键触发中断(接到P3.2/P3.3),当中断0触发时,执行左移循环跑马灯,当中断1触发时,执行在8段数码管上的0~9循环计数
#include "reg52.h"
unsigned char x=0;
unsigned char SEG[]={0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char LED[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
void delay()
{
unsigned char i,j;
for(i = 0; i < 200; i++)
for(j = 0; j < 200; j++)
;
}
void int0() interrupt 0 //INT0中断
{
x=1;
}
void int1() interrupt 2 //INT1中断
{
x=2;
}
void main()
{
IT0 = 1;
EX0 = 1; //中断0
IT1 = 1;
EX1 = 1; //中断1
EA = 1;
while(1)
{
unsigned char i;
//判断按键的第一种写法
if(x==1)
{
for (i=0;i<8;i++)
{
P0=LED[i]; //查表法
delay();
}
x=0;
}
else if(x==2)
{
for(i=0;i<9;i++)
{
P2=SEG[i];
delay();
}
x=0;
}
}
}
单片机连线图
实验七 汇编语言定时器
实验7 汇编语言定时器
1. 创建一个汇编语言的工程。源码后缀asm
2. 中断代码的框架
ORG 0000H;上电后的程序启动地址
JMP STARTORG 000BH;定时器0中断的入口地址
JMP TIME0ORG 001BH;定时器1中断的入口地址
JMP TIME1START: ;此处写主程序
TIME0: ;此处写定时器0中断的代码
RETI
TIME1: ;此处写定时器1中断的代码
RETI
3. 如何初始化定时器
;初始化定时器参数
本系统的主频12MHZ
上课时,案例是方式0,我在课堂上修改成了方式1
涉及到TMOD:GATE C/T M1 MO
计算 TH0 TL0 TH1 TL1
自己搞定
;初始化定时器0中断
SETB TR0;启动定时器0
SETB ET0;使能定时器0中断
;初始化定时器1中断
SETB TR1;启动定时器1
SETB ET1;使能定时器1中断
SETB EA;使能总中断4. 今天的任务
(1)做方波信号发生器,用定时器在一个IO口上产生1HZ方波(CPU主频是12MHZ,用16位定时器是无法产生0.5秒延时的,需要再配合计数器),把IO口接在指示灯上,肉眼能看到1HZ闪烁
(2)利用定时器的0.5秒延时,控制跑马灯的延时,产生每隔0.5秒灯左移的效果
ORG 0000H
AJMP START
ORG 000BH;定时器0中断的入口地址
AJMP TIME0
ORG 001BH
AJMP TIME1
START:
MOV A,#0FEH ;LED低电平点亮
MOV SP,#60H
MOV TMOD,#11H
MOV R0,#10H
MOV TH1,#09H
MOV TL1,#0DCH
MOV R1,#10H
MOV TH0,#09H
MOV TL0,#0DCH
SETB TR0;启动定时器0
SETB ET0;使能定时器0中断
SETB TR1
SETB ET1
SETB EA
MAIN: AJMP MAIN
TIME0:
DJNZ R1,NEXT0
MOV P0,A
RL A
MOV R1,#10H
MOV TH0,#09H
MOV TL0,#0DCH
NEXT0: RETI
TIME1:
DJNZ R0,NEXT1
CPL P2.0
MOV R0,#10H
MOV TH1,#09H
MOV TL1,#0DCH
NEXT1: RETI
END
单片机连线图
实验八 C语言的定时器
实验8 C语言定时器
1. 创建一个C语言的工程。源码后缀c
2. C语言的中断代码框架
#include "reg52.h"
void int0() interrupt 1 //定时器0中断
{
}
void main()
{
while(1)
{
}
}3. C语言定时器初始化
TR0 = 1;//启动定时器0
ET0 = 1;//使能定时器0中断
EA = 1;//使能总中断
4. 程序需求
(1)做方波信号发生器,用定时器在一个IO口上产生1HZ方波(CPU主频是12MHZ,用16位定时器是无法产生0.5秒延时的,需要再配合计数器),把IO口接在指示灯上,肉眼能看到1HZ闪烁
(2)利用定时器的0.5秒延时,控制跑马灯的延时,产生每隔0.5秒灯左移的效果
#include "reg52.h"
sbit p11=P3^1;
sbit p22=P3^0;
unsigned A=0x01;
unsigned char c=0;
unsigned char x,y=0;
void time0() interrupt 1 //定时器0中断
{
TH0=0x3C;
TL0=0XB0;
c++;
if(c==10)
{
c=0;
if(x==1)
{
P1=~A;
A=A<<1;
if(A==0)
{
A=0x01;
}
}
if(y==1)
{
P1=~A;
A=A>>1;
if(A==0)
{
A=0X80;
}
}
}
}
void main()
{
P1=~A;
TMOD=0x01;
TH0=0x3C;
TL0=0xB0;
TR0 = 1;//启动定时器0
ET0 = 1;//使能定时器0中断
EA = 1;//使能总中断
while(1)
{
if(p11==0)
{
x=1;
y=0;
}
if(p22==0)
{
x=0;
y=1;
}
}
}