信号发生器 (正弦波,方波,三角波)51单片机 C语言代码
- 格式:doc
- 大小:43.00 KB
- 文档页数:12
STC51单片机的函数信号发生器(c语言)————————————————————————————————作者:————————————————————————————————日期:基于51单片机的函数信号发生器设计报告摘要本系统利用单片机AT89C52采用程序设计方法产生锯齿波、三角波、正弦波、方波四种波形,再通过D/A转换器DAC0832将数字信号转换成模拟信号,滤波放大,最终由示波器显示出来,能产生10Hz—10kHz的波形。
通过键盘来控制四种波形的类型选择、拨码开关控制频率的变化,并通过液晶屏1602显示其各自的类型以及数值,系统大致包括信号发生部分、数/模转换部分以及液晶显示部分三部分,其中尤其对数/模转换部分和波形产生和变化部分进行详细论述。
关键词:单片机AT89S52、DAC0832、液晶1602目录1. 系统设计1.1 设计要求1.2方案设计与论证1.2.1 信号发生电路方案论证 1.2.2 单片机的选择论证1.2.3 显示方案论证1.2.4 键盘方案论证1.3 总体系统设计1.4 硬件实现及单元电路设计1.4.1 单片机最小系统的设计1.4.2 波形产生模块设计1.4.3 显示模块的设计1.4.4 键盘模块的设计1.5 软件设计流程1.6 源程序2. 输出波形的种类与频率的测试2.1 测试仪器及测试说明2.2 测试结果3、附录3.1 参考文献3.2 附图1、系统设计经过考虑,我们确定方案如下:利用AT89C52单片机采用程序设计方法产生锯齿波、三角波、正弦波、方波四种波形,再通过D/A转换器DAC0832将数字信号转换成模拟信号,滤波放大,最终由示波器显示出来,通过键盘来控制四种波形的类型选择、频率变化,最终输出显示其各自的类型以及数值。
1.1、设计要求1)、利用单片机采用软件设计方法产生四种波形2)、四种波形可通过键盘选择3)、波形频率可调4)、需显示波形的种类及其频率1.2方案设计与论证1.2.1 信号发生电路方案论证方案一:通过单片机控制D/A,输出四种波形。
目录1 引言 (1)1.1 题目要求及分析 (1)1.1.1 示意图 (1)1.2 设计要求 (1)2 波形发生器系统设计方案 (2)2.1 方案的设计思路 (2)2.2 设计框图及系统介绍 (2)2.3 选择合适的设计方案 (2)3 主要硬件电路及器件介绍 (4)3.1 80C51单片机 (4)3.2 DAC0832 (5)3.3 数码显示管 (6)4 系统的硬件设计 (8)4.1 硬件原理框图 (8)4.2 89C51系统设计 (8)4.3 时钟电路 (9)4.4 复位电路 (9)4.5 键盘接口电路 (10)4.7 数模转换器 (11)5 系统软件设计 (12)5.1 流程图: (12)5.2 产生波形图 (12)5.2.1 正弦波 (12)5.2.2 三角波 (13)5.2.3 方波 (14)6 结论 (16)主要参考文献 (17)致谢....................................................... 错误!未定义书签。
1引言1.1题目要求及分析题目:基于51单片机的波形发生器设计,即由51单片机控制产生正弦波、方波、三角波等的多种波形。
1.1.1示意图图1:系统流程示意图1.2设计要求(1) 系统具有产生正弦波、三角波、方波三种周期性波形的功能。
(2) 用键盘控制上述三种波形(同周期)的生成,以及由基波和它的谐波(5次以下)线性组合的波形。
(3) 系统具有存储波形功能。
(4) 系统输出波形的频率范围为1Hz~1MHz,重复频率可调,频率步进间隔≤100Hz,非正弦波的频率按照10次谐波来计算。
(5) 系统输出波形幅度范围0~5V。
(6) 系统具有显示输出波形的类型、重复频率和幅度的功能。
2波形发生器系统设计方案设计并制作一个波形信号发生器,能够产生正弦波、方波、三角波的波形,其中不使用DDS和一些专用的波形产生芯片。
并让系统的频率范围在1Hz~1MHZ可调节,在频率范围在1HZ~10KHz时,步进小于或等于10Hz,在频率范围在10KHz~1MHz时,步进小于或等于100Hz,并且电压在0~5V范围,能够实时的显示波形的类型、频率和幅值。
波形发生器是一种常用的信号源,广泛地应用于电子电路、自动控制系统和教学实验等领域。
本次课程设计使用的AT89S51 单片机构成的发生器可产生锯齿波、三角波、正弦波等多种波形,波形的周期可以用程序改变,并可根据需要选择单极性输出或双极性输出,具有线路简单、结构紧凑等优点。
在本设计的基础上,加上按钮控制和LED显示器,则可通过按钮设定所需要的波形频率,并在LED上显示频率、幅值电压,波形可用示波器显示。
二、系统设计波形发生器原理方框图如下所示。
波形的产生是通过AT89S51 执行某一波形发生程序,向D/A转换器的输入端按一定的规律发生数据,从而在D/A转换电路的输出端得到相应的电压波形。
在AT89S51的P2口接5个按扭,通过软件编程来选择各种波形、幅值电压和频率,另有3个P2口管脚接TEC6122芯片,以驱动数码管显示电压幅值和频率,每种波形对应一个按钮。
此方案的有点是电路原理比较简单,实现起来比较容易。
缺点是,采样频率由单片机内部产生故使整个系统的频率降低。
1、波形发生器技术指标1)波形:方波、正弦波、锯齿波;2)幅值电压:1V、2V、3V、4V、5V;3)频率:10HZ、20HZ、50HZ、100HZ、200HZ、500HZ、1KHZ;2、操作设计1)上电后,系统初始化,数码显示6个…-‟,等待输入设置命令。
2)按钮分别控制“幅值”、“频率”、“方波”、“正弦波”、“锯齿波”。
3)“幅值“键初始值是1V,随后再次按下依次增长1V,到达5V后在按就回到1V。
4)“频率“键初始值是10HZ,随后在按下依次为20HZ、50HZ、100HZ、200HZ、500HZ、1000HZ循环。
三、硬件设计本系统由单片机、显示接口电路,波形转换(D/A)电路和电源等四部分构成。
电路图2附在后1、单片机电路功能:形成扫描码,键值识别、键处理、参数设置;形成显示段码;产生定时中断;形成波形的数字编码,并输出到D/A接口电路和显示驱动电路。
显示频率,幅度可调,可产生四种波形,正弦波,方波,锯齿波,三角波,希望你能喜欢,给你发了一张效果图,喜欢的话别忘了采纳我的回答啊#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define DAdata P0 //DA数据端口sbit DA_S1= P2^0; // 控制DAC0832的8位输入寄存器,仅当都为0时,可以输出数据(处于直通状态),否则,输出将被锁存sbit DA_S2= P2^1; // 控制DAC0832的8位DAC寄存器,仅当都为0时,可以输出数据(处于直通状态),否则,输出将被锁存sbit key= P3^2;uchar wavecount; //'抽点'计数uchar THtemp,TLtemp;//传递频率的中间变量uchar judge=1; //在方波输出函数中用于简单判别作用uchar waveform; //当其为0、1、2时,分别代表三种波uchar code freq_unit[3]={10,50,200}; //三种波的频率单位uchar idata wavefreq[3]={1,1,1}; //给每种波定义一个数组单元,用于存放单位频率的个数uchar code lcd_hang1[]={"Sine Wave " "Triangle Wave " "Square Wave " "Select Wave: " "press No.1 key! "};uchar idata lcd_hang2[16]={"f= Hz "};uchar code waveTH[]={0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xf6,0xf9,0xfb,0xfc,0xfc,0xfd,0xfd,0xfd,0xfe};uchar code waveTL[]={0x06,0x8a,0x10,0x4e,0x78,0x93,0xa8,0xb3,0xbe,0xc6, //正弦波频率调整中间值0xac,0xde,0x48,0x7a,0x99,0xaf,0xbb,0xc8,0xd0,0xde, //三角波频率调整中间值0x88,0x50,0x90,0x32,0x34,0xbe,0x4a,0xa3,0xe5,0x2c};/**************************************************************************************** *********/uchar code triangle_tab[]={ //每隔数字8,采取一次0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x 60,0x68,0x70,0x78,0x80,0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,0xc0,0xc8,0xd0,0xd8,0x e0,0xe8,0xf0,0xf8,0xff,0xf8,0xf0,0xe8,0xe0,0xd8,0xd0,0xc8,0xc0,0xb8,0xb0,0xa8,0xa0,0x9 8,0x90,0x88,0x80,0x78,0x70,0x68,0x60,0x58,0x50,0x48,0x40,0x38,0x30,0x28,0x20,0x 18,0x10,0x08,0x00};uchar code sine_tab[256]={//输出电压从0到最大值(正弦波1/4部分)0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa 5,0xa8,0xab,0xae,0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5,0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,0xda,0xdd ,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd, 0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,//输出电压从最大值到0(正弦波1/4部分)0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7 ,0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda,0xd8,0x d6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9 c,0x99 ,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,//输出电压从0到最小值(正弦波1/4部分)0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,0x66,0x63,0x60,0x5d,0x5 a,0x57,0x55,0x51,0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,0x33,0x30,0x2e,0x2b,0x29,0x27,0x25,0x 22,0x20,0x1e,0x1c,0x1a,0x18,0x16 ,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x 03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,//输出电压从最小值到0(正弦波1/4部分)0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02 ,0x02,0x03,0x04,0x05,0x 06,0x07,0x08,0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15 ,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,0x27,0x 29,0x2b,0x2e,0x30,0x33,0x35,0x38,0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e,0x51,0x55,0x57,0x5a,0x5d,0x60,0x 63,0x66 ,0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80};void delay(uchar z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void triangle_out() //三角波输出{DAdata=triangle_tab[wavecount++];if(wavecount>64) wavecount=0;DA_S1=0; //打开8位输入寄存器DA_S1=1; //关闭8位输入寄存器void sine_out() //正弦波输出{DAdata=sine_tab[wavecount++];DA_S1=0; //打开8位输入寄存器DA_S1=1; //关闭8位输入寄存器}void square_out() //方波输出{judge=~judge;if(judge==1) DAdata=0xff;else DAdata=0x00;DA_S1=0; //打开8位输入寄存器DA_S1=1; //关闭8位输入寄存器}/************1602液晶的相关函数*************/#define lcd_ports P1sbit rs=P2^2;sbit rw=P2^3;sbit lcden=P2^4;void write_com(uchar com){rs=0; //置零,表示写指令lcden=0;lcd_ports=com;delay(5);lcden=1;delay(5);lcden=0;}void write_date(uchar date){rs=1; //置1,表示写数据(在指令所指的地方写数据)lcden=0;lcd_ports=date;delay(5);lcden=1;delay(5);lcden=0;void disp_lcd(uchar addr,uchar *temp1){uchar num;write_com(addr);delay(1); //延时一会儿???for(num=0;num<16;num++){write_date(temp1[num]);//或者这样写write_date(*(temp1+num));delay(1);}}void init_lcd(){//uchar num;lcden=0; //可有可无???rw=0; //初始化一定要设置为零,表示写数据write_com(0x38); //使液晶显示点阵,为下面做准备write_com(0x0c); //初始设置write_com(0x06); //初始设置write_com(0x01); //清零write_com(0x80); //使指针指向第一行第一格disp_lcd(0x80,&lcd_hang1[3*16]); //在第一行显示disp_lcd(0xc0,&lcd_hang1[4*16]); //在第二行显示}/********************1602液晶函数声明结束*********************/ void main(){uchar i=0;DA_S2=0; //使DAC寄存器处于直通状态DAdata=0;DA_S1=1; //关闭8位输入寄存器init_lcd();waveform=0;TMOD=0x01; //设置定时器0为16位工作方式IT0=1; //设置外部中断0为下降沿触发ET0=1; //开定时器中断EX0=1;EA=1;while(1){//DAout(0xff); //可输出TTL波形//DAout(0x80);//T_temp=32;}}void timer0() interrupt 1{TH0=THtemp;TL0=TLtemp;if(waveform==0) sine_out();else if(waveform==1) triangle_out();else if(waveform==2) square_out();}void key_int0() interrupt 0{uchar keytemp;uint total_freq; //总频率EA=0; TR0=0; //关总中断与定时器delay(5); //延时够吗???if(key==0) //确实有按键按下而引发中断{keytemp=P3&0xf0; //获取P3口高四位的值switch(keytemp){case 0xe0: //选择波形waveform++;if(waveform>2) waveform=0;break;case 0xd0: //频率按规定单位依次增加wavefreq[waveform]++;if(wavefreq[waveform]>10) wavefreq[waveform]=1; // /*这边要用“>10”,因为它比“=11”可靠break;case 0xb0: //频率按规定单位依次衰减wavefreq[waveform]--;if(wavefreq[waveform]<1) wavefreq[waveform]=10; //这边要用“<1”,因为它比“=0”可靠性更高break;case 0x70: //TTL输出DA_S2=1; //使DAC寄存器关闭break;}THtemp=waveTH[waveform*10+(wavefreq[waveform]-1)]; //方括号中选取第几个数后,并把该值赋给T_tempTLtemp=waveTL[waveform*10+(wavefreq[waveform]-1)];total_freq= wavefreq[waveform] * freq_unit[waveform]; //求输出频率(个数*单位)lcd_hang2[5]=total_freq%10+0x30; //在液晶中显示个位,(0x30 在液晶显示中表示数字0)total_freq/=10; lcd_hang2[4]=total_freq%10+0x30; //在液晶中显示时十位total_freq/=10; lcd_hang2[3]=total_freq%10+0x30; //在液晶中显示时百位total_freq/=10; lcd_hang2[2]=total_freq%10+0x30; //在液晶中显示时千位disp_lcd(0x80,&lcd_hang1[waveform*16]); //在第一行显示disp_lcd(0xc0,lcd_hang2); //在第二行显示}wavecount=0; //'抽点'计数清零while(!key);EA=1; TR0=1; //开启总中断与定时器}。
51单片机制作的波形发生器相信很多朋友都可能接触到一个波型发生器的制作,可能刚刚入门,做的东西也不会说是很复杂。
可能就一个矩形波,或者是三角波。
但是网上的很多资料是忽悠人的,就此,我也提供一个比较完整的波型发生器 C51 原代:该系统的软件比较典型:包括键盘的应用,显示的应用和 DA 转换器的应用。
本设计中,输出的波形有三种:正弦波,方波,三角波。
方波的输出最为简单,只要按照设定的周期值将输出的电压改变即可。
三角波的输出也比较简单,单片机的输出只要完成数字量递增和递减交替进行即可。
、正弦波的输出最麻烦,如果在软件中计算出输出的各点电压值,将会浪费很多的 CPU 时间,以至于无法满足频率的要求。
通常最简单的方法是通过手动的方法计算出输出各点的电压值,然后在编写程序时以数组的方式给出。
当需要时,只要按照顺序进行输出即可。
这种方法比运算法速度快且曲线的形状修改灵活。
在本设计中将 360 度分为 256 个点,则每两个点之间的间隔为1.4 度,然后计算出每个点电压对应的数字量即可。
只要反复输出这组数据到 DAC0832, 就可以在系统输出端得到想要的正弦波。
具体程序如下:#include ;#define uchar unsigned char#define uint unsigned int#define DAdata P0uchar code Sinetab[256]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xab,0xad,0xaf,0xb1,0xb2,0xb4,0xb6,0xb7,0xb9,0xba,0xbc,0xbd,0xbf,0xc0,0xc1,0xc3,0xc4,0xc5,0xc6,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd2,0xd3,0xd3,0xd3,0xd2,0xd2,0xd1,0xd1,0xd0,0xcf,0xce,0xce,0xcd,0xcc,0xcb,0xca,0xc9,0xc8,0xc6,0xc5,0xc4,0xc3,0xc1,0xc0,0xbf,0xbd,0xbc,0xba,0xb9,0xb7,0xb6,0xb4,0xb2,0xb1,0xaf,0xad,0xab,0xaa,0xa8,0xa6,0xa4,0xa2,0xa0,0x9e,0x9c,0x9a,0x98,0x96,0x94,0x92,0x90,0x8e,0x8c,0x8a,0x88,0x86,0x84,0x82, 0x80,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71, 0x6f,0x6d,0x6b,0x69,0x67,0x65,0x63,0x61, 0x5f,0x5d,0x5b,0x59,0x57,0x55,0x54,0x52, 0x50,0x4e,0x4d,0x4b,0x49,0x48,0x46,0x45, 0x43,0x42,0x40,0x3f,0x3e,0x3c,0x3b,0x3a, 0x39,0x37,0x36,0x35,0x34,0x33,0x32,0x31, 0x31,0x30,0x2f,0x2e,0x2e,0x2d,0x2d,0x2c, 0x2c,0x2b,0x2b,0x2b,0x2b,0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2b, 0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2f,0x30, 0x31,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x39,0x3a,0x3b,0x3c,0x3e,0x3f,0x40,0x42, 0x43,0x45,0x46,0x48,0x49,0x4b,0x4d,0x4e, 0x50,0x52,0x54,0x55,0x57,0x59,0x5b,0x5d, 0x5f,0x61,0x63,0x65,0x67,0x69,0x6b,0x6d, 0x6f,0x71,0x73,0x75,0x77,0x79,0x7b,0x7d, };uchar code Triangletab[58]={0x1a,0x21,0x28,0x2f,0x36,0x3d,0x44,0x4b, 0x52,0x59,0x60,0x67,0x6e,0x75,0x7c,0x83,0x8a,0x91,0x98,0x9f,0xa6,0xad,0xb4,0xbb,0xc2,0xc9,0xd0,0xd7,0xde,0xe5,0xde,0xd7,0xd0,0xc9,0xc2,0xbb,0xb4,0xad,0xa6,0x9f,0x98,0x91,0x8a,0x83,0x7c,0x75,0x6e,0x67,0x60,0x59,0x52,0x4b,0x44,0x3d,0x36,0x2f,0x28,0x21,};uchar code Squaretab[2]={0x56,0xaa};uchar code disp1[]={"Sine Wave ""Triangle Wale ""Square Wave "};uchar idata disp2[16]={"Frequency:Hz"};uchar code Coef[3]={10,100,200};uchar idata WaveFre[3]={1,1,1};uchar code WaveTH[]={0xfc,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xfc,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, };uchar code WaveTL[]={0xf2,0x78,0xfb,0x3c,0x63,0x7d,0x8f,0x9d,0xa8,0xb1, 0x17,0x0b,0xb2,0x05,0x37,0x58,0x70,0x82,0x90,0x9b, 0x4d,0xa7,0xc4,0xd3,0xdc,0xe2,0xe6,0xea,0xec,0xee };uchar Wavecount,THtemp,TLtemp;uchar Waveform;sbit rs=P2^5;sbit rw=P2^6;sbit e=P2^7;sbit DA=P2^0;sbit KEY=P3^2;void delay(uchar i){uchar j;for(;i>;0;i--)for(j=20;j>;0;j--);}void busy(){uchar temp;temp=0x00;rs=0;rw=1;while((temp&0x80)==0x80) {P0=0xff;e=1;temp=P0;e=0;}}void WR_Com(uchar temp) {busy();rs=0;rw=0;P0=temp;e=1;e=0;}void WR_Data(uchar num){busy();rs=1;rw=0;P0=num;e=1;e=0;}void disp_lcd(uchar addr,uchar *temp1) {uchar i;WR_Com(addr);delay(100);for(i=0;i;0;i--){P0=0x30;rs=0;rw=0;e=1;e=0;delay(100);P0=0x38;rs=0;rw=0;e=1;e=0;delay(100);}void lcd_Reset(){WR_Com(0x01);delay(100);WR_Com(0x06);delay(100);WR_Com(0x0c);delay(100);}void SineOUT(uchar Wavecount) {DAdata=Sinetab[Wavecount++]; Wavecount=0;DA=0;}void TriangleOUT(uchar Wavecount) {DAdata=Triangletab[Wavecount++]; if(Wavecount>;57)Wavecount=0;DA=0;DA=1;}void SquareOUT(uchar Wavecount) {DAdata=Squaretab[Wavecount++];if(Wavecount>;1)Wavecount=0;DA=0;DA=1;}void timer() interrupt 1{TH0=THtemp;TL0=THtemp;if(Waveform==0)SineOUT(Wavecount); else if(Waveform==1)TriangleOUT(Wavecount); else if(Waveform==2)SquareOUT(Wavecount); }void key_int() interrupt 0 {uchar keytemp,keytemp1;uint WaveCoef;EA=0;TR0=0;keytemp1=0;delay(10);while(!KEY);keytemp=~P2&0x1e; keytemp>;>;=1;while(keytemp!=8){keytemp=~P2&0x1e;keytemp>;>;=1;if(keytemp!=keytemp1){keytemp1=keytemp;switch(keytemp){case 1:if(++Waveform==3)Waveform=0;break;case 2:if(++WaveFre[Waveform]==11)WaveFre[Waveform]=1;break;case 4:if(--WaveFre[Waveform]==0)WaveFre[Waveform]=10;break;}THtemp=WaveTH[Waveform*16+(WaveFre[Waveform]-1)]; TLtemp=WaveTL[Waveform*16+(WaveFre[Waveform]-1)];WaveCoef=WaveFre[Waveform]*Coef[Waveform]; disp2[13]=WaveCoef%10+0x30;WaveCoef/=10;disp2[12]=WaveCoef%10+0x30;WaveCoef/=10;disp2[11]=WaveCoef%10+0x30;WaveCoef/=10;disp2[10]=WaveCoef%10+0x30;WaveCoef/=10;disp_lcd(0x80,&disp1[Waveform*16]);disp_lcd(0xc0,disp2);}}TH0=THtemp;TL0=THtemp;Wavecount=0;TR0=1;}void main(){uint WaveCoef;uchar i;lcd_ini();lcd_Reset();WaveCoef=WaveFre[Waveform]*Coef[Waveform]; disp2[13]=WaveCoef%10+0x30;WaveCoef/=10;disp2[12]=WaveCoef%10+0x30;WaveCoef/=10;disp2[11]=WaveCoef%10+0x30;WaveCoef/=10;disp2[10]=WaveCoef%10+0x30;WaveCoef/=10;disp_lcd(0x80,&disp1[Waveform*16]);disp_lcd(0xc0,disp2);i=0;DAdata=0x00;DA=0;TMOD=0x01;IT0=1;ET0=1;EX0=1;EA=1;while(1);}。
51单片机延时函数在嵌入式系统开发中,51单片机因其易于学习和使用、成本低廉等优点被广泛使用。
在51单片机的程序设计中,延时函数是一个常见的需求。
通过延时函数,我们可以控制程序的执行速度,实现定时器功能,或者在需要的时候进行延时操作。
本文将介绍51单片机中常见的延时函数及其实现方法。
一、使用for循环延时这种方法不精确,但是对于要求不高的场合,可以用来估算延时。
cvoid delay(unsigned int time){unsigned int i,j;for(i=0;i<time;i++)for(j=0;j<1275;j++);}这个延时函数的原理是:在第一个for循环中,我们循环了指定的时间次数(time次),然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有很大差异,所以只适用于对延时时间要求不精确的场合。
二、使用while循环延时这种方法比使用for循环延时更精确一些,但是同样因为硬件和编译器的不同,延时时间会有差异。
cvoid delay(unsigned int time){unsigned int i;while(time--)for(i=0;i<1275;i++);}这个延时函数的原理是:我们先进入一个while循环,在这个循环中,我们循环指定的时间次数(time次)。
然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有差异,所以只适用于对延时时间要求不精确的场合。
三、使用定时器0实现精确延时这种方法需要在单片机中开启定时器0,并设置定时器中断。
在中断服务程序中,我们进行相应的操作来实现精确的延时。
这种方法需要使用到单片机的定时器中断功能,相对复杂一些,但是可以实现精确的延时。
基于51单片机的函数发生器以STC89C51单片机为核心设计了一个低频函数信号发生器。
信号发生器采用数字波形合成技术,通过硬件电路和软件程序相结合,可输出自定义波形,如正弦波、方波、三角波、三角波、梯形波及其他任意波形,波形的频率和幅度在一定范围内可任意改变。
波形和频率的改变通过软件控制,幅度的改变通过硬件实现。
介绍了波形的生成原理、硬件电路和软件部分的设计原理。
本系统可以产生最高频率798.6HZ的波形。
该信号发生器具有体积小、价格低、性能稳定、功能齐全的优点。
关键词:低频信号发生器;单片机;D /A转换;一.设计任务设计一个由单片机控制的信号发生器。
运用单片机系统控制产生多种波形,这些波形包括方波、三角波、锯齿波、正弦波等。
信号发生器所产生的波形的频率、幅度均可调节。
二.系统概述2.1总体方案:采用AT89C51单片机和DAC0832数模转换器生成波形,加上一个低通滤波器,生成的波形比较纯净。
它的特点是可产生任意波形,频率容易调节,频率能达到设计的500HZ以上。
性能高,在低频范围内稳定性好、操作方便、体积小、耗电少。
将输出电压通过一个运算放大器的放大来改变幅度。
这样还有个优点是幅度连续可调。
2.2工作原理:数字信号可以通过数/模转换器转换成模拟信号,因此可通过产生数字信号再转换成模拟信号的方法来获得所需要的波形。
89C51单片机本身就是一个完整的微型计算机,具有组成微型计算机的各部分部件:中央处理器CPU、随机存取存储器RAM、只读存储器ROM、I/O接口电路、定时器/计数器以及串行通讯接口等,只要将89C51再配置键盘及、数模转换及波形输出、放大电路等部分,即可构成所需的波形发生器,其信号发生器构成系统框图如下图所示。
系统框图89C51是整个波形发生器的核心部分,通过程序的编写和执行,产生各种各样的信号,并从键盘接收数据,进行各种功能的转换和信号幅度的调节。
当数字信号电路到达转换电路,将其转换成模拟信号也就是所需要的输出波形。
创新性实验研究报告实验项目名称_简易函数信号发生器四、实验内容1、运用keil软件对程序进行编写,运行程序,并进行程序修改。
2、运用protues软件进行硬件电路仿真设计。
3、将程序下载到仿真单片机中,并观测输出波形。
4、对程序进行修改,再次运行仿真软件,直到输出理想的波形。
5、仿照仿真软件进行硬件电路的焊接。
6、将程序下载到单片机,并用示波器测试输出波形。
7、对程序进行修改,直到输出满意的波形为止。
3、实验步骤1、首先打开keil软件.2、运用keil软件对程序进行编写,程序见附件。
3、打开protues软件.4、运用protues软件对硬件电路进行设计。
9C51单片机是该信号发生器的核心,具有2个定时器,32个并行I/O口,1个串行I/O口,5个中断源。
由于本设计功能简单,数据处理容易,数据存储空间也足够,因为我们采用了片选法选择芯片,进行芯片的选择和地址的译码。
在单片机最小最小系统中,单片机从P1口接收来自键盘的信号,并通过P0口输出控制信号,通过DA转换芯片最终由示波器显示输出波形。
单片机引脚分配如下:�XTAL1,XTAL2:外接晶振,产生时钟信号。
�RST:复位电路;�P2口:8位数字信号输出输出,外接DAC0832;�P3.6口和P3.7口:DAC0832的时钟信号;单片机模块单片机输出的是数字信号,因为要得到模拟信号的波形就必须对其进行数模转换。
我们采用了DAC0832数模转换器,该芯片具由8位输入锁存器、8位DAC寄存器、8位D/A转换器及转换控制电路四部分构成。
由于其输出为电流输出,因为外加运算放大器LM324使之转换为电压输出。
最后通过示波器显示输出的波形。
数模转换模块运放模块整体硬件电路图五、实验结果与分析1、实验现象、数据记录仿真波形2、对实验现象、数据及观察结果的分析与讨论:经过观察调试,再观察,再调试,最终输出的波形较为理想。
此次试验经过一系列的调试,最终输出的波形为正弦波、方波、三角波。
正弦信号发生器C程序及解释/*1 、可通过按键实现频率输出步进加减;步进频率范围0~10MHz;2、步进值有六种选择:10Hz、100Hz、1000Hz、10KHz、100KHz、1000KHz3、采用1602液晶显示屏,可以实时显示输出频率值,显示当前步进值,显示频率的单位都为Hz。
*///基本功能全部实现;2009041407#include <reg52.h> //调用头文件(单片机内部的寄存器定义)#define uchar unsigned char#define uint unsigned int/******本段为硬件I/O口定义********/sbit LCD_E = P1^1;//定义1602液晶的使能管脚;sbit LCD_RW = P1^2;//定义1602液晶的读写管脚;sbit LCD_RS = P1^3;//定义1602液晶的选通管脚;sbit reset = P1^4; //ad9850的复位引脚;//sbit w_clk = P1^7; //ad9850的时钟引脚;//sbit fqud = P1^6; //ad9850的输出更新引脚;sbit w_clk = P3^1; // ad9850 w_clk;sbit fqud = P3^0; //ad9850 fqud;#define LCD_DATA P2 //向1602液晶传送数据的端口,这里用的是P2口;#define LCD_BUSY 0x80 // 用于检测LCD的忙标识(本程序中用的是延时,未检测)//LCD显示内容,定义到代码段;unsigned char code LcdBuf1[]= {"FRQ: Hz"};unsigned char code LcdBuf2[]= {"Step:"};double Con_Word_1 = 0x00;//定义了一个浮点变量,用于计算控制字;double Con_Word_2 = 0x00;//定义了一个浮点变量,用于计算控制字;long uint ConTrol_Word = 0x00;//用来存储控制字的数值;long uint Frequency_Out;//设置的频率值;uchar a,b,c,d,e,f,g,h; //为了向1602写入频率值,首先将频率值拆分存于这8个变量中;sbit Light = P1^0; //程序状态指示灯,它与单片机对9850控制无关,只是调试程序的时候使用!//定义按键;2X3矩阵键盘;sbit P3_3 = P3^3;sbit P3_4 = P3^4;sbit P3_5 = P3^5;sbit P3_6 = P3^6;sbit P3_7 = P3^7;uchar dat = 0;//键盘子程序处理过程中使用的中间变量;uchar keyzhi = 0x00;//键值;键盘扫描子程序的返回值存于该变量中;//函数声明void lcd_init(void);//1602液晶初始化子程序;void display_string(unsigned char x,unsigned chary,unsigned char *s);//显示字符子程序;x、y是坐标;x:从左边数起第几个字符:y:是第一行还是第二行;/**************************************************** 函数名称: delay** 入口参数:h(unsigned int型)** 出口参数:无** 功能描述: 短暂延时,使用11.0592晶体,约0.01MS****************************************************/void delay(long unsigned int h){while(h--); //延时子程序}/**************************************************** 函数名称: WriteDataLcd** 入口参数:wdata(unsigned char型)** 出口参数:无** 功能描述: 写数据到LCD****************************************************/void WriteDataLcd(unsigned char wdata)//向1602液晶写入数据;{LCD_RS=1;LCD_RW=0;LCD_E=0;LCD_E=1;LCD_DATA=wdata;delay(100); //短暂延时,代替检测忙状态LCD_E=0;}/**************************************************** 函数名称: WriteCommandLcd** 入口参数:wdata(unsigned char型)** 出口参数:无** 功能描述: 写命令到LCD****************************************************/void WriteCommandLcd(unsigned char wdata)//向1602液晶写入命令;{LCD_RS=0;LCD_RW=0;LCD_E=0;LCD_E=1;LCD_DATA=wdata;delay(100); //短暂延时,代替检测忙状态LCD_E=0;}//LCD初始化void lcd_init(void){LCD_DATA = 0;delay(1000);WriteCommandLcd(0x38);delay(500);WriteCommandLcd(0x38); //显示模式设置delay(500);WriteCommandLcd(0x38); //显示模式设置delay(500);WriteCommandLcd(0x01); //关闭显示WriteCommandLcd(0x38); //显示清屏WriteCommandLcd(0x0c); //显示光标移动设置WriteCommandLcd(0x06); //显示开及光标移动设置}/**************************************************** 函数名称: display_xy** 入口参数:x(unsigned char型),y(unsigned char型)** 出口参数:无** 功能描述: 设置光标位置, x是行号,y是列号****************************************************/void display_xy(unsigned char x,unsigned char y){if(y==0x01){x = x + 0x40 + 0x80;}else{x = x+0x80;}WriteCommandLcd(x);}/********************************************************** ************* 函数名称: display_string** 入口参数:x(unsigned char型),y(unsigned char型),s(指针型)** 出口参数:无** 功能描述: 在具体位置显示字符串,以/0结束,x是列号,y是行号*********************************************************** ***********/void display_string(unsigned char x,unsigned chary,unsigned char *s){display_xy(x,y);while(*s){WriteDataLcd(*s);s++;}}Qu_Chu_Shu_Ma_Ge_Wei() //取出要显示的每一位数据;{a = Frequency_Out % 10;b = (Frequency_Out % 100)/10;c = (Frequency_Out % 1000)/100;d = (Frequency_Out % 10000)/1000;e = (Frequency_Out % 100000)/10000;f = (Frequency_Out % 1000000)/100000;g = (Frequency_Out % 10000000)/1000000;h = (Frequency_Out % 100000000)/10000000;}display_data() //显示数据子程序{Qu_Chu_Shu_Ma_Ge_Wei();//取出要显示的每一位数据;display_string(1,0,LcdBuf1);//显示第一行,从第2个位置开始WriteCommandLcd(0x85);//显示数值的话,用其真实的地址,如0x83等,WriteDataLcd(0x30+h); //如果要显示字符的话,暂时用x、y坐标的方式WriteDataLcd(0x30+g);//以下都是送显示数据;WriteDataLcd(0x30+f);WriteDataLcd(0x30+e);WriteDataLcd(0x30+d);WriteDataLcd(0x30+c);WriteDataLcd(0x30+b);WriteDataLcd(0x30+a);}////////////////////////////20081207scan_KEY(void) //键值处理子程序{uchar key = 0;key = P3;key = key & 0xf8;switch(key){case 0xb0:keyzhi = 3 ;break;case 0xa8:keyzhi = 2 ;break;case 0x98:keyzhi = 1 ;break;case 0x70:keyzhi = 6 ;break;case 0x68:keyzhi = 5 ;break;case 0x58:keyzhi = 4 ;break;default:keyzhi=0;}return(keyzhi);}keychuli()//键盘扫描子程序{P3_3 = 0x01;P3_5 = 0x01;P3_4 = 0x01;P3_6 = 0x00;P3_7 = 0x00;delay(100);if((P3_3&P3_4&P3_5) == 0x00){if((P3_3&P3_4&P3_5) == 0x00){P3_6 = 0x00;P3_7 = 0x01;dat = scan_KEY();if(dat == 0x00){P3_6 = 0x01;P3_7 = 0x00;dat = scan_KEY();}}else{dat = 0x00;goto down;//无键按下}}down:return(dat);}Calculate_Control_Word(long uint Frequency_Out){Con_Word_1 = Frequency_Out * 42;Con_Word_2 = Frequency_Out *0.94967296;//100MHz计算方法//首先有源晶体是100MHz的,然后用2的32次方减1,再除以100MHz得到的;//Con_Word_1 = Frequency_Out * 85;//Con_Word_2 = Frequency_Out *0.89934592;//100MHz计算方法//首先有源晶体是100MHz的,然后用2的32次方减1,再除以100MHz得到的;Con_Word_2 = Con_Word_2 + 0.5;//小数部分四舍五入;Con_Word_1 = Con_Word_1 + Con_Word_2;//根据设定的频率以浮点形式计算控制字ConTrol_Word = Con_Word_1 / 1;//将控制字换算成整数形式 }Send_Control_Word(long uint ConTrol_Word)//向AD9850送入频率控制字;{long uint ConTrol_Word_Temporary ;uchar data_word ;w_clk = 0x00; //根据时序图fqud = 0x00; //根据时序图//data_word = 0x00; //设置AD9851相位、掉电等相关控制字data_word = 0x00; //设置AD9850相位、掉电等相关控制字P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word_Temporary = ConTrol_Word;ConTrol_Word = ConTrol_Word >> 24;data_word = ConTrol_Word % 256;//取出W1,频率控制字中的最高字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;ConTrol_Word = ConTrol_Word >> 16;data_word = ConTrol_Word % 256;//取出W2,频率控制字中的次高字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;ConTrol_Word = ConTrol_Word >> 8;data_word = ConTrol_Word % 256;//取出W3,频率控制字中的第三字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;data_word = ConTrol_Word % 256;//取出W4,频率控制字中的最后一个字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0; //根据时序图fqud=1; //根据时序图}/************主程序**************/main(){unsigned char i = 0x00;uint Step_Bian_Liang = 0x00;//步进变量;long uint Step_Data = 1;//默认为1Hz;long unsigned int Step_Data_Xian_Shi = 0x00;reset = 1; //复位AD9850;delay(1000);reset = 0; //使AD9850进入正常的工作状态;lcd_init(); //初始化子程序;Frequency_Out = 0;//开机默认的频率;Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word); //向AD9850送出频率控制字;display_data(); //显示数据;display_string(0,1,LcdBuf2); //显示第二行,从第0个位置开始;WriteCommandLcd(0xc5);//从第二行第六个开始显示数据;WriteDataLcd(0x30+(Step_Data/1000));//送出显示数据;WriteDataLcd(0x30+(Step_Data/100)%10);//送出显示数据;WriteDataLcd(0x30+(Step_Data/10)%10);//送出显示数据;WriteDataLcd(0x30+(Step_Data%10));//送出显示数据;display_string(9,1,"Hz");//显示Hz;while(1){keychuli();//键处理子程序if(dat == 0x01)//键值为1;步进加{dat = 0x00;delay(5000);Frequency_Out = Frequency_Out + Step_Data;if(Frequency_Out > 1000000){Frequency_Out = Frequency_Out - Step_Data;}Light =~Light;display_data();Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word); //向AD9850送出频率控制字;}if(dat == 0x04)//键值为4;步进减{dat = 0x00;delay(5000);if(Frequency_Out >= Step_Data){Frequency_Out = Frequency_Out - Step_Data;if(Frequency_Out < 20){Frequency_Out = Frequency_Out + Step_Data;}}Light =~Light;display_data();Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word); //向AD9850送出频率控制字;}if(dat == 0x06)//步进选择;这里有六种选择 {dat = 0x00;delay(10000);Light =~Light;Step_Bian_Liang++;Step_Bian_Liang = Step_Bian_Liang%6;if(Step_Bian_Liang == 0x00){Step_Data = 1;//步进1}if(Step_Bian_Liang == 0x01){Step_Data = 10;}if(Step_Bian_Liang == 0x02){Step_Data = 100;}if(Step_Bian_Liang == 0x03){Step_Data = 1000;}if(Step_Bian_Liang == 0x04){Step_Data = 10000;}if(Step_Bian_Liang == 0x05){Step_Data = 100000;}if(Step_Data <= 1000){WriteCommandLcd(0xc5);//参考上面类似的部分WriteDataLcd(0x30+(Step_Data/1000));WriteDataLcd(0x30+(Step_Data/100)%10);WriteDataLcd(0x30+(Step_Data/10)%10);WriteDataLcd(0x30+(Step_Data%10));display_string(9,1,"Hz ");}else{Step_Data_Xian_Shi = Step_Data/1000;WriteCommandLcd(0xc5);//参考上面类似的部分WriteDataLcd(0x30+(Step_Data_Xian_Shi/1000)); WriteDataLcd(0x30+(Step_Data_Xian_Shi/100)%10); WriteDataLcd(0x30+(Step_Data_Xian_Shi/10)%10); WriteDataLcd(0x30+(Step_Data_Xian_Shi%10));display_string(9,1,"kHz");}}}}。
STC89C51单片机产生正弦波、方波、三角波LED显示频率源程序#include <stdio.h>#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit LATCH1=P2^6;//定义锁存使能端口段锁存sbit LATCH2=P2^7;// 位锁存unsigned char TempData[8]; //存储显示值的全局变量unsigned char code DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9unsigned char code DuanMa2[10]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};// 显示段码值0~9unsigned char code DuanMa1[3]={0x77,0x7c,0x39};unsigned char code WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码#define DataPort P0sbit keyA=P3^3;sbit keyB=P3^4;sbit keyC=P3^5;sbit wc=P1^0;sbit scl=P1^1;sbit sda=P1^2;sbit scl1=P1^3;sbit sda1=P1^4;sbit p5=P1^5;sbit p6=P1^6;sbit p7=P1^7;uint sign,ad;uchar temp[10], temp1[3];//定义显示区域临时存储数组uchar voltage; //定义浮点变量uchar l=0,m=100,n=0;uchar code sin[200] = {52,53,55,56,58,59,61,62,64,65,67,68,70,71,73,74,75,77,78,79,81,82,83,84,85,86,88,89,90,90,91,92,93,94,95,95,96,96,97,97,98,98,98,99,99,99,99,100,100,100,100,100,9 9,99,99,99,98,98,98,97,97,96,96,95,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,79,7 8,77,75,74,73,71,70,68,67,65,64,62,61,59,58,56,55,53,52,50,48,47,45,44,42,41,39,38,3 6,34,33,32,30,29,27,26,24,23,22,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,5,4,4,3,2,2,2,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,2,2,2,3,4,4,5,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,26,27,29,30,32,33,35,36,38,39,41,42,44,45,47,48,50};void DelayUs2x(unsigned char t){while(--t);}void DelayMs(unsigned char t){while(t--){//大致延时1mSDelayUs2x(245);DelayUs2x(245);}}void delay(){ ;; }void delay1(uchar x){uchar a,b;for(a=x;a>0;a--)for(b=110;b>0;b--);}void Delay2(unsigned int t){while(--t);}void Display(){uchar i;for(i=0;i<4;i++){DataPort=WeiMa[i]; //取位码LATCH2=1; //位锁存LATCH2=0;if(i==0) DataPort=DuanMa1[sign-1];else if(i==1) DataPort=DuanMa2[temp1[i]];else DataPort=DuanMa[temp1[i]]; //取显示数据,段码LATCH1=1; //段锁存LATCH1=0;Delay2(500); // 扫描间隙延时,时间太长会闪烁,太短会造成重影}}//pcf8591void init1(){sda1=1;delay();scl1=1;delay();}void start1() //开始信号{sda1=1;delay();scl1=1;delay();sda1=0;delay();}void stop1() //停止{sda1=0;delay();scl1=1;delay();sda1=1;delay();}void respons1() //应答{uchar i;scl1=1;delay();while((sda1==1)&&(i<250))i++;scl1=0;delay();}void write_byte1(uchar date) {uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl1=0;delay();sda1=CY;delay();scl1=1;delay();}scl1=0;delay();sda1=1;delay();}uchar read_byte1(){uchar i,k;scl1=0;delay();sda1=1;delay();for(i=0;i<8;i++){scl1=1;delay();k=(k<<1)|sda1;scl1=0;delay();}return k;}void write_add1(uchar date) //写入DA{start1();write_byte1(0x90);respons1();write_byte1(0x40);respons1();write_byte1(date);respons1();// delay1(100);stop1();}uchar read_add1( uchar address ) //读AD值{uchar date;start1();write_byte1(0x90);respons1();write_byte1(0x40|address);respons1();start1();write_byte1(0x91);respons1();date=read_byte1();stop1();return date;}//键盘void keyscan(){if(keyA==0){delay1(10);if(keyA==0)sign=1;while(!keyA);}if(keyB==0){delay1(10);if(keyB==0)sign=2;while(!keyB);}if(keyC==0){delay1(10);if(keyC==0)sign=3;while(!keyC);}}//eepromvoid start() //开始信号{sda=1;delay();scl=1;delay();sda=0;delay();}void stop() //停止{sda=0;delay();scl=1;delay();sda=1;delay();}void respons() //应答{uchar i;scl=1;delay();while((sda==1)&&(i<250))i++;scl=0;delay();}void init(){sda=1;delay();scl=1;delay();}void write_byte(uchar date){uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl=0;sda=CY;delay();scl=1;delay();}scl=0;delay();sda=1;delay();}uchar read_byte(){uchar i,k;scl=0;delay();sda=1;delay();for(i=0;i<8;i++){scl=1;delay();k=(k<<1)|sda;scl=0;delay();}return k;}void write_add(uchar date[],uchar address ) {uchar i,*pdate;pdate=date;for(i=0;i<2;i++){write_byte(0xae);respons();write_byte(address+i);respons();write_byte(*(pdate+i));respons();stop();}}void read_add(uchar date[] ,uchar address ) {uchar i,*pdate;pdate=date;for(i=0;i<2;i++){start();write_byte(0xae);respons();write_byte(address+i);respons();start();write_byte(0xaf);respons();*(pdate+i)=read_byte();stop();}}void sj(){if(l<100){write_add1(l);l++;}if(l>=100&m>0){write_add1(m);m--;}if(l>=100&m<=0){l=0;m=100;}p5=0;p6=1;p7=1;}void zx(){if(l<200){write_add1(sin[l]);l++;}if(l>=200)l=0;p6=0;p7=1;p5=1;}void fb(){if(l<100){write_add1(255);l++;}if(l>=100&n<100){write_add1(0);n++;}if(l>=100&n>=100){l=0;n=0;}p7=0;p5=1;p6=1;}void main(){uchar i,num,tab[2];//定义显示区域临时存储数组wc=0;num=0;tab[0]=0;tab[1]=0;TMOD=0x21;//设置定时器1为工作方式2定时器0为工作方式1 TH1=0xfd;TL1=0xfd;TR1=1;REN=1;SM0=0;SM1=1;EA=1;ES=1;init();init1();for(i=0;i<5;i++)num=read_add1(0);read_add(tab,1);sign=tab[0];ad=(uint)num*100;TH0=(65536-ad)/256;TL0=(65536-ad)%256;ET0=1; //定时器中断打开TR0=1;while(1){keyscan();for(i=0;i<5;i++)num=read_add1(0);voltage=500/num;ad=(uint)num*100;tab[0]=sign;tab[1]=ad;write_add(tab,1);num=read_add1(0);voltage=500/num;temp1[0]=voltage/100;temp1[1]=(voltage%100)/10;temp1[2]=voltage%1000;Display();}}void ser() interrupt 4{RI=0;sign=SBUF;}void T0_time() interrupt 1{ad=(uint)read_add1(0)*100;TH0=(65536-ad)/256;TL0=(65536-ad)%256;if(sign==1) sj(); if(sign==2) zx(); if(sign==3) fb(); }。
摘要本文以STC89C51单片机为核心设计了一个低频函数信号发生器。
信号发生器采用数字波形合成技术,通过硬件电路和软件程序相结合,可输出自定义波形,如正弦波、方波、三角波、三角波、梯形波及其他任意波形,波形的频率和幅度在一定范围内可任意改变。
波形和频率的改变通过软件控制,幅度的改变通过硬件实现。
介绍了波形的生成原理、硬件电路和软件部分的设计原理。
本系统可以产生最高频率798.6HZ的波形。
该信号发生器具有体积小、价格低、性能稳定、功能齐全的优点。
关键词:低频信号发生器;单片机;D /A转换;1设计选题及任务设计题目:基于单片机的信号发生器的设计与实现任务与要求:设计一个由单片机控制的信号发生器。
运用单片机系统控制产生多种波形,这些波形包括方波、三角波、锯齿波、正弦波等。
信号发生器所产生的波形的频率、幅度均可调节。
并可通过软件任意改变信号的波形。
基本要求:1. 产生三种以上波形。
如正弦波、三角波、矩形波等。
2.最大频率不低于 500Hz。
并且频率可按一定规律调节,如周期按1T,2T,3T,4T或1T,2T,4T,8T变化。
3.幅度可调,峰峰值在0——5V之间变化。
扩展要求:产生更多的频率和波形。
2系统概述2.1方案论证和比较2.1.1总体方案:方案一:采用模拟电路搭建函数信号发生器,它可以同时产生方波、三角波、正弦波。
但是这种模块产生的不能产生任意的波形(例如梯形波),并且频率调节很不方便。
方案二:采用锁相式频率合成器,利用锁相环,将压控振荡器(VCO)的输出频率锁定在所需频率上,该方案性能良好,但难以达到输出频率覆盖系数的要求,且电路复杂。
方案三:使用集成信号发生器发生芯片,例如AD9854,它可以生成最高几十MHZ的波形。
但是该方案也不能产生任意波形(例如梯形波),并且价格昂贵。
方案四:采用AT89C51单片机和DAC0832数模转换器生成波形,加上一个低通滤波器,生成的波形比较纯净。
它的特点是可产生任意波形,频率容易调节,频率能达到设计的500HZ以上。
/**************************************/
/* 信号发生器(正弦波,方波,三角波)
*/
/*************************************/
#include<reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit cs=P2^0; //tlc5615片选端口
sbit clk=P2^1; //tlc5615时钟线
sbit din=P2^2; //tlc5615传输端口
sbit key1=P1^0;
sbit key2=P1^1; //按键的单片机接口
uchar keydat;
uchar flag; //波形发生终止信号的标志位一旦被置零立马停止发信号
uchar flagsqu; //方波高低电平控制为(运用定时器1中断控制)
uchar m,num;
uchar dat=0xff;
uchar code tosin[141]={ //正弦波的编码
0x00,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15,0x16,
0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,0x27,0x29,0x2b,
0x2e,0x30,0x33,0x35,0x38,0x3a,0x3d,0x40,0x43,0x45,
0x48,0x4c,0x4e,0x51,0x55,0x57,0x5a,0x5d,0x60,0x63,
0x66,0x69,0x6c,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7e,
0x7f,0x80,0x7f,0x7e,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,
0x78,0x77,0x76,0x75,0x74,0x73,0x72,0x6f,0x6c,0x69,
0x66,0x63,0x60,0x5d,0x5a,0x57,0x55,0x51,0x4e,0x4c,
0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,0x33,0x30,
0x2e,0x2b,0x29,0x27,0x25,0x22,0x20,0x1e,0x1c,0x1a,
0x18,0x16,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,
0x00};
void delay(uchar z) //延时函数
{
uchar x,y;
for(x=0;x<110;x++)
for(y=z;y>0;y--);
}
void prepare() //tlc5615的初始化
{
cs=1;
din=1;
clk=0;
cs=0; //cs的上升沿和下降沿必须在clk 为低时进?
}
/* 用中断来产生方波
void Squtranslator()
{
TR1=1; //启动定时器1 控制高低电平的持续时间占空比
do{
do{
_wave=0;
}while((!flagsqu) && flag==1);//如果一旦终止信号的
//产生可以立马退出循环flagsqu=0;
do{
_wave=1;
}while((!flagsqu) && flag==1);
flagsqu=0;
}while(flag);
flag=1;
TR1=0;
}
*/
void Squtranslator() //方波函数
{
uchar j;
uchar dat1=0x7f;
while(flag)
{
do{
prepare();
dat=dat1;
for(j=0;j<12;j++)
{
din=(bit)(dat>>7); //将数据的最高位赋给din
clk=1;
dat=dat<<1; //一位位的传输
clk=0;
}
cs=1; //cs的上升沿和下降沿必须在clk 为低时进行
delay(200); //使高低电平持续一段时间
if(dat1==0)
dat1=0x7f; //完成了0和0x7f之间的替换else
dat1=0;
}while(flag);
}
}
void Tratranslator() //锯齿波的发生函数
{
uchar j;
uchar dat1=0x7f;
while(flag)
{
do{
prepare();
dat=dat1;
for(j=0;j<12;j++)
{
din=(bit)(dat>>7); //将数据的最高位赋给din
clk=1;
dat=dat<<1; //一位位的传输
clk=0;
}
cs=1; //cs的上升沿和下降沿必须在clk 为低时进行
delay(2); //稍加延时
dat1--;
}while(flag && dat1); //一旦有终止信号就可以停止
do{
prepare();
dat=dat1;
for(j=0;j<12;j++)
{
din=(bit)(dat>>7); //将数据的最高位赋给din
clk=1;
dat=dat<<1; //一位位的传输
clk=0;
}
cs=1; //cs的上升沿和下降沿必须在clk 为低时进行
delay(2); //稍加延时
dat1++;
}while(flag && (!(dat1==0x7f)));
}
}
void Sintranslator(uchar wave[],uchar num )//正弦波的转换函数
{
uchar i,j;
uchar dat1;
do{
for(i=0;i<num;i++)
{
prepare();
dat1=wave[i]; //打开片选开始工作
for(j=0;j<12;j++)
{
din=(bit)(dat1>>7); //将数据的最高位赋给din
clk=1;
dat1=dat1<<1; //一位位的传输
clk=0;
if(flag==0)break;
}
cs=1; //cs的上升沿和下降沿必须在clk为低时进行
delay(1); //稍加延时
if(flag==0)break;
}
}while(flag); //等待控制键的暂停
}
void keyscan() //切换功能按键返回键值函数{
uchar i;
for(i=0;i<4;i++)
{
if(key1==0)
{
delay(10);
if(key1==0)
{
keydat++;
do{}while(!key1); //松手检测
if(keydat==4)keydat=1;//加满回零处理
}
}
}
}
void keycountrl() //切断输出控制函数
{
if(key2==0)
{
delay(10);
if(key2==0)
{
flag=0;
do{}while(!key2); //松手检测
}
}
}
void main ()
{
uchar temp;
TMOD=0x01; //确定定时器的工作方式
TH0=(65536-50000)/256; //给定时器0赋予初值
TL0=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //开启定时器0中断
TR0=1;
while(1)
{
do{
switch(keydat)
{
case 1:
flag=1;do{Sintranslator(tosin,141);}while(flag);break;
case 2: flag=1;do{Tratranslator();}while(flag);break;
case 3: flag=1;do{Squtranslator();}while(flag);break;
default:break;
}
}while(flag);
temp=keydat; //装载键值
while(keydat==temp); //在这里等待键值的改变}
}
void Time0() interrupt 1
{
TH0=(65536-50000)/256; //定时器0用来扫描按键不断地扫描d
TL0=(65536-50000)%256;
num++;
if(num==4)
{
keyscan();
keycountrl();
num=0;
}
}。