51单片机波形发生器
波形发生器是一种在电子实验、教学以及工程测试中不可或缺的设备,用于产生各种电信号以激励电路或模拟信号。本设计旨在利用价格低廉、应用广泛的MCS-51系列单片机作为核心控制单元,结合模块化的外围电路,在Proteus仿真平台上一款简易实用的函数信号发生器。
一、系统设计
1、51单片机
51单片机是指兼容Intel 8051指令系统的一系列单片机型号(如AT89C51、STC89C52等),是本次波形发生器设计的"大脑"。采用8位中央处理器,拥有32个可编程I/O口、3个16位定时器/计数器和8个中断源。通常包含4K-8K字节的Flash程序存储器和128-256字节的RAM。常用12MHz晶振,此时机器周期为1μs,指令执行速度适中。

2、PCF8591
PCF8591是NXP公司生产的一款单芯片、低功耗8位CMOS数据采集器件,它集成了A/D和D/A转换功能于一体。采用I²C串行总线通信,仅需SDA(数据线)和SCL(时钟线)两根线与单片机连接。4路模拟输入(可编程为单端或差分输入),1路模拟输出,8位分辨率(即数字量0-255对应模拟电压0-VREF),电源电压2.5V-6V宽范围,典型值5V,3个地址引脚(A0、A1、A2)允许同一I²C总线上挂接最多8个PCF8591。

3、按键
按键(按钮)是一种通过触点的通断来控制电路的人工控制主令电器。在单片机系统中,按键是最基础、最常用的人机交互工具。未按下时,按键的常开触点断开,I/O口通过上拉电阻保持高电平;按下后触点闭合,I/O口被拉到低电平。单片机通过检测I/O口电平的变化来判断按键是否被按下。

二、软件设计
1、PCF8591
PCF8591使用IIC协议进行通信,支持adc输入和dac输出。本次设计主要使用他的一个输出功能。参考代码如下:
#include "iic.h"
//本代码加入了读取ACK问题,使用了goto语句
//AD转换,读取com通道的8位数据,0x00/0x40表示打开通道AIN0 0x01/0x41表示打开通道AIN1 0x02/0x42表示打开通道AIN2 0x03/0x43表示打开通带AIN3
unsigned char read_AD_data(unsigned char com)
{
unsigned char dat = 0;
unsigned char i = 0;
read_ad_data:
START_IIC();
write_1_byte_IIC(0x90);//准备向pcf8591器件写入数据,此器件的地址为1001 A0 A1 A2 R/W
if (!read_ACK_IIC())//若接收到ACK则与器件握手成功
{
write_1_byte_IIC(com);//向器件写入使用哪个AD通到开始采集数据,0x00/0x40表示通道AIN0 0x01/0x41表示通道AIN1 0x02/0x42表示通道AIN2 0x03/0x43表示通带AIN3
if (!read_ACK_IIC())
{
START_IIC();//和at24c02 读取数据有点类似 马来币之前没有写 手册英文没有看到这个地方如何读取的,参考别人写的代码
write_1_byte_IIC(0x91);//准备读取pcf8591发来的数据
if (!read_ACK_IIC())
{
dat = read_1_byte_IIC();
write_ACK_IIC(1);//主机接收到数据向从设备不发送应答信号
STOP_IIC(); //结束本次通讯
return dat;
}
else
{
STOP_IIC();
goto read_ad_data;
}
}
else
{
STOP_IIC();
goto read_ad_data;
}
}
else
{
i++;
if (i == 255)
{
return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
}
STOP_IIC();
goto read_ad_data;
}
}
//DA转换,输出模拟量通过芯片的AOUT端口输出
unsigned char write_DA_data(unsigned char dat)//0~255对应0V~5V
{
unsigned char i = 0;
write_da_data:
START_IIC();
write_1_byte_IIC(0x90);
if (read_ACK_IIC() == 0)
{
write_1_byte_IIC(0x40);//允许器件模拟输出,并且不自动增加输出端口
if (!read_ACK_IIC())
{
write_1_byte_IIC(dat);
if (!read_ACK_IIC())
{
STOP_IIC();
return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
}
else
{
STOP_IIC();
goto write_da_data;
}
}
else
{
STOP_IIC();
goto write_da_data;
}
}
else
{
i++;
if (i == 255)
{
return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
}
STOP_IIC();
goto write_da_data;
}
}
//数字量转换成模拟电压公式如下
unsigned char convert_data(unsigned char DA)
{
unsigned char i = 0;
i = (unsigned char)(DA * 5 / 256.0 + 0.0005);//pcf8591内部数字量转化为模拟量的计算公式
return i;
}
#ifndef __PCF8591_H__
#define __PCF8591_H__
unsigned char read_AD_data(unsigned char com);//直接读取的就是芯片转换后的数字信号
//DA转换,输出模拟量通过芯片的AOUT端口输出
unsigned char write_DA_data(unsigned char dat);//芯片直接接收数字信号后自动转换为模式信号并输出
//数字量转换成模拟电压公式如下
unsigned char convert_data(unsigned char DA);
#endif // !__PCF8591_H__
2、波形生成相关
本次设计使用数组加定时器的方式生成波形,由于单片机性能的原因,做不到高频,但是一般情况下够用,参考代码如下:
#include <reg51.h> //51头文件
#include "PCF8591.h"
#define uchar unsigned char
#define uint unsigned int
sbit s1=P3^2;
sbit s2=P3^3;
uchar k=0,p=0,delay=0;
int bxxz=0;pinglv=0;
uchar a=1,b=0,c=0,d=0;
//正弦波数据
uchar code sin[64]={
135,145,158,167,176,188,199,209,218,226,234,240,245,249,252,254,254,253,251,247,243,237,230,222,213,204,193,182,170,158,
146,133,121,108,96,84,72,61,50,41,32,24,17,11,7,3,1,0,0,2,5,9,14,20,28,36,45,55,66,78,90,102,114,128
};
//方波数据报表
uchar code juxing[64]={
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
//锯齿波数据
uchar code juchi[64]={
0,4,8,12,16,20,24,28,32,36,40,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,130,134,138,142,
146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,215,219,223,227,231,235,239,243,247,251,255
};
//三角波数据
uchar code sanjiao[64]={
0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,
248,240,232,224,216,208,200,192,184,176,168,160,152,144,136,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,0
};
void delay1() //延时 ms级
{
int a,b;
for(a=1;a>0;a--)
for(b=122;b>0;b--);
}
void int0() interrupt 0 //外部中断0 P3.2 中断处理,用于波形切换
{
EX0=0;
delay1();
if(s1==0)
{
bxxz++;
if(bxxz==4)
bxxz=0;
switch(bxxz)
{
case 0 :
{a=1,b=0,c=0,d=0;} //正弦波
break;
case 1 :
{a=0,b=1,c=0,d=0;} //方波
break;
case 2 :
{a=0,b=0,c=1,d=0;} //锯齿波
break;
case 3 :
{a=0,b=0,c=0,d=1;} //三角波
break;
}
delay1();
while(!s1);
}
while(!s1);
EX0=1;
}
void int1() interrupt 2 //外部中断1 P3.3 中断处理,用于频率调节
{
EX1=0;
delay1();
if(s2==0){
pinglv += 15;
pinglv %= 500;
}
while(!s2);
EX1=1; //开中断
}
void main()
{
EA=1;
IT0=1;
EX0=1;
IT1=1;
EX1=1;
pinglv=15;
while(1)
{
while(a) //产生正弦波
{
delay=pinglv; //获取周期数据
write_DA_data(sin[k]);
k++;
if(k==64) //一个周期取64点波数据
k=0;
while(delay) //延时处理
delay--;
}
while(b) //产生方波
{
delay=pinglv;
write_DA_data(juxing[k]);
k++;
if(k==64)
k=0;
while(delay)
delay--;
}
while(c) //产生锯齿波
{
delay=pinglv;
write_DA_data(juchi[k]);
k++;
if(k==64)
k=0;
while(delay)
delay--;
}
while(d) //产生三角波
{
delay=pinglv;
write_DA_data(sanjiao[k]);
k++;
if(k==64)
k=0;
while(delay)
delay--;
}
}
}
三、项目演示
(1)上电后单片机默认是正弦波,可以看到下图:

(2)按下第一个按键,可以切换波形,如下:


(3)按下第三个按键,可以进行频率调节。

四、项目总结
本项目基于51单片机和PCF8591设计并实现了一款简易多波形信号发生器。系统以AT89C51为控制核心,利用其定时功能产生精确的时间基准,通过I²C总线控制PCF8591进行数模转换,配合按键调节,在Proteus仿真环境中成功实现了正弦波、方波、三角波和锯齿波四种波形的输出,并能实时调节频率。关注本人微信公众号“小念电子设计”回复“波形发生”即可获取完整源码。
更多推荐



所有评论(0)