便携式学生自主微机原理实验装置
实验报告
姓名:
班级:
学号:
联系电话:
电子信箱:
日期: 2015 年 1 月 18 日
一、实验心得:
本学期学习了微机原理这门实践性非常强的课程,这门课程内容丰富详实,包含汇编语言程序设计、8086微处理器、89C510单片机等。复杂的知识极大的增加了理解掌握的难度。在正常实验教学安排的基础上,我们还初次享受到了便携式学生自主微机原理实验装置带来的便利,使我们能够利用课余时间,自主完成实验设计。更有助于我们将理论与实践相结合,加深对知识的理解和掌握。
在使用这个箱子后,我首先进行了一些简单的流水灯实验,又复习巩固了各种定时器计时器以及外部中断的使用方法。接着尝试着用驱动了步进电机,利用外部中断增加了对电机转速的调节。交通灯实验是对以上知识的综合运用提升,经历了反复调试,最总才得以稳定运行。键值的读取及显示实验通过7279读取4*4矩阵,获取键值并将键值送入芯片驱动数码管显示。
由于是三个人共用一台实验装置,我们有时错开时间独自进行实验,有时聚在一起讨论交流,很多问题在交流中便解决了。
通过对实验装置的操作,加深的我对于单片机的结构和原理,各种定时器中断的使用方法,编译码的方法,输入输出通道的设计等。知道了目前自身存在的问题,能力欠缺的地方,今后定将继续努力,不断提高学业水平!
二、建议:
(1) 建议出版一本与便携式学生自主微机原理实验装置相配套的实验指导书,指导学生自主学习运用实验装置,方便学生正确使用实验装置,提高学生自主学习的能力。
(2) 由于本人程序设计基础较为薄弱,自己觉得老师讲的电路和程序设计原理都懂,但在实际编写程序时存在很大的困难,难以自主完成程序的编写,只能自己在网上搜索相关的程序进行修改。因为实验装置的不同,修改理解的过程有点费劲。希望能根据实验装置的特点,由简单到复杂的提供相应源程序供不同层次的学生在编程时作参考。
(3) 如果出第二代产品,希望能够每人配备一台试验箱,USB接头能够平着放在边缘,这样连线时箱子盖砸下来不会砸坏接口。烧录程序的USB数据线希望能再长些,在实验室连接台式电脑不易出现拉扯。
(4) 实验装置的发放时间有点晚,很快迎来了多门科目的考试,自主实验的时间不够。希望能够在开学初发放箱子,提供足够多的时间自主学习。
三、实验装置出现的问题:
小组内一名成员在做键盘实验时,将修改好的程序烧录进去,发现数码管无法点亮;反复尝试之后,重新下载数码管检测程序,依然无法点亮。(在领箱子那天用数码管检测程序可以点亮)。可能是HD7279芯片烧坏了,之后我们没有再用那个程序,利用室友的实验装置,参考别人修改好的程序完成了按键显示的实验。
四、实验程序
实验一 步进电机实验
编程实现:由拨动开关改变步进电机的转动方向,绕组通电时间采用软件延时法,利用外部中断实现电机转动过程中可以增速与减速。
#include<reg51.h>
sbit direc = P3^5; //正反转控制位
int flag = 0; //速度标志:flag=0时,减速;flag=1时,加速。
unsigned char time=15;
unsigned char code TAB1[8] = {0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09};//电机正转
unsigned char code TAB2[8] = {0x09,0x08,0x0C,0x04,0x06,0x02,0x03,0x01};//电机反转
void DELAY()
{
unsigned char i,j;
for(j=0;j<time;j++)
for(i=0;i<255;i++);
}
void rotate(unsigned char code *p)
{
unsigned char i;
for(i=0;i<8;i++)
{
P1 = p[i];
DELAY();
}
}
void INTPT_0() interrupt 0
{
flag++;
if(flag==2)
flag=0;
switch(flag)
{
case 0:time = 15;break;
case 1:time = 60;break;
default: break;
}
}
void main()
{
unsigned char i=0;
IE = 0x81; //允许INT0中断
IT0 = 1;
while(1)
{
if(direc==0)
rotate(TAB1); //如果direct=0,则电机反转
else
rotate(TAB2);
//如果direct=1,则电机正转
}
}
心得:利用两组不同次序的数组,在if语句的选择下实现电动机的正反转。引入外部中断,利用软件延时的方法,改变绕组的通电时间,以此来改变转速。
编程实现:由拨动开关改变步进电机的转动方向,绕组通电时间采用定时器定时,利用外部中断改变电机转速。
/* 在外部中断子函数中改变电机转速 */
/* 四相八拍控制 A-AB-B-BC-C-CD-D-DA */
/* 实验连线: P1.0—P1.3接步进电机的A, B, C, D, */
/* INT0接单脉冲发生器OUT- */
/* P3.5接一拨动开关 */
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar idata plus[10]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09,0x00}; /*正转*/
uchar idata minu[10]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x00}; /*反转*/
void init_Timer0();
void Timer0_fun();
void INT0_fun();
uchar SpeedFlag = 0;
uchar runStep = 0;
uchar DirFlag = 0;
//初始化Timer0配置参数
void init_Timer0()
{
TMOD = 0x01;
TH0 = 0x00;
TL0 = 0x00;
TR0=1;
}
void main(void)
{
uchar InputCode = 0;
runStep = 0;
SpeedFlag = 0;
init_Timer0();
IE=0x83;
IT0=1;
while(1)
{
InputCode = P3;
if(InputCode&0x20)
{
DirFlag = 0;
}
else
{
DirFlag = 1;;
}
InputCode=0;
}
}
//Timer0中断响应函数
void Timer0_fun() interrupt 1 using 1
{
if(DirFlag==1) //如果方向标志位为1, 实现正转
P1=plus[runStep];
else
P1=minu [runStep]; //如果方向标志位为0, 实现反转
runStep=(runStep+1)%8;
if(SpeedFlag ==1)
{
TH0=0x80;
TL0=0x00;
//电机加速(绕组通电时间取T0最大定时的1/2时间)
}
else
{
TH0=0x00;
TL0=0x00; //电机减速(绕组通电时间取T0最大定时时间)
}
}
//INT0中断响应函数
void INT0_fun() interrupt 0 using 2 /* Timer1中断服务程序 */
{
EA=0;
SpeedFlag = (SpeedFlag+1)%2;
EA=1;
}
心得:利用数组让数组不断加一实现变换。利用外部中断改变速度标志实现不同转速。
实验二:交通灯实验
/* 交通灯控制问题。
设东西方向和南北方向均有红、黄、绿灯,控制规定为:南北绿灯亮10s,黄灯亮3s;
绿灯亮8s,黄灯亮3s.
端口分配:东西方向 P2.0 红灯,P2.1 黄灯, P2.2 绿灯
南北方向 P2.3 红灯,P2.4 黄灯, P2.5 绿灯
使用定时/计数器T0作定时器,设f0sc=12MHz,定时间隔为0.05s。定时常数为
a=-0.05*12000000/12=-50000
由于定时/计数器无法定时1s,故将1s定时分为20段,每段0.05s,在定时中
断服务函数中使用一个计数变量,当计数变量达到20时,就完成了1s的定时,
謻标志flag. */
#include<reg51.h>
#define uchar unsigned char
sbit P1_0=P1^0; /* 东西方向 /* 红 灯 */
sbit P1_1=P1^1; /* 黄 灯 */
sbit P1_2=P1^2; /* 绿 灯 */
sbit P1_3=P1^3; /* 南北方向 /* 红 灯 */
sbit P1_4=P1^4; /* 黄 灯 */
sbit P1_5=P1^5; /* 绿 灯 */
uchar data count;
bit flag;
delay()
{
int x=10000;
while(x--);
}
void T0_srv (void) interrupt 1 using 1 /* T0中断服务函数完成1s定时*/
{
TH0=-(50000/256);
TL0=-(50000%256);
count++;
if(count==20)
{
count=0;
flag=1;
}
}
void int0_srv(void) interrupt 0 using 2 /* 外中断0完成当有救护车和消防车通过
时,两个方向均亮红灯,救护车和消防车通过后恢复原来状态。
用一个手动控制开关,接在INT0的输入端,当开关接通时,保存
P1口状态,使两个方向红灯亮,等开关断开后,恢复P1口状态。*/
{
uchar a;
delay();
if(!INT0)
{
a=P1; /*保留P1鬃态*/
P1=0xff;
P1_0=0;
P1_3=0;
while(!INT0); /*等待开关断开*/
P1=a; /*恢复P1状态*/
}
}
void main()
{
uchar sum=0;
TMOD=0x01;
TH0=-(50000/256);
TL0=-(50000%256);
EA=1;
ET0=1;
PX0=1;
EX0=1;
TR0=1;
P1=0xff;
while(1)
{
P1_0=0;P1_5=0; /*(东西:红;南北:绿) 亮10秒*/
while(sum<10)
{
while(!flag);
flag=0;
sum++;
}
sum=0;
P1_5=1; P1_4=0;/* 南北方向(绿灯灭,黄灯亮)3秒 */
while(sum<3)
{
while(!flag);
flag=0;
sum++;
}
sum=0;
P1_4=1; P1_3=0; /* 南北方向(黄灯灭,红灯亮) 8秒 */
P1_0=1; P1_2=0; /* 东西方向(红灯灭,绿灯亮)8秒 */
while(sum<8)
{
while(!flag);
flag=0;
sum++;
}
sum=0;
P1_2=1; P1_1=0; /* 东西方向(绿灯灭,黄灯亮)3秒 */
P1_3=0;
while(sum<3)
{
while(!flag);
flag=0;
sum++;
}
sum=0;
P1_1=1; /* 东西方向黄灯灭 */
P1_3=1; /* 南北方向红灯灭 */
}
}
心得:利用定时器计数器断实现了定时功能,并在各种灯间循坏切换,实现交通灯的控制。亮点在于增加一个外部中断,实现了救护车,消防车通过等紧急情况下,交通灯的处置情况。
实验三:键值的读取与显示程序
#include <REG51.H>
#include <intRIns.h>
#include <ABSACC.h>
#include <math.h>
#include <var.h>
#include <sigmod.h>
#include <tc.h>
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
// 变量及I/O口定义
uchar digit[5];
uchar key_number, j, k;
uint tmr;
ulong wait_cnter;
sbit AA = P1^0;
sbit BB = P1^1;
sbit CC = P1^2;
sbit DD = P1^3;
sbit dat = P1^4;
sbit key = P1^5;
sbit cs = P1^6;
sbit clk = P1^7;
uchar P8255_CTL _at_ 0xF803;
uchar P8255_A _at_ 0xF800;
uchar P8255_B _at_ 0xF801;
uchar P8255_C _at_ 0xF802;
uchar P8253_CTL _at_ 0xF903;
uchar P8253_1 _at_ 0xF900;
uchar P8253_2 _at_ 0xF901;
uchar P8253_3 _at_ 0xF902;
uchar P374 _at_ 0xFA00;
uchar P245 _at_ 0xFB00;
uchar code code1[] = {0x7e,0x4e,0x70,0x77,0x7f,0x4e,0x07,0x47,0x9d,0x77,
// O C T A B C f F a A
0x37,0x0e,0x5b,0x3e,0x0d,0xfe,0x67,0x70,0x1d,0x3d};
// H L S U c Q p T o d
// O:On-Off, C:Cold, T:Timerecord, A:Adress, B:Baud, C:Celiang, f:fbefore, F:Fafter, a:abefore, A:Aafter
// H:ms$hih, L:ms$low, S:Signal, U:Unit, c:cut$off, Q:Q$mode, p:p$spec, T:T$spec
uchar code code2[] = {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b,0x01,0x80,0x00, 0x6f};
// 0 1 2 3 4 5 6 7 8 9 - . blank error
uchar code code3[] = {0x0F,0x0B,0x07,0x03,0xCC,0xCC,0xCC,0xCC,
0x0E,0x0A,0x06,0x02,0xCC,0xCC,0xCC,0xCC,
0x0D,0x09,0x05,0x01,0xCC,0xCC,0xCC,0xCC,
0x0C,0x08,0x04,0x00,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
// HD7279指令
#define CMD_RESET 0xa4
#define CMD_TEST 0xbf
#define DECODE0 0x80
#define DECODE1 0xc8
#define CMD_READ 0x15
#define UNDECODE 0x90
#define RTL_CYCLE 0xa3
#define RTR_CYCLE 0xa2
#define RTL_UNCYL 0xa1
#define RTR_UNCYL 0xa0
#define ACTCTL 0x98
#define SEGON 0xe0
#define SEGOFF 0xc0
#define BLINKCTL 0x88
// 函数定义
void long_delay(void);
void short_delay(void);
void delay1ms(unsigned char);
void led_write(unsigned char,unsigned char);
uchar key_read(void);
void send_byte(unsigned char);
uchar receive_byte(void);
//void led_real_disp(uchar biaoshi, uchar c_num, float m1, uchar len);
//void led_int_disp (uchar biaoshi, uchar c_num, ulong m, uchar len);
void main(void)
{
uchar num = 0x3f;
uchar H,L;
P1 = 0x00; delay1ms(25);
while(1==1)
{
num = key_read();
if(key_read() == 0xff)
{
led_write(0x97,code2[0x0c]);
led_write(0x96,code2[0x0c]);
delay1ms(25);
}
else
{
H = code3[num]/10;
L = code3[num]%10;
delay1ms(25);
led_write(0x97,code2[H]);
delay1ms(25);
led_write(0x96,code2[L]);
}
}
}
/*
//主程序
void main(void)
{
uchar i, j;
P1 = 0x00; delay1ms(25);
for(j=0; j< 10; j++)
{
for(i = 0; i < 8; i++)
{
led_write(0x97-i, code2[j]);
}
delay1ms(250);
}
P8255_CTL = 0x80; P8253_CTL = 0x36; P8253_1 = 0x14; P8253_1 = 0x00;
while(1)
{
// P8255_A = 0x55; delay1ms(250); P8255_A = 0xaa; delay1ms(250);
P1 = 0x03; delay1ms(25); P1 = 0x06; delay1ms(25); P1 = 0x0c; delay1ms(25); P1 = 0x09; delay1ms(25);
i = P245; delay1ms(1); P374 = i;
}
}
*/
/* ============ 7279a.c =============
void led_real_disp(uchar biaoshi, uchar c_num, float m1, uchar len);
{
float mn[] = {1.0, 10.0, 100.0, 1000.0}; ulong m;
uchar i, j, k; uchar buf[6];
i = code1[biaoshi];led_write(0x97,i);
if biaoshi < 5
{
do case biaoshi;
i = code1[7];
i = code1[18];
i = code1[14];
i = code1[19];
i = code1[8];
end;
}
else i = code2[c_num];
led_write(0x96,i);
if m1 < 0.0 { buf[0] = 10; m1 = m1 * -1.0; j = 1; }
else j = 0;
if len = 0x40 and m1 < 1000.0 then len = 0x41;
else if len = 0x31 and m1 < 100.0 then len = 0x32;
else if len = 0x22 and m1 < 10.0 then len = 0x23;
k = len and 0x0f; m = unsign(fix(m1 * mn[k]));
if j = 0 then buf[0] = m / 100000; m = m mod 100000;
buf[1] = m / 10000; m = m mod 10000;
buf[2] = m / 1000; m = m mod 1000;
buf[3] = m / 100; m = m mod 100;
buf[4] = m / 10; m = m mod 10;
buf[5] = m / 1;
for(i = 0; i < 6; i++)
{
if buf[i] > 9 and buf[0] <> 10 then buf[i] = 13; buf[i] = code2[buf[i]];
}
if k <> 0 then buf[5-k] = buf[5-k] or 0x80;
if buf[0] = 0x7e
{
buf[0] = 0;
if buf[1] = 0x7e
{
buf[1] = 0;
if buf[2] = 0x7e
{
buf[2] = 0;
if buf[3] = 0x7e
{
buf[3] = 0;
if buf[4] = 0x7e { buf[4] = 0; }
}
}
}
}
if buf[0] = 0x01
{
if buf[1] = 0x7e { buf[0] = 0; buf[1] = 0x01;}
if buf[1] = 0x01
{
if buf[2] = 0x7e { buf[1] = 0; buf[2] = 0x01; }
}
if buf[2] = 0x01
{
if buf[3] = 0x7e { buf[2] = 0; buf[3] = 0x01; }
}
if buf[3] = 0x01
{
if buf[4] = 0x7e { buf[3] = 0; buf[4] = 0x01; }
}
}
for(i = 0; i < 6; i++)
{
led_write(0x95-i, buf[i]);
}
}
void led_int_disp(uchar biaoshi, uchar c_num, ulong m, uchar len);
{
uchar i, j, k; uchar buf[6];
i = code1[biaoshi];
led_write(0x97,i);
if biaoshi < 5
{
do case biaoshi;
i = code1[7];
i = code1[18];
i = code1[14];
i = code1[19];
i = code1[8];
end;
}
else i = code2[c_num];
led_write(0x96,i);
buf[0] = m / 100000; m = m mod 100000;
buf[1] = m / 10000; m = m mod 10000;
buf[2] = m / 1000; m = m mod 1000;
buf[3] = m / 100; m = m mod 100;
buf[4] = m / 10; m = m mod 10;
buf[5] = m / 1;
if len <> 6 then do i = 0 to 5-len; buf[i] = 12; end;
for(i = 0; i < 6; i++)
{
if buf[i] > 9 then buf[i] = 12; buf[i] = code2[buf[i]];
}
for(i = 0; i < 6; i++)
{
led_write(0x95-i, buf[i]);
}
}
void led_write(uchar cmd, uchar dta)
{
send_byte(cmd); send_byte(dta);
}
uchar key_read(void)
{
send_byte(0x15); return(receive_byte());
}
void send_byte(uchar out_byte)
{
uchar i;
cs = 0; long_delay();
for (i=0;i<8;i++)
{
if (out_byte & 0x80) { dat = 1; }
else { dat = 0; }
clk = 1; short_delay(); clk = 0; short_delay(); out_byte = out_byte*2;
}
dat = 0;
}
uchar receive_byte(void)
{
uchar i, in_byte;
dat = 1; long_delay();
for (i=0;i<8;i++)
{
clk = 1; short_delay(); in_byte = in_byte*2;
if (dat) { in_byte = in_byte|0x01; }
clk = 0; short_delay();
}
dat = 0; return(in_byte);
}
void delay1ms(unsigned char time)
{
uchar i; uint j;
for (i=0;i<time;i++)
{
for (j=0;j<355;j++){;}
}
}
void long_delay(void)
{
uchar i;
for (i=0;i<0x30;i++){;}
}
void short_delay(void)
{
uchar i;
for (i=0;i<8;i++){;}
}
心得:这个实验最难,再加上试验箱这一部分的损坏,让我在接下来用室友箱子时小心翼翼,着重参考了室友的程序,弄懂的键盘输入的原理方法。