Category Archives: 电路设计

A01.png

AD如何把隐藏的元件丝印名称显示出来?

新开机械层;
Shift F选中正面/反面的所有丝印的Designator,F11按照正反面分别移动到对应的机械层;
选中丝印,F11,Placement方式选Auto的Center。

如果你的元件库在机械层有器件外框和极性标识,那么直接出的PDF就是很好的位置图;并且,PDF文件还可以直接根据元件名称选择,直接找到位置。

附图是个例子。

A01.png
AD7705%E4%B8%87%E8%83%BD%E8%BE%93%E5%85%A5%E7%94%B5%E8%B7%AF%E7%9A%84%E8%BE%93%E5%87%BA%E7%AB%AF%E7%94%B5%E8%B7%AF%E5%9B%BE.jpg

采用AD7705设计的万能信号输入电路

在智能仪器仪表的数据采集中,由于传统的传感器信号是模拟信号,所以对于智能化的仪器,肯定需要A/D转换器将多种输入信号进行转换,以实现单片机的控制。在许多应用场合需要16位以上的高精度测量,而传统的积分型和逐次比较型A/D实现起来难度较大,成本很高。因此本电路采用了16位的∑-∆型AD7705作为模数转换器,实现了电压、电阻电流等不同量程信号输入,进而进行数据的存储和显示。

1.AD7705介绍

AD7705是一种片内带数字滤波的∑-∆型A/D转换器,是为满足宽动态范围测量、工业控制或工艺控制中的低频信号的轮换而设计的。该器件可以接受直接来自传感器的低电平输人信号,然后产生串行的数字输出,利用∑-∆转换技术实现了16位无丢失代码性能。AD7705串行接口可配置为三线SPI接口,增益值、信号极性以及更新速率的选择可用串行输人口由软件来配置,该器件还包括自校准和系统校准选项,以消除器件本身或系统的增益和偏移误差。AD7705的引脚排列如图1所示,各引脚的功能说明如下:

pIYBAGAGrP2AUD7UAAEoQVVQ64Q923.png

图1 AD7705的引脚排列图

SCLK:串行时钟输入;MCLKIN:主时钟输入,时钟频率为500~5MHz;

MCLK OUT:主时钟输出;/CS:片选,低电平有效;

/RESET:复位。该端口为低电平时,可以将控制逻辑、接口逻辑、校准系数以及数字滤波器等复位为上电状态;

AIN2(﹢)、AIN2(﹣):分别为差分模拟输入通道2的正、负输入端;

AIN1(﹢)、AIN1(﹣):分别为差分输入通道1的正、负输入端;

REFIN(﹢)、REFIN(﹣):分别为参考电压的正、负端。为了确保元件的正常工作,REFIN(﹢)端口的输入信号必须大于REFIN(﹣)端的输入;

/DRDY:逻辑输出。低电平表示可以读取新的数据转换;高电平时不可读取数据;

DIN,DOUT:分别为串行数据输入和输出端;

VDD:电源电压,+2.7~+5.25V;GND:内部电路的地电位基准点。

2.电路设计

在该电路设计中,必须考虑隔离技术的实施,以提高系统的抗干扰能力。并且使A/D转换过程容易进行,这是系统关键技术之一。

2.1AD7705输入电路

基于AD7705的万能信号输入电路的输入端电路图,如图2所示:

AD7705%E4%B8%87%E8%83%BD%E8%BE%93%E5%85%A5%E7%94%B5%E8%B7%AF%E7%9A%84%E8%BE%93%E5%85%A5%E7%AB%AF%E7%94%B5%E8%B7%AF%E5%9B%BE.jpg

图2 AD7705万能信号输入电路的输入端电路图

202004231742%E8%BE%93%E5%85%A5%E4%BF%A1%E5%8F%B7%E6%8E%A5%E7%BA%BF%E6%96%B9%E5%BC%8F%E5%9B%BE.jpg

图3 输入信号接线方式图

该电路的3个端子有多种不同的接法,可以实现多种输入信号的采集和转换。这里介绍四种输入信号类型,分别为电压、电流、热电偶、热电阻和电阻,各种输入信号的接线方式,如图3所示。AD7705作为数据采集电路的模数转换器,具有两个双差分输入通道。由于检测的信号有的是双极性的,而两通道是差分模拟输入,只有将模拟输入端负端的电位抬高,才能检测双极性信号,因此,将AIN1(﹣)和AIN2(﹣)接至基准电压VREF上,基准电压值为2.5V,作为输入电路的模拟地端。用两通道的模拟输入正端AIN1(﹢)和AIN2(﹢)来检测输入信号,这两个输入端的电压值分别记为UAIN1(﹢)和UAIN2(﹢),两检测电压最终转换成数字量输出,因此,通过这两个已知的检测电压可以得到输入信号的值。为了提高该万能信号输入电路的精度,AD7705的输入电路部分的所有电阻均为标准电阻。

量程校准:外加输入信号的下限值,采用上位机软件,按画面指示(自动,手动)可进行零点校准;外加输入信号的上限值,按画面指示(自动,手动)可进行满度校准,结果存储在24C64中。

当输入信号为电压时,电压正端接仪表通道A端子,电压负端接仪表通道B端子,电压为0~5V,1~5V,0~2.5V,0~1V,0~100mV,0~55mV,0~25mV,统记为UAB由电路图可知该电压信号经过两个20KΩ的电阻分压后输入到通道2,因此由通道2,AIN2(﹢)来检测该电压信号,UAB与UAIN2(﹢)的关系式如下:

%E5%BC%8F%E5%AD%901.jpg

当输入信号为电流时,电流正端接仪表通道A端子,电流负端接仪表通道C端子,电流值可以为4-20mA,0-10mA,统记为IAC,AC端子之间并联250Ω的标准电阻,使线性电流转换为线性电压,由于基准电压的存在,即使输入电流为0时,经过250Ω和3.6KΩ电阻对基准电压的分压,通道1AIN1(﹢)仍有检测电压的存在,AIN1(﹢)的检测电压值要减去输入电流为0时的检测电压值,检测电压值同样是经过两个20KΩ的电阻分压后得到的。而输入电流分为250Ω和3.6KΩ电阻两个回路,即这两个电阻在电流的回路上是并联的。具体的计算关系如下:

%E5%BC%8F%E5%AD%902.jpg

热电阻是中低温区最常用的一种温度检测器,它的主要特点是测量精度高,性能稳定。热电阻测温是基于金属导体的电阻值随温度的变化而变化这一特性来进行温度测量的,当输入信号为温度时,通过热电阻来检测温度,实际上输入信号就变成了热电阻,求得热电阻的阻值,通过热电阻的阻值与温度的对照关系就求出了温度值。

由于热电阻要安装在被测环境中,距离电阻测量装置有一定距离,这样实际测量的时候就会带来导线电阻的误差,因此实际使用热电阻的时候都是采用三线制接法,通过电路处理,剔除了导线电阻的影响。

热电阻一端接仪表通道A端子,另外两端接仪表通道B、C端子,电阻值可以为Cu50,Pt100,统记为RT。为了推导公式和解释方便,需要对一些变量进行设定。三根导线的电阻值设为RL,从基准电压源出来的总电流为I,通过热电阻这一支路的电流为I1,通过250Ω电阻的电流为I2,两支路的电流最终都通过3.6KΩ电阻,即3.6KΩ电阻的电流也是I,下面开始对热电阻RT进行逐步推到:

%E5%BC%8F%E5%AD%903,4,5.jpg

由上面三个式子可以得到I1,计算整理后得:

%E5%BC%8F%E5%AD%906.jpg

在热电阻这条支路上,由热电阻、导线电阻和电流可以得到通道1检测电压UAC和通道2检测UAB,即UAIN1(﹢)和UAIN2(﹢)的关系式:

%E5%BC%8F%E5%AD%907.jpg
%E5%BC%8F%E5%AD%908.jpg

由公式(6)、(7)和(8)得热电阻RT的计算公式如下:

%E5%BC%8F%E5%AD%909.jpg

输入信号为电阻的情况和热电阻的推导公式相同。

当输入信号为热电偶时,热电偶正端接仪表通道A端子,负端接仪表通道B端子。按IEC国际标准,采用S、B、E、K、R、J、T七种标准化热电偶作为输入信号。在AD7705的两通道对热电偶进行检测时,实际上是对热电偶的电动势进行检测,因此,热电偶与电压作为输人信号的情况相同,只是最终将测得的电压值转换为温度值,有关冷端温度补偿问题由室温测量元件测出冷端温度与输入电压进行相加。

2.2AD7705输出电路

AD7705%E4%B8%87%E8%83%BD%E8%BE%93%E5%85%A5%E7%94%B5%E8%B7%AF%E7%9A%84%E8%BE%93%E5%87%BA%E7%AB%AF%E7%94%B5%E8%B7%AF%E5%9B%BE.jpg

图4 AD7705万能输入电路的输出端电路图

该万能信号输入模块中的24C64芯片,是64K的电可擦除可编程存储器E²PROM。该存储器是用来存储AD7705的信息的,在初始设定时将AD7705的信息写入24C64芯片中,这样AD7705的设置信息将永远保存在该存储器中,以后不用重复设定.24C64芯片和AD7705放在一个模块上,可以即插即用,使用方便。

设计的这个基于AD7705的万能信号输入电路的输出端采用SPI串行通信协议,SPI就是串行外围设备接口,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。SPI总线系统以主从方式工作,在本电路中SPI总线包括DIN(串行数据输入)、DOUT(串行数据输出)、SCLK(串行时钟输入)和/CS(片选)。

/CS是控制芯片是否被选中的,也就是说只有片选信号为低电平时,对AD7705的操作才有效。因此将片选管脚直接接地,也就是让AD7705始终处于工作状态,这时SPI总线实际上就只剩下DIN、DOUT和负责通信的三根线了,通信是通过数据交换完成的,这里先要知道SPI是串行通信协议,也就是说数据是一位一位的传输的,这就是时钟线SCLK存在的原因,由SCLK提供时钟脉冲,DIN,DOUT则基于此脉冲完成数据传输。数据输出通过DIN线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,数据输入也使用同样原理。这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。

要注意的是SCLK信号线只由主设备控制,即由该仪表的CPU来控制,AD7705不能控制信号线。SPI允许数据一位一位的传送,甚至允许暂停,因为SCLK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据;也就是说,主设备通过对SCLK时钟线的控制可以完成对通信的控制。SPI还是一个数据交换协议,因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出;由于本电路是数据采集电路,因此只需要AD7705对数据进行采集输出就可以。

输出端子信号为:

H-24C64数据线和串行同步时钟线;

G、F-24C64地址线;

+、–电源线;

E-AD7705串行时钟线;

D-AD7705数字信号输入、输出线。

结束语

本文总结了采用AD7705的万能信号输入电路设计。该电路实测结果达到了设计标准,具有多种信号输入功能。本电路通道数多,功耗低,精度高,采取隔离设计,抗干扰能力强,运行稳定,可靠性高,可作为各种智能显示仪表的数据采集电路使用。

开源伪和弦淫乐声的产生原理及电路,源码

有位兄弟发帖问如何产生清脆的“丁丁”声音,手贱回了一帖,没想到引来更多兄弟对此的性趣。约下的炮,肯定要打完,在此奉上电路和源码。
其实,这种听起来比较悦耳的声音产生原理也非常简单。就是利用电容的放电产生一个渐弱的尾音,模拟出击打风铃的音色。
电路如下:

BUZ-H负责输出音频频率,BUZ-L负责对C12的充电作控制。
例如,要发出“叮~~~~”的一声,在BUZ-H输出2400Hz的方波,BUZ-L输出72ms的高电平,此段时间内,蜂鸣器将由幅值12V的频率驱动,发出类似击打瞬间的声音,同时对C12充电。72ms后,BUZ-L输出低电平,这个时候,蜂鸣器将由C12来提供驱动电流,并且随著电容放电,声音逐渐减弱,产生类似风铃尾音的效果。1秒后,关闭BUZ-H的输出。
这种发声方式,其实还是单音频发声,只是在单音频的基础上,用电容的充放电模拟了击打和尾音,产生比较丰满悦耳的听感,所以称之为“伪和弦”。
各位有兴趣的话,可以用多个蜂鸣器同时发出不同音调,组成多音的真和弦,一个音调输出占用一个定时器。俺以前10多年前蛋疼,搞过几十个蜂鸣器的(5和弦,蜂鸣器多个并联),并且并增加一个IO用作电容的放电回路来产生短音,听感还是不错的。真有空时回老家翻出来拍个视频给大家看看。
源码如下,带音量控制,带家电常用的音调组合,还附上一个超级玛丽的1UP声音,玩过的朋友肯定会觉得很亲切,哈哈。
源码不是整个工程,我也懒得整理了,生活艰苦,搬砖不易。
用法,在您的工程里面增加两个文件,一个名为Music.c,一个名为Music.h(头文件)。现在源码,使用的是STM32F1xx,主频72M,使用的定时器是TIM2(任意定时器均可,自己修改),使用硬件PWM输出。所以您单片机有N个定时器,则可以最多N-1个真和弦(留一个做主时基),做产品,通常一个伪和弦就够了。Music_Srv()这个函数,没4ms调用一次,您放中断也行,放主循环也行(前提是您主循环没有阻塞的占用)。需要发声的时候,任意地方放一句 Music_Triger=MUSIC_XXX;  即可,不阻塞,也不用等它播完再调用,随传随叫春。
BUZ-L现在接的是PA1,这个任意IO即可,请自行修改。BUZ-H接的是PA0,这个随您用不同的TIM而不同,自己修改,例程用的是TIM2。

//*************************************************************************************************************************************
Music.h源码:

#ifndef __MUSIC_H_
#define __MUSIC_H_

//BUZ-L定义IO
#define BEEPL_1 GPIOA_DSRR=BIT1
#define BEEPL_0 GPIOA_DRR=BIT1
#define BEEPL_XOR {if(BitTst(GPIOA_ODR,BIT1)) BEEPL_0; else BEEPL_1;}

//音乐声定义
#define MUSIC_PWR_UP 1
#define MUSIC_TURN_ON 2
#define MUSIC_TURN_OFF 4
#define MUSIC_DING 3
#define MUSIC_UP 5
#define MUSIC_DOWN 6
#define MUSIC_1UP 7

extern volatile  uint8  Music_Triger;    //触发发声标志
extern uint8  flg_MusicPlaying;         //非0表示正在发声


void Music_Srv(void);     //4ms调用一次
void Music_InitIO(void);    //初始化IO
void Music_Init(void);   //初始化Music模块。

#endif


//*************************************************************************************************************************************
Music.c源码:
#include "music.h"


#define TIM2_ARR (*((volatile uint16 *)(TIM2_BASE + 0x002c)))
#define TIM2_CR1 (*((volatile uint16 *)(TIM2_BASE + 0)))
#define TIM2_CCR1 (*((volatile uint16 *)(TIM2_BASE + 0x0034)))
#define TIM2_CCER (*((volatile uint16 *)(TIM2_BASE + 0x0020)))
#define TIM2_CNT   (*((volatile uint16 *)(TIM2_BASE + 0x0024)))
#define TIM2_CCR2 (*((volatile uint16 *)(TIM2_BASE + 0x0038)))




// 定义常用频率,数字多少就是多少Hz
#define _28 2850   
#define _24 2400
#define _22 2250
#define _21 2100
#define _18 1850
#define _16 1650


// 定义duo,rui,mi,fa,so等等
#define _l1 130
#define _l2 146
#define _l3 164
#define _l4 174
#define _l5 196
#define _l6 220
#define _l7 246

#define _1 261
#define _2 293
#define _3 329
#define _4 349
#define _5 392
#define _6 440
#define _7 494

#define _1d1 523
#define _2d1 587
#define _3d1 659
#define _4d1 698
#define _5d1 784
#define _6d1 880
#define _7d1 987

#define _1d2 1046
#define _2d2 1175
#define _3d2 1318
#define _4d2 1397
#define _5d2 1568
#define _6d2 1760
#define _7d2 1976

#define _1d3 (_1d2*2)
#define _2d3 (_2d2*2)
#define _3d3 (_3d2*2)
#define _4d3 (_4d2*2)
#define _5d3 (_5d2*2)
#define _6d3 (_6d2*2)
#define _7d3 (_7d2*2)


//定义不同的乐曲数组,0 结束
const uint16 Music1_FrqTab[]={  //频率表,对应BUZ-H的输出频率,0 结束
        _18,        _18,        _21,        _21,        _24,        _24,        _28,        _28,        0,
};
const uint8 Music1_TimeTab[]={        //BUZ-L输出时间,偶数高电平,奇数为低电平尾音,x4ms,0 结束
        20,        30,        20,        30,        20,        30,        20,        255,        0,
};


const uint16 Music2_FrqTab[]={
        _21,        _21,        _22,        _22,        _24,        _24,        0
};
const uint8 Music2_TimeTab[] ={                //x4ms
        10,        18,        10,        18,        10,        255,        0,
};


const  uint16 Music3_FrqTab[]={
        _24,        _24,        0,
};
const  uint8 Music3_TimeTab[] ={                //x4ms
        18,        255,        0,
};


const  uint16 Music4_FrqTab[] ={
        _28,        _28,        _24,        _24,        _21,        _21,        0
};
const  uint8 Music4_TimeTab[]={                //x4ms
        10,        18,        10,        18,        10,        255,        0,
};


const  uint16 Music5_FrqTab[] ={
        _16,        _16,        _18,        _18,        _21,        _21,        0
};
const  uint8 Music5_TimeTab[] ={                //x4ms
        6,        16,        6,        16,        6,        255,        0,
};


const  uint16 Music6_FrqTab[] ={
        _21,        _21,        _18,        _18,        _16,        _16,        0
};
const  uint8 Music6_TimeTab[] ={                //x4ms
        6,        16,        6,        16,        6,        255,        0,
};




const uint16 Music7_FrqTab[]={
        1324,1324,1574,1574,2645,2645,        2114,2114,2347,2347,3154,3154,        0,
};
const uint8 Music7_TimeTab[]={                //x4ms
        15,          25,           15,            25,   15,    25,        15,     25        , 15 ,     25  ,  15,  255,        0,
};




uint8 Music_Vol=137;    //音量
volatile uint8  Music_Triger=0;   //触发播放哪一支,例如播放“叮~~~”,则任意地方调用 Music_Triger=MUSIC_DING;
uint8  flg_MusicPlaying=0;   //非零播放中。

//乐曲表指针
uint16 const  *  music_frq_tab;      
uint8 const  *  music_interval_tab;




TIM_TimeBaseInitTypeDef T2_TimeBaseStruct;
TIM_OCInitTypeDef T2_OCInitStruct;

void Music_SetVolumn(uint8 vol){     //设置音量,并且初始化TIM输出
        uint32 lTmp;
        lTmp=T2_TimeBaseStruct.TIM_Period;
        lTmp*=vol;
        lTmp/=255;
        T2_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;            
        T2_OCInitStruct.TIM_Pulse = lTmp;
        T2_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
        T2_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OC1Init(TIM2, &T2_OCInitStruct);
}


/* ---------------------------------------------------------------
  TIM2 Configuration: Output Compare Toggle Mode:
  TIM2CLK = 72 MHz, Prescaler = 0x9, TIM2 counter clock = 7.2 MHz
--------------------------------------------------------------- */

void Music_SetFrq(uint16 frq){    //  设置频率并初始化TIM
        uint32 clk;
        clk=7200000;
        clk/=frq;
        clk--;
        /* Time base configuration */
        T2_TimeBaseStruct.TIM_Period = clk;         
        T2_TimeBaseStruct.TIM_Prescaler = 0x9;      
        T2_TimeBaseStruct.TIM_ClockDivision = 0x0;   
        T2_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &T2_TimeBaseStruct);

        Music_SetVolumn(Music_Vol);
       
}


void Music_ChangeFrq(uint16 frq){    //改变频率。
        uint32 clk;
        clk=7200000;
        clk/=frq;
        clk--;
        /* Time base configuration */
        TIM2_ARR = clk;     
        clk*=Music_Vol;
        clk/=255;
        TIM2_CCR1=clk;
}


void Music_Frq_Enable(void){
        TIM2_CCER|=BIT0;
}

void Music_Frq_Diable(void){
        TIM2_CCER&=(~BIT0);
}



void Music_Init(void){
        Music_SetFrq(4000);

        TIM_ARRPreloadConfig(TIM2, ENABLE); // 这个记得要开

        //启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

        Music_Frq_Diable();
        TIM_Cmd(TIM2, ENABLE);
}


void Music_InitIO(void){
        GPIO_InitTypeDef tmpGPIO;
       
        tmpGPIO.GPIO_Mode=GPIO_Mode_Out_PP;
        tmpGPIO.GPIO_Speed=GPIO_Speed_50MHz;

        tmpGPIO.GPIO_Pin=GPIO_Pin_1;
        GPIO_Init(GPIOA,&tmpGPIO);

        tmpGPIO.GPIO_Pin=GPIO_Pin_0;
        tmpGPIO.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA,&tmpGPIO);
       
        BEEPL_1;
}


void Music_Select(void){
        switch(Music_Triger){
                default:       
                        flg_MusicPlaying=0;
                        return;
                case MUSIC_PWR_UP:
                        music_frq_tab=Music1_FrqTab;
                        music_interval_tab=Music1_TimeTab;
                        break;
                case MUSIC_TURN_ON:
                        music_frq_tab=Music2_FrqTab;
                        music_interval_tab=Music2_TimeTab;
                        break;
                case MUSIC_DING:
                        music_frq_tab=Music3_FrqTab;
                        music_interval_tab=Music3_TimeTab;
                        break;
                case MUSIC_TURN_OFF:
                        music_frq_tab=Music4_FrqTab;
                        music_interval_tab=Music4_TimeTab;
                        break;
                case MUSIC_UP:
                        music_frq_tab=Music5_FrqTab;
                        music_interval_tab=Music5_TimeTab;
                        break;
                case MUSIC_DOWN:
                        music_frq_tab=Music6_FrqTab;
                        music_interval_tab=Music6_TimeTab;
                        break;
                case MUSIC_1UP:
                        music_frq_tab=Music7_FrqTab;
                        music_interval_tab=Music7_TimeTab;
                        break;
        }
        flg_MusicPlaying=1;
}



void Music_Srv(void){
        static uint8  PlayStep=0;
        static uint8  PlayCt=0;
        uint8 cTmp;

        if(Music_Triger){
                Music_Select();
                Music_Triger=0;
                PlayStep=0;
                PlayCt=0;
               
                Music_ChangeFrq(music_frq_tab[PlayStep]);
                Music_Frq_Enable();

                BEEPL_1;
        }
        if(flg_MusicPlaying){
                cTmp=music_interval_tab[PlayStep];
                PlayCt++;
                if(PlayCt>=cTmp){
                        PlayCt=0;
                        PlayStep++;
                        Music_ChangeFrq(music_frq_tab[PlayStep]);
                        if(music_interval_tab[PlayStep]==0){
                                flg_MusicPlaying=0;       
                        }
                        else{
                                BEEPL_XOR;
                        }
                }
               
        }
        else{
                BEEPL_0;
                Music_Frq_Diable();
        }
}