单片机实验报告.docx
- 文档编号:7598323
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:17
- 大小:21.89KB
单片机实验报告.docx
《单片机实验报告.docx》由会员分享,可在线阅读,更多相关《单片机实验报告.docx(17页珍藏版)》请在冰豆网上搜索。
单片机实验报告
单片机实验报告
实验一
一、实验目的:
利用外部中断实现时钟计数0-9999(跑马灯)。
二、实验代码:
voidsystem_init(void)
{
_intc0=0;
_intc1=0;
_tmr0c=0;
_tmr1c=0;
_pac=0;//outputmode
_pbc=0;
_pcc=0;
//显示0000
_pc=0;//data
_pb=0;//bit_select
time=0;
}
voidAddOne()
{
if(time<9999)
time++;
else
time=0;
}
voidDisplay(unsignedlongi)
{
uchartemp1;
uinttemp2;
//秒低位
temp1=i%10;
temp2=i/10;
_pc&=0xf0;//pc3-pc0
_pc|=temp1;
_pb|=0x0f;//pb0
_pb&=0xfe;
#include
#defineucharunsignedchar
#defineuintunsignedint
//定义中断如何函数
#pragmavectorint_4@0x4
#pragmavectortimer0_8@0x8
#pragmavectortimer1_c@0xc
voidint_4()//外部中断函数
{}
voidtimer0_8()//定时器0中断函数
{}
voidtimer0_c()//定时器1中断函数
{}
//函数声明
voidsystem_init(void);//单片机初始化
voidAddOne();//计时函数
voidDisplay(unsignedlongi);//LED显示
voidDelay(unsignedlongi);//延时
unsignedlongtime;
voidmain()
{
system_init();
while
(1)
{
Delay(5);//0.5s
AddOne();
Display(time);
}
}
//秒高位
temp1=temp2%10;
temp2=temp2/10;
_pc&=0xf0;//pc3-pc0
_pc|=temp1;
_pb|=0x0f;
_pb&=0xfd;//pb1
//分低位
temp1=temp2%10;
temp2=temp2/10;
_pc&=0xf0;//pc3-pc0
_pc|=temp1;
_pb|=0x0f;//pb2
_pb&=0xfb;
//分高位
temp1=temp2%10;
temp2=temp2/10;
_pc&=0xf0;//pc3-pc0
_pc|=temp1;
_pb|=0x0f;//pb3
_pb&=0xf7;
}
voidDelay(unsignedlongi)//t=i*0.1s
{
while(i--)
{
_delay(5000);
_delay(5000);//delayfor0.1s
}
}
三、实验心得:
由于之前并没有学习过单片机的知识,在做此试验时只能对着程序和电路图慢慢学习相关知识。
在已有的程序基础上,理解程序的流程、语句的含义,并对着书本了解各种寄存器、单片机各种功能的运用及各引脚的的功能。
此试验中主要是弄清楚几个寄存器分别用来做什么。
PC口用来存放当前的记数值,PB口作为使能端控制LED的显示,使得低位在计数变化而没有进位时,高位被锁存不发生变化。
PB口置低电平时为锁存态,高电平时为解锁态。
这是我认为这个实验中在电路上最需要重要理解的部分,理解了这一部分就知道了整个电路工作基本原理。
整个程序分解为多个函数,每个函数实现相应的功能。
例如有中断函数、初始化函数、计时函数和显示函数等。
这将是接下来的诸多程序的基础。
只要将相应函数部分进行改动,配合主函数的编写就可以实现不同的程序功能。
第一个实验只是用来熟悉电路原理及单片机的简单运用,在操作上没有很困难的地方。
只要将电路搭接正确,运行程序就能观察到实验结果,即LED灯上显示0到9999的计数。
实验二
1、实验目的:
利用定时器实现分和秒的计时。
利用按键外部中断实现计数及暂停。
二.实验代码:
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineulongunsignedlong
#defineFALSE0
#defineTRUE1
//定义中断程序地址
#pragmavectorint_4@0x04
#pragmavectortimer0_8@0x08
#pragmavectortimer1_c@0x0c
//定义全局变量
uinttimeh,timel,count;
ucharflag1;
voidint_4()//外部中断函数
{}
voidtimer0_8()
{
_t0on=0;
_tmr0h=0x3c;
_tmr0l=0xaf;
if(count==0)
flag1=TRUE;
else
count--;
_t0on=1;
}
voidtimer0_c()//定时器1中断函数
{}
//函数声明
voidsystem_init(void);
voidAddOne();
voidDisplay(uinth,uintl);
voidsystem_init(void)//端口和定时器0的初始化子程序
{
_intc0=0;
_intc1=0;
flag1=FALSE;
count=20;
_pac=0;
_pbc=0;
_pcc=0;
_pc=0;//data
_pb=0;//bitdata
_tmr0c=0x82;//
_tmr1c=0;
_tmr0h=0x3c;
_tmr0l=0xaf;//65565-50000
timeh=0;
timel=0;
_intc0=0x05;
_t0on=1;
}
voidAddOne()//时间+1子程序
{//若秒数(timel)<59,则秒数加1;否则秒数清零,分钟加1,若满60分则分钟也清零
if(timel<59)
timel++;
else
{
timel=0;
if(timeh<59)
timeh++;
else
timeh=0;
}
}
voidDisplay(uinth,uintl)//显示时间子程序
{
uchartemp1;
uinttemp2;
temp1=l%10;
temp2=l/10;
_pc&=0xf0;
_pc|=temp1;
_pb&=0xfe;
_pb|=0x0f;
_pc&=0xf0;
_pc|=temp2;
_pb&=0xfd;
_pb|=0x0f;
temp1=h%10;
temp2=h/10;
_pc&=0xf0;
_pc|=temp1;
_pb&=0xfb;
_pb|=0x0f;
_pc&=0xf0;
_pc|=temp2;
_pb&=0xf7;
_pb|=0x0f;
}
voidmain()
{
system_init();//端口和定时器0初始化
while
(1)
{
inta;
a=0;
if(flag1==1)
{
count=20;
AddOne();
flag1=FALSE;
Display(timeh,timel);//显示timeh和timel的值
}
}
}
三.实验心得:
这个程序是在上个程序的基础上进行加工,使得LED显示分秒计时。
要了解这个程序,首先翻阅了相关书籍,学习定时器的应用。
如何设置初始值,配合上相应的循环次数以使定时器每一秒产生一次中断,实现LED每一秒变化一次时间。
在实验中有改动计时部分,使得原来程序中0到9999的计时,能够进行分秒计时。
将前两位和后两位作为一个整体分别均是六十进制。
显示函数保持不变。
对每一位轮流进行显示。
对每一位均先锁存再显示,即先将对应的PB口电平拉低,再拉高。
这两个程序均是比较基础的程序,我通过对这两个程序的熟悉,能够对单片机有了一定的了解,并且能够动手编制单片机程序。
更通过老师的帮助,初步学习了如何使用单片机程序的的运行环境,了解到利用设置断点来检查程序的错误。
因为均是基础程序,做的过程中主要是在学习单片机的有关知识,由于程序较为简单并未遇到实验现象出不来的情况。
实验三
一实验目的:
LED每一位轮流显示按键的值
二、实验代码:
#include
#defineucharunsignedchar
#defineuintunsignedint
//定义各中断入口地址
#pragmavectorint_4@0x04
#pragmavectortimer0_8@0x08
#pragmavectortimer1_c@0x0c
voidint_4()
{}
voidtimer0_8()
{}
voidtimer1_c()
{}
unsignedintreadkey,j;
voidsystem_init(void);
voidgetkey();
voidDisplay();
voidDelay(unsignedlongi);
voidmain()
{
system_init();
while
(1)
{
getkey();
Delay(10);
Display();
}
}
voidsystem_init()
{
_intc0=0;
_intc1=0;
_tmr0c=0;
_tmr1c=0;
_pac=0xf0;
_pbc=0;
_pcc=0;
_pc=0;
_pb=0;
j=0;
}
voidgetkey()
{inti;
unsignedlongkey;
for(i=0;i<3;i++)
{
switch(i)
{
case0:
{
_pa=0x0e;
key=_pa;
switch(key)
{
case0x7e:
{readkey=1;j++;}break;
case0xbe:
{readkey=4;j++;}break;
case0xde:
{readkey=7;j++;}break;
case0xee:
{readkey=0x0a;j++;}break;
}
}break;
case1:
{
_pa=0x0d;key=_pa;
switch(key)
{
case0x7d:
{readkey=2;j++;}break;
case0xbd:
{readkey=5;j++;}break;
case0xdd:
{readkey=8;j++;}break;
case0xed:
{readkey=0;j++;}break;
}
}break;
case2:
{
_pa=0x0b;key=_pa;
switch(key)
{
case0x7b:
{readkey=3;j++;}break;
case0xbb:
{readkey=6;j++;}break;
case0xdb:
{readkey=9;j++;}break;
case0xeb:
{readkey=0x0b;j++;}break;
}
}break;
}
}
}
voidDisplay()
{_pb=0x0f;
_pc=readkey;
switch(j%4)
{
case0:
{_pb=0x07;_pb=0x0f;}break;
case1:
{_pb=0x0b;_pb=0x0f;}break;
case2:
{_pb=0x0d;_pb=0x0f;}break;
case3:
{_pb=0x0e;_pb=0x0f;}break;
}
}
voidDelay(unsignedlongi)//延时0.1*i秒子程序
{
while(i--)
{
_delay(10000);//调用系统延时1微秒子程序
_delay(10000);
}
}
三、实验心得:
这个实验需要运用到按键板。
将板上的行和列按顺序接至PA6~PA0,并将行接至高电平。
我所设想的原理是,通过人为的轮流使每一列的电平为低实现循环扫描,可先确定目前的列值。
再检测行中有哪一行电平变低,则可确定按键所在行值。
根据行列值得到对应的按键值。
显示部分则使用一个全局变量计数,使其除4取余,若整除则在右边第一位显示,余1则在右边第二位,依此类推实现循环显示。
调试程序的时候首先是按键值不显示。
经过单步运行程序,发现在display()函数中,原先用if语句写的情况运行时总是跳过,即没有进行判别就直接跳出。
老师帮忙也没有查找出原因,故改用switch语句编写。
改写后的程序能够一步一步运行,即没有出现跳出判别语句块的情况。
但又出现了4个LED均显示同一按键值的错误。
排查程序没有问题。
思考了很久之后猜想是不是由于按键的抖动,造成了实际上按键按了很多次,导致LED显示相同的按键值。
故在主程序的显示之前加上延迟后,这个问题也得到了解决。
但这个程序仍存在一定缺点,我只运用了简单的延迟消抖,而没有严格的判断前后两次按键是否一致来消除抖动。
而又由于一定的延迟,导致较少的按键有读不到的现象。
这个程序花费了我较长的时间,也是我能够通过前面程序的学习,自行编写单片机程序的实践。
虽然过程曲折,碰到了很多困难,但都一一排除了程序的错误,得到了正确的实验现象。
通过这个程序的编写,使我更加深了对单片机的学习以及编写环境的运用。
实验四
1、实验目的:
通过按键演奏音乐。
二、实验代码:
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineFALSE0
#defineTRUE1
ucharflag1,flag2;
#pragmavectorint_4@0x4
#pragmavectortimer0_8@0x8
#pragmavectortimer1_c@0xc
uintt;
uintGetKey(void);//得到键值
voidFrequency(inti);//发出声音的频率
voidDelay(unsignedlongi);//延迟函数
voidmain()
{
_pcc=0;//C口作为输出口
while
(1)
{
t=GetKey();
Frequency(t);
t=0;
}
}
voidDelay(unsignedlongi)//延迟函数
{
while(i--)
{
_delay(400);
_delay(400);
}
}
voidFrequency(inti)//根据i的大小选择发出声音频率的不同
{
intj;
for(j=0;j<100;j++)
{
switch(i)
{
case1:
_pc4=~_pc4;_delay(960);break;
case2:
_pc4=~_pc4;_delay(850);break;
case3:
_pc4=~_pc4;_delay(760);break;
case4:
_pc4=~_pc4;_delay(720);break;
case5:
_pc4=~_pc4;_delay(640);break;
case6:
_pc4=~_pc4;_delay(570);break;
case7:
_pc4=~_pc4;_delay(500);break;
case8:
_pc4=~_pc4;_delay(480);break;
}
}
Delay
(2);
}
uintGetKey(void)
{
ucharreadkey;
ucharpre_key;
uchartemp1,temp2;
_pac=0x0f;//将PA口低4位作输入而高4位作输出
_pa=0x0f;//将列输出为低
_delay
(2);//等待PA口数据稳定
temp1=_pa;
temp1&=0x0f;//取PA口低4位
if(temp1==0x0f)
return0xff;
_pac=0xf0;//将PA口高4位作输入而低4位作输出
_pa=0xf0;//将行输出为高
_delay
(2);//等待数据稳定
temp2=_pa;
temp2&=0xf0;取PA口高4位
if(temp2==0xf0)
return0xff;
pre_key=temp2|temp1;
_delay(10000);//消除抖动
_pac=0x0f;
_pa=0x0f;//列输出低
_delay
(2);//等待数据稳定
temp1=_pa;
temp1&=0x0f;//取PA口低4位
if(temp1==0x0f)
return0xff;
_pac=0xf0;
_pa=0xf0;//行输出为高
_delay
(2);等待数据稳定
temp2=_pa;
temp2&=0xf0;//取PA口高4位
if(temp2==0xf0)
return0xff;
readkey=temp2|temp1;
if(pre_key!
=readkey)//判断前后两次的按键是否一致
return0xff;
switch(readkey)
{
case0xee:
readkey=1;break;
case0xde:
readkey=2;break;
case0xbe:
readkey=3;break;
case0x7e:
readkey=4;break;
case0xed:
readkey=5;break;
case0xdd:
readkey=6;break;
case0xbd:
readkey=7;break;
case0x7d:
readkey=8;break;
case0xeb:
readkey=9;break;
case0xdb:
readkey=10;break;
case0xbb:
readkey=11;break;
case0x7b:
readkey=12;break;
defalut:
readkey=0xff;break;
}
returnreadkey;//返回readkey
}
三、实验心得:
这个实验是在上个得到按键值实验基础上的应用。
得到按键值的原理是一样的,增加的部分是如何使不同的按键值对应不同的频率。
刚开始不懂其中的原理,喇叭怎么也不出声音。
检查程序也没有发现错误。
后来经过老师的指导,才理解了喇叭发声的原理。
用PC口作为喇叭的输入,要输入不同频率的方波。
故不断使PC口电平取反,实现高低电平变化实现方波。
而不同的频率则由高低电平间的时延来实现。
相同时间内方波个数不同,自然频率也就不一样。
我的错误就在于在取反时没有加上循环,也就是没有形成喇叭发声所需要的方波,喇叭自然也就不会有反应。
进过改正后,就能够得到正确的实验现象了。
通过这个实验,更加让我明白必须要弄懂硬件上的原理,才能真正编写好正确的程序。
有时候程序本身并没有出错,但是却不符合硬件原理,自然得不到正确的结果。
这就是单纯软件编程和与硬件相结合的单片机的最大差别。
通过这些实验,让我初步学习到了单片机的知识。
但这只是冰山一角,要真正掌握单片机,还需要日后更多的学习。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 实验 报告