发帖数

43

原创数

43

关注者

17

阅读数

10116

点赞数

2

张角

  • STM32 C语言预处理深入解析

    大家好,我是张飞实战电子张角老师! 我们今天对C语言的预处理指令做一个总结其实C语言的预处理指令主要有三大类文件包含宏定义和条件编译我们首先要明白什么是预处理第二个C语言编译之前为什么需要预处理或者说这些预处理的添加能够给C语言的编程带来什么好处?再一个,我们就展开讲解一下C语言常用的三种预处理指令,看看他们如何使用以及有各自有什么优缺点。

    所谓预编译或者说预处理,就是在编译之前进行的一些操作,这其中比较主要的可能就是展开操作。那么C语言为什么要添加这些预编译指令呢?从设计者的角度上来看,这些指令肯定会对C语言的编程带来效率的提升,C语言才会保留这些关键字。因为整体上各个预处理指令之间的关联性比较小,我们这里没有办法给他们的优点和缺点做一个统一的定论,这里只能是展开来讲一个一个仔细讲解。

    第一个我们我来看一下,头文件指令#include”。那么在回答这个文件之前,我们要先讨论一下头文件存在的必要性,或者说为什么C语言要分为头文件和源文件。为什么C语言不能像C#Java那样,不需要头文件么?

    第一个我们从C语言发展的历史来看或者说从共享代码对存储空间的使用量上来看,C语言头文件的必要性。之所以C语言一定需要头文件,一个最本质的原因,是因为C编译器编译出来的二进制码(.o, .obj, .lib, .dll)不包括自我描述的符号信息,那么要复用这种可执行代码的话,需要另外的文件。C#Java的可执行代码可以自带元数据信息,但是这也意味着运行时的内存需求的增加,毕竟这种自我描述的数据对最终用户来说是无用的。当然在C#Java被发明的时候,存储空间以及很便宜了。但是C被发明的时候,64K的内存是400多美金。一个程序经常几十个模块,运行的程序为某给模块去浪费几十K是不可能的,价格太高了。那么头文件也就应运而生了,可执行代码的元数据信息是在头文件中保存的,头文件可以充当这些模块复用的桥梁,那么进而就可以降低可执行模块复用时对存储空间的需求。

    第二,我们从编程器的角度来看一下。C时代的时候编译器比较简单,是固定的编译和链接两个过程,编译一次只处理一个文件,进行预处理之后,头文件会插入到这一个文件里,不同源代码文件的处理时独立的,这样如果头文件里面定义了一个函数的实现,编译的时候所有引用这个头文件的源码文件,生成的obj里都会有这个符号。而链接是通用的链接程序,从汇编时代就用的工具,没有什么高级功能,同一个符号链接时出现两次是会报错的。但是,我们又说了,每个文件的编译是独立的,所以如果实现不在当前源文件里面,调用的时候编译器就不知道这个函数的类型和签名,没法生成调用代码,所以必须在调用之前先声明一遍。如果不把声明写在头文件里面,就必须在每个用到这个函数的源文件里都声明一遍,很不方便,所以综合之后的解决方案就是实现写源码文件里面,声明写头文件里面。

    最后,我们从知识产权保护的角度上来分析一下。接口和实现分立之后,使用者只需要关注接口就行了,按照接口的说明使用就好了,不用关注具体是如何实现的。那么作为开发者呢,则可以对实现部分进行加密,那样是不是就可以保护一定的商业秘密了。具体到头文件来说,我们在头文件中进行的函数声明,其实就有这个作用。

    也就是说基于以上各种原因,头文件对于C语言来说,是一个确定的存在。那么就肯定要有一个关键字来处理头文件,那这个关键字就是“#include”。在程序正式编译之前,预处理程序会首先展开头文件中的函数以及变量声明。然后程序在编译的时候,对于没有在本文件中实现的变量或者函数,就会做好标记。然后在链接阶段,就会根据类型、名称信息,去其他可执行文件中去找在该文件中没有实现的同时声明过的变量或者函数,如果找到了,而且不重复,那么程序的编译就能够通过。如果没找到,或者找到两个,那么编译就不会成功。

    具体到#include的用法,这里还有区别。#include <xx.h>,这种尖括号写法,预编译程序只会到系统指定的目录中去找这些头文件,看看他们是否存在。#include xx.h这种写法则不是,这种双引号类型的写法,预编译程序会首先到工程目录去找相应的头文件,如果找不到,预处理程序会再到系统指定的目录里面去找。那也就是说,如果是自己写的头文件,我们一定需要使用#include xx.h的写法;如果是系统头文件,两种写法都行,但是#include <xx.h>这种写法,效率应该会更高一些。

    讲完了文件包含,我们看一下宏定义的预处理指令#define。这个指令大家应该都比较常见。使用宏定义,可以带来不少优点,比如可以避免意义相对模糊的数字出现,#define PI 3.1415926,那么我们就可以在程序中直接使用PI来代替那么一长串的数字。再一个,这个PI会在预编译的时候,直接进行值替代,并不需要为这些常量提供存储空间,那么就进一步提高了程序的执行效率。但是这个也会有隐患的,编译器这里只是进行展开,并不进行类型检查,与此对比的就是const的类型的变量,使用这个变量就有可能避免潜在的错误。再一个,像下面这个,#define FILE_PATH E:folder11.txt如果目录较长的话使用起来是不是非常不方便呀我们就可以直接使用FILE_PATH这个字符串去去代替较长的目录,这样是不是就方便了许多。

    虽然#define,给我们带来了许多便利,但是使用它的时候,一定要小心再小心,否则编程的时候,就比较容易出错。

    #define PCHAR char*

    PCHAR p1,p2;

    char** a = &p1;

    char** b = &p2

    像这段代码,其实就有问题。这里p2其实是char类型,并不是char*类型。对于这种类型的错误,可以使用typedef的方式来解决。

    我们再举一个例子,#define MUL(A,B) A*B而在使用的时候,这样的调用:int a=1,b=2,c=3,d=0;d=MUL(a+b,c)经过编译时候展开,就变成了d=a+b*c而不是我们所希望的d=(a+b)*c其解决办法也很简单,就是给每个分量,都加上括号,就可以避免此类问题,在宏定义的时候,如此定义:#define MUL(A,B) ((A)*(B))不过有些时候加了括号也没有办法避免这些问题

    但是使用#define来定义函数,确实可以减少系统开销,提高运行效率。为什么会这样呢?因为在C语言中,发生函数调用的时候,需要保留调用函数的现场,子函数执行完毕以后还有回复函数调用的现场,这都需要一定的时间。如果子函数执行的任务比较多,这点时间是可以忽略的,但是如果子函数的功能比较少,比如只是一个加法的操作,那这部分转换操作的开销就太大了。使用带参数的宏定义就不会出现这样的问题,因为他是在预处理阶段就进行了宏展开,在执行的时候不需要进行转换,即在当地执行。宏定义可以完成简单的操作,但是复杂的操作还是要借助函数调用来实现。另外,宏定义的代码如果比较长,预编译的时候,所有引用的部分的代码都需要展开,那么目标代码的空间就会相对较大。所以,我们还是要根据实际情况来决定是否使用宏定义。

    实际上,针对宏定义函数的一些缺点,C++引入了inline函数这个关键字。inline函数,可以像宏定义的函数一样,直接展开,而不会发生函数调用的开销。但是呢,inline函数,本质上就是函数,会有参数以及返回执行类型的检查,使用的时候,相对要安全很多。

    讲完了宏定义,我们就到了条件编译的部分。所谓条件编译,就是满足条件的时候,就编译,不满足条件的时候,就不编译。条件编译一个很重要的作用,就是可以提高程序的可移植性,我们可以根据不同的平台选择编译不同的程序。条件编译一般有三种格式,这里总结如下。

     

    第一种:

    #ifdef 标示符 (注意:标示符一般用#define命令定义)
    程序段1
    #else
    程序段2
    #endif

        第二种:

    #ifndef 标示符 (注意:标示符一般用#define命令定义)
    程序段1
    #else
    程序段2
    #endif

        第三种:

    #if 表达式 (注意:标示符一般用#define命令定义,如果表达式为真则编译程序1
    程序段1
    #else
    程序段2
    #endif

    大家在实际使用的时候,参考这三种类型进行使用,就可以了。

    我们今天对预编译指令的总结,就先到这里。下一篇文章,我们就谈谈其他的预编译指令。


    参考资料:

    1. 为什么C/C++要分为头文件和源文件 https://www.zhihu.com/question/280665935

    2. C语言预编译的缺点 https://blog.csdn.net/weixin_39632379/article/details/117079935

    3. C语言预处理详解 https://blog.csdn.net/czc1997/article/details/81079498

    4. #define宏定义的优点和缺点 https://blog.csdn.net/u013910522/article/details/22672057

    5. C语言提供的三种预处理命令 https://blog.csdn.net/xiongzebao/article/details/45586743

     


    收藏 1 回复 0 浏览 347
  • RISC-V 开发板 Buck电源调试记录(项目连载3)

    基于RISCV单片机的鸿蒙开发板

    Buck电源部分调试记录

    1. 起因

    这个开发板前期demo板的焊接,我这边焊接了两块电路板,主要是方便对比调试。前期的焊接都还比较顺利。各个模块(包括电源,LED灯,温湿度检测以及单片机最小系统等)测试都可以正常工作。

    等到两个开发板都焊接到红外模块的时候,两个板子同时出现了问题,程序再也烧录不进去了。没有开发板可以进行程序调试,问题就严重了。

    图片12.jpg

    1: 红色部分为红外探头

    出现这个事情的原因,很有可能是因为红外这个模块是射频模块,功率比较大或者有射频干扰,导致电路板上其他模块的工作出现异常。

    只所以能够得到这个结论,是基于以下两个判断:①两个板子同时出现焊接问题的可能性很小,②红外模块本身原理图出现问题很小,我司其他类型的开发板已经验证过这个电路模块的可行性。

    关于对红外模块的干扰处理,我们后面会有专文进行剖析,本文只做简要介绍。

     

    出现这个问题之后,我们首先想到的就应该是把红外模块的外围电路去除,看看程序的烧录工作还能不能正常进行。

    图片13.jpg

    2 红框中的电路即为红外模块的外围电路

    可是拆除这些模块之后,烧录工作并不能正常进行了,两块手动焊接的开发都是这么一个情况。开发板中肯定有其他模块因为红外模块的焊接出现了损坏,那么到底是哪个模块出现了问题呢?整个开发板,那么多元器件,怎么才能够快速的锁定问题,是一件棘手的事情。

    1. 解决问题的思路及注意事项

    现在的情况是不知道哪个模块出现问题了,只能是进行地毯式的搜查。排查问题的顺序,最好是先从电源部分入手,依次往后看。先看看各个芯片工作的电压是不是正常。如果电压正常,那么就有可能是芯片本身已经被损坏了,就需要把芯片更换掉,再进行测试。如果电压不正常,那么就是电源坏掉了。

    不断重复这个过程(以芯片的工作电压为抓手),最终锁定出问题的地方。

    在这个过程中,芯片会被拆掉,重新焊接,对调试人员焊接元器件的能力是有比较高的要求的。这个要求主要有以下几点:①焊接过程本身对焊盘是用损伤的,多次的焊接很容易把焊盘搞掉。一旦焊盘被搞掉了,可能整个板子就会被废掉,前期所有的工作都白费了。所以烙铁头一定不能剐蹭焊盘。另外同时烙铁头的温度也不能太高,否则粘稠的锡也可能把焊盘带掉。②拆除和焊接芯片的工程中,很容易把芯片的外围器件移动掉,导致外围器件也需要重新焊接,使开发板调试是速度变慢。

    2. 解决问题的过程

    我们首先测量Buck电源能不能够正常工作,结果发现3V3buck输出电压是3.5V。输出电压和实际的设计值之间差别巨大。

    我们使用的Buck芯片是SY8077,这一款工作频率高达1.5MhzBuck芯片,电路工作时典型的拓扑结构如下图:

    图片14.jpg

    3 SY8077芯片工作原理图

    电路正常工作是FB引脚的反馈电压是0.6V,如下图所示。

    图片15.jpg

    4 SY8077 FB接口引脚电压

    但是实际测量时候,FB引脚的电压是0.65V。这就很奇怪了,是Buck芯片出问题了,还是Buck电路的外围芯片出问题了?

    我们可以做出如下假设:

    ①芯片本身被损坏了,导致输出电压不正常,并且FB引脚电压也不正常。

    ②反馈电阻坏掉了,导致FB引脚的电压输出不正常。

     

    但是更换一个新的SY8077 Buck芯片之后,输出依然是3.5V。同时替换下了新的反馈电阻,FB引脚的电压依然是0.65VBuck电路依然没有能够正常工作。难道SY8077更换上去后,只要上电立即就坏掉了?至少到目前是有这个可能的。

    那这是哪里出问题了呢?问题一下子又复杂化了。

    这个Buck电路的输出电压不正常,那输出电流是什么样子呢?我们可以查看一下输出电流的波形,进一步确定buck电路的工作状态。

    图片16.jpg


    3  Buck电路电流测试电路


    图片17.jpg

    4 电流探头

     

    我们把这个电感竖起来,用一根白色的线延长电感的线路。这样把电流探头套到这根线上,就可以查看流过电感的电流波形,从而确定这个电感是工作在什么状态,是断续模式、临界连续模式还是连续模式状态?

    可是把电流探头套到这根线上之后,实测电流波形如下:

    图片18.jpg

    5 输出电流及电压波形

    图中蓝色部分的波形是输出电流的波形,可以看到电流在上电之后,出现了一个波动,然后电流就归于0了。也就是说,5V3.3V的这个buck电路并没有电流输出。

    Buck电流的输出电压不正常,而且输出电流为0;同时SY8077这个芯片以及外围电路已经更换过,应该也是没有问题。那么影响这个buck电路不能正常工作的因素只能是负载了,3V3这个输出电压的负载如果有短路的话,是不是会导致SY8077出现这样的情况呢?如果是负载的原因,那是哪个负载呢?

    确实一下很难猜出是哪个负载导致的,这个时候有两个办法一个是一个个拆解,看看拆掉哪个负载后,buck电路可以正常工作了;另外一个办法是,先把所有的负载拆掉,然后一个一个往电路上添加,如果添加到某一个负载时,buck电路不能工作了,那说明就是这个负载出了问题。

    我们上面还留有了一个疑问,是不是新换的buck芯片SY8077上电之后就坏掉了?我们需要首先验证一下buck电路是不是可以正常工作。要验证这个buck电路是不是可以正常工作,只有先把所有的负载先拆除掉,只留一个阻性负载或者选择电子负载用作测试。

    结合上面的因素,我们选择先把所有3V3的负载先全部拆掉。拆掉之后,重新查看电感的电流波形,发现电流是有输出的。而且随着电子负载的加重,电感的工作模式实现了从断续模式到连续模式的转变。这个测试结果说明SY8077这个芯片并没有损坏,同时SY8077这个芯片在自我保护的时候,其输出电流是0FB脚的电压是0.65V。具体为什么会是这么一个机制,SY8077datasheet并没有说清楚。

    后面就是不断把3.3V的负载(各个芯片,比如温湿度传感器SH20、电平转换芯片、电平逻辑芯片等等,只要供电电压是3.3V的,都算是3V3电源电压的负载)往电路板上添加。添加的过程一定要注意,最好是使用风枪吹,这样对周边焊接元器件的影响是最小的,可以加快调试板子的速度。

    等到添加FT4222HQ这个SPIFlash的时候,发现Buck电路电流又变成0了,也就是说Buck电路不能正常工作了。经过漫长的分析与调试,终于找到被损坏的芯片了!!!

    更换上新的FT4222HQ之后,Buck电源的输出就正常了,自然程序的烧录也就正常了。


    收藏 0 回复 0 浏览 326
  • ESP8266物联网开发板设计3 ---晶振起振原理

    大家好,我是张飞实战电子张角老师!我们今天继续物联网开发板硬件电路设计相关的探讨。

    我们先来看晶振这块。首先,单片机是可以看成是一个高速数字电路的集合体,其中速度最快的部件就要算是中央处理器了,其余的外围部件,比如PWM模块、I2C模块、SPI模块等等速度相对慢一些。我们先看CPU,它自己需要进行计算,但是多长时间CPU及其相关寄存器的状态改变一次,必须有一个时钟信号进行配合。换句话说,晶振的频率影响或者决定了CPU的动作周期。从另外一个层面来看,各个部件之间要协同工作,这肯定是需要同步的。这个同步的动作,肯定就需要时钟的参与。

    仅仅从上面两个部分来看,单片机要想高效地完成编程者设定的任务,时钟信号是不可或缺的。目前单片机的时钟信号的来源主要有两类,一类是内部的RC振荡器,另一类是外部的晶振电路。内部的RC振荡器,频率相对来说比较低,一个主要的原因是它受温度的影响比较大。主要的原因就是RC振荡器的外围电路,其实还都是半导体器件组成,而偏偏半导体器件温飘特性相对来说就是比较大。那么也就是RC振荡电路的周期就不准了,温度高的时候和温度低的时候,周期不一样。所以有些朋友家里安装的电子时钟,相对来说,时间一长,就容易不准,其实很大一部分原因就是这个产品使用的芯片内部的RC振荡器。

    但是有一个器件,能够提供非常精准的震荡频率,那就是石英晶体。石英晶体是一种具有压电效应的器件,在石英晶体两个管脚添加上交变的电场时,它将会产生一定的机械变形,这种机械变形反过来又会产生交变电场。一般情况下,无论是机械震动的振幅,还是交变电场的振幅都非常小。但是,当交变电场达到某一个特定值的时候,振幅陡然增大,产生共振。这个频率,我们称之为石英晶体的谐振频率。

    那么我们单片机配套的石英晶体振荡器,具体是如何起振的呢?我们只有知晓了具体的起振过程,才有可能搞清楚设计上需要注意的地方。

    我们单片机上的晶振电路,本质上就是电容三点式震荡电路的改进版。那么我们要讲清楚单片机上的晶振电路,就要讲清楚以下几个问题。第一,什么是震荡电路,震荡电路起振需要满足什么条件。第二,电容三点式震荡电路怎么起振的,它怎么就满足了震荡条件了。第三,电容三点式振荡电路的改进方向是什么,石英晶体震荡器符合电容三点式振荡器的改进方向么?第四,我们单片机内部电容三点式震荡电路一般是怎么实现的,我们设计晶振电路的时候有哪些需要注意的地方。在讲解这些地方的时候,我们尽量减少公式的表达,更多的追求直观的理解,毕竟我们的目的不是去设计单片机的晶振电路。

    我们说正弦波震荡电路起振的条件,主要是两个条件,一个是必须要引入正反馈,也就是说反馈信号必须要能够替代输入信号;第二个要有外加的选频网络,进而用来确定震荡的频率。我们下面来看一下,常见的电容三点式震荡电路是什么样子的。

    如下图所示,图中的三极管T1是放大部分,对A点输入的信号进行了放大。同时三极管的基极和射极信号是反向的,这个是三极管本身的特性导致的。如果对这个不熟悉的话,大家可以下去看看三极管的知识。那么三极管在这里也就是提供了两个功能,一个是信号的幅值放大(当然放大的倍数可以通过调整RcRe等进行调节),另一个功能提供了信号的相位的反相(图中A点和B点信号)。

    图中黑色虚线中的部分,就是电容三点式振荡器的选频网络。发生共振的时候,电感L1和电容C2C3组成的LC网络,可以近似为阻抗无穷大,也就是说电感L1和电容C2C3电流是环路电流。大家知道电容的特性,是不是电流相位超前电压90度呀。我们把C2C3的中间点接地,C点电压超前B90度,D点电压又超前C90度,那么D点电压是不是超前B180度呀。D点电压超前B180度,那是不是说D点的波形和B点是反向的呀。D点的波形和B点是反向的,B点的波形和A点是反向的,那么D点的波形和A点是不是就是同相的。那么这里是不是既有了正反馈,又有了选频网络。那么是不是就有可能满足正弦波的震荡条件呀,只要这个电路参数得当,那么就会产生正弦波。

    image.png

    这个电路的反馈系数F等于C2/C3, 电压放大倍数A = β*RL/rbe,其中RL = Rc//(Ri/F^2)

    我们是正弦波要能够起振,是不是 AF的值要大于1呀。如果我们通过调整C2/C3的值,就会出现一个相悖的结论,调大了F,结果A却小了。那么AF的乘积变化的趋势反而不明朗了。实际实验中,C2/C3的值既不能太大,也不能太小,具体指只能靠测试来设定。电容三点式震荡电路,相对来说它的缺点也在于此,通过调节电容去调节频率的话,会影响起振条件,但是通过调节电感办法来调节震荡频率,实现上又会比较困难。

    通过LC谐振点的公式来看,如果我们要想提高震荡的频率,只能是不断减小C2C3以及电感L。但是C2C3减小到一定程度的时候,比如和电路的杂散电容一个级别的时候,我们就很难确定震荡的频率了,因为杂散电容的电容值几乎很难确定。那么我们有没有其他办法来解决这个问题呢?如果我们把C2C3电容的容值设定在远大于杂散电容,那么杂散电容对电路的影响是不是就可以忽略掉了,电路的震荡频率是不是就会相对来说非常稳定。那么问题来了,震荡的频率如何提高呢?具体的措施,就是在电感上串联一个小电容C,同时C<<C2, C<<C3, 这样震荡频率只和这个C有关,f = 1/(2πsqrt(LC))。电容C2C3这里只是起到分压作用而已。整体的设计,如下图所示。

    image.png

    分析完了电容三点式震荡电路,那么我们看一下晶振怎么参与进来。因为我们前面已经提到了,我们单片机电路的晶振模块本质上也是电容三点式震荡电路。要看清楚这个问题,我们必须要了解晶振的高频模型,看看晶振的物理特性到底是什么。

    image.png

    实际上,晶振的高频等效模型如上图所示。这里的L,可以等效为晶振的惯性,这个值大概是几mH到几十mH。电容C等效为晶振的弹性,这个电容比较小,容值大概在0.01pF0.1pFR等效为晶振的摩擦损耗,这个值大概在100R,当然理想情况下这个值是零。电容C0等效为晶振的静态电容,它的大小和晶振的几何尺寸和极间面积有关,一般是几到几十个pF。那么实际上,晶振是惯性和弹性的结合体。结合我们前面提到的电容三点式振荡电路,我们更希望利用的其实是晶振的惯性部分,也就是电感部分对吧。在晶振组成的震荡电路中,震荡的稳定性主要是靠晶振本身的高Q值来稳定的,不是靠我们上面提到的那个思路,而且我们也不需要在外部震荡处那么高的频率,比如100Mhz的震荡。一般情况下,我们使用的是12Mhz的无源晶振,单片机内部的更高频次的震荡信号,是通过分频器和锁相环来实现的。

    既然,我们使用的是晶振的惯性部分,那么我们就来分析一下,在什么频率下晶振会更多的呈现惯性,也就是感性。

    当晶振的LCR电路发生谐振的时候,这个回路呈现纯阻性,等效电阻为R。谐振频率fs=1/(2πsqrt(LC))。当f低于fs的时候,C0这里起到主导作用,晶振呈现容性。当f大于fs的时候,LCR这条支路呈现感性。LCR这条支路将和C0发生并联谐振,谐振的频率fp = fs*sqrt(1+C/C0),这个具体的公式大家可以下去推导一下,我们这里就不再做更深入的介绍了。大家可以看一下,因为C远远小于C0,所以fsfp是不是无限接近呀。那么也就是说晶振只有在很窄的频率范围内,才会呈现感性。

    回到我们前面提到的电容三点式震荡电路,晶振只在一个很窄的范围内呈现感性,而且受温度的影响比较小。那么是不是说用晶振组成的三点式震荡电路,它的频率会非常稳定呀。具体电路设计如下图所示。那这样,我们使用晶振搭建的电容三点式震荡电路就算完成了。

    image.png

    那么下一个任务就要回答,单片机中的晶振电路一般是如何实现的呢?我们以80C51来距离,它震荡电路的框图大概是下面这个样子。

    image.png

    image.png

    收藏 0 回复 0 浏览 295
  • 讲透有史以来广受欢迎的运算放大器μA741(6)---放大级及输出级

    大家好,我是张飞实战电子张角老师!

    image.pngimage.png

    我们来看一下R5这个电阻的作用,如果没有R5这个电阻,那么T5T6的基极到地的阻抗就是不可以调节的,那么T7Ib电流也就确定了。T7Ib电流确定了,那么T7基极的电压也就确定了。我们前面分析过,T7这个管子的存在主要是增强两个输入端的对称性,我们先假定两个输入端的回路是完全对称的。那么T5T6C极电压就是相等的。那么对于输出来说,我们是不是希望当Vin+等于Vin-的时候,输出电位是不是零呀。那是不是要求T5T6C极电压有一个确定的值呀,这个确定的值可以使得当Vin+ = Vin-的时候,输出电压为零。R5这个电阻的作用也就在于此,它可以调节T7基极的电压,也就是T6 集电极的电压(也就是T5集电极的电压,根据对称性得来),使得输出电位为零。

    我们下面看一下放大级,放大级采用的是达林顿管的结构。什么是达林顿管呢,总体上而言,就是两个N管或者P管串联,这样就可以增大放大倍数。这个我们前面也提到过,使用这种方式来提高输入级的内阻。我们从另外一个层面看问题,其实从维护输入桥臂对称性的角度上来讲,从F点输出的电流也不宜较大,那样会拉低F点的电位。因为电流越大,相当于F点到负电源的阻抗也就越低,那么很显然会把F点的电位拉低。那么也就是说,如果把F点看成一个电源的话,它也是希望后级负载的阻抗相对较高。其实这个需求也是必然的,因为F点的作为源的话,它本身的阻抗是也是比较高的,那么自然它就会要求它的负载的阻抗相对高一些。

    image.png

    上图中T10这个管子是一种特殊的三极管,有两个集电极。我们可以通过控制集电极面积的大小,进而控制流过它们的电流。T10这个管子是镜像Q5这个管子的电流的,也是一个电流镜,总的Ic电流也是Iref。这个原理,我们就不再赘述了。在uA741中,流过T9这个管子的电流是0.75Iref,前面我们算过Iref大概是0.73mA,那么流过T9Ic电流大约就是0.548mA

    我们来看一下uA741的输出级,它的输出级采用的是上NP的推挽结构,这样可以提高输出功率。这个推挽结构,大家应该比较熟悉了。R9R10这两个电阻主要是用来进行限流使用的,具体起作用的方式我们后面再讲。T10T11这两个管子是一个Vbe发生器,也来产生一个固定的压差,这个压差骑在T12Q7的基极之间,这样就可以防止推挽结构导致的交越失真。在uA741中,这个压差的值是1.2V,这个值大了会导致T12Q7的损耗比较高;小了,交越失真就会相对严重一些。

    image.png

    Q6这个管子可以看成一个电压抬升器,把T9这个管子集电极电压又抬升了0.7VQ6这个管子很明显是放大状态接法,同时把信号放大和功率输出隔离开,尽可能减少功率输出部分对信号放大的影响。从驱动能力的角度看,T9最好也是驱动一个高内阻的负载,这样对T9的影响是最小的。


    收藏 0 回复 0 浏览 290
  • 讲透有史以来广受欢迎的运算放大器μA741(2)---恒压恒流源

    大家好,我是张飞实战电子张角老师!

    上一篇文章对uA741的电流源还没有分析结束,下面我们继续往下看741运放内部P管构成的镜像电流源是怎么工作的。下图就是P管组成的电流镜的具体方案,这个和我提出来的方案是不一样的,具体它们的不同之处在哪里,这篇文章就给大家做下详细的分析。

    image.png

    Q1Q2两个P管镜像恒流源这个地方,能够提供多大的能力,表面上看这个能力是取决于Q2这个电流源的负载。如果它的负载越大,那么提供的电流肯定是越小,反之电流也就越大。实际上真的是这样么? 

    T4集电极处的电压是T4RceR2Q1Rce三个电阻分压的结果。我们假定T4的集电极电压Vc上升了,那么Q3/Q4Vb肯定上升,那自然T1T2Ve肯定上升。上面这些都没有疑问对吧。T1T2这两个管子都是恒流源接法,对吧。也就是说T1T2这两个管子都是处于放大状态,流经它们的Ib小了,那么自然Ic也会小了。那Q2自身的Ie也就会小了,是吧。Q2这个管子处于临界饱和状态,那么自然它的Ib也就小了。Q1Q2这两个管子的Ib电流是相同的,那么Q1Ib电流也就小了,那么Ib放大之后能够提供的电流Ib*βt也就小了,那是不是这个电流就小于原来的电流IcT3Ic电流值)了。这个时候,Q1这个管子就往放大状态移动了对吧,同时T4这个管子往饱和方向移动。管子往放大状态移动,它的Rce是不是变大了呀;管子往饱和方向移动,它的Rce是不是变小了呀。所以就有了Q1Rce上升,T4Rce下降状态。那么T4这个管子集电极处的Vc是不是要下降了,那这样就对冲了T4集电极处电压上升的影响,T4集电极处的电压就会保持一个稳定的状态。这个电位稳定了,按照刚才的逻辑推理,那么T1T2Ic之和,也就是Q2Ic是不是就稳定了。所以我们说,流过Q2Ie电流是一个定值。

    当然这个分析过程也可以直接从Q2 Ie或者Ic的角度进行分析,分析的结果其实是一样的,大家可以尝试一下。

    image.png

    反向的调节过程,大家可以自己下去分析一下,这里我们就不再赘述了。

    image.png

    另外大家还发现没有Q2C极电位,是不是一个固定的电位呀,这个电位是不是Vcc-0.7V。为什么Q2Vbe一定是0.7V呢?因为Q2这个管子处于临界饱和状态,大家下去可以查一查相关的资料。这里因为Vcc是固定的,Q2Vbe也是固定的,所以Q2C极电压一定是固定的。所以这个电源是不是可以认为是一个恒压恒流源。这个设计确实非常巧妙。

    在上篇文章中,我们是不是提出了一个自创的恒流源设计方式,如下图所示。

    image.png

    我们这里是不是使用的Q1Ib电流作为偏置的呀,那么是不是也就是说Q2最大也只能流经这么大的电流,这个是电流镜的根本特征是吧。我们举个例子,当上图中负载的阻抗变大的时候,是不是它就不需要那么多的电流了呀,那这个时候,流经Q2 Ic电流是不是就没有流经Q1Ic电流大了呀。但是它们的Ib电流是不是还是相等的,那这个时候Q2是不是就往饱和方向移动了,而且这个时候Q2的集电极电压也不再是Vcc-0.7V了。那么也就是说,这个电流镜的做法,不能够保证Q2 集电极处的恒压恒流特征,具体是不是恒压恒流,取决于负载的状态。

    那么我们能不能同样使用反馈的方式来做到让这个电流镜一样恒压恒流呢?比如像刚才那样同样进行电流反馈,我们依然按照刚才的逻辑来分析。假定T2 C极的电压上升了,这肯定会导致Q2Ic变小,但是这个反馈回路是不是对Q1Ib是不是没有什么影响呀,大家可以看一下图纸。由于T2 C极的电位上升,确实会导致导致了Q1Ib变小,那么也就是说Q2IbIc是同时变小的,这个也没有办法保证Q2集电极处恒压、恒流特征。所以我们提出的那个方案,没有芯片设计方给出的方案更好。

    image.png

    那这样,运放电源部分的设计我们就先到这里。如果我们能够知道每个运放的放大倍数,那么我们就可以精确地计算出来各个支路的电流值到底是多少,这样也算是对电源部分有较为深入的理解了。

    Q5Q6这两个管子的作用主要是调整偏置电压和增加运放的差分增益,这块内容我们下节课再进行探讨。


    收藏 0 回复 0 浏览 250
×
张角