1、51单片机波形发生器第 大组 第 小组 课程设计报告课程设计名称 低频正弦波、锯齿波 信号发生器的设计与实现 姓 名 学 号 专 业 班 级 院 别 指导老师 完成时间 低频正弦波、锯齿波信号发生器的设计与实现摘 要 在以51单片机为核心的HNIST-2型单片机实验装置上设计一个低频正弦波、锯齿波信号发生器。可以通过键盘选择输出哪种类型的信号,还可以通过键盘对输出信号的频率、幅度进行实时设置。键盘设立了数字小键盘,用户使用非常方便。各种工作状态的切换也同样通过数码管显示出来,方便用户进行操作。装置断电后重新上电,可以按掉电前的设置继续进行工作,所有的设置数据都不会丢失。输出波形的同时输出波形的
2、类型、幅度和频率通过数码管进行显示。其中,波形的每个周期之内输出32个采样点,基本接近波形的形态。关键词 单片机; 正弦波; 锯齿波; EE2PROM; 1. 概述此次单片机课程设计,要求使用以51单片机为核心的HNIST-2型单片机实验装置实现正弦波、锯齿波波形发生器。1.1 课程设计的背景在学习过了数字电路、单片机原理与接口技术之后,拥有了利用51单片机设计出小项目的能力和经验。此次单片机课程设计,正是为了巩固和检验学过的知识。1.2 课程设计的要求以AT89C51为核心设计一个信号发生器,可产生锯齿波、正弦波信号输出。其中用户可以方便的选择和设置输出波形,波形形态基本与理论波形一致。 1
3、.3 课程设计完成情况(1)课程设计完成情况:完全符合课程设计要求。作品具备数码管显示、矩阵键盘、EEPROM掉电保护与存储、D/A输出功能,经过检测,发现作品完全符合课程实际要求。(2)在实验平台上随机抽取输出波形的数据,用示波器检测的结果如下:检测数据依次是 正弦波 5.0V 23HZ 4.0V 46HZ 锯齿波 5.0V 23HZ 4.0V 46HZ可以看到,实际输出波形也基本与输出数据一致,可见达到了课程设计要求。2. 总体设计思想此次软件设计,分为以下模块:1. 主函数模块:进行初始化,并且调用其他函数。2. 波形产生模块:产生波形数据。3. D/A转换模块:讲波形数据传送到D/A芯
4、片,进行D/A转换。4. 人机交互模块:包括键盘扫描和数码管显示,方便用户使用。5. EEPROM模块:进行数据保护,即使突然断电,也可以保存设置的数据。基本原理:将波形数据放在数组里面,间隔一段时间Ts产生一个中断,将数据送到D/A进行转换,就可以得到输出波形。假设波形频率为f,那么Ts = 1/f/32。 图1-1 功能模块框图3. 单元模块设计主函数模块流程图如图1-2所示,波形产生模块流程图如图1-3所示,D/A转换模块流程图如图1-4所示,人机交互模块流程图如图1-5所示,EEPROM流程图如图1-6所示。图1-2 1.c流程图 图1-3 T1_INTERRUPT.H流程图图1-4
5、DA.H的流程图 图1-5 HCI.H的流程图图1-6 E2PROM.H中读函数和写函数各自的流程图DA.H模块,EEPROM模块,1.c模块,HCI相对较易,是严格按照器件手册上的参数进行时序控制,不赘述。其中T1_INTERRUPT.H模块涉及到中断频率的设定,决定了本次课程设计的成败。现在详细分析如何计算参数。T1定时器的初始值由如下分析确定:根据公式T = 1 / f ; (2.1)T1的中断间隔理论上等于 Ts = 1/f/32;然后添加了软件修正time_repire。由于晶振为12MHz,所以一个脉冲是1us,一秒钟有1000000us。所以定时器初值为: TH1=(65536-
6、(1000000/fre/32)-time_repire)/256); TL1=(65536-(1000000/fre/32)-time_repire)%256);4、系统调试与使用操作说明一、 调试中出现的问题以及排查问题1:输出波形的频率不对。输入数据50Hz,但是示波器测出来却只有30Hz左右。原因:第一,T0中断优先级高,对T1中断有影响,而T1才是控制波形输出的。第二,使用的思路是定时器初始值固定,而在内部使用中间变量time,对time进行自增运算,判断time的值来判断延时的时长。然而T1中断服务子程序需要消耗大量时间。这对中断时放入到定时器的初始值有限制。不可能用很频繁的中断来
7、保证输出波形。解决:改变思路,使用改变定时器初始值的办法来控制波形输出频率。关键代码模板如下LOAD_H = ;LOAD_L= ;void T1_int(void) interrupt 3 /定时器T1服务函数 TH1= (LOAD_H); THL = (LOAD_L);问题2:在问题1解决之后,输入数据50Hz,输出实际频率47Hz,还有3HZ的误差。 原因:51单片机中断发生时,并不能立即执行中断服务程序;因为它还要先执行保存现场的工作,所以有一个中断响应时间为3-8个机器周期。此外,给定时器装初值同样需要消耗时间。 解决:添加软件修正变量time_repair,让定时器装的初始值有所增加
8、,抵消这些干扰性的延时影响。关键代码模板如下int time_repire=-40; /40us偏差修正#define LOAD_H_two_fre_num_2 (65536-(1000000/two_fre_num_2/32)-time_repire)/256)#define LOAD_L_two_fre_num_2 (65536-(1000000/two_fre_num_2/32)-time_repire)%256)问题3: EEPROM有时写不进。原因:I2C把数据传送到它的数据缓冲区之后,EEPROM还需要时间去把数据缓冲区的数据烧录到自身中。烧录时间手册上写有5ms左右。解决:在通过
9、I2C写入数据之后,进行适当的延时。 关键代码模板如下#define _Nop( ) _nop_( ); _nop_( );_nop_( );_nop_( );_nop_( ) ;/定义空操作,5sInt i=0;init_E2PROM(); /EEPROM初始化,释放总线 save_date(1,0xad); /通过I2C将数据发送到EEPROM for(i=1000;i0;i-) /进行延时 _Nop( )问题4:锯齿波输出幅度比实际的值要小一点。原因:1.步进过小。2.单片机不支持浮点运算,造成运算结果的偏差。解决:步进 = 256/31;且根据这个步进,就适合使用波形数组来保存波形数据
10、,免得在运算之中出现偏差。51单片机不支持浮点运算。二、操作使用说明 a.键盘布局b.设置(1)、进入与退出设置状态 按设置键,进入设置状态;处于设置状态再按设置键,退出设置状态。(2)、选择波形 进入设置状态后,按选择波形键,选择输出信号波形,按一下切换一次。例如选择输出信号波形为正弦波,按一下选择波形键,选择输出信号波形为锯齿波。(3)、参数选择 进入设置后,按选择参数键,选择参数,按一下切换一次参数,例如正弦波,若处于选择频率状态,按选择参数键,切换到处于选择幅度状态。 在选择参数状态,按键、 键改变调整数字位,按数字键改变参数值,要求各输出信号的参数值按如下范围设置。正弦波参数:频率,
11、10Hz50Hz;幅度,1.0V5.0V。锯齿波参数:频率,10Hz50Hz;幅度,1.0V5.0V。(4)、设置时的显示例如处于设置状态正弦波频率显示为:S 1 F - - - x x 显示的各位从左到右意义是: 最高位:S表示是在设置状态, 次高位:1 、2 表示是正弦波、锯齿波,处于选择波形时,该位闪烁。 第3位:F 表示频率,A 表示幅度,d 表示占空比,处于选择参数时,该位闪烁。第4-8位: x 表示设置数据,当前要设置的数据位闪烁,按 、键改变设置数据的位数,按确认键,当前参数设置完毕,进入下一个参数或波形设置。设置状态下各种显示如下正弦波频率显示 S 1 F - - - x x
12、正弦波幅度显示 S 1 A - - - x x 锯齿波频率显示 S 2 F - - - x x 锯齿波幅度显示 S 2 A - - - x x c、选择输出波形 在非设置状态,按选择波形键,选择输出波形,按一下切换一次,这时显示所选择输出波形代码和频率,但并不输出所选择的输出波形,要按确认键后,才输出所选择的输出波形。 在非设置状态,按选择参数键,选择显示的参数,按一下切换一次。 在非设置状态的显示与设置时的显示仅最高位不同,最高位显示“O”,并且没有闪烁。例如输出正弦波频率显示 O 1 F - - - x x 输出正弦波幅度显示 O 1 A - - - x x 5、总结(1)此次作品的优缺点
13、分析此次课程设计的作品,其优点在于成本低,用户方便控制,不足之处在于输出波形的采样点数单个周期之内只有32个点,导致波形看上去有明显的阶梯感,且输出频率不能达到很高,并不能满足大多数的使用要求。我建议的方式是使用并行的、高速率的D/A芯片和高性能的单片机。高性能的单片机控制能力强大,管脚的功能相对复杂,不但能够输出采样点数更多的波形,还能提高输出频率,并且还可以设计出更加好的用户界面。并且方便建立波形数据库,不单单只能输出正弦波、锯齿波这么几种简单波形,还能按照用户需要设计出多种多样譬如被调制的高频正弦波等等。但是成本较高。(2)本次课程设计的心得体会只有去认真的探索,才能发现和解决问题。只有
14、真正在查找问题,解决问题,才能使得人的能力得到提高,经验也慢慢丰富起来。随随便便搞一搞,对老师不敬重,更是对自己的不负责任。这样的课程设计,不论难易,认真的做,肯定是有收获。就算是查找了很多问题,也没有把问题解决,你也明白了自己解决问题的方式有可能存在欠缺,这本身也是一笔很大的收获。参考文献1 郭天祥.51单片机C语言教程.电子工业出版社,20072 张毅刚,王少军,付宁单片机原理及接口技术.人民邮电出版社,2015 3 恰汗合孜尔.C语言程序设计.中国铁道出版社,20104 刘卫国.MATLAB程序设计与应用.高等教育出版社,2006.75 谭浩强.C程序设计.北京:清华大学出版社,1991
15、附件1:程序代码/*-1.c-*/*注意:time_repire 可以考虑软件修正时间 (我们学院的单片机真的是12M,而不是11.0592M)*/#include sbit TEST = P11;int time_repire=-40; /修复中断响应时间以及 TL1= (LOAD_L);TH1= (LOAD_H)的耗时 int LOAD_H = (65536-276)/256;int LOAD_L = (65536-276)%256; #define LOAD_H_two_fre_num_2 (65536-(1000000/two_fre_num_2/32)-time_repire)/25
16、6)#define LOAD_L_two_fre_num_2 (65536-(1000000/two_fre_num_2/32)-time_repire)%256)#define LOAD_H_one_fre_num_2 (65536-(1000000/one_fre_num_2/32)-time_repire)/256)#define LOAD_L_one_fre_num_2 (65536-(1000000/one_fre_num_2/32)-time_repire)%256)#include#include#include#includebit test=0;int save= 0; /防
17、止I2C冲突void main() PT1 = 1; /t1中断为高优先级中断 PT0 = 0; /t0中断为低优先级中断 TEST = 0; /-上电初始化,从EEPROM读入数据-/ disp3 = 17; disp4 = 17; disp5 = 17; disp0 = 5; save = 1; ET1=0; init_E2PROM(); wave = read_add(1); fre_amp = read_add(2); one_fre_num = read_add(3); one_amp_num = read_add(4); two_fre_num = read_add(5); two
18、_amp_num = read_add(6); /上电初始化 wave_2 = wave; /副本更新 , 主本从i2c获取数据 fre_amp_2 =fre_amp; one_fre_num_2 =one_fre_num; one_amp_num_2 =one_amp_num; two_fre_num_2 =two_fre_num; two_amp_num_2 =two_amp_num; /(变量副本:仅用于输出) if(wave_2=0) /波形数据更新 sawtooth(two_amp_num_2); LOAD_H = LOAD_H_two_fre_num_2;LOAD_L = LOAD
19、_L_two_fre_num_2; if(wave_2=1) sine(one_amp_num_2); LOAD_H = LOAD_H_one_fre_num_2;LOAD_L = LOAD_L_one_fre_num_2; save = 0; ET1=1; /- DA_init(); T1_init(); key_display(); /*-HCI.H-*/*人机交互模块 输入:按下矩阵键盘 输出:keynum = 0 - 15 对应矩阵键盘 输入:dispX= Y 输出:在第X位上显示tableY的数据 关键变量: waveset_allow= 0, wave = 0, fre_amp=0
20、; one_fre_num=12;one_amp_num=34; two_fre_num=56; two_amp_num=78; / 设置? 波形? 频率/幅度? 频率和幅度具体的数值 int one_fre_num_low=0, one_fre_num_hign=0;int one_amp_num_low=0, one_amp_num_hign=0; /位数分离int two_fre_num_low=0, two_fre_num_hign=0; /int two_amp_num_low=0, two_amp_num_hign=0; /位数分离 */#ifndef _HCI_#define _
21、HCI_#define uchar unsigned char#define uint unsigned intsbit oe=P13; /数码管段选、位选锁存器输出控制信号sbit dula=P14; /数码管段选锁存器控制信号sbit wela=P15; /数码管位选锁存器控制信号uchar j=0;uchar a,b,c,i,keynum=-1;extern int save;extern int SAWFRE;extern int SINFRE;extern void sawtooth(int ampSAW);extern void sine(int ampSIN);extern vo
22、id save_date(uchar address,uchar date);extern uchar read_date(uchar address);extern void init_E2PROM();extern void DA_init();extern void T1_init(); uchar code sled_bit=0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f; /定义点亮数码管位选码data uchar disp8=16,16,16,16,16,16,16,16; /要显示在8个数码管上的数据在table上的位置uchar code tab
23、le18=0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71, 0x00,0x40; /共阴极数码管显示段码(0-F) /关键变量 uchar waveset_allow= 0, wave = 0, fre_amp=0; one_fre_num=12;one_amp_num=5; two_fre_num=30; two_amp_num=5; uchar waveset_allow_2= 0, wave_2 = 0, fre_amp_2=0; one_fre_num_2=12;one
24、_amp_num_2=5; two_fre_num_2=30; two_amp_num_2=5; /(变量副本) / 设置? 波形? 频率/幅度? 频率和幅度具体的数值 int time_flash = 0, time_flash1=0, time_flash2=0 , waveflash=0,fre_ampflash=0; /闪烁时间计数/-其他变量-int amp_point_dis=0;int set; /是否在设置状态uchar keydef = N; /键位定义int one_fre_num_low=0, one_fre_num_hign=0;int one_amp_num_low=
25、0, one_amp_num_hign=0; /位数分离int two_fre_num_low=0, two_fre_num_hign=0; /int two_amp_num_low=0, two_amp_num_hign=0; /位数分离int high_dis=0;low_dis=0;int hign_flash =0,low_flash=0;/-void delay( n ) /延时函数data uchar n; data uchar m; while(n-) for(m=0;m1;m+);void key_display(void) TMOD=0x01|TMOD; / 设置定时器T0为
26、方式1定时 TH0=(65536-1000)/256; / 给T0装入初值 TL0=(65536-1000)%256; / 给T0装入初值 ET0=1; / 允许T0中断 EA=1; / CPU开中断 TR0=1; / 启动T0 oe=0; P2=0xff; while(1) P2=0xf0; delay(5); P2=0xf0; a=P2; P2=0x0f; delay(5); P2=0x0f; b=P2; a=a|b; if(a!=0xff) while(P2!=0x0f); switch(a) /keynum = 0 -15 对应矩阵键盘16个按键 /keydef 为实际模型 case
27、0xee: keynum=0; keydef = 0; break; case 0xde: keynum=1; keydef = 1; break; case 0xbe: keynum=2; keydef = 2; break; case 0x7e: keynum=3; keydef = 3; break; case 0xed: keynum=4; keydef = 4; break; case 0xdd: keynum=5; keydef = 5; break; case 0xbd: keynum=6; keydef = 6; break; case 0x7d: keynum=7; keydef = 7; break; case 0xeb: keynum=8; keydef = ; break; case 0xe7: keynum=12; keydef = S; break; case 0xd7: keynum=13; keydef = W; break; case 0xb7: keynum=14; keydef = X; break; case 0x77: keynum=15; k
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1