我所设计的题目为“基于魔术棒的多功能单片机系统”,主要是在魔术棒的基础上添加了单片机的其他功能,例如红外遥控,蜂鸣器,温度传感器,LED灯等装置。具体要求有以下几点:
- 利用数码管实现主要功能“魔术棒”。
- 利用红外装置控制温度传感器,并显示温度。
- 利用蜂鸣器使其能发出乐音。
- 利用LED灯实现跑马灯功能。
- 利用按键控制以上几种功能。
二、设计方案及论证
1、任务分析
我所做的主要部分为“魔术棒”,“魔术棒”的原理是利用人眼的视觉暂留原理,即物体在快速运动时, 当人眼所看到的影像消失后,人眼仍能继续保留其影像0.1-0.4秒左右的图像,因此,我们可以利用数码管或LCD显示屏,逐个控制每一位的点亮,并送入数据,再控制好相邻位之间亮起的频率,就可以实现一个动态显示功能,但实际上在当前时刻只有1位点亮并送入数据,控制一定频率使得人眼看起来每个位置都在同时点亮。
红外传感模块和温度传感器单片机上已经存在,需要编写程序控制温度传感器工作,并实时显示温度,并且编写控制红外遥控装置的程序,令红外装置能接收信号和发出红外线,通过红外遥控器控制温度传感器的开启。
蜂鸣器是将音符表和节拍表送入寄存器中,通过改变蜂鸣器的音调和延迟时间实现演奏歌曲。
LED灯发光可以通过改变P1端口8位来选择不同的LED发光。
按键开关是单片机的一个基础元件,可以通过开关控制许多功能的开启和关闭,我用不同的按键开关控制以上功能的实现。
经过我们多次的设计方案讨论,我们大致确定了2种设计方向。
①“魔术棒”用数码管来实现,这个方案的优点是我们可以在一个时间点控制一个数码管的点亮,控制好点亮频率我们可清楚地观察到“魔术棒”现象的生成。但缺点是数码管只有4位,无法显示多个字符,而且显示内容较少,只有数字和部分英文字母。
②“魔术棒”用LCD显示屏来实现,这个方案的优点是显示的内容比数码管多,且能显示所有的英文字母和数字,但缺点是无法很好的观察到现象,且可能会出现未知的显示错误。
最后,我们确定了主体方案为方案1,因为数码管可以更好地观察到现象,可以将大于4的字符循环显示,也可以观察到魔术棒效果。
3、系统关键模块设计
上图为C51单片机数码管原理图,P2口为位选端口,P0口为段选端口,8个LED发光二极管为共阳极接法,不点亮时为高电平,点亮为低电平,即相应管脚送0为低电平,送1为高电平,低电平有效,因此控制P2端口地址0的位置可使相应数码管点亮。
4、软件算法流程(将完整代码放在附录1中)
下图为控制数码管依次显示字符的算法流程图,首先设次数为1,设置P2的值使第一个数码管点亮,设置P0的值将数据送入第一个数码管,再进行延迟,判断次数是否大于3,是则关闭所有数码管, 否则次数加1,并回到设置P2值的步骤。
三、开发及调试过程
1、开发过程
根据我们确定的主体方案以及我自己的设计方案,我开始了程序的开发过程,我利用了Keil软件进行程序的开发和调试,我的程序运用到的编程语言为C51语言和汇编语言,我将程序的开发分为以下3个模块:温度传感器工作及显示函数,数码管显示函数,红外传感器控制及工作函数。其中红外传感器模块是用汇编语言编写的,其他模块是用C51语言编写的。
对于汇编语言我还不是特别精通,所以我把红外传感器模块安排到了最后进行。首先进行数码管的开发过程,数码管的段选是由P0端口扩展的74HC573芯片控制的,74HC573芯片是拥有八路输出的透明锁存器,输出为三态门的控制芯片,通过控制P0.0---P0.7管脚使a~g不同位置数码管亮起,数码管为共阳极接法,因此低电平有效,当一个管脚置0时,其代表的数码管对应位置就会亮起,实现送数功能。数码管的位选是由P2口控制的四个三极管-电阻电路,通过控制P2.0~P2.3端口控制哪一位数码管开启,低电平有效。根据数码管原理特性,首先定义两个数组,一个向P0口送数,一个向P2口送数,再编写延迟函数,最后用循环执行代码,首先P2=0xFE,即打开数码管1,之后P0=0xF9,送入数据1,调用延迟函数将这一状态延时。延时过后判断是否满足循环条件,若不满足则继续执行循环,直到满足循环条件为止,满足则跳出循环,进行下一项内容。调试时可以通过改变延迟时间观察现象,直到利用视觉暂留原理达到人眼捕捉动画的效果。基于上述原理,我又加了另外4个数字,使得数码管能循环显示8位数字,实现送入长度大于4的字符串功能。
C51单片机温度传感器型号为DS18B20,DS18B20内部由4个部分构成,分别是64位光刻ROM 、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。它们可以实现温度的测量,温度值的存入和提取,温度的转换等功能。并可以将提取的温度值通过数码管显示出来。温度传感器函数设计分为以下几点:定义延时函数,初始化18B20,读取18B20一个字节,向18B20写入一个字节,读温度值,温度处理,显示温度。将18B20初始化是给其一个工作条件。读取18B20一个字节是要将数据从ROM中提取出来,向18B20写入一个字节是要将测出来的数据写入到ROM中,读温度值通过温度传感器特性得知环境实时温度,温度处理将温度值变为4位有效数字的温度值,温度显示是通过数码管实现。遍译好程序后经过不同温度的测试,发现在误差范围内温度测量精准,且温度也在随环境温度实时变化。
以上两个功能都可以通过按键控制的方式开启,即设计一个按键去抖函数,当按键按下,按键就处于低电平有效状态,相应的功能开始工作,当别的按键按下后上一个功能停止工作执行当前按下按键的功能。通过按键可实现功能切换的功能。
红外传感器模块用汇编语言编写,红外传感器和遥控器搭配使用,当在正常无遥控信号时,一体化红外接收头输出是高电平,不执行相应功能。当接入信号后,首先要进行解码,传输的红外信号是以高低电平的形式送入的,于是设定外部中断IR,触发方式为下降沿触发,将高低电平信号存入寄存器中,获得16位地址码和8位数据码,从而实现解码。之后进行遥控执行部分,设定遥控器按键1为LED灯闪烁程序。LED灯位选通过P1口控制,为低电平有效,当按下按键1后,执行LED灯循环亮起程序。首先将第一个LED灯亮起地址送入累加器A中,经过延迟后再将第二个LED灯亮起地址送入累加器A中,之后以此类推,实现LED跑马灯功能。设定遥控器按键8为蜂鸣器播放乐音程序,蜂鸣器产生乐音原理是将预先设计好的节拍表和音符表送入蜂鸣器中,并进行定时,使蜂鸣器能完整播放一首乐音。当播放完后清除遥控值使连按失效。红外遥控程序结束。通过测试,遥控器在对准红外传感器且距离在10cm以内可顺利遥控,LED跑马灯以及蜂鸣器均可正常工作,且交换顺序也并不影响,说明程序符合预期设计目标。
①若想将循环结束后的数码管每一位清零,只将数码管位选信号全部置1是不行的,需设置P0的值使发光二极管全部置1,令发光二极管熄灭,原因是Keil中执行一条命令总在下一条命令开始执行时执行上一条命令,因此需加一条命令关闭发光二极管。
②温度传感器在环境温度突变时显示数据会有错误,这是其器件特性所致,只能通过改进温度读取函数来实现。
本次课设中用到的关键知识点为C51语言及汇编语言的应用,输入输出端口的应用,各种芯片元器件的应用,定时器,中断以及许多数字电子技术和模拟电子技术上的知识。这些知识的综合运用使我顺利完成了本次课程设计。
为期4周的单片机课程设计结束了,我经历了查阅资料,小组讨论,设计方案选取,编写调试代码,单片机调试,代码修改,小组及个人答辩等一系列流程,我学到的不仅是这门课传授我的只是,更学到了团队合作,多途径查阅资料,分析问题能力和沟通能力,这些都是我成功做完这次课设的保证,我也要感谢我的队友,是我们一起经过讨论确定了选题和主体方案设计,当程序有问题或需要改进时我们也深入广泛地交换了彼此的意见,每个人在这次课设中都收获到了许多。我还要感谢多次热心帮助我们的老师和助教,是他们多次帮助我们发现问题,提出建议,帮助我们在原有功能上增添了更多功能,并且还提供了许多参考资料给我们,令我们有丰富的知识储备。但我们这次的课设还是有很多方面的不足,对于我仍然有很大的提升空间,碍于现在自身知识储备和时间问题,我在一些方面上没能做得更加细致,我会总结经验教训,努力完成以后的课程。
单片机课程设计是一门对于电子专业学生很重要的一门课,它培养了我们的独立工作能力和小组协作能力,但可能一个小组中并没有很好的创意,我觉得可以在确定选题前先开一个选题交流会,大家踊跃发言,集思广益,可以增加我们题目创新性,也可以与别的组成员进行有效沟通,增加我们的完成机率。
单片机源程序如下:
- <font face="宋体"><font style="font-size: 10.5pt">#include<reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- extern void infrared(void);
- uchar display[ ]={0xF9,0x82,0xA4,0xF8};
- uchar display4[ ]={0xF9,0xC0,0xF8,0xC0};
- uchar code display2[ ]={0xff,0xC7,0x83,0xE1};
- //uchar code con[ ]={ 0xff,0xfe,0xfd,0xfb,0xf7};
- uchar code con[ ]={0xfe,0xfd,0xfb,0xf7};
- uchar code table[]={0xc0,0xf9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};
- //四位8段数码管共阳0——9
- uchar code table1[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
- //四位8段数码管带小数点共阳0——9
- sbit s2=P3^3;
- sbit s3=P3^4;
- sbit s4=P3^5;
- void delay(uint i)
- {
- while(i--)
- ;
- }
-
- //**************按键处理*******************************
- char check_s2(void)
- {
- if(s2==0)
- {
- delay(2000);
- {
- if(s2==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- char check_s3(void)
- {
- if(s3==0)
- {
- delay(2000); // 按键去抖
- {
- if(s3==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- char check_s4(void)
- {
- if(s4==0)
- {
- delay(2000); // 按键去抖
- {
- if(s4==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- //***********************温度传感器************************
- uint x;
- sbit DQ =P3^7; //DS18B20接P3^7口
- uint tvalue;
- uchar disdata[]={0,0,0,0};
- void delaytimer(void)
- {
- EA=1;//打开中断
- TMOD=0x10;//
- TL1=(65536-500)%256;//设置定时器1低8位
- TH1=(65536-500)/256; //设置定时器1高8位
- TR1=0;//停止计数
- ET1=1;//打开定时器
- }
- void delay_18B20( uint i) //延时
- {
- while(--i);
- }
- void delay2(uchar n) //延时
- {
- uchar i,j;
- for(i=n;i>0;i--)
- for(j=20;j>0;j--);
- }
- void ds1820rst() //初始化DS18B20
- {
- unsigned char x=0;
- DQ = 1; //DQ复位
- delay_18B20(4); //
- DQ = 0; //单片机将DQ拉低
- delay_18B20(60); //
- DQ = 1; //拉高总线
- delay_18B20(14);//
- x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
- delay_18B20(20);
- }
- uchar ds1820rd() //从DS18B20读取一字节
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--) //一位一位地读,共8位
- {
- DQ = 0; //给一脉冲信号
- dat>>=1; //dat往右移一位
- DQ = 1; //给一脉冲信号
- if(DQ)
- dat|=0x80;
- delay_18B20(4);//
- } return(dat);
- }
- void ds1820wr(uchar wdata) //写入一字节
- {
- unsigned char i=0;
- for (i=8;i>0;i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(5);
- DQ = 1;
- wdata>>=1;
- }
- }
- uint read_temp() //读取温度
- {
- float aaa;
- uchar a,b;
- ds1820rst();
- ds1820wr(0xcc); //向DS18B20发跳过读ROM命令
- ds1820wr(0x44); //启动DS18B20进行温度转换命令,转换结果存入内部RAM
- delay_18B20(80); //延时
- ds1820rst();
- ds1820wr(0xcc); //向DS18B20发跳过读ROM命令
- ds1820wr(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
- delay_18B20(80); //延时
- a=ds1820rd(); //读内部RAM 低位
- b=ds1820rd(); //读内部RAM 高位
- aaa=(b*256+a)*6.25;
- tvalue=(uint)aaa;
- return(tvalue);
- }
- void display1(uchar a1,uchar a2,uchar a3,uchar a4) //显示温度
- {
- P2=0xfe;
- P0=table[a1];
- delay2(20);
- P2=0xfd;
- P0=table1[a2];
- delay2(20);
- P2=0xfb;
- P0=table[a3];
- delay2(20);
- P2=0xf7;
- P0=table[a4];
- delay2(20);
- }
- void ds1820disp( unsigned int tvalue1) //温度处理
- {
- disdata[0]=tvalue1/1000; //十位
- disdata[1]=tvalue1%1000/100; //个位
- disdata[2]=tvalue1%100/10; //小数点后一位
- disdata[3]=tvalue1%10;; //小数点后两位
- display1(disdata[0],disdata[1],disdata[2],disdata[3]);
- }
- //void stop(){
-
- void t18B20() //温度传感器显示函数
- {
- uint temp;
- delaytimer();
- while(1)
- {
- temp=read_temp();
- ds1820disp(temp);
-
- }
- }
- /*void smg()
- {
- uchar shift,j,k,m;
- while(1)
- { for(m=1;m<101;m++)
- {for(j=0;j<4;j++)
- {
-
- P2=con[j];
- P0=display[j];
- delay(10000);
-
- }
- P2=0xFF;
-
- for(k=0;k<4;k++)
- {
- P2=con[k];
- P0=display4[k];
- delay(10000);
- }
- P2=0xFF;
- }
- P0=0xFF;
- P2=0xFF;
- }}*/
- //*************主函数***********************
- void main()
- { uchar shift,j,k,m;
- for(m=1;m<5;m++)
- { for(j=0;j<4;j++)
- {
-
- P2=con[j];
- P0=display[j];
- delay(10000);
-
- }
-
- P2=0xFF;
-
- /* for(j=0;j<3;j++)
- {
-
- P2=con[j];
- P0=display2[j];
- delay(1000);
- }*/
- for(k=0;k<4;k++)
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
- </font></font>
复制代码
所有资料51hei提供下载(仿真+源码+完整论文):
魔术棒.zip
(270.6 KB, 下载次数: 21)