基于DAC0832的程控衰减器

基于DAC0832的程控衰减器

一、需求分析:

1、对输入信号Vin(2.56V直流)进行程控衰减,倍数为2~256倍,由按键控制

2、程控放大器模式,对输入信号(0.02V直流)进行程控放大

3、程控放大器模式,对输入信号(Vp-p=0.1V正弦信号)放大128倍

4、显示器(SMS0801)显示倍数和电压

5、通过程控方式,在衰减器和放大器两种模式下切换

二、主要元器件:

稳压源TL431;稳压二极管LM385;

数模转换DAC0832;模数转换ADS1115;

显示器SMS0801;运算放大器OP07;继电器

三、设计流程

在这里插入图片描述

四、工作原理

4.1完整原理图

在这里插入图片描述

①—2.56V基准源;②—0.02V基准源;③—衰减/放大电路;④—模式切换;⑤—DAC0832的输出状态、继电器输入的模拟;⑥显示的模拟

4.2仿真环境

在线仿真:电子森林 https://www.eetree.cn/war/circuitjs.html?lang=zh

离线仿真:Protues;

4.3基准源 2.56V

功能描述:

对应原理图模块①,采用TL431的恒压电路产生2.56V的稳定电压,使用可调电阻可以精确调节输出电压值Vo,又简化了阻值的计算,但对电路造成了后置影响,即在连接后续电路后输出电压会低于2.56V。

原理分析:

TL431的内部含有一个2.5V的基准电压,所以当在REF端引入输出反馈时,器件可以通过从阴极到阳极很宽范围的分流,控制输出电压。如上图所示,当R1和R2的阻值确定后,两者对Vo的分压引入反馈,若Vo增大,反馈量增大,TL431的分流也就增加,从而又导致Vo下降。显见,这个深度的负反馈电路必然在VI等于基准电压处稳定,此时Vo=(1+R1/R2)Vref。选择不同的R1和R2的值可以得到从2.5V到36V范围内的任意范围电压输出,特别地,当R1=R2时,Vo=5V。需要注意的是,在选择电阻时必须保证TL431工作的必要条件,就是通过阴极的电流要大于1mA

在这里插入图片描述

[1]资料来源:TL431常用电路整理-电子发烧友网 http://m.elecfans.com/article/577647.html

4.4基准源 0.02V

功能描述:

对应原理图模块②,使用LM385制作输出电压约为1.2V的电压基准,经过一个运放构成的电压跟随器后(实现阻抗变换,保障信号衰减小),通过两个电阻分压实现0.02V的稳定输出。同上采用了可调电阻,虽然本次结果显示影响较小,但实际上采用阻值固定的电阻较好。

原理分析:

参考LM324的数据手册构建电压基准源,使用一个电阻器保证有大于Iz(min)=8uA的电流流入阴极。

在这里插入图片描述

4.5衰减电路

功能描述:

对应原理图模块③,DAC0832的8脚VREF作输入端9脚RFB作反馈电阻,通过改变DAC0832的DI7~0口输出状态实现不同倍数的衰减。第二个运算放大器起输出电压反相的作用。

原理分析:

DAC0832是采用CMOS工艺制成的单片直流输出型8位数/模转换器。如图所示,它由倒T型R-2R电阻网络、模拟开关、运算放大器和参考电压VREF四大部分组成。

在这里插入图片描述

倒T型R-2R电阻网络

可以等效为
在这里插入图片描述

网路特点:任何一个节点的三条分支的等效电阻都是2R,因此流进任何一个选定分支的电流为I=UR/3R。同时因为并联结构,流入其他节点时,电流会被平分。

以图中模拟A0=1为例,A0的电流为I=UR/(2R||2R+2R)=UR/3R,A1的电流就为I/2,A2的电流为I/4…以此类推,A7的电流为1/128,流入Rfb的电流为I/256,最终输出电压为Vo=I/256*Rfb。当Rfb=3R时,Vo=1/256UR。

运算放大器的输出模拟量Vo为:

在这里插入图片描述

4.6放大电路

功能描述:

对应原理图模块③,与衰减电路相似,8脚VREF作为反馈,9脚RFB作为输入端,改变DAC0832的DI7~0口输出状态实现不同倍数的放大。

原理分析:

电路原理与衰减相同,简言之是将输入、输出交换。

在这里插入图片描述

运算放大器的输出模拟量Vo为:在这里插入图片描述

4.7模式切换

功能描述:

对应原理图模块④,电路上,通过继电器实现不同线路的切换;程序上,通过改变控制端口的输出电压,让继电器在跳转/未跳转两种状态之间切换。

原理分析:

对比衰减和放大电路,可以发现模式的切换只需要交换输入、输出端即可,因而采用继电器控制不同线路的选择,电路中使用三极管实现控制端口的电压变化影响继电器工作状态的效果。

五、程序代码

程序代码主要包括按键功能、液晶显示、AD采集三大部分。

/********************
*主程序代码参考(C51)
*********************/
#include <reg52.h>
#include <ads1115.h>

sbit CLKPIN  = P3^0;  	//CLK对应单片机引脚
sbit DIPIN   = P3^1;  	//DI对应单片机引脚
sbit KEY_1 = P1^2;		//按键1减小倍数
sbit KEY_2 = P1^3;		//按键2增加倍数
sbit KEY_3 = P1^4;		//按键3切换模式
sbit KEY_4 = P1^5;		//按键4置空

sbit P1_6  = P1^6;		// P1.6、1.7 控制继电器的工作状态
sbit P1_7  = P^7;



//以下Num1_Ram至Num8_Ram为数字1至8在演示程序中的RAM地址预定义
#define NUMBERS 8                       //显示数字的个数
unsigned char Num1_Ram;                 //数字1
unsigned char Num2_Ram;                 //数字2
unsigned char Num3_Ram;                 //数字3
unsigned char Num4_Ram;                 //数字4
unsigned char Num5_Ram;                 //数字5
unsigned char Num6_Ram;                 //数字6
unsigned char Num7_Ram;                 //数字7
unsigned char Num8_Ram;                 //数字8

//数码笔段顺序:  D76543210
//               ABCDEFGX
unsigned char code NUMCODETAB[]={0xFC,0x60,0xDA,0xF2,  //数字0,1,2,3
                                 0x66,0xB6,0xBE,0xE0,  //数字4,5,6,7
                                 0xFE,0xF6,0x00,0x02,  //数字8,9,字符空格,字符-
                                 0x9C,0xCE,0x9E,0x8E}; //字符C,字符P,字符E,字符F

unsigned char KeySta[4] ={1,1,1,1};				//按键的当前状态

unsigned int ValVoltage(unsigned char n);				//ADC读取函数
void delay(unsigned int xms);							//软件延时函数,单位1ms
void ConfigTimer0(unsigned int ms);						//定时器0配置函数
void ShowNumber(unsigned int num,unsigned int value);	//数码管显示函数
void KeyScan();											//按键扫描函数
void KeyDriver();										//按键功能驱动函数

//SMS0801B的函数定义
void decodetolcd(void);                 //液晶显示控制器译码子程序
void transram(void);                    //LCD显示刷新子程序
void transbyte(unsigned char d);        //送1字节数据到液晶显示控制器子程序
void transbit(bit d);                   //送1位数据到液晶显示控制器子程序


unsigned char T0RH =0; 					// T0重载值的高字节
unsigned char T0RL =0; 					// T0重载值的低字节
unsigned int shift =32;					// DAC当前的输出状态,即衰减/放大的倍数,初始为256/32=8倍
unsigned int adcValue;					// ADC1115获取的电压值

//--------------------------------------------------------------------------------------------------

void main()
{  
	
		EA = 1;       			//使能总中断
		ConfigTimer0(10);		//配置T0定时10ms
		Confige1115();			//配置AD寄存器
		delay(5);           
//		P1_6=0;					//设置P1.6、P1.7的初始状态,需根据硬件电路作改动
//		P1_7=0;
	
    while (1)
    {
			KeyDriver();				// 调用按键驱动函数			
			delay(100);
			P2=shift;					// 将倍数发送至DAC
			adcValue=ValVoltage(100);	// ADS1115采集电压信息
			ShowNumber(shift,adcValue);	//显示放大倍数、电压值,SMS0801本质上是8个数码管			
    }
}

//--------------------------------------------------------------------------------------------------
/*延时函数,单位1ms*/
void delay(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=30;j>0;j--);
}

//----------------------------------------------------------------------
/*按键驱动函数*/
void KeyDriver()
{
	unsigned char i;
	
	for(i=0;i<4;i++)		// 循环检测4个按键
	{
		if(KeySta[i]==0)	// 检测按键动作
		{
			if(i==0)								// 减小键,DAC数值增加,倍数减小
			{
				while(KeySta[i]==0)					//等待按键释放,实现长按功能
				{
					if(shift<255)	shift++;
					delay(500);						//延时0.5s,约每隔0.5s加1
					ShowNumber(shift,adcValue);	
				}
			}
			else if (i == 1)						// 增大键,DAC数值减小,倍数增加
			{
				while(KeySta[i]==0)					//等待按键释放,实现长按功能
				{
					if(shift>1)	shift--;			//延时0.5s,约每隔0.5s减1
					delay(500);
					ShowNumber(shift,adcValue);	
				}
			}
			else if (i == 2)						//模式转换按键,P2.7,P2.6输出反转
			{
				while(KeySta[i]==0) delay(1000);
				P1_6 = ~P1_6;
				P1_7 = ~P1_7;
			}
		}
	}
}

//----------------------------------------------------------------------
/*显示函数*/
void ShowNumber(unsigned int num,unsigned int val)
{
	signed char i;
	unsigned char buf[8];
	
	//倍数显示
	//num = 256/num;
	for(i=7; i>=5 ;i--) 				//把长整型数转换为8位十进制数组
	{									
			buf[i] = num%10;			//个位存入buf[7],十位存入buf[6],百位存入buf[5]
			num = num/10;
	}
	for(i=5;i<=7;i++)					//高位0不显示
	{
			if(buf[i]==0)
				buf[i]=10;
			else 
				break;
	}

	//电压显示
	val = val*187.5/1000000*100;		//对ADS1115采集的数据进行换算,
										// *100 的作用是将小数化为所需整数,以便显示,如2.56变为256
	for(i=3; i>=0 ;i--)					//把长整型数转换为8位十进制数组
	{
			buf[i] = val%10;
			val = val/10;
	}
	
	
	Num1_Ram=buf[0];            //第1位
	Num2_Ram=buf[1];            //第2位,输出该位时点亮小数点
	Num3_Ram=buf[2];            //第3位
	Num4_Ram=buf[3];			//第4位
	Num5_Ram=buf[4]; 			//第5位,显示'-'
	Num6_Ram=buf[5];            //第6位
	Num7_Ram=buf[6];            //第7位
	Num8_Ram=buf[7];            //第8位
	
	transram();
	delay(300);
}

//----------------------------------------------------------------------
/*ADC1115读取电压值*/
unsigned int ValVoltage(unsigned char n)
{
	unsigned long int idata sum=0;
	unsigned int idata val;
	unsigned char idata i;
	val=read1115();
	val=read1115();
	for(i=0;i<n;i++)
	{
		sum += read1115();
	}
	val = sum/n;
	return val;
}

//----------------------------------------------------------------------
/*液晶刷新*/
void transram(void)                     //LCD显示刷新子程序
{   decodetolcd();                      //按地址映射表字节顺序,所有数据译码后送
                                        //LCD液晶显示控制器
}

void decodetolcd(void)                  //按地址映射表字节顺序,所有数据译码后送
{ unsigned char buf;                    //LCD液晶显示控制器子程序
//LCDBUF+0 缓冲区第1个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGZ位
  buf|=NUMCODETAB[Num1_Ram]&0xFE;       //第1个8字的ABCDEFG笔段译码                         
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+1 缓冲区第2个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGZ位
  buf|=NUMCODETAB[Num2_Ram]&0xFE;       //第2个8字的ABCDEFG笔段译码
  buf+=0x01;							//显示小数点
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+2 缓冲区第3个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGZ位
  buf|=NUMCODETAB[Num3_Ram]&0xFE;       //第3个8字的ABCDEFG笔段译码
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+3 缓冲区第4个字节译码
	buf=0x00;                             //当前译码数据置初始值
																				//需译码的BIT为ABCDEFGZ位
	buf|=NUMCODETAB[Num4_Ram]&0xFE;       //第4个8字的ABCDEFG笔段译码
	transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+4 缓冲区第5个字节译码
  buf=0x02;                             //当前译码数据置初始值,第5位一直为'-'
	transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+5 缓冲区第6个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGZ位
  buf|=NUMCODETAB[Num6_Ram]&0xFE;       //第6个8字的ABCDEFG笔段译码                         
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+6 缓冲区第7个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGZ位
  buf|=NUMCODETAB[Num7_Ram]&0xFE;  //第7个8字的ABCDEFG笔段译码                          
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器

//LCDBUF+7 缓冲区第8个字节译码
  buf=0x00;                             //当前译码数据置初始值
                                        //需译码的BIT为ABCDEFGX位
  buf|=NUMCODETAB[Num8_Ram]&0xFE;       //第8个8字的ABCDEFG笔段译码
  transbyte(buf);                       //将当前译码数据送LCD液晶显示控制器
}

//----------------------------------------------------------------------
/*字节数据传输*/
void transbyte(unsigned char d)         //送1字节数据到液晶显示控制器子程序
{   unsigned char i;
    for(i=0;i<8;i++)
    {   if((d&0x1) == 0x1)
            transbit(1);
        else
            transbit(0);
        d>>=1;                          //从低到高位送字节位数据到液晶显示控制器
    }
}

//----------------------------------------------------------------------
/*位数据传输*/
void transbit(bit d)                    //送1位数据到液晶显示控制器子程序
{  DIPIN = d;                           //先送数据到数据口线DI
   _nop_();
   _nop_();
   CLKPIN = 1;                          //再使时钟口线发一个负脉冲
   _nop_();
   _nop_();
   CLKPIN = 0;
   _nop_();
   _nop_();
   CLKPIN = 1;
}

//----------------------------------------------------------------------
/*按键扫描*/
void KeyScan()
{
	unsigned char i;
	static unsigned char keybuf[4] = {0xFF,0xFF,0xFF,0xFF};
	// 将一行按键值移入缓冲区
	keybuf[0] = (keybuf[0] << 1) | KEY_1;
	keybuf[1] = (keybuf[1] << 1) | KEY_2;
	keybuf[2] = (keybuf[2] << 1) | KEY_3;
	keybuf[3] = (keybuf[3] << 1) | KEY_4;
	//消抖后更新按键状态
	for(i=0;i<4;i++)
	{
		if((keybuf[i]&0x0F) == 0x00)
		{	// 连续4次扫描值为0,认为按键已稳定的按下
			KeySta[i] = 0;
		}
		else if ((keybuf[i])&0x0F == 0x0F)
		{
			KeySta[i] = 1;
		}
	}
}

//----------------------------------------------------------------------
/*定时器配置*/
void ConfigTimer0(unsigned int ms)
{
	unsigned long tmp;	//临时变量
	
	tmp = 11059200 / 12;	// 定时器计数频率
	tmp = (tmp*ms)/1000;	// 计算所需的计数值
	tmp = 65536 - tmp;		// 计算定时器重载值
	tmp = tmp +12;
	T0RH = (unsigned char)(tmp >>8);
	T0RL = (unsigned char)tmp;
	TMOD &= 0xF0;		// 清零T0的控制位
	TMOD |= 0x01;		// 配置T0为模式1
	TH0 = T0RH;			// 加载T0重载值
	TL0 = T0RL;
	ET0 = 1;				// 使能T0中断
	TR0 = 1;				// 启动T0
}

//----------------------------------------------------------------------
/* 定时器0中断服务函数*/
void InterruptTimer0() interrupt 1
{	
	TH0 = T0RH;	// 重新加载重载值
	TL0 = T0RL;
	KeyScan();	// 调用按键扫描函数
}

六、相关资料下载

https://download.csdn.net/download/AriesPIG/20466303

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值