基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)

您所在的位置:网站首页 单片机AIN2模拟通道的地址 基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)

基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)

#基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)| 来源: 网络整理| 查看: 265

        正弦波、三角波、锯齿波和方波是我们平时最常见的四种波形,那么学会使用单片机产生这四种波就很重要了。但学过51单片机就知道,其IO引脚只能输出高电平或低电平,单靠其引脚生成以上波形,好像不大可能,因此我们需要配合使用另一个很重要的芯片,DAC芯片,将数字量转换为模拟量,这样,生成以上波形就变得有可能了。

       本次设计,我们通过 按键切换输出波模式,1-正弦波,2-三角波,3-锯齿波,4-方波,使用数码管显示当前输出的波模式。本次设计的波形为示意图,其中正弦波、三角波、锯齿波等频率都比较低,如果想要可变频率,可以通过定时器实现,但转化时间的存在使得频率依旧比较低。

文末有完整源码文件与仿真文件分享

注意本次仿真采取的proteus版本为8.15,低于此版本无法打开。如发现波形不显示,请点击控制栏debug,勾选如下:

 

        (1)PCF8591

        pcf8591是一款8位的ad/da转换芯片,其使用的是IIC通信方式,支持电压2.5-6V。拥有四路输入和一路输出。本次设计如下:

        

         参考电压为5V,A0、A1、A2接地,因此,写地址为0x90,读地址为0x91。

(2)正弦波生成

        生成正弦波的方法我们可以这么想:我们将一个正弦曲线进行离散,可以得到一系列的点,将这些点对应到0-5V的电压,然后我们通过pcf8591输出这些电压,同时在间隔时间内进行保持,我们就可以得到一个近似的正弦曲线,只要这个间隔时间够短,这个曲线就越接近于正弦曲线。

        OK,理论有了,下面就可以开始实践了。首先,我们想想怎么通过51单片机得到正弦曲线。自己写一个函数?也行,但有点麻烦。这时我们可以借鉴另一个常用头文件,math.h,里面就有我们需要的sin函数,但需要注意的是,我们日常看到的曲线横坐标是角度,而这个函数处理的是弧度,这时就设计到一个转换关系。即180度=3.1415......。如果我们取间隔均匀的角度,我们就可以得到离散化的曲线。其次,将-1到1转换为0-255的值,但PCF8591不会输出负压,因此我们最低为0V,即sin值*128+128。最后,电压输出,我们需要写一个I基于IC的电压输出函数。下面是具体的实现代码。

1)正弦波的离散与转换

void dac_sine()//正弦波 { static u16 angle = 0; //角度 static float radian = 0; //弧度 angle = angle + 5; //每次加5度 if(angle == 360) //一个周期369度 { angle = 0; } radian = angle * 0.0055; //角度转弧度 volt_sine = 128 + (sin(radian * pi) * 128);//标度变换,1~-1转换到 //0-255 set_volt(volt_sine);//电压输出 }

2)电压输出

注意写入的0x40,4代表开启电压输出,0x90是电压输出控制字,上文有说。

void set_volt(u8 value) { I2CStart(); I2CSendByte(0x90); //写地址 I2CWaitAck(); I2CSendByte(0x40); //通道选择 I2CWaitAck(); I2CSendByte(value); //写入数据0-255对应5V I2CWaitAck(); I2CStop(); }

借助以上代码,我们就可以得到如下的曲线:

 (3)三角波生成

        相对于生成正弦波,生成三角波就简单太多了。PCF8591输出0-5V,对应0-255,我们只要让一个变量从0加到255,再从255降到0,不断循环,三角波就出现了。

1)程序

void dac_triangular()//三角波 { static bit flag = 0; //切换标志 if(!flag) //上升段 { volt_trian = volt_trian + 5; if(volt_trian == 255) { flag = 1; } } else //下降段 { volt_trian = volt_trian - 5; if(volt_trian == 0) { flag = 0; } } set_volt(volt_trian);//电压输出 }

2)仿真效果

(4)生成锯齿波

        所谓锯齿波,就是三角波的一半。让一个变量从0加到255,再突降到0。重复上述过程,即可得到锯齿波。

1)程序

void dac_zigzag()//锯齿波 { volt_zigzag = volt_zigzag + 5; if(volt_zigzag == 255) { volt_zigzag = 0; } set_volt(volt_zigzag); }

2)效果

 

(5)方波

至于方波,我们用IO口就可以实现。用PCF8591的话,那就输出一段时间5V后切换0V,重复。

1)程序

void Delay10ms() //@12.000MHz { unsigned char i, j; i = 20; j = 113; do { while (--j); } while (--i); } void dac_square()//方波 { volt_aquare = 255; set_volt(volt_aquare); Delay10ms();//延时等待 volt_aquare = 0; set_volt(volt_aquare);//电压输出 Delay10ms(); }

2)效果

 

OK,OK,讲解完毕,以下为全部代码

(1)mian.c

/********************************************* Author:sakura Time:2023/5/16 funcation:利用8位的AD/DA转换器PCF8591产生正弦波 、三角波、锯齿波、方波四种常用波形。 通过按键切换波形输出,同时数码管显示 当前波形模式,0-正弦波,1-三角波、 2-锯齿波,3-方波。 copyright:版权所有,借鉴请注明 *********************************************/ #include "main.h" #include "iic.h" #include "dacout.h" #include "switchover.h" /************************************************ 函数名:main 功能:主函数入口 参数:无 返回值:无 ************************************************/ void main() { while(1) { waveform_out(); key_pron(); seg_pron(); } }

main.h

#ifndef __MAIN_H #define __MAIN_H #include #include #include #define u8 unsigned char #define u16 unsigned int #define pi 3.14159//Π #endif

(2)iic.c

#include "iic.h" #define DELAY_TIME 5 /************************************************ 函数名:I2C_Delay 功能:iic延时函数,15个机器周期 参数:n,延时n*15 返回值:无 ************************************************/ static void I2C_Delay(unsigned char n) { do { _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); } while(n--); } /************************************************ 函数名:I2CStart 功能:iic起始信号 参数:无 返回值:无 ************************************************/ void I2CStart(void) { sda = 1; scl = 1; I2C_Delay(DELAY_TIME); sda = 0; I2C_Delay(DELAY_TIME); scl = 0; } /************************************************ 函数名:I2CStop 功能:iic终止信号 参数:无 返回值:无 ************************************************/ void I2CStop(void) { sda = 0; scl = 1; I2C_Delay(DELAY_TIME); sda = 1; I2C_Delay(DELAY_TIME); } /************************************************ 函数名:I2CSendByte 功能:iic写字节 参数:byt,写入的数据 返回值:无 ************************************************/ void I2CSendByte(unsigned char byt) { unsigned char i; for(i=0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3