原创 基于aduc842瞬态波形存储器

2010-4-29 21:10 2047 7 7 分类: MCU/ 嵌入式

摘要,本作品由增益放大与控制模块、极性转换模块、触发以及以aduc841/ aduc831为核心的单片机最小系统4个部分构成,由单片机实现控制与波形存储回放功能。<?XML:NAMESPACE PREFIX = O />


 


一、方案论证与设计


 1. 增益放大与测量方案


    方案一:将输入信号经放大后送入窗口比较器,上限1V,下限0.1V。若小于0.1V,则通过单片机(p0.2=1,p0.3=0)控制增益放大电路将信号放大10倍,再输入到控制模块与0.1V1V比较,若仍小于0.1V,则通过单片机控制增益放大电路将信号放大100倍;若大于1V,则通过单片机(在一个周期内出现p0.2=1,p0.3=0;p0.2=1,p0.3=1;p0.2=0,p0.3=1这几种情况)控制增益放大电路将信号衰减10倍(当前信号已经放大100倍或10倍),如果信号放大1倍,则衰减为零,阻止通过;若在0.1V1V之间,则通过单片机(在一个周期内出现p0.2=1,p0.3=0;p0.2=1,p0.3=1这两种种情况)控制增益放大电路将信号无增益的输出。通过此电路使输出信号幅度控制在0.2V2V之间。


    方案二:将放大后的信号其中一路转换为直流信号,再将此信号给窗口比较器,上限2V,下限0.2V。若小于0.2V,则通过单片机(p0.2=1,p0.3=0)控制增益放大电路将信号放大10倍,再输入到控制模块与0.2V2V比较,若仍小于0.2V,则通过单片机控制增益放大电路将信号放大100倍;若大于2V,则通过单片机(p0.2=0,p0.3=1)控制增益放大电路将信号衰减为零,阻止通过;若在0.2V2V之间,则通过单片机(p0.2=1,p0.3=1)控制增益放大电路将信号无增益的输出。通过此电路使输出信号幅度控制在0.2V2V之间。


   对以上两种方案进行比较,方案一虽在软件控制方面稍繁,但也易于实现,而方案二在将交流变为直流的硬件方面较为复杂,故采用方案二。



2. 采样方案


     方案一:通过触发模块提供给单片机一个周期信号,通过软件实现定时采样。


      方案二:先将信号经过100倍频之后,送给单片机作为采样触发信号,也就是说每个周期固定采100个点。但是同步回放频率难以控制。


   对以上两种方案进行比较,方案二虽然在采样方面比较精准,但回放难以实现,而方案一在两方面均可兼顾。故采用方案一。


 


二、原理分析与硬件电路图


    根据题目要求,该调理系统包括增益放大与控制模块、极性转换模块、触发3个模块,由于3个模块相对独立,其中增益放大与控制模块是重点。以下分别对其进行原理分析与电路设计。


1.增益放大与循环取样模块


1)原理分析


   输入信号幅度为A,将输入信号输入循环取样模块与0.1V1V比较:若小于0.1V,则通过单片机控制增益放大电路将信号放大10倍,再输入到控制模块与0.1V1V比较,若仍小于0.1V,则通过单片机控制增益放大电路将信号放大100倍;若大于1V,则通过单片机控制增益放大电路将信号衰减10倍(当前信号已经放大100倍或10倍),如果信号放大1倍,则衰减为零,阻止通过;若在0.1V1V之间,则通过单片机控制增益放大电路将信号无增益的输出。通过此电路使输出信号峰峰值控制在0.2V2V之间。


2)原理电路


循环取样模块。本电路采用专用比较器LM339,使用三端稳压管TL431提供2.5V的稳压源,通过调节滑动变阻器使LM3396脚和5脚分别得到0.1V1V的电平。将取样信号送给由LM339构成的窗口比较器,可以从1脚和2脚得到随信号变化的TTL电平,从而将比较结果送给单片机,以便单片机做出判决,发出控制信号。该增益控制模块电路的基本原理如下图所示。


bm10.H16.gif


增益控制模块。根据单片机发出的控制信号送给CD4051,选择X0X1X2X3导通,从而改变运放U2B的放大倍数。通过滑动变阻器的微调使放大倍数达到指标(1倍、10倍、100倍)。该增益放大模块电路的基本原理如下图所示。


点击看大图


2.极性转换模块


1)原理分析


     将输入信号通过极性转换模块(含有一加法器和一提供稳定电压的稳压源),使信号幅度均抬高1.25V,从而将输入的双极性信号转换成单极性信号输出。


2)原理电路


    使用三端稳压管TL431TL084的正极提供1.25V的稳压源,由TL084组成加法器,使输入信号与1.25V相加。该极性转换模块电路的基本原理如下图所示。


 


bm10.H18.gif


 


3.触发模块


1)原理分析


     将输入信号通过触发模块(含有比较器),一周期的输入信号得到一上升沿触发。 


2)原理电路


     将输入信号接入比较器LM339的正极,负极接入一可通过滑动变阻器微调的电压,通过与8脚电压比较,得到一个周期与输入信号相同的方波,作为触发信号送给单片机。该触发模块电路的基本原理如下图所示。


 


 


 


 


bm10.H19.gif


三、软件设计与流程


 


点击看大图点击看大图



四、总结


在这个电路中,通过模拟处理模块和单片机配合实现对输入信号的自动放大,当输入信号在0.002V2V之间,


使单片机采样信号始终保持在0.2V2V之间。同时利用ADuC842内部的ADDA对信号采样并同步输出,


在这个过程中,把采样值保存在数组中,通过按键实现回放。      


 


附件:

主程序

#include "zlg7290b.h"


//SCLK--SCL    MOSI--SDA   INT--INT0


 


#define uchar unsigned char


#define uint  unsigned int


bit con_caiji=0;


bit tongb_hf=0;


sbit P0_0=P2^0;


sbit P0_1=P2^1;


sbit P0_2=P0^2;


sbit P0_3=P0^3;


unsigned int k,tb_shuzu;


unsigned int j="0",i=0;


unsigned char caiji_2=100;


unsigned char panduan,panduan1;


unsigned int xdata tongbu[4000]={0};


 


/******************************************


函数:void DispValue(unsigned char x, unsigned char dat)


功能:通过ZLG7290 显示一个字符型数据


说明:显示范围:0--255


参数:x,显示起始位置。dat,需要显示的数据


******************************************/


void DispValue(unsigned char x, unsigned char dat)


{


   unsigned char d;


   d =dat / 10;


   ZLG7290_Download(x,0,0,d);


   d =dat - d * 10;


   ZLG7290_Download(x+1,0,0,d);


}


 


/******************************************


函数:unsigned int ADC(unsigned char channel)


功能:控制单片机的AD的工作


说明:无


参数: channel,AD通道选择


******************************************/


unsigned int ADC(unsigned char channel)


{


    ADCCON2 =channel;     //选择通道


    SCONV =1;             //启动转换


    while(SCONV);          //等待转换完成


    return((ADCDATAH & 0x0F) * 256 + ADCDATAL);     


}


 


/******************************************


函数:void DAC1(unsigned int da_data)


功能:控制单片机DA1的工作


说明:无


参数:da_data,AD转换的数字量


******************************************/


void DAC1(unsigned int da_data)    


{


    DAC1H =da_data >> 8;


    DAC1L =da_data;


}


 


/******************************************


函数:INT0_SVC()


功能:ZLG7290 键盘中断服务程序


说明:中断触发方式选择负边沿触发,


      因此不必等待中断请求信号恢复为高电平


参数:无


******************************************/


void INT0_SVC() interrupt 2


{


    unsigned char KeyValue="1";


    unsigned char RepeatCnt="0";


    unsigned char FunctionKey="0";


    EA=0;


    FunctionKey=gets2(ZLG7290_FunctionKey);   //读功能计数器的值


    KeyValue=gets2(ZLG7290_Key);              //读键值


    RepeatCnt=gets2(ZLG7290_RepeatCnt);       //读连击计数器


    DispValue(0,KeyValue);                    //显示连键值


    if(KeyValue==1)


    {


        tongb_hf=0;


        caiji_2=0;


    }


    if(KeyValue==2)


    {


        tongb_hf=1;


        j=0;


    }


    P0_0=P0_0;


    P0_1=P0_1;


    EA=1;


}


 


/******************************************


函数:caiji_data()


功能:数据采集触发


说明:无


参数:无


******************************************/


void caiji_data() interrupt 0


{


    EA=0;


    caiji_2++;


    panduan++;


    panduan1++;


    if(caiji_2==4)


    {


        con_caiji=1;


        i=0;


    }


    if(caiji_2==60)


    {


        con_caiji=0;


        tb_shuzu=i;


    }


    if(caiji_2>=200)


    {


        caiji_2=80;


    }


    if(panduan==30)


    {


        panduan=0;


    }


    EA=1;  


}


 


/******************************************


函数:ad_start()


功能:AD转换,同时DA进行,实现同步输出


说明:无


参数:无


******************************************/


void ad_start() interrupt 1


{


    uint temp_data;


    EA=0;


    TH0=(65536-1800)/256;


    TL0=(65536-1800)%256;


    temp_data =ADC(5);


    if(tongb_hf==0)


    {


        DAC1(temp_data);


        if(con_caiji==1)


        {


            tongbu=temp_data;


            i++;


        }          


    }


    if(tongb_hf==1)


    {


        DAC1(tongbu[j]);


        j++;


        if(j==tb_shuzu)


        {


            j=1;


        } 


    }     


    EA=1;   


}


 


 


void main()


{


    uint k;


    uchar x1,x2,x3,x4;


    uchar fanda;


    SystemInit();               //7290复位


    PLLCON =0x00;              //for 842


    I2CCON=0xa8;                //I2C初始化


    I2C_Init();                 //I2C初始化 7290用


    ClearAll();                 //7290全部清除


    ADCCON1 =0xBC;             //ADC上电,内部基准,clk 8分频


    DACCON =0x16;              //DAC采用内部ref做基准


    TMOD=0x01;                 //定时器0方式1


    TH0=(65536-1000)/256;


    TL0=0;


    IT0 =1;                     //负边沿触发中断


    EX0 =1;                     //允许外部中断


    EA =1;                      //开中断


    ET0=1;                       //开c0的中断


    EX1=1;                       //开中断 int1


    TR0=1;                       //启动c0记时 


    PT0=1;                       //同步回放中断优先


    k=5000;


    while(k--)


    {


       P2=0x00;


    }      


    while(1)


    {


        while(panduan!=28)


        {


            if(P0_3!=1)


            {


                x1++;


            }


            if(P0_2!=0)


            {


                x2++;   


            }


        }


        if(panduan==29)


        {


            x3=x1;


            x4=x2;


            x1=0;


            x2=0;


        }


        if((fanda==10)&&(x4==0)&&(x3==0))


        {


            P0_0=1;


            P0_1=0;


            fanda=100;


        }


        if(P0_2==1)


        {


            P0_0=0;


            P0_1=0;    


        }


        if(x4==0&&x3==0)


        {


            if(P0_0==1&& P0_1==0)


            {


                P0_0=1;


                P0_1=0;


            }


            else


            {


                P0_0=0;


                P0_1=1;


                fanda=10;


            }


        }


    }


}


头文件1


 


/********************************************************************


ZLG7290.c


数码管显示与键盘管理芯片ZLG7290 的标准80C51 驱动程序C 文件


Copyright (c) 2005,广州周立功单片机发展有限公司


All rights reserved.


本程序仅供学习参考,不提供任何可靠性方面的担保;请勿用于商业目的


******************************************************************/


#include "i2c.h"


#include "zlg7290.h"


 


 


/****************************************************


函数:ZLG7290_WriteReg()


功能:向ZLG7290 的某个内部寄存器写入数据


参数:


RegAddr:ZLG7290 的内部寄存器地址


dat:要写入的数据


返回:


0:正常


1:访问ZLG7290 时出现异常


*************************************************/


/*bit ZLG7290_WriteReg(unsigned char RegAddr, char dat)


{


bit b;


b =I2C_Puts(ZLG7290_I2C_ID,RegAddr,1,&dat,1);


return b;


}*/


 


/***********************************************


函数:ZLG7290_cmd()


功能:向ZLG7290 发送控制命令


参数:


cmd0:写入CmdBuf0 寄存器的命令字(第1 字节)


cmd1:写入CmdBuf1 寄存器的命令字(第2 字节)


返回:


0:正常


1:访问ZLG7290 时出现异常


**************************************************/


bit ZLG7290_cmd(char cmd0, char cmd1)


{


bit b;


char buf[2];


buf[0] =cmd0;


buf[1] =cmd1;


b =I2C_Puts(ZLG7290_I2C_ID,ZLG7290_CmdBuf,1,buf,2);


return b;


}


 


 


/******************************************************


函数:ZLG7290_SegOnOff()


功能:段寻址,单独点亮或熄灭数码管(或LED)中的某一段


参数:


seg:取值0~63,表示数码管(或LED)的段号


b:0 表示熄灭,1 表示点亮


返回:


0:正常


1:访问ZLG7290 时出现异常


说明:


在每一位数码管中,段号顺序按照“a,b,c,d,e,f,g,dp”进行


*******************************************************/


/*bit ZLG7290_SegOnOff(char seg, bit b)


{


char cmd;


cmd =seg & 0x3F;


if ( b ) cmd |=0x80;


return ZLG7290_cmd(0x01,cmd);


}*/


 


 


/*************************************************


函数:ZLG7290_Download()


功能:下载数据并译码


参数:


addr:取值0~7,显示缓存DpRam0~DpRam7 的编号


dp:是否点亮该位的小数点,0-熄灭,1-点亮


flash:控制该位是否闪烁,0-不闪烁,1-闪烁


dat:取值0~31,表示要显示的数据


返回:


0:正常


1:访问ZLG7290 时出现异常


说明:


显示数据具体的译码方式请参见ZLG7290 的数据手册


*************************************************/


bit ZLG7290_Download(char addr, bit dp, bit flash, char dat)


{


char cmd0;


char cmd1;


cmd0 =addr & 0x0F;


cmd0 |=0x60;


cmd1 =dat & 0x1F;


if ( dp ) cmd1 |=0x80;


if ( flash ) cmd1 |=0x40;


return ZLG7290_cmd(cmd0,cmd1);


}


 


 


/********************


函数:SystemInit()


功能:系统初始化


********************/


void SystemInit()   //等待7290初始化完毕


{ 


    unsigned int i;


    for(i =0;i < 60000;i ++);


}


 


/*************************


函数:ClearAll()


功能:清除所有显示


*************************/


void ClearAll()


{


 unsigned char x;


 for ( x="0"; x<8; x++ )


 {


   ZLG7290_Download(x,0,0,31);    //00011111,表示不显示,循环8次,将8个数码管显示都清除


 }


}


 


 


 


头文件2


 


#include<ADuC842.h>


#include <stdio.h>


#define I2C_SCL MCO                  //ADUC831的I2CCON寄存器中的1位,时钟位


#define I2C_SDA_O MDO                //ADUC831的I2CCON寄存器中的1位,数据输出


#define I2C_SDA_I MDI                //ADUC831的I2CCON寄存器中的1位,数据输入


#define IO_ENABLE  MDE               //ADUC831的I2CCON寄存器中的1位,数据输入/输出的使能


#define ZLGWR 0x70                   //ZLG7290的写地址


#define ZLGRD 0x71                   //ZLG7290的读地址


 


/*************************


I2C延时程序


*************************/


void I2C_Delay()


{


  char i;


  for(i=0;i<50;i++);


}


 


/*********************************************************


函数:I2C_Init()


功能:I2C 总线初始化,使总线处于空闲状态


说明:在main()函数的开始处,通常应当要执行一次本函数


************************************************************/


void I2C_Init()


{


IO_ENABLE=1;                  //使能为1,则为输出;为0,则为输入


I2C_SCL =1;


I2C_Delay();


I2C_SDA_O =1;


I2C_Delay();


}


 


 


 


/**************************************************************


函数:I2C_Start()


功能:产生I2C 总线的起始状态


说明:


SCL处于高电平期间,当SDA 出现下降沿时启动I2C 总线


不论SDA 和SCL 处于什么电平状态,本函数总能正确产生起始状态


本函数也可以用来产生重复起始状态


本函数执行后,I2C 总线处于忙状态


******************************************************************/


void I2C_Start()


{


IO_ENABLE=1;


I2C_SDA_O =1;


I2C_Delay();


I2C_SCL =1;


I2C_Delay();


I2C_SDA_O =0;


I2C_Delay();


I2C_SCL =0;


I2C_Delay();


}


 


 


/*****************************************


函数:I2C_Write()


功能:向I2C 总线写1 个字节的数据


参数:


dat:要写到总线上的数据


********************************************/


void I2C_Write(char dat)


{


  unsigned char t =8;


  IO_ENABLE=1;


  do


  {


    I2C_SDA_O =(bit)(dat & 0x80);


    dat <<=1;


    I2C_SCL =1;


    I2C_Delay();


    I2C_SCL =0;


    I2C_Delay();


  } while ( --t !=0 );


}


 


 


 


 


/**************************************


函数:I2C_Read()


功能:从从机读取1 个字节的数据


返回:读取的一个字节数据


**************************************/


char I2C_Read()


{


char dat="0";


unsigned char t =8;


do


{


I2C_SCL =0;


I2C_Delay();


I2C_SCL =1;


I2C_Delay();


dat <<=1;


IO_ENABLE=0;


if ( I2C_SDA_I ) dat |=0x01;


I2C_SCL =0;


I2C_Delay();


} while ( --t !=0 );


return dat;


}


 


 


/******************************************************


函数:I2C_GetAck()


功能:读取从机应答位


返回:


0:从机应答


1:从机非应答


说明:


从机在收到每个字节的数据后,要产生应答位


从机在收到最后1 个字节的数据后,一般要产生非应答位


***********************************************************/


bit I2C_GetAck()


{


bit ack;


IO_ENABLE=1;


I2C_SDA_O =1;


I2C_Delay();


I2C_SCL =1;


I2C_Delay();


IO_ENABLE=0;


ack =I2C_SDA_I;


I2C_SCL =0;


I2C_Delay();


return ack;


}


 


 


 


/********************************************************


函数:I2C_PutAck()


功能:主机产生应答位或非应答位


参数:


ack=0:主机产生应答位


ack=1:主机产生非应答位


说明:


主机在接收完每一个字节的数据后,都应当产生应答位


主机在接收完最后一个字节的数据后,应当产生非应答位


*********************************************************/


void I2C_PutAck(bit ack)


{


IO_ENABLE=1;


I2C_SDA_O =ack;


I2C_Delay();                                                                                                           


I2C_SCL =1;


I2C_Delay();


I2C_SCL =0;


}


 


 


/***************************************************************


函数:I2C_Stop()


功能:产生I2C 总线的停止状态


说明:


SCL处于高电平期间,当SDA 出现上升沿时停止I2C 总线


不论SDA 和SCL 处于什么电平状态,本函数总能正确产生停止状态


本函数执行后,I2C 总线处于空闲状态


******************************************************************/


void I2C_Stop()


{


unsigned int t =1;


IO_ENABLE=1;


I2C_SDA_O =0;


I2C_Delay();


I2C_SCL =1;


I2C_Delay();


I2C_SDA_O= 1;


I2C_Delay();


while ( --t !=0 ); //在下一次产生Start 之前,要加一定的延时


}


 


 


/*****************************************************


函数?


功能:将I2C总线置于空闲状态,即将时钟线和数据线都拉高


******************************************************/


void idle()


{


   I2C_SCL=1;


   IO_ENABLE=1;


   I2C_SDA_O=1;


   IO_ENABLE=0;


}


 


/********************************************************************


函数:I2C_Puts()


功能:I2C 总线综合发送函数,向从机发送多个字节的数据


参数:


SlaveAddr:从机地址(7 位纯地址,不含读写位)


SubAddr:从机的子地址


SubMod:子地址模式,0-无子地址,1-单字节子地址,2-双字节子地址


*dat:要发送的数据


Size:数据的字节数


返回:


0:发送成功


1:在发送过程中出现异常


说明:


本函数能够很好地适应所有常见的I2C 器件,不论其是否有子地址


当从机没有子地址时,参数SubAddr 任意,而SubMod 应当为0


**********************************************************************/


bit I2C_Puts(unsigned char SlaveAddr,unsigned int SubAddr,unsigned char SubMod,char *dat,unsigned int Size)


{


unsigned char i;          //定义临时变量


char a[3];


if ( Size ==0 ) return 0;     //检查长度


a[0] =(SlaveAddr << 1);      //准备从机地址


if ( SubMod > 2 ) SubMod =2;   //检查子地址模式


switch ( SubMod )             //确定子地址


{


   case 0:break;


   case 1:a[1] =(char)(SubAddr);break;


   case 2:a[1] =(char)(SubAddr >> 8);a[2] =(char)(SubAddr);break;


   default:break;


}


a[1] =(char)(SubAddr);


SubMod++;                 //发送从机地址,接着发送子地址


I2C_Start();


for ( i="0"; i<SubMod; i++ )


{


  I2C_Write(a);


  if ( I2C_GetAck() )


   {


    I2C_Stop();idle();


    return 1;


   }


}


 do                             //发送数据


  {


   I2C_Write(*dat++);


   if ( I2C_GetAck() ) break;


  } while ( --Size !=0 );


  I2C_Stop();  idle();              //发送完毕,停止I2C 总线,并返回结果


  if ( Size ==0 ) return 0;


  else return 1;


}


 


 


/********************************************************************


函数:I2C_Gets()


功能:I2C 总线综合接收函数,从从机接收多个字节的数据


参数:


SlaveAddr:从机地址(7 位纯地址,不含读写位)


SubAddr:从机的子地址


SubMod:子地址模式,0-无子地址,1-单字节子地址,2-双字节子地址


*dat:保存接收到的数据


Size:数据的字节数


返回:


0:接收成功


1:在接收过程中出现异常


说明:


本函数能够很好地适应所有常见的I2C 器件,不论其是否有子地址


当从机没有子地址时,参数SubAddr 任意,而SubMod 应当为0


********************************************************************/


/*bit I2C_Gets(unsigned char SlaveAddr,unsigned int SubAddr,unsigned char SubMod,char *dat,unsigned int Size)


{


 


unsigned char i;          //定义临时变量


char a[3];


 


if ( Size ==0 ) return 0;   //检查长度


 


a[0] =(SlaveAddr << 1);   //准备从机地址


 


if ( SubMod > 2 ) SubMod =2;  //检查子地址模式


 


if ( SubMod !=0 )            //如果是有子地址的从机,则要先发送从机地址和子地址


  {


 


    if ( SubMod ==1 )          //确定子地址


     {


       a[1] =(char)(SubAddr);


     }


    else


    {


    a[1] =(char)(SubAddr >> 8);


    a[2] =(char)(SubAddr);


    }


}


SubMod++;


t0=1;                    //发送从机地址,接着发送子地址


I2C_Start();


for ( i="0"; i<=SubMod; i++ )


  {


  I2C_Write(a);


 


  }


}


I2C_PutAck(1);


I2C_Stop();


t0=0;


I2C_Start();             //这里的I2C_Start()对于有子地址的从机是重复起始状态


                           //对于无子地址的从机则是正常的起始状态


I2C_Write(a[0]+1);       //发送从机地址


if ( I2C_GetAck() )


{


I2C_Stop();


return 1;


}


 


for (;;)     //接收数据


{


while( I2C_GetAck() );


*dat =I2C_Read();


if ( --Size ==0 )


{


I2C_PutAck(1);


I2C_PutAck(0);


break;


}


}


I2C_Stop(); //接收完毕,停止I2C 总线,并返回结果


return 0;


}*/


 


char gets2(unsigned char subaddr)


{


    char i,dat;


    I2C_Start();


    I2C_Write(ZLGWR);


    I2C_GetAck();


    I2C_Write(subaddr);


    I2C_SCL=1;


    for(i=0;i<2;i++){;}


    I2C_SCL=0;


    I2C_Stop();


    for(i=0;i<5;i++){;}


    I2C_Start();


    I2C_Write(ZLGRD);


    I2C_GetAck();


    dat=I2C_Read();


    I2C_PutAck(1);


    I2C_Stop();


    idle();


    return dat;


}

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条