基于单片机的波形发生器(C语言)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机原理及接口技术
课程设计报告
波形发生器设计
波形发生器作为一种常用的信号源,是现代测试领域内应用最为广泛的通用仪器之一。
在研制、生产、测试和维修各种电子元件、部件以及整机设备时,都学要有信号源,由它产生不同频率不同波形的电压、电流信号并加到被测器件或设备上,用其他仪器观察、测量被测仪器的输出响应,以分析确定它们的性能参数。
信号发生器是电子测量领域中最基本、应用最广泛的一类电子仪器。
它可以产生多种波形信号,如正弦波,三角波,方波等,因而广泛用于通信、雷达、导航、宇航等领域。
本系统利用单片机AT89C51采用程序设计方法产生锯齿波、正弦波、三角波三种波形,再通过D/A转换器DAC0832将数字信号转换成模拟信号,滤波放大,最终由示波器显示出来,通过键盘来控制三种波形的类型选择、频率变化,并通过LED显示其各自的周期。
本次关于产生不同低频信号的信号源的设计方案,不仅在理论和实践上都能满足实验的要求,而且具有很强的可行性。
该信号源的特点是:体积小、价格低廉、性能稳定、实现方便、功能齐全。
1. 设计任务
结合实际情况,基于AT89C51单片机设计一个波形发生器。
该系统应满足的功能要求为:
(1) 产生三种波形(三角波、锯齿波、正弦波);
(2) 按键选择波形,加减键选择频率;
(3) 在示波器中显示三种波形;
(4) 在六位数码管上显示周期;
主要硬件设备:单片机实验开发系统、AT89C51单片机、DAC数模转换芯电路、六位数码管(LED)、矩阵键盘、8155芯片、示波器。
2. 整体方案设计
波形发生器系统以AT89C51单片机作为整个系统的控制核心,应用其强大的接口功能,构成整个波形发生器系统。
利用 AT89S52 单片机构造多功能信号发生器,可产生正弦波,方波,三角波,锯齿波四种波形,通过 C 语言对单片机的编程即可产生相应的波形信号,并可以通过键盘进行各种功能的转换和信号频率的控制,当输出的数字信号通过
数模转换成模拟信号也就得到所需要的信号波形,通过运算放大器的放大输出波形,同时让显示器显示输出的波形信息。
(1)三角波产生思路
首先,根据按键设定的波形频率,选择一个周期内合适的点数,根据点数和峰值计算相邻2个点的幅度的步进值,根据点数和频率设定相邻2点的时间值,计算出定时器的初值,然后,设置一个变量每进一次定时中断DA数据就加幅值步进,当等于总点数的一半时,每进一次定时中断就把DA数据减幅值步进直到DA数据为0,计数变量清零。
每进一次定时中断输出刷新DA的数据就可以产生一定频率和幅值的三角波。
(2)锯齿波产生思路
首先,根据按键设定的波形频率,选择一个周期内合适的点数,根据点数和峰值计算相邻2个点的幅度的步进值,根据点数和频率设定相邻2点的时间值,计算出定时器的初值,然后,定时输出刷新DA的数据就可以产生一定频率和幅值的波形。
(3)正弦波产生思路
首先,写一个表格,然后根据按键设定的波形频率,选择一个周期内合适的点数,根据点数和峰值计算相邻2个点的幅度的步进值,根据点数和频率设定相邻2点的时间值,计算出定时器的初值,然后,设置一个变量每进一次定时中断DA数据就加幅值步进,当等于总点数的一半时,每进一次定时中断就查表把DA数据减幅值步进直到DA数据为0,计数变量清零。
每进一次定时中断查表输出刷新DA的数据就可以产生一定频率和幅值的正弦波。
图2-1 系统的整体方案设计图
本系统硬件主要由D/A转换器、显示系统、矩阵键盘等几部分组成。
各模块的主要功能如下:
(1) D/A转换器的功能是把单片机输出的数字信号转换成0-5V的模拟信号。
(2) 显示系统中六位数码管显示波形频率,示波器显示波形。
(3) 矩阵键盘选择波形,增加减少频率。
3. 系统硬件电路设计
3.1 时钟电路
单片机的时钟信号通常用两种电路形式得到:内部振荡和外部振荡方式。
在引脚XTAL1 和 XTAL2 外接晶体振荡器,构成了内部振荡方式。
由于单片机内部有一个高增益的反相放大器,当外接晶振后,就构成了自激振荡,并产生振动时钟脉冲。
晶振通常选用 6MHZ、12MHZ、24MHZ。
本设计中时钟电路图如图3-1,我们选择了12MHZ和晶振分别接引脚XTAL1和XTAL2,电容 C1,C2 均选择为30pF,对振荡器的频率有稳定作用,当频率较大时,正弦波、三角波、锯齿波中每一点的延时时间为几微妙,故延时时间还要加上指令时间才能获得较大的频率波形。
单片机的时序单位
振荡周期:晶振的振荡周期,又称时钟周期,为最小的时序单位。
机器周期:1个机器周期由12个振荡周期组成,是计算机执行一种基本操作的时间单位。
指令周期:执行一条指令所需的时间。
一个指令周期由1-4个机器周期组成,依据指令不同而不同.
图3-1 时钟电路
3.2 复位电路
复位引脚 RST 通过一个斯密特触发器与复位电路相连,斯密特触发器用来抑制噪声,在每个机器周期的 S5P2,斯密特触发器的输出电平由复位电路采样一次,然后才能得到内部复位操作所需要的信号。
复位电路通常采用上电自动复位和按钮复位两种方式。
本设计选择了按键复位如图3-2,在系统运行时,按一下按键,就在 RST 断出现一段高电平,使器件复位。
此时 ALE、PSEN、P0、图3-2时钟电路图P1、P2、P4 输出高电平,RST 上输入返回低电平以后,变退出复位状态开始工作。
图3-2 复位电路
单片机的复位操作使单片机进入初始化状态,其中包括使程序计数器PC=0000H,这表明程序从0000H地址单元开始执行。
单片机冷启动后,片内RAM 为随机值,运行中的复位操作不改变片内RAM区中的内容,21个特殊功能寄存器复位后的状态为确定值统复位是任何微机系统执行的第一步,使整个控制芯片回到默认的硬件状态下。
51单片机的复位是由RESET引脚来控制的,此引脚与高电平相接超过24个振荡周期后,51单片机即进入芯片内部复位状态,而且一直在此状态下等待,直到RESET引脚转为低电平后,才检查EA引脚是高电平或低电平,若为高电平则执行芯片内部的程序代码,若为低电平便会执行外部程序。
51单片机在系统复位时,将其内部的一些重要寄存器设置为特定的值,至于内部RAM内部的数据则不变。
3.3 数模转换电路
DAC0832是8分辨率的D/A转换集成芯片。
与微处理器完全兼容。
这个DA 芯片以其价格低廉、接口简单、转换控制容易等优点,在单片机应用系统中得到广泛的应用。
D/A转换器由8位输入锁存器、8位DAC寄存器、8位D/A转换电路及转换控制电路构成。
DAC0832的主要特性参数如下:
1)分辨率为8位;
2)电流稳定时间1us;
3)可单缓冲、双缓冲或直接数字输入;
4)只需在满量程下调整其线性度;
5)单一电源供电(+5V~+15V);
6)低功耗,200mW。
DAC0832的工作原理:利用8位D/A转换器DAC0808,可以将8位数字量转换成模拟量输出。
数字量输入的范围为0~255,对应的模拟量输出的范围在VREF-到VREF+之间。
根据这一特性,可以利用单片机的并行口输出的数字量,产生常用的波形。
DAC0832电路与单片机的接口电路如图3-3所示。
图3-3 DAC0832与单片机的接口电路
3.4 运算放大电路
图3-4 运算放大电路
LM324的5管脚与DAC0832的(IOUT2)12管脚相连,LM324的6管脚与DAC0832的(IOUT1)11管脚相连,LM324的7管脚与DAC0832的REF(9)管脚相连.
第一级运算放大器的作用是将DAC0832输出的电流信号转化为电压信号V1,第二级运算放大器的作用是将V1通过反向放大电路-(R2/R1)倍。
题目要求输出的电压在0-5V可调,而V1的电压大约是5V,所以R1选择5K的电阻,R2选择10K的电位器,这样最大的输出电压为5*(10/2)=10,最小电压为0,可以实现题目要求的0-5V。
3.5 矩阵键盘电路
图3-5 矩阵键盘电路
图中键盘独立键盘行引出的四根线接8155芯片的PC口,六根列线接8155芯片的PA口,采用线反转法扫描键盘,确定键位。
如图按键K1为频率加、K2
为频率减,按键K4切换三角波,按键K5切换锯齿波,按键K6切换正弦波。
3.6 六位数码管(LED)显示电路
图3-6 LED显示电路
本设计选择了6位共阴极数码管如图3-6,它的6个发光二极管的阴极(二极管正端)连接在一起,通常公共阴极接低电平电平,其它管脚接段驱动电路输出端。
当某段驱动电路的输出端为低电平时,则该端所连接的字段导通并点亮,根据发光字段的不同组合可显示出各种数字或字符。
此时,要求段驱动电路能吸收额定的段导通电流,还需根据外接电源及额定段导通电流来确定相应的限流电阻。
显示电路用于显示信号的频率,并且使系统能根据按键实时显示先关信息。
该系统中添加一个74LS241 锁存器,用于驱动数码显示管,使其更易于控制,增加显示的准确性。
数码管第三位用来显示波形信号的频率,频率是以100HZ 步进显示。
要使显示管显示不同的数字或者字符,需要使端口输出相应的字型码,显
共阴极0 1 2 3 4 5 6 7
3FH 06H 5BH 4FH 66H 6DH 7DH 07H 8 9 A B C D E F
7FH 6FH 77H 7CH 39H 5EH 79H 71H
4. 系统程序设计
4.1 主程序流程图
图4-1 主流程图
主程序首先将需要初始化的部分进行初始化,然后负责循环执行按键扫描,数码管显示、DA数据输出和示波器显示。
这些过程都是以模块化的程序实现的,程序中有,按键扫描程序、数码管扫描显示程序、定时器定时计算程序、查表程序和DA数据输出程序,通过调用这些程序完成波形的产生,幅值和频率的改变。
4.2 按键处理子程序流程图
程序位于函数Scan-Key()和Shao-Key()中,函数位于主循环中,每循环一次调用一次,检测键盘是否按下,如果按下去延时抖动,然后检测到底是哪个按键按下,针对不同的按键按下采取不同的动作。
因为按键采用的是扫描法,故需要注意消抖的处理,在此用软件法去抖动即可。
软件法去抖动的实质是软件延时,即检测到某一键状态变化后延时一段时间,再检测该按键的状态是否保持着,如是则作为按键处理,否则,视为抖动,不予理睬。
去抖动的延时时间一般参考资料多描述为20ms左右,在实际应用中应大于20ms。
否则,会导致按一次多处理,影响程序正常执行。
图4-2 键盘控制程序流程图
4.3 数码管输出子程序流程图
图4-3 数码管子程序流程图
数码管输出程序是送段选码和位选码的程序,位于主程序中。
轮流点亮6个数码管,每大约5ms变换一次,由于轮换的次数太快,由于视觉暂留效应,看上去是6个数码管看上去好像一直点亮。
5.系统调试
5.1 Proteus软件仿真调试(1)键K4按下,示波器显示三角波
(2)键K5按下,示波器显示锯齿波
(3)键K6按下,示波器显示正弦波5.2 Proteus仿真原理图
图5- Proteus仿真原理图
5.2 硬件调试
在单片机实验开发系统中,将AT89C51的P1口用8排位线接到DAC0832的Dl口,DAC0832的CS5和WR端口接地,VOUT接示波器输入端。
打开示波器,调节水平与垂直方向,屏幕上出现一条水平亮线即可。
按下按键K4,示波器输出三角波形,再连续按下键K1,波形周期随之增大,六位数码管显示的数字亦随之增加。
按下键K6,示波器则输出正弦波,再连续按下键K2,波形周期随之减小,六位数码管显示的数字亦随之减小。
按下键K5,示波器输出锯齿波,连续按下K1或K2,示波器显示的波形的周期随之增大或减小,六位数码管上显示的周期数也随之增大减小。
6. 程序清单
#include<reg51.h>
#include<absacc.h>
#include<intrins.h>
#include<stdlib.h>
#include<math.h>
#define PA8155 XBYTE[0XFF21]
#define PB8155 XBYTE[0XFF22]
#define PC8155 XBYTE[0XFF23]
#define PP8155 XBYTE[0XFF20]
#define uint unsigned int
#define uchar unsigned char
uint j,i;
uint XSSJ,num,SS;
uchar Xi=0,Xl=0xfe;
uint KeyY,KeyNum,NUMM=3;
uint numbsj=0,numbjc=0,numbsin=0;
uchar stable[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 };/* 0~f十六个数的代码 */ uchar Xtable[6]={0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char code 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,0xDF,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,0x1C,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};
void Scan_Key(void) ;
void Shao_Key(void) ;
void delay(unsigned int x);
void XianShiSJ(void);
void Sanjiaobo(void) ;
void Juchibo(void) ;
void Zhengxianbo(void);
uint WW,WWW,W;
void Sanjiaobo(void)/*产生三角波*/ {
WWW=0XFF;
for(WW=0;WW<120;WW++)
{
P1=WWW;/*三角波最大值*/
WWW--;
for(SS=0;SS<numbsj;SS++) {
_nop_;
}
}
for(W=0;W<120;W++)
{
P1=WWW;
WWW++;
for(SS=0;SS<numbsj;SS++) {
_nop_;
}
}
}
uint QQ,QQQ;
void Juchibo(void)/*产生锯齿波*/ {
QQQ=0XFF ;
for(QQ=0;QQ<120;QQ++)
{
P1=QQQ;/*锯齿波最大值*/
QQQ--;
for(SS=0;SS<numbjc;SS++)
{
_nop_;
_nop_;
}
}
}
uint AA;
void Zhengxianbo(void)/*产生正弦波*/
{
for(AA=0;AA<255;AA++)
{
P1=Tab[AA];/* 查表 */
for(SS=0;SS<numbsin;SS++)
{
_nop_;
_nop_;
}
}
}
void XianShiSJ(void)/*数码管显示信号周期*/
{
Xtable[0]=stable[0];
Xtable[1]=stable[((XSSJ)%10)];//个位
Xtable[2]=stable[((XSSJ)%100)/10];//十位
Xtable[3]=stable[((XSSJ)%1000)/100];//百位 Xtable[4]=stable[0];
Xtable[5]=stable[0];
}
void T0_time() interrupt 1 //50ms
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
num++;
if(num==5) //250ms
{
num=0;
Scan_Key();
delay(10);
Scan_Key();
if(KeyY==1) //有键按才会执行
{
KeyY=0;
Shao_Key(); //求键盘号
switch(KeyNum) //键盘01的次数{
case 0: numbjc=numbjc+1;
numbsj=numbsj+1;
numbsin=numbsin+1;
break;
case 1: numbjc=numbjc-1;
numbsj=numbsj-1;
numbsin=numbsin-1;
break;
default: NUMM=KeyNum;break; //不变
}
switch(NUMM)
{
case 3: {XSSJ=5*numbjc+10; break; } case 4: {XSSJ=10*numbsj+20; break;} case 5: {XSSJ=10*numbsin+23; break;}
default: { break;}
}
XianShiSJ();
}
}
}
void main()
{
int q;
for(q=0;q<=15;q++)
{
stable[q]=~stable[q];
}
XSSJ=10;
XianShiSJ(); //求显示数据
IP=0X08;
PP8155=0x43 ;
EA=1;
ET0=1;
ET1=1;
TMOD=0X11;
TH0=(65536-50000)/256; // 高八位
TL0=(65536-50000)%256;
TH1=(65536-1000)/256; // 高八位
TL1=(65536-1000)%256;
TR0=1;
TR1=1;
while(1)
{
while(NUMM==3)
{ Juchibo(); }
while(NUMM==4)
{ Sanjiaobo(); }
while(NUMM==5)
{ Zhengxianbo() ;}
}
}
void delay(unsigned int x)
{
for(j=0;j<x;j++)
{
for(i=0;i<120;i++)
{
;
}
}
}
void Scan_Key(void) //判断有键按下
{
uint i;
PA8155=0x00;
PB8155=0XFF;
i=PC8155;
i=~i;
i=i&0x0f;
if(i!=0)
{
KeyY=1;
}
else
{
KeyY=0;
}
}
uchar Keyh,Keyl;
void Shao_Key(void) //求键盘号
{
Keyl=0Xfe;
PB8155=0XFF;
for( KeyNum=0; KeyNum<=5; KeyNum++) {
PA8155=Keyl;
Keyl=Keyl<<1;
Keyl=Keyl+1;
Keyh=PC8155;
Keyh=~Keyh;
Keyh=Keyh&0x0f;
if(Keyh!=0)
{
return;
}
}
}
void T1_time() interrupt 3 //1ms
{
TH1=(65536-1000)/256; // 高八位
TL1=(65536-1000)%256;
PB8155=Xtable[Xi]; //显示数据
PA8155=Xl;
Xl=Xl<<1;
Xl=Xl+1;
Xi++;
if(Xi==6)
{
Xi=0;
Xl=0xfe;
}
}
7.小结
经过将近两周的单片机课程设计,终于完成了我们的多功波形发生器的设计,基本达到设计要求,从心底里来说,还是很高兴的,毕竟这次设计把实物都做了出来。
在本次设计的过程中,我发现很多的问题,得到很大的锻炼。
对于单片机设计,其硬件电路是比较简单的,主要是解决程序设计的问题,而程序设计是一个很灵活的东西,它反映了你解决问题的逻辑思维和创新能力,它才是一个设计的灵魂所在。
因此在整个设计过程中大部分时间是用在程序上面的。
很多子程序是可以借鉴书本上的,但怎样衔接各个子程序才是关键的问题所在,这需要对单片机的结构很熟悉。
因此可以说单片机的设计是软件和硬件的结合,二者是密不可分的。
要设计一个成功的电路,必须要有耐心,要有坚持的毅力。
在整个电路的设计过程中,花费时间最多的是各个单元电路的连接及电路的细节设计上,如在多种方案的选择中,我们仔细比较分析其原理以及可行的原因。
这就要求我们对硬件系统中各组件部分有充分透彻的理解和研究,并能对之灵活应用。
完成这次设计后,我在书本理论知识的基础上又有了更深层次的理解。
同时在本次设计的过程中,我还学会了高效率的查阅资料、运用工具书、利用网络查找资料。
我发现,在我们所使用的书籍上有一些知识在实际应用中其实并不是十分理想,各种参数都需要自己去调整。
偶而还会遇到错误的资料现象,这就要求我们应更加注重实践环节。
同样波形发生还存在诸多问题。
一,示波器的显示波形不稳定,跳动厉害;二,当频率减小到零时,便不能通过频率加恢复波形,只能通过重新运行程序来恢复;三,键盘按键有时会严重滞后,键按下后,很长时间才有反应。
虽然问题多多,我会坚持完善波形发生器。
最后还要在此感谢指导老师们和我的同学,他们在整个过程中都给予了我充分的帮助与支持。