新闻  |   论坛  |   博客  |   在线研讨会
基于aduc842瞬态波形存储器
0750long | 2010-05-02 22:21:26    阅读:1921   发布文章

 

 

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

 

一、方案论证与设计

 1. 增益放大与测量方案

    方案一:将输入信号经放大后送入窗口比较器,上限1V,下限0.1V。若小于0.1V,则通过单片机(p0.2=1,p0.3=0)控制增益放大电路将信号放大10倍,再输入到控制模块与0.1V和1V比较,若仍小于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.1V和1V之间,则通过单片机(在一个周期内出现p0.2=1,p0.3=0;p0.2=1,p0.3=1这两种种情况)控制增益放大电路将信号无增益的输出。通过此电路使输出信号幅度控制在0.2V至2V之间。

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

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

 

2. 采样方案

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

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

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

 

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

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

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

(1)原理分析

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

(2)原理电路

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

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

点击看大图

2.极性转换模块

(1)原理分析

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

(2)原理电路

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

 

 

3.触发模块

(1)原理分析

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

(2)原理电路

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

 

 

 

 

三、软件设计与流程

 

点击看大图点击看大图

 

四、总结

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

使单片机采样信号始终保持在0.2V至2V之间。同时利用ADuC842内部的AD和DA对信号采样并同步输出,

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

 

附件:

主程序

#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[i]=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[i]);

  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[i]);

 

  }

}

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();

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客