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

这篇具有很好参考价值的文章主要介绍了基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

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

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

 

        (1)PCF8591

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

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

         参考电压为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();
}

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

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

 (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)仿真效果

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

(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)效果

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

 

(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)效果

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

 

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 <reg51.h>
#include <intrins.h>
#include <math.h>

#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<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

/************************************************
函数名:I2CReceiveByte
功能:iic读字节
参数:无
返回值:da,读出的数据
************************************************/
/*unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}*/

/************************************************
函数名:I2CWaitAck
功能:主机等待应答信号
参数:无
返回值:ackbit,0-应答,1-非应答
************************************************/
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

/************************************************
函数名:I2CSendAck
功能:从机发送应答信号
参数:ackbit,0-应答,1-非应答
返回值:无
************************************************/
/*void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}*/

iic.h

#ifndef __IIC_H
#define __IIC_H

#include "main.h"

sbit sda = P2^1;//数据线
sbit scl = P2^0;//时钟线

static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
//unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
//void I2CSendAck(unsigned char ackbit);
#endif

(3)dacout.c

#include "dacout.h"
#include "iic.h"
u8 volt_sine = 0;    	//正弦波
u8 volt_trian = 0;		//三角波
u8 volt_zigzag = 0;		//锯齿波
u8 volt_aquare = 0;		//方波

extern u8 mode;			//输出模式
/************************************************
函数名:dac_sine
功能:输出正弦波
参数:无
返回值:无
************************************************/
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);//电压输出
}
/************************************************
函数名:dac_triangular
功能:输出三角波
参数:无
返回值:无
************************************************/
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);//电压输出
}
/************************************************
函数名:dac_zigzag
功能:输出锯齿波
参数:无
返回值:无
************************************************/
void dac_zigzag()//锯齿波
{
	volt_zigzag = volt_zigzag + 5;
	if(volt_zigzag == 255)
	{
		volt_zigzag = 0;
	}
	set_volt(volt_zigzag);
}
/************************************************
函数名:Delay10ms
功能:10ms延时
参数:无
返回值:无
************************************************/
void Delay10ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 20;
	j = 113;
	do
	{
		while (--j);
	} while (--i);
}
/************************************************
函数名:dac_square
功能:输出方波
参数:无
返回值:无
************************************************/
void dac_square()//方波
{
	volt_aquare = 255;
	set_volt(volt_aquare);
	Delay10ms();//延时等待
	volt_aquare = 0;
	set_volt(volt_aquare);//电压输出
	Delay10ms();
}
/************************************************
函数名:waveform_out
功能:波形输出选择
参数:无
返回值:无
************************************************/
void waveform_out()
{
	switch(mode)
	{
		case 0:dac_sine();break;		//模式0,正弦波
		case 1:dac_triangular();break;	//模式1,正弦波
		case 2:dac_zigzag();break;		//模式2,正弦波
		case 3:dac_square();break;		//模式3,正弦波
		default:break;
	}
}
/************************************************
函数名:set_volt
功能:使用pcf8591输出电压
参数:value 0-255
返回值:无
************************************************/
void set_volt(u8 value)					
{
	I2CStart();
	I2CSendByte(0x90);						//写地址
	I2CWaitAck();
	I2CSendByte(0x40);						//通道选择
	I2CWaitAck();
	I2CSendByte(value);						//写入数据0-255对应5V
	I2CWaitAck();
	I2CStop();
}

dacout.h

#ifndef __DACOUT_H
#define __DACOUT_H
#include "main.h"

void dac_sine();//正弦波
void dac_triangular();//三角波
void dac_zigzag();//锯齿波
void Delay10ms();		//@12.000MHz
void dac_square();//方波
void waveform_out();
void set_volt(u8 value);

#endif

(4)switchover.c

#include "switchover.h"
//共阴数码管段码0-9
u8 code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//无小数点
u8 mode = 0;//输出模式
/************************************************
函数名:key_pron
功能:切换输出波模式,1-正弦波,2-三角波,3-锯齿波
		4-方波
参数:无
返回值:无
************************************************/
void key_pron()
{
	if(!key)
	{
		Delay10ms();
		if(!key)
		{
			while(!key);
			mode++;
			if(mode == 4)
			{
				mode = 0;
			}
		}
	}
}
/************************************************
函数名:seg_pron
功能:数码管显示输出波模式
参数:无
返回值:无
************************************************/
void seg_pron()
{
	P1 = SMG_NODOT[mode];
}

switch.h

#ifndef __SWITCHOVER_H
#define __SWITCHOVER_H
#include "main.h"

sbit key = P2^7;

extern void Delay10ms();		//@12.000MHz

void key_pron();
void seg_pron();

#endif

6.源码及仿真资源下载

链接:https://pan.baidu.com/s/1_ug6Ih4NxAT39CVCHRjFCg?pwd=pmuo 
提取码:pmuo文章来源地址https://www.toymoban.com/news/detail-485129.html

到了这里,关于基于51单片机的波形发生器(PCF8591、正弦波、三角波、锯齿波、方波)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 51单片机入门教程(4)——波形发生器

    51单片机入门教程(4)——波形发生器

    目录 1、总述 2、系统硬件设计  3、系统软件设计思路  3、测试与分析 (1)Proteus仿真测试 (2)直流稳压电源测试 (3)实物测试 该篇为51单片机入门教程的实战篇 ,本篇介绍了以51单片机和DAC0832数模转换芯片为核心的波形发生器,并对DAC0832和UA741的结构和工作原理以及电

    2024年02月08日
    浏览(23)
  • 单片机——C51实验含Proteus仿真(AD转换器(数字电压表),DA转换器(波形发生器))

    单片机——C51实验含Proteus仿真(AD转换器(数字电压表),DA转换器(波形发生器))

    分为两部分:AD转换器实现数字电压表,DA转换器实现波形发生器(在仿真部分详细说明) 所用到的原理图:  AD转换器实现数字电压表部分         需要打开main函数中LCD_init(),ADC(),display()三个注释其中电压的输出显示用到了LCD1602关于这部分详情见(96条消息) 单片机——

    2024年02月08日
    浏览(15)
  • 单片机课程设计波形发生器

    单片机课程设计波形发生器

    怎么说呢,前面半个月被这个单片机课程设计搞得焦头烂额的,再加上运气属实有点“好”,就脾气有点“暴躁”,好的,也就骂了半天的脏话。有一说一,没有素质确实舒服。 好了,事情目前是过去了,那就好好回顾一下遇到的问题,以及找到了怎样的解决方案,和最后仍

    2024年02月09日
    浏览(9)
  • 单片机实验——简易波形发生器设计

    单片机实验——简易波形发生器设计

    波形发生器广泛地应用于电子和通信等领域,是应用最广泛的电子仪器之一,本设计用51单片机以及DAC0832实现基本波形的输出,参考电路如下: 可以产生方波、三角波、正弦波、锯齿波等波形,用仿真的示波器查看。 用4个按键分别控制输出相应波形。 利用C51设计程序完成以

    2024年02月12日
    浏览(12)
  • 【微机原理课设protues-汇编】基于8086四种波形发生器仿真设计-基于8086数码管矩阵键盘控制设计-基于8086微机原理直流电机控制系统-基于单片机PWM直流电机控制系统设计汇编

    【微机原理课设protues-汇编】基于8086四种波形发生器仿真设计-基于8086数码管矩阵键盘控制设计-基于8086微机原理直流电机控制系统-基于单片机PWM直流电机控制系统设计汇编

    文章转自电设屋,资料百度网盘下载地址  https://www.aiesst.cn/share.html 目录 1207基于8086四种波形发生器仿真设计-微机原理汇编仿真资料 1202基于8086数码管矩阵键盘控制设计-全套资料 1218基于8086智能汽车控制系统设计-微机原理课设 1209基于8086微机原理直流电机控制系统-设计资料

    2024年02月12日
    浏览(20)
  • STM32单片机示例:64位全局时间戳发生器

    STM32单片机示例:64位全局时间戳发生器

    STM32H743 / H750 系列的芯片有一个64位的全局时间戳发生器( Global timestamp generator ),这篇文章将对它的使用做个记录。 全局时间戳发生器相关的内容可以参考官方参考手册: TGS时钟来源与APB总线时钟,这就是TGS计数器时钟了,并且用于TGS计数时没法对其进行分频操作。我们使

    2024年02月10日
    浏览(48)
  • 蓝桥杯单片机学习13——NE555方波发生器&频率测量

    蓝桥杯单片机学习13——NE555方波发生器&频率测量

    NE555是一种高度稳定的控制器,内部用三个阻值为5KΩ的电阻分压,因此叫做555芯片。能够产生精确的定时脉冲。单稳态工作时,延时由一个外部电阻和一个电容控制。工作稳定,频率和占空比由两个外部电阻和一个电容器精确控制。具有以下特点: 【1】:大电流驱动能力(

    2024年02月03日
    浏览(8)
  • 单片机实验七 NE555脉冲发生器实验(定时/计数器)

    单片机实验七 NE555脉冲发生器实验(定时/计数器)

    1.熟悉实验软件和硬件,进行正确的接线; 2.1602显示脉冲频率,调节电位器可改变频率。 1.Keil uVision4 2.PZISP自动下载软件 3.HC6800S开发板 实验界面及跳线帽位置 NE555是一种应用特别广泛作用很大的的集成电路,属于小规模集成电路,在很多电子产品中都有应用。 NE555的作用是

    2024年02月06日
    浏览(12)
  • 基于51单片机的四种波形信号发生器仿真设计(仿真+程序源码+设计说明书+讲解视频)

    基于51单片机的四种波形信号发生器仿真设计(仿真+程序源码+设计说明书+讲解视频)

    本设计 (仿真+程序源码+设计说明书+讲解视频) 仿真原版本:proteus 7.8 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0015 1、本设计采用AT89C51单片机作为控制核心,外围采用数字/模拟转换电路(DAC0832)、运放电路(LM324)、按键和LCD1602液晶显示电路。 2、电路采用单

    2024年02月05日
    浏览(10)
  • 51单片机可调幅度频率波形信号发生器( proteus仿真+程序+原理图+报告+讲解视频)

    51单片机可调幅度频率波形信号发生器( proteus仿真+程序+原理图+报告+讲解视频)

    51单片机可调幅度频率信号发生器( proteus仿真+程序+原理图+报告+讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0055 基于51单片机的可调幅度频率波形信号发生器 基于51单片机的三角波信号发生器 1、幅值在0-5V可以通过按键调整,频率在

    2024年02月08日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包