基于AT89C52单片机简易函数信号发生器的设计

更新时间:2024-06-09 10:43:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

学 号: 51

湖南文理学院

机械工程学院 课 程 设 计

基于AT89C52单片机的

题 目

简易函数信号发生器设计

专 业 班 级 姓 名 指导教师

机械电子工程 机电08101班 谭鹏辉 陈卫国

2011 年 12 月 07 日

1

课程设计任务书

姓 名 课程名称 设计时间 设计名称 谭鹏辉 学 号 51 课程性质 班 级 机电08101班 必修 单片机课程设计 2011年 11 月 28日—— 2011年 12 月 9 日 基于AT89C52单片机的简易函数信号发生器设计 设计要求 1) 以单片机为核心,经过D/A转换和放大电路的处理,最后输出信号; 2) 要求能输出正弦波、三角波、锯齿波和方波四种信号; 3) 输出信号可以通过按键来改变 4) 完成系统电路设计; 5) 完成系统软件设计; 6) 完成系统Proteus下的仿真。 5)完成课程设计报告。 计划与进度 时间:二周 1) 方案设计 2天 2) 电路设计 2天 3) 软件设计 3天 4) 软、硬件联调 2天 5) 系统仿真 2天 6) 答辩 1天 7) 完成报告 2天 任课教师 意 见 教研室主任 签 名 年 月 日 年 月 日 平时考勤:20% 设计:30% 仿真:20% 答辩:10% 说明 设计报告:20% 共计100分。

2

目 录

目 录 .............................................................. 摘 要 .............................................................................................................................4 第一章 绪论 .........................................................5 1.1单片机概述 .....................................................5 1.2信号发生器的分类 ...............................................5 1.3研究内容 .......................................................5 第二章 函数信号发生器设计 ...........................................6 2.1课程设计的目的 ...................................................6 2.2课程设计要求 ...................................................6 第三章 设计方案 .....................................................7 3.1系统主要功能 ...................................................7 3.2系统硬件构成及功能 .............................................7 2.2.1 AT89C52单片机及其说明 ....................................7 3.2.2资源分配 ................................................. 10 3.2.3 D/A转换模件部件 ......................................... 11 3.2.4 外部控制模块部件 74LS22 .................................. 12 3.2.5 放大部分 ................................................. 12 3.3系统软件设计及接口电路 ........................................ 13 3.3.1 信号频率数据采集 ......................................... 13 3.3.2 正弦波产生程序 ........................................... 13 3.3.3 三角波产生程序 ........................................... 14 3.3.4方波产生程序 ............................................. 14 3.3.5 锯齿波产生程序.......... ................................. 15 3. 3. 6信号放大模块设计...................................................................................15 3. 3. 7 数模转换模块设计..................................................................................16 第四章 仿真图及及结果分析...................................................................................................17

4.1波形发生器的调试与测试.............................................................................17

4.2仿真结果图.....................................................................................................18 第五章 总结与展望...................................................20 参考文献 ........................................................... 21 附录一 元器件清单 .................................................. 22 附录二 程序清单 .................................................... 23 附录三 电路原理图...................................................30

3

1.1单片机概述

随着大规模集成电路技术的发展,中央处理器(CPU)、随机存取存储器(RAM)、只读存储器(ROM)、(I/O)接口、定时器/计数器和串行通信接口,以及其他一些计算机外围电路等均可集成在一块芯片上构成单片微型计算机,简称为单片机。单片机具有体积小、成本低,性能稳定、使用寿命长等特点。其最明显的优势就是可以嵌入到各种仪器、设备中,这是其他计算机和网络都无法做到的[9,10]。

1.2信号发生器的分类

信号发生器应用广泛,种类繁多,性能各异,分类也不尽一致。按照频率范围分类可以分为:超低频信号发生器、低频信号发生器、视频信号发生器、高频波形发生器、甚高频波形发生器和超高频信号发生器。按照输出波形分类可以分为:正弦信号发生器和非正弦信号发生器,非正弦信号发生器又包括:脉冲信号发生器,函数信号发生器、扫频信号发生器、数字序列波形发生器、图形信号发生器、噪声信号发生器等。按照信号发生器性能指标可以分为一般信号发生器和标准信号发生器。前者指对输出信号的频率、幅度的准确度和稳定度以及波形失真等要求不高的一类信号发生器。后者是指其输出信号的频率、幅度、调制系数等在一定范围内连续可调,并且读数准确、稳定、屏蔽良好的中、高档信号发生器。

1.3 研究内容

本文是做基于单片机的信号发生器的设计,将采用编程的方法来实现三角波、锯齿波、矩形波、正弦波的发生。根据设计的要求,对各种波形的频率和幅度进行程序的编写,并将所写程序装入单片机的程序存储器中。在程序运行中,当接收到来自外界的命令,需要输出某种波形时再调用相应的中断服务子程序和波形发生程序,经电路的数/模转换器和运算放大器处理后,从信号发生器的输出端口输出

第二章:函数信号发生器的设计

设计一个基于单片机的函数信号发生器,该函数信号发生器可以输出四种波形,有

4

正弦波,锯齿波,三角波,方波。在此基础上进一步实现对波形频率和占空比的调节,并用液晶屏分两行显示波形名称和波形频率。 2.1课程设计的目的:

1、巩固、加深和扩大单片机应用的知识面,提高综合及灵活运用所学知识解决实际课题设计的能力。

2、培养针对课题需要,选择和查阅有关手册、图表及文献资料的能力,提高组成系统、编程、调试的动脑动手能力。

3、通过对课题设计方案的分析、选择、比较,熟悉运用单片机系统开发、软硬件设计的方法内容及步骤。

4、掌握DAC0832,LM324,74LS22的接口电路,及使用方法。 5、熟悉掌握函数信号发生器的工作原理。 2.2 课程设计要求:

1、 熟悉组成系统中的实验模块原理,画出实验原理图。

2、 写出完整的设计任务书:课题的名称、系统的功能、硬件原理图、软件框图、元件清单、程序清单、参考资料。

3、输出几种波形,实现对频率和占空比的调节,以1HZ作为步进进行调节。

第三章:设计方案

3.1 系统主要功能

5

该函数信号发生器可以输出四种波形,有正弦波,锯齿波,三角波,方波。在此基础上进一步实现对波形频率和占空比的调节,并用液晶屏分两行显示波形名称和波形频率。

3.2 系统硬件构成及功能

函数信号发生器的设计总体框图如图所示,主要有单片机AT89C52,电源,键盘模块,LCD1602显示模块构成。

按案件模块:由5个复位开关与74LS21组成的系统通过对单片机传输中断信号来实现波形切换及频率和占空比的调节。

显示模块:用LCD1602,分行显示波形类型和波形频率的显示。

电源模块:电源模块有220V市变电压经变压,整流,稳压得到+ -5V, + -12V的电压,维持系统正常工作。

系统的总体框图如图1所示:

主 控 器 AT89C52 键盘显示控制显示模块 键盘模块 电 源 波形输出模块

图1系统总体框图

3.2.1 AT89C52单片机及其说明

AT89C52为8 位通用微处理器 图2.PDIP封装的AT89C52引脚图

6

采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。主要管脚有:XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚,其功能用途由软件定义,在本设计中,P0 端口(32~39 脚)被定义为N1 功能控制端口,分别与N1的相应功能管脚相连接,13 脚定义为IR输入端,10 脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12 脚、27 脚及28 脚定义为握手信号功能端口,连接主板CPU 的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。 P0 口

P0 口是一组8 位漏极开路型双向I/O 口, 也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的 方式驱动8 个TTL逻辑门电路,对端口P0 写“1”时,可作为高阻抗输入端用。 在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8 位)和数据总线复用,在访问期间激活内部上拉电阻。

在Flash 编程时,P0 口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。 P1 口

P1 是一个带内部上拉电阻的8 位双向I/O 口, P1 的输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑

门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉

电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。 参见表1。

Flash 编程和程序校验期间,P1 接收低8 位地址。

P2 口

P2 是一个带有内部上拉电阻的8 位双向I/O 口,P2 的输出缓冲级可驱动

(吸收或输出电流)4 个TTL 逻辑

门电路。对端口P2 写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。

在访问外部程序存储器或16 位地址的外部数据存储器(例如执行MOVX @DPTR 指令)时,P2 口送出高8 位地址数据。在访问8 位地址的外部数据存储器(如执行MOVX @RI 指令)时,P2 口输出P2 锁存器的内容。 Flash 编程或校验时,P2亦接收高位地址和一些控制信号。 P3 口

P3 口是一组带有内部上拉电阻的8 位双向I/O 口。P3 口输出缓冲级可驱动

7

(吸收或输出电流)4 个TTL 逻 辑门电路。对P3 口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3 口将用上拉电阻输出电流(IIL)。

P3 口除了作为一般的I/O 口线外,更重要的用途是它的第二功能

P3 口还接收一些用于Flash 闪速存储器编程和程序校验的控制信号。 RST

复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。 ALE/PROG

当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8 位字

节。一般情况下,ALE 仍以时钟振荡频率的1/6 输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE 脉冲。

对Flash 存储器编程期间,该引脚还用于输入编程脉冲(PROG)。

如有必要,可通过对特殊功能寄存器(SFR)区中的8EH 单元的D0 位置位,可禁止ALE 操作。该位置位后,只有一条

MOVX 和MOVC指令才能将ALE 激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE 禁止位无效。 PSEN

程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C52 由外部程序存储器取指令(或数

据)时,每个机器周期两次PSEN 有效,即输出两个脉冲。在此期间,当访问外部数据存储器,将跳过两次PSEN信号。 EA/VPP

外部访问允许。欲使CPU 仅访问外部程序存储器(地址为0000H—FFFFH),EA 端必须保持低电平(接 地)。需注意的是:如果加密位LB1 被编程,复位时内部会锁存EA端状态。 如EA端为高电平(接Vcc端),CPU 则执行内部程序存储器中的指令。 Flash 存储器编程时,该引脚加上+12V 的编程允许电源Vpp,当然这必须是该器件是使用12V 编程电压Vpp。 XTAL1

振荡器反相放大器的及内部时钟发生器的输入端。 XTAL2

振荡器反相放大器的输出端。 特殊功能寄存器

在AT89C52 片内存储器中,80H-FFH 共128 个单元为特殊功能寄存器(SFE),SFR 的地址空间映象如表2 所示。

并非所有的地址都被定义,从80H—FFH 共128 个字节只有一部分被定义,

8

还有相当一部分没有定义。对没有定义的

单元读写将是无效的,读出的数值将不确定,而写入的数据也将丢失。 不应将数据“1”写入未定义的单元,由于这些单元在将来的产品中可能赋予新的功能,在这种情况下,复位后这些单 元数值总是“0”。

AT89C52除了与AT89C51所有的定时/计数器0 和定时/计数器1 外,还增加了一个定时/计数器2。定时/计数器2 的控 制和状态位位于T2CON(参见表3)T2MOD(参见表4),寄存器对(RCAO2H、RCAP2L)是定时器2 在16 位捕获方式或16 位 自动重装载方式下的捕获/自动重装载寄存器。 数据存储器

AT89C52 有256 个字节的内部RAM,80H-FFH 高128 个字节与特殊功能

寄存器(SFR)地址是重叠的,也就是高128

字节的RAM 和特殊功能寄存器的地址是相同的,但物理上它们是分开的。 当一条指令访问7FH 以上的内部地址单元时,指令中使用的寻址方式是不同的,也即寻址方式决定是访问高128 字节 RAM 还是访问特殊功能寄存器。如果指令是直接寻址方式则为访问特殊功能寄存器。

例如,下面的直接寻址指令访问特殊功能寄存器0A0H(即P2 口)地址单元。 MOV 0A0H,#data

间接寻址指令访问高128 字节RAM,例如,下面的间接寻址指令中,R0 的内容为0A0H,则访问数据字节地址为0A0H, 而不是P2 口(0A0H)。 MOV @R0,#data

堆栈操作也是间接寻址方式,所以,高128 位数据RAM 亦可作为堆栈区使用。 ·定时器0和定时器1: 3.2.2 资源分配

晶振采用12MHZ。P1口的P1.0-P1.4分别与四个按键连接,分别控制波形切换、频率加、频率减,占空比加,占空比减。

P2口与DAC0832的D0-D7数据输入端相连。

P3口用来控制DAC0832的输入寄存器选择信号CS。 3.2.3 D/A转换模块部件

DAC0832芯片原理

管脚功能介绍(如图6所示)

9

76541615141311720lsbDI0DI1DI2DI3DI4DI5DI6msbDI7CSXferVccIout1Iout2RfbVref111298ILEWR2WR1U219182图3 DAC0832管脚图 DAC0832

DI7~DI0:8位的数据输入端,DI7为最高位。

ILE:数据锁存允许控制信号输入线,高电平有效。

CS:选片信号输入线(选通数据锁存器),低电平有效。

WR1:数据锁存器写选选通输入线,负脉冲有效,由ILE、CS、WR1的逻辑组合产生LE1,当LE1为高电平时,数据锁存器状态随输入数据线变化,LE1的负跳变时将输入数据锁存。

XFER:数据传输控制信号输入线,低电平有效,负脉冲有效。 WR2:DAC寄存器选通输入线,负脉冲有效,由WR2、XFER的逻辑组合产生LE2,当LE2为高电平时,DAC寄存器的输出随寄存器的输入而变化,LE2的负跳变时将数据锁存器的内容打入DAC寄存器并开始D/A转换。

IOUT1:模拟电流输出端1,当DAC寄存器中数据全为1时,输出电流最大,当 DAC寄存器中数据全为0时,输出电流为0。

IOUT2:模拟电流输出端2, IOUT2与IOUT1的和为一个常数,即IOUT1+IOUT2=常数。

RFB:反馈电阻引出端,DAC0832内部已经有反馈电阻,所以 RFB端可以直接接到外部运算放大器的输出端,这样相当于将一个反馈电阻接在运算放大器的输出端和输入端之间。

VREF:参考电压输入端,此端可接一个正电压,也可接一个负电压,它决定0至255的数字量转化出来的模拟量电压值的幅度,VREF范围为(+10~-10)V。VREF端与D/A内部T形电阻网络相连。

Vcc:芯片供电电压,范围为(+5~+15)V。 AGND:模拟量地,即模拟电路接地端。 DGND:数字量地。

3.2.4 外部控制模块部件 74LS22

10

图4

74LS22为四输入双与门

A1,B1,C1,D1为第一个与门的输入,Y1为第一个与门的输出。

A2,B2,C2,D2为第一个与门的输入,Y2为第一个与门的输出。在此系统中用来给单片机提供中断信号。 3.2.5 放大部分 LM324 LM324引脚图(管脚图)

11

图5 LM324引脚图

简介:

LM324系列器件为价格便宜的带有真差动输入的四运算放大器。与单电源应用场合的标准运算放大器相比,它们有一些显著优点。该四放大器可以工作在低到3.0伏或者高到32伏的电源下,静态电流为MC1741的静态电流的五分之一。共模输入范围包括负电源,因而消除了在许多应用场合中采用外部偏置元件的必要性。它有5个引出脚,其中“+”、“-”为两个信号输入端,“V+”、“V-”为正、负电源端,“Vo”为输出端。两个信号输入端中,Vi-(-)为反相输入端,表示运放输出端Vo的信号与该输入端的位相反;Vi+(+)为同相输入端,表示运放输出端Vo的信号与该输入端的相位相同。

3.3 系统的软件设计及接口电路

3.3.1 信号频率数据采集

本程序通过外部中断,接收减频或加频按键,单片机内部对接受的值经过运算得出波形的输出延时,从而产生频率的改变。电路较为简单,成本较低。 3.3.2 正弦波产生程序

输入正弦波的采样点,计算出256个(一个周期内)正弦波信号值。然后通过输出的两点间的延时来实现调频。依次循环输出,可得出正弦波。

采点值放在table2[]中,程序如下:

void sin()//正弦波 {

unsigned int i; for(i=0;i<256;i++)

{

12

}

}

DAC0832=table2[i]; delay(pinlv/256);

3.3.3 三角波产生程序

设个自变量i让它不断地自加1,直到加到255时,t=i,对t进行不断地自减1直到减到t=0,然后再不断地重复上述过程产生三角波。程序如下:

void tran()//三角波 { }

3.3.4 方波产生程序

设个自变量i=0使之延时一段时间,再另i=255时在延时与i=0相同的时间,然后再重复上述过程。程序如下:

void fang()//方波

unsigned char i; for(i=0;i<255;i++)

{ }

DAC0832=i; delay(pinlv/64);

for(i=255;i>0;i--)

{ }

DAC0832=i; delay(pinlv/64);

13

{ }

DAC0832=0; delay(pinlv/2);

DAC0832=0xff; delay(pinlv/2);

3.3.5 锯齿波产生程序

锯齿波中的斜线用一个个小台阶来逼近,在一个周期内从最小值开始逐步递增,当达到最大值后又回到最小值,如此循环,当台阶间隔很小时,波形基本上近似于直线。适当选择循环的时间,可以得到不同的周期锯齿波。锯齿波发生原理与方波类似,只是高低两个时延的常数不同,所以用延时法,来产生锯齿波,设个自变量i让它不断地自加1,直到叫到255,DAC0832可以又自动归0,然后再不断地重复上述过程。程序如下:

void jvchi()//锯齿波 { }

3.3.6信号放大模块设计

unsigned char i;

for(i=0;i<255;i++)

{ }

DAC0832=i; delay(pinlv/256);

从单片机中输出的数字信号经过DAC0832转换后,由于信号的幅值比较小,所以

14

需要放大。采用常规的放大方式,采用两片运放,实现两级放大,设计的电路如图6:图6

图6放大电路接口

3. 3. 7数模转换模块设计

本设计模数转换采用常见的芯片:DAC0832,本设计采用直通方式进行模数转换。为了简洁起见,在仿真图中采用网络节点的方式进行连线,从单片机P0口输出的数据直接连接到模数芯片DAC0832的数据口。如图:

图7 DA转换接口电路

15

第四章 仿真图及结果分析

4.1波形发生器的调试与测试

本系统是在protues下仿真,使用Keil C编程。从而实现其设计及仿真。

在测试本系统是采用的是将设置的数值与示波器所测值进行对比,进而可以知道本系统的性能。

频率测试数据: 设定频率(HZ) 示波器测试频率(HZ) 相对误差% 3.9 7.8 15.63 3.96 7.93 16.13 1.5 1.28 3.19

16

4.2仿真结果图

正弦波仿真图

图8正弦波图

三角波仿真图

图9三角波图

17

锯齿波仿真图

图10锯齿波图

方波仿真图

图11方波图

18

第五章 总结与展望

本次的设计中利用AT89C52和DAC0832以及放大器完成电路的设计,用开关来控制各种波形的发生及转换,用单片机输出后,经过模数转换器生成波形,最终可以通过示波器观察。

在这次的软件设计中,程序设计采用的是汇编语言。汇编语言具有速度快,可以直接对硬件进行操作的优点,它可以极好的发挥硬件的功能。但是汇编语言也存在编写的代码非常难懂,不好维护,很容易产生 bug,难于调试的缺点。因此,在大型程序的设计中,多采用C语言进行程序编译。C语言简洁高效,是最贴近硬件的高级编程语言,经过多年的发展,现在已成熟为专业水平的高级语言。而且,现在单片机产品推出时纷纷配套了C语言编译器,应用广泛。不过就本次课程设计来说,汇编语言还是适用的。

由于真正意义上的程序设计还不多,因此还不是很得心应手,所以在设计中遇到一些问题和一些难点。比如:在程序设计中如何实现程序结构的最优化,以达到较高的质量。这是以后设计中要注意的问题。

通过这次课程设计,我进一步了解了波形发生器的原理,在实际动手操作过程中,使我接触了许多我以前没接触过的元件,而且重新温习了刚学不久的汇编语言,使我学得了许多知识,使我获益匪浅。

这次课程设计,使我的动手能力得到了很大的提高,更使我们懂得理论知识的重要性,没有理论的指导一切实际行动都是盲目的,且实际操作是我们得到的理论知识得到验证,更能增加对理论知识的理解。

19

参考文献

[1] 程全.基于AT89C52实现的多种波形发生器的设计[J].周口师范学院学报,

2005.22(5):57~58.

[2] 周明德.微型计算机系统原理及应用[M].北京:清华大学出版社,2002.341~364. [3] 刘乐善.微型计算机接口技术及应用[M].北京:北京航空航天大学出版社,2001.258~264.

[4] 童诗白.模拟电路技术基础[M].北京:高等教育出版社,2000.171~202. [5] 杜华.任意波形发生器及应用[J].国外电子测量技术,2005.1:38~40.

[6] 张友德.单片微型机原理、应用与实践[M].上海:复旦大学出版社,2004.40~44. [7] 程朗.基于8051单片机的双通道波形发生器的设计与实现[J].计算机工程与应用,

2004.8:100~103.

[8] 张永瑞.电子测量技术基础[M].西安:西安电子科技大学出版社,2006.61~101. [9] 李叶紫. MCS-51单片机应用教程[M].北京:清华大学出版社,2004.232~238.

20

附录1元器件清单

元件名称 AT89C52 74LS22 LM324 电阻 排阻 液晶显示屏 滑动变阻器 晶振

数量 1 1 1 3 1 1 1 1 备注 10k 4.7K LCD1602 10K 12MHZ 21

附录2 程序清单

#include

#define uchar unsigned char #define uint unsigned int

//#define Fosc 24000000/12000000 //12分频后的频率

#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;//传递频率的中间变量 //uint T_temp;

uchar judge=1; //在方波输出函数中用于简单判别作用 uchar waveform; //当其为0、1、2时,分别代表三种波

uchar code freq_unit[4]={10,50,200,10}; //三种波的频率单位 sawtooth

uchar idata wavefreq[4]={1,1,1,1}; //给每种波定义一个数组单元,用于存放单位频率的个数

uchar code lcd_hang1[]={\Wave \\Wave \\Wave \ \ \

uchar idata lcd_hang2[16]={\ Hz \

/*uchar code wave_freq_adjust[]={ //频率调整中间值

0xff,0xb8,0x76,0x56,0x43,0x37,0x2e,0x26,0x20,0x1c, //正弦波频率调整中间值

0xff,0x8e,0x5a,0x41,0x32,0x28,0x20,0x1b,0x17,0x0e, //三角波频率调整中间值 0xff,0x8e,0x5a,0x41,0x32,0x28,0x20,0x1b,0x17,0x0e}; uint code wave_freq_adjust[]={ //频率调整中间值 380,184,118,86,67,55,46,28,38,32, 295,142, 90,65,50,40,32,27,23,14,

295,142, 90,65,50,40,32,27,23,14}; */

/*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};*/

22

/***********这两组数组很重要,需要根据波形来调试,选择合适的值,使输出波形达到频率要求************/

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,0x60,0x68,0x70,0x78,

0x80,0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,0xc0,0xc8,0xd0,0xd8,0xe0,0xe8,0xf0,0xf8,0xff,

0xf8,0xf0,0xe8,0xe0,0xd8,0xd0,0xc8,0xc0,0xb8,0xb0,0xa8,0xa0,0x98,0x90,0x88,0x80,

0x78,0x70,0x68,0x60,0x58,0x50,0x48,0x40,0x38,0x30,0x28,0x20,0x18,0x10,0x08,0x00};

uchar code sine_tab[256]={

//输出电压从0到最大值(正弦波1/4部分)

0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,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,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc5,0xc2,

0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99 ,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,

//输出电压从0到最小值(正弦波1/4部分)

0x80,0x7c,0x79,0x76,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,0

23

x1c,0x1a,0x18,0x16 ,0x15,0x13,

0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,

//输出电压从最小值到0(正弦波1/4部分)

0x00,0x00,0x00,0x00,0x00,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,0x72,0x76,0x79,0x7c,0x80};

uchar code sawtooth_tab[]={

0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,

0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,

0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e};

// 0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,

// 0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee};

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位输入寄存器

24

}

void square_out() //方波输出 {

judge=~judge;

if(judge==1) DAdata=0xff; else DAdata=0x00;

DA_S1=0; //打开8位输入寄存器 DA_S1=1; //关闭8位输入寄存器 }

void sawtooth_out() //锯齿波输出 {

DAdata=sawtooth_tab[wavecount++]; if(wavecount>71) wavecount=0; DA_S1=0; //打开8位输入寄存器 DA_S1=1; //关闭8位输入寄存器 }

/************1602液晶的相关函数*************/ #define lcd_ports P1 sbit 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; }

25

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[4*16]); //在第一行显示 disp_lcd(0xc0,&lcd_hang1[5*16]); //在第二行显示 /*for(num=0;num<16;num++) { write_date(table[num]); delay(5); }

write_com(0x80+0x40); //给指针重新赋值,使之指向第二行第一格 for(num=0;num<16;num++) { write_date(table1[num]); delay(5); } */

/*TMOD=0x01; //选用定时方式1 TH0=(65536-50000)/256; //赋初值 TL0=(65536-50000)%6; // EA=1; //开总中断

ET0=1; //开定时器中断 TR0=1; //启动定时器*/ }

26

/********************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();

else if(waveform==3) sawtooth_out(); //tian jian }

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)

27

{ case 0xe0: //选择波形 waveform++; if(waveform>3) waveform=0; //jiang 2 gai wei 3 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_temp

TLtemp=waveTL[waveform*10+(wavefreq[waveform]-1)];

total_freq= wavefreq[waveform] * freq_unit[waveform]; //求输出频率(个数*单位)

lcd_hang2[5]=total_freq+0x30; //在液晶中显示个位,(0x30 在液晶显示中表示数字0)

total_freq/=10; lcd_hang2[4]=total_freq+0x30; //在液晶中显示时十位 total_freq/=10; lcd_hang2[3]=total_freq+0x30; //在液晶中显示时百位 total_freq/=10; lcd_hang2[2]=total_freq+0x30; //在液晶中显示时千位 disp_lcd(0x80,&lcd_hang1[waveform*16]); //在第一行显示 disp_lcd(0xc0,lcd_hang2); //在第二行显示 }

wavecount=0; //'抽点'计数清零 while(!key);

EA=1; TR0=1; //开启总中断与定时器

28

附录三 电路原理图

图12 电路原理图

29

本文来源:https://www.bwwdw.com/article/aho6.html

Top