单片机实验报告
南京晓庄学院电子工程学院
课程名称:姓 名:专 业:年 级:学 号:实验报告
单片机系统设计与应用
森
电子信息科学与技术
14级 05
2016年 12 月 1 日
实验项目列表
1、实验箱端口为com6。 2、芯片选择切换到51
3、停止运行使用实验箱上的复位按钮
实验室号:___ 实验时间: 成绩:
实验一 仿真软件的使用
1.实验目的和要求
1)熟悉Keil C51软件界面,以及编辑、编译、运行程序的步骤;
2)掌握单片机仿真软件使用和调试的方法。
2.实验原理
Keil C51软件使用
在Keil C51集成开发环境下,建立一个工程并编辑源程序,熟悉Keil C51集成开发环境下各种菜单、命令的使用。
3.主要仪器设备(实验用的软硬件环境)
安装有Keil C51软件的PC机1台
4.操作方法与实验步骤
Keil C51软件使用 (1)建立用户文件夹 (2)建立工程
(3)建立文件并编码。输入以下源程序,并保存在项目所在的目录中 (4)把文件加入工程中
(5)编译工程。编译时观察在界面下方的“Build”页中的到编译错误信息和使用的系统资源情况等。
(6)调试。利用常用调试命令,如复位、运行、暂停、单步、单步跳过、执行完当前子程序、运行到当前行、下一状态、打开跟踪、观察跟踪、反汇编窗口、观察窗口、代码作用范围分析、1#串行窗口、内存窗口、性能分析、工具按钮等命令进行调试,观察并分析调试结果。
(7)目标代码文件的生成。运行生成相应的.HEX文件。
5.实验内容及程序
1)从DATA区地址起始地址为40H的连续10个内存单元的内容传送到XDATA区起始地址为2000H的10个内存单元中。
注意:DATA区地址起始地址为40H的连续10个内存单元必须先赋初值。 P83-5源程序
#include
#define uchar unsigned char
xdata unsigned char buffer1[10]_at_ 0x2000;
//在xdata区定义数组变量BUF1,首地址为2000H
data unsigned char buffer2[10]_at_ 0x40;
//在data区定义数组变量BUF2,首地址为40H
void main(void)
{ uchar i; for(i=0;i
buffer2[i]=buffer1[i]; //把data区中的内容传送给xdata区 while(1); }
6.实验现象
P83-5运行效果图
个单元的数据拼成56H,存入XDATA区地址为2000H的单元。 程序(程序中请对应写出关键注释语句) P275源程序
#include #include
#define a XBYTE[0x2001] #define b XBYTE[0x2002] main(void) {
a=0x05; b=0x06; a=a
2)将DATA区地址为20H的单元赋初值为05H,地址为21的单元赋初值为06H,将这两
P275运行效果图
实验室号:___ 实验时间: 成绩:
实验二 单片机I/O接口应用—流水灯
1.实验目的和要求
1)进一步掌握单片机仿真软件的使用方法。
2)掌握单片机最小系统的构成。
3)掌握单片机I/O口的使用方法,如何控制I/O口检测按键及驱动LED发光二极管。 4)熟悉C51程序编程和调试方法。
2.电路原理图(附proteus电路原理图)
3.主要仪器设备(实验用的软硬件环境)
安装有Keil C51软件与Proteus仿真软件PC机1台 单片机试验箱一套
4.实验说明及实验步骤
P1口为准双向口,P1的每一位都能独立地定义为输出线或输入线,作为输入的口线,
必须向锁存器相应位写入“1”,该位才能作为输入。
延时程序的实现。现常用的有两种方法,一是用定时器中断来实现,一是用指令循环实
现。在系统时间允许的情况下可以采用后一种方法。本实验中延时子程序采用指令循环来实现。 1)源程序设计
分析设计要求,根据任务要求,绘制源程序流程图,然后使用Keil C进行源程序文件的设计与调试,观察并分析程序调试结果。 2)硬件运行
加载目标代码至单片机中,运行,观察运行结果
5.实验内容及程序
1)在P1口实现流水灯。 #include #include //包含移位函数的头文件 #define uchar unsigned char #define uint unsigned int void delay(uint i) //延时函数 { uchar t; while (i--)
{ for(t=0; t
void main( ) //主程序
{ P1=~0xfe; //高电平点亮第一个灯 while (1) { delay( 500 ); //500为延时参数 P1=_crol_(P1,1) ; //P1中的数据循环左移1位,实现流水灯 } }
2)任选某P端口接开关,控制流水灯的启动和停止。 接线:P10-P17接D0-D7;P2.x接K0 #include #include //包含移位函数的头文件 #define uchar unsigned char #define uint unsigned int void delay(uint i) //延时函数 { uchar t; while (i--)
{ for(t=0; t
sbit KEY=P2^0; //定义P2^0口作为开关 void main( ) //主程序
{ P1=~0xfe; //高电平点亮第一个灯
while (1) { if(KEY==0) //开关接地,低电平启动流水灯 { delay( 500 ); //延时 P1=_crol_(P1,1); //P1中的数据循环左移1位,实现流水 } } }
*3)设计花样流水灯:自行设计两种花样流水灯,利用开关实现两种流水灯的切换,例如K0控制第一种流水灯的启动和停止;K1控制第二种流水灯的启动和停止,两种流水灯可以通过两个开关实现切换。
程序(程序中请对应写出关键注释语句) #include
#define uchar unsigned char //定义无符号字符型变量 sbit S0=P0^0; //将S0定义为P0.0 unsigned char state;
void flow(void); //申明函数flow
void key_scan(void); //申明函数key_scan
void delay( ) //延时函数 {
uchar i,j;
for(i=0;i
void delay1ms(void) //延时消抖函数 {
uchar i,j;
for(i=0;i
void main( ) {
state=0;
while(1) {
key_scan(); switch(state) {
case 0:P1=0xff;break; case 1:flow( );break; }
} }
void key_scan(void) //开关检测函数 {
P0=0xff;
if((P0&0x0f)!=0x0f) //检测到有按键按下 {
delay1ms( ); //延时1ms再去检测 if(S0==0) state=0; else state=1; } }
void flow(void) //流水灯点亮函数 {
P1=0xfe; delay( ); P1=0xfd; delay( ); P1=0xfb; delay( ); P1=0xf7; delay( ); P1=0xef; delay( ); P1=0xdf; delay( ); P1=0xbf; delay( ); P1=0x7f; delay( ); }
6.实验讨论及分析
如果将P1口高4位定义为输入,低4位定义为输出,将高4位输入的值在低4位显示出来,请写出对应程序。
实验室号:___ 实验时间: 成绩:
实验三 外部中断实验——工业顺序控制模拟
1.实验目的和要求
1)掌握单片机系统中断原理和使用方法。
2)掌握中断处理程序的编写方法
2.电路原理图(附proteus电路原理图)
3.主要仪器设备(实验用的软硬件环境)
安装有Keil C51软件与Proteus仿真软件PC机1台
单片机试验箱一套
4.实验说明及实验步骤
在工业控制中,象冲压、注塑、轻纺、制瓶等生产过程,都是一些继续生产过程,按某种顺序有规律的完成预定的动作,对这类继续生产过程的控制称顺序控制,象注塑机工艺过程大致按“合模注射延时开模产伸产退”顺序动作,用单片机最易实现。
1)源程序设计
分析设计要求,根据任务要求,绘制源程序流程图,然后使用Keil C进行源程序文件的设计与调试,观察并分析程序调试结果。
2)硬件运行
加载目标代码至单片机中,运行,观察运行结果
5.实验内容及实验程序
P1口控制注塑机的八道工序,现模拟控制八只发光二极管的点亮,即正常情况下P1口走亮流水(低电平点亮LED)。P2.4为开工启动开关,高电平启动。未启动及开关停止时LED全灭。INT0为外部故障1输入模拟开关,产生故障1使P1.0~P1.3口接的LED闪烁8次 ;INT1
为外部故障2输入模拟开关,产生故障2使P1.4~P1.7口接的LED闪烁8次 ; 接线:P10-P17接D0-D7;,INT0接KK1-(单次脉冲);INT1接KK2-(单次脉冲) 附程序(程序中请对应写出关键注释语句)
#include
#define uchar unsigned char //定义无符号字符变量
#define uint unsigned int //定义无符号整型变量
sbit K0=P2^4; //将K0定义为P2.4
void delay(uint t); //申明延时函数delay()
void delay(uint t) //延时函数
{
uchar j;
for(;t>0;t--)
for(j=0;j
;
}
void main(void)
{
uchar display[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯显示数组 int a;
while(1)
{
if(K0==1) //当开关为1
{
IE=0x85;
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
PX0=0; //外部中断0为低优先级
PX1=1; //外部中断1为高优先级
for(a=0;a
{
delay(500); //延时
P1=display[a]; //将已经定义的流水灯显示数据送入P1口
}
}
else
if(K0==0) //当开关为0
{
IE=0x00;
P1=0x00; //P1口全亮
delay(500); //延时
}
}
}
void int0_isr(void) interrupt 0 //外部中断0的服务函数
{
uchar n;
for(n=0;n
{
P1=0x0ff; //全灭
delay(500); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
delay(500); //延时
}
}
void int1_isr(void) interrupt 2 //外部中断1的服务函数
{
uchar m;
for(m=0;m
{
P1=0x0ff; //全灭
delay(500); //延时
P1=0x0f; //低4位LED灭,高4位LED亮
delay(500); //延时
}
}
开关未启动LED全灭
启动开关正常走流水
中断T0使P1.0~P1.3口接的LED闪烁8次
使P1.4~P1.7口接的LED闪烁8次
中断结束回到主程序又开始正常走流水
运行效果图
6.实验讨论及分析
1)INT0和INT1的中断优先级如何?在什么样的情况下会出现中断嵌套?如果要使INT1的中断优先级为高,该如何修改程序?
答:INT0和INT1的中断优先级如何是采用的都是低优先级。
在什么样的情况下会出现中断嵌套是T0和T1有一个优先级高。
如果要使INT1的中断优先级为高,该如何修改程序是IP=0; 改为
PX0=0;PX1=1
实验室号:___ 实验时间: 成绩:
实验四/五 定时计数器实验
1.实验目的和要求
熟悉单片机内部定时/计数器功能,掌握初始化编程方法。
2.电路原理图(附proteus电路原理图)
3.主要仪器设备(实验用的软硬件环境)
安装有Keil C51软件与Proteus仿真软件PC机1台
单片机试验箱一套
4.实验说明及实验步骤
设单片机的主频为12Mhz,在方式1下最大定时时间仅为毫秒数量级,所以采用定时
器和软件循环结合的方法。
在计数工作中,工作方式设为方式2(可自动重赋初值),初值设为0xff,每计数一次产
生一次溢出中断,所以进中断次数即为计数个数。
1)源程序设计
分析设计要求,根据任务要求,绘制源程序流程图,然后使用Keil C进行源程序文件的设计与调试,观察并分析程序调试结果。
2)硬件运行
加载目标代码至单片机中,运行,观察运行结果
5.实验内容及实验程序
1)将定时器0设置为方式1,编写程序在P1.0上产生周期为1s的方波信号,可通过LED或示波器观察P1.0的输出。
*如果产生占空比为4:1的方波,程序应该如何修改。(假设周期不变)
接线:P10接D0,或接示波器
附程序(程序中请对应写出关键注释语句)
#include
sbit P1_0=P2^4; //定义特殊功能寄存器P1的为变量P2_4
unsigned int counter=1000;//定义循环次数
void main( )
{
TMOD=0x01; //定时器T0为方式1
EA=1; //开总中断
ET0=1; //开定时器TO中断
TH0=(65536-500)/256;//置T0高8位初值
TL0=(65536-500)%256;//置T0低8位初值
TR0=1; //启动定时器T0
while(1) //循环等待
{;}
}
void TIM0(void) interrupt 1 using 0 //T0中断函数
{
TH0=(65536-500)/256;//重新赋值
TL0=(65536-500)%256;
counter--; //循环次数减一
if(counter
{
P1_0=~P1_0; //P1口按位取反
counter=1000; //重置循环次数
}
}
运行效果图
#include
#define uchar unsigned char //定义无符号字符变量
uchar time;
//定义time
uchar counter=100; //定义周期
uchar high=80; //定义高电平时长
sbit p1_0=P2^4; //定义特殊功能寄存器P1的为变量P2_4
void main( )
{
TMOD=0x01; //定时器T0为方式1
TH0=(65536-5000)/256;//置T0高8位初值
TL0=(65536-5000)%256;//置T0低8位初值
EA=1; //开总中断
ET0=1; //开定时器T0中断
TR0=1; //启动定时器T0
time=0;
while(1)
{;}
}
void timer0() interrupt 1 //T0中断程序
{
TH0=(65536-5000)/256; //重新赋值
TL0=(65536-5000)%256;
time++;
if(time==high)
p1_0=0;
if(time==counter)
{
time=0;p1_0=1;
}
}
运行效果图
2) 将定时器/计数器1设定为计数方式,方式2,计数器初值设为0xff,每计数一次溢出产生一次中断。 P1口连接发光二极管,执行程序,利用按钮产生单脉冲信号,观察LED上计数脉冲个数。例如:00000001为1,00000010为2,00000011为3,依次显示。(亮为1) 接线:T1接单脉冲脉冲信号KK1-,P10-P17接D0-D7
#include
sbit P1_0=P2^4; //定义特殊功能寄存器P1的为变量P2_4
unsigned char counter=100;//定义循环次数
int f;
void main()
{
TMOD=0x51;
TL0=(65536-5000)%256;//置T0低8位初值
TH0=(65536-5000)/256; //置T0高8位初值
EA=1;//开总中断
ET0=1;//
ET1=1;
TH1=0xff;
TL1=0xff;
f=0;
TR1=1;
while(f==0);
TR0=1;
while(1)
{;}
}
void timer0( ) interrupt 1 using 0 //外部中断1的服务函数
{
TL0=(65536-5000)%256;//重新赋值
TH0=(65536-5000)/256;
counter--;//循环次数减一
if(counter
{
P1_0=~P1_0; //P1口按位取反
counter=100; //重新定义循环次数
}
}
void timer1( ) interrupt 3 using 0 //外部中断2的服务函数
{
TH1=0xff; //重新赋值
TL1=0xff;
TR1=0;
f=1;
}
运行效果图
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define C8255_A XBYTE[0x7f00] // A
#define C8255_B XBYTE[0x7f01] // B
#define C8255_C XBYTE[0x7f02] // C
#define C8255_CON XBYTE[0x7f03] // Control
uchar code tube[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // 段选
uchar code chos[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; // 位选
uchar counter = 0;
void init_8255(); // 初始化8255
void init_timer1(); // 初始化计数器1
void display(uchar i); // 显示函数
void delay(uint z); //延时函数
void main()
{
init_8255();
init_timer1();
while(1)
{
display(counter);
P1 = counter;
}
}
void display(uchar counter)
{
uchar i,j;
uchar ge,shi,bai;
bai = counter / 100;
shi = counter / 10 %10;
ge = counter % 10;
for(i=0;i
{
if(i==0)j=bai;
if(i==1)j=shi;
if(i==2)j=ge;
C8255_B = chos[i]; //PB口位码
C8255_A = tube[j];
delay(1);
}
/*C8255_B = chos[0]
C8255_A = tube[bai];
delay(1);
C8255_B = chos[1]
C8255_A = tube[shi];
delay(1);
C8255_B = chos[3]
C8255_A = tube[ge];
delay(1);
*/
}
void init_8255()
{
C8255_CON = 0x80;
}
void init_timer1()
{
TMOD = 0x60; // 01100000计数、八位自动重装
EA = 1;
ET1 = 1;
TR1 = 1;
TH1 = 0xff;
TL1 = 0xff;
}
void timer1() interrupt 3
{
if(counter >255)
counter = 0;
counter++;
}
void delay(uint z)
{
uint x,y;
for(x=z; x>0; x--);
for(y=114; y>0; y--);
}
运行效果图
6.实验讨论及分析
实验室号:___ 实验时间: 成绩:
实验六 综合实验
1.实验目的和要求
利用用8255实现I/O口扩展,实验键盘检测及数码管显示。
2.电路原理图(附proteus电路原理图)
3.主要仪器设备(实验用的软硬件环境)
安装有Keil C51软件与Proteus仿真软件PC机1台
单片机试验箱一套
4.实验说明与实验步骤
8255端口地址定义
#define C8255_A XBYTE[0x7F00]
#define C8255_B XBYTE[0x7F01]
#define C8255_C XBYTE[0x7F02]
#define C8255_CON XBYTE[0x7F03]
共阴极七段码:0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0x7f, 0x6f, 0x77, 0x7c, 0x39,
0x5e, 0x79, 0x71
1)源程序设计
分析设计要求,根据任务要求,绘制源程序流程图,然后使用Keil C进行源程序文件的设计与调试,观察并分析程序调试结果。
2)硬件运行
加载目标代码至单片机中,运行,观察运行结果
5.实验内容及程序
控制8255完成键盘扫描及数码显示
键盘采用4×4键盘,每个数码管显示值可为0~F16个数。键盘编号为0~F,当按下其中一个按键时,将该按键对应的编号在一个数码管上显示出来,当再按下一个按键时,便将这个按键的编号在下一个数码管上显示出来,数码管上可以显示最近6次按下的按键编号。 程序中请对应写出关键注释语句
#include
#define uint unsigned int
#define uchar unsigned char
uchar code
tube[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; // 0 to F,段码
uchar code chos[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; 位码
uchar cord_l,cord_h;
void delay(uint z);//申明延时函数
void keyPro();//申明按键扫描函数
uchar keyScan();//申明开关检测函数
void main(void)
{
P0=0;
P1=0;
while(1)
{
keyPro();
}
}
uchar keyScan()//开关检测函数
{
P3=0xf0;
if(P3!=0xf0)
{
delay(5);
if(P3!=0xf0)
{
cord_l=P3;
P3=cord_l|0x0f;
cord_h=P3&0x0f;
return(cord_l+cord_h);
}
}
}
void keyPro()//按键扫描函数
{
switch(keyScan())
{
//Line 1
case 0xee:P0=tube[0];break;
case 0xde:P0=tube[1];break;
case 0xbe:P0=tube[2];break;
case 0x7e:P0=tube[3];break;
//Line 2
case 0xed:P0=tube[4];break;
case 0xdd:P0=tube[5];break;
case 0xbd:P0=tube[6];break;
case 0x7d:P0=tube[7];break;
//Line 3
case 0xeb:P0=tube[8];break;
case 0xdb:P0=tube[9];break;
case 0xbb:P0=tube[10];break;
case 0x7b:P0=tube[11];break;
//Line 4
case 0xe7:P0=tube[12];break;
case 0xd7:P0=tube[13];break;
case 0xb7:P0=tube[14];break;
case 0x77:P0=tube[15];break;
}
}
void delay(uint z)//延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
6.实验现象
运行效果图
#include "Absacc.h"
#define C8255_A XBYTE[0x7F00] //8255端口地址定义 #define C8255_B XBYTE[0x7F01]
#define C8255_C XBYTE[0x7F02]
#define C8255_CON XBYTE[0x7F03]
//共阴极七段码
unsigned char a[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; unsigned char b[] = {0x00, 0x00, 0x00, 0x00};
unsigned char key_down;
unsigned char key_value;
unsigned char key_count;
void delay(unsigned int time)
{
unsigned int i;
for(i=0; i
}
void keyscan()
{
unsigned char cc;
C8255_A = 0x00;
cc = C8255_C;
key_down = (~cc) & 0x0f;
}
void display()
{
unsigned char i, j = 0xF7;
for(i=0; i
{
C8255_A = j;
C8255_B = a[b[i]];
delay(0x100);
j >>= 1;
}
}
void clear()
{
C8255_B = 0x00;
}
void writebuffer()
{
b[key_count] = key_value;
key_count--;
if(key_count == -1)
key_count = 3;
display();
clear();
keyscan(); //按键扫描函数 //X1~X4置0 //得到Y1~Y4的值 //显示函数 //查表输出显示
while(key_down) //键盘消抖 {
display();
clear();
keyscan();
}
}
void getkey() //得到按键值 {
unsigned char value;
unsigned char i, j = 0xFE;
for(i=0; i
{
C8255_A = j;
value = C8255_C;
if(!(value & 0x01))
{
key_value = i + 0;
writebuffer();
return;
}
if(!(value & 0x02))
{
key_value = i + 4;
writebuffer();
return;
}
if(!(value & 0x04))
{
key_value = i + 8;
writebuffer();
return;
}
if(!(value & 0x08))
{
key_value = i + 12;
writebuffer();
return;
}
j
}
void main()
{
C8255_CON = 0x81;
key_count = 3;
while(1)
{
display(); clear(); keyscan(); if(key_down) {
display(); delay(0x100); clear(); keyscan(); if(key_down) {
getkey(); }
}
}
}
//8255初始化 //显示 //清屏 //按键扫描 //判是否有键按下 //得到按键值