本文讨论的是惠斯通电桥与热电阻的实际应用,不讨论理论知识,关于惠斯通电桥的理论知识请看这篇文章:https://zhuanlan.zhihu.com/p/267085334

1. 四分之一桥

  使用Multisim仿真,搭建一个电桥,其中R2,R3,R4都为120Ω,R1是阻值随温度变化的电阻,假设R1的电阻为250Ω(因为温度变化导致电阻增加了130Ω),假设Vs为2.5V,此时根据公式Vo = Vs * (R2 / (R1 + R2) - R4 / (R3 + R4))计算得出,Vo ≈ -439mV,仿真结果如下:

  

  仿真结果与计算值相同。意思就是如果我们知道Vo的电压为-439mV,那么我们就知道R1增加了130Ω,进而可以算出温度变化。

  但是实际情况往往是R1会拉很长的线连出去,线上也是有电阻的,并且线上的电阻也是随温度变化的(任何材料的电阻都会随温度变化而变化),那么实际的模型就会变成下面的模型:

  

  a等效线上的电阻,此时Vo为-461mV,我们认为R1的电阻增加了140Ω,而实际上只增加了130Ω,有10Ω是导线引入的,这样就带来了误差。

  有一个方法可以减小这种误差,在R1的其中一端引出2根导线,按照下图的接法连接:

  

  这样得到的Vo是-428mV,当R2=R3=R4时,这3种情况Vo的计算方法分别为:

  

   结果是:

  

   并且通过仿真也验证了,当R1=3R2时,2根线和3根线的误差相同,如下图:

  

  如果传感器接到R2的位置,用同样的方法计算得出,当R2≤3R1时,接3根线的误差才会比接2根线的误差更小,R3,R4同理。

  也就是说,“使用四分之一桥,3根线的接法误差比2根线的接法误差更小”这句话是有前提条件的,前提条件就是变化的电阻不能比其他电阻的3倍要大,因此必须根据温度的变化范围去选择合适的阻值,否则效果会更差。

  在实际使用时按照理想情况去计算,无论将变化的电阻接到R1还是R2的位置,Vo的值与可变电阻之间的关系都是反比例函数,并且接R1和接R2时他们的导数互为相反数,结论就是将任何一个电阻充当可变电阻,它们的精度都是相同的。因此不需要考虑到底将桥中哪个电阻充当可变电阻,因为它们都是一样的。

  并且根据反比例函数的性质可以知道,当电阻的值越大时,导数的绝对值越小,意味着电桥(Vo)对电阻的变化越不敏感(电桥中任何一个电阻都是如此)。因此如果想要电桥的精度更高,那么电阻的选取要尽可能小,但同时要满足可变电阻最大值的3倍比其他固定电阻的值要大

2. 热电阻温度与阻值计算

  先说一下热电阻的型号定义,以PT100举例,PT指的是铂,100指的是该电阻在0℃时呈现的阻值为100Ω,那么CU50指的就是该电阻的材料是铜,在0℃时的阻值为50Ω。

  铂热电阻(常见的如PT100,PT1000等)温度与阻值的关系为 RT = R0(1 + AT + BT² + C(T-100)T³) ,铜热电阻(常见的有CU50等)温度与阻值的关系为 RT = R0(1 + AT + BT(T-100) + C(T-100)T²),其中R0表示该电阻在0℃时的阻值,单位Ω,对于不同的电阻A,B,C的值会不同,如下:

  PT100 PT1000 CU50
R0 100 1000 50
A 0.0039083 0.0038623139728 0.00428
B -0.0000005775 -0.00000065314932626 -0.0000000931
C

当T≤0时 -0.000000000004183

当T>0时,0

0 0.00000000123

  网上的那些分度表都是用这个公式生成的,下面的程序可以直接生成这3种型号的分度表:

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <fcntl.h>
  4 #include <sys/stat.h>
  5 #include <math.h>
  6 #include <string.h>
  7 
  8 /* 定义热电阻的型号 */
  9 //char RES_TYPE[16] = "PT100";
 10 //char RES_TYPE[16] = "PT1000";
 11 char RES_TYPE[16] =    "CU50";
 12 
 13 /**
 14  * \brief 铂热电阻温度与阻值的关系为 RT = R0(1 + AT + BT² + C(T-100)T³) 
 15  *          铜热电阻温度与阻值的关系为 RT = R0(1 + AT + BT(T-100) + C(T-100)T²)
 16  * 其中R0表示该电阻在0℃时的阻值,单位Ω
 17  * 对于不同的电阻A,B,C的值会不同
 18  */
 19 
 20 int main(int argc, const char *argv[])
 21 {
 22     double R0, A, B, C;    
 23     double min_t, max_t, step;    /* min_t是最小测量温度,max_t是最大测量温度,step是温度步长 */
 24     double result = 0;
 25     double i, j;
 26     
 27     int k;
 28     int fd;
 29     char buff[256] = { 0 };
 30     char acc[16] = { 0 };    /* 打印精度 */
 31     
 32     if (argc == 2) {
 33         strcpy(RES_TYPE, argv[1]);
 34     }
 35     
 36     if (!strcmp(RES_TYPE, "PT100")) {
 37         R0 = 100;
 38         A = 0.0039083;
 39         B = -0.0000005775;
 40         C = -0.000000000004183;
 41         min_t = -200;
 42         max_t = 660;
 43         step = 1;
 44         strcpy(acc, "%.02f,");    /* 保留2位小数 */
 45     } else if (!strcmp(RES_TYPE, "PT1000")) {
 46         R0 = 1000;
 47         A = 0.0038623139728;
 48         B = -0.00000065314932626;
 49         C = 0;
 50         min_t = -50;
 51         max_t = 300;
 52         step = 0.1;
 53         strcpy(acc, "%.03f,");    /* 保留3位小数 */
 54     } else if (!strcmp(RES_TYPE, "CU50")) {
 55         R0 = 50;
 56         A = 0.00428;
 57         B = -0.0000000931;
 58         C = 0.00000000123;
 59         min_t = -50;
 60         max_t = 150;
 61         step = 1;
 62         strcpy(acc, "%.03f,");    /* 保留3位小数 */
 63     } else {
 64         printf("暂不支持该型号!\n");
 65         return 0;
 66     }
 67     
 68     //printf("A = %f\nB = %f\nC=%f\n", A, B, C); //可以看浮点数有截断误差
 69 
 70     strcpy(buff, RES_TYPE);
 71     strcat(buff, "热电阻常用阻值对应表.csv");
 72     fd = open(buff, O_CREAT | O_RDWR | O_TRUNC, 0666);
 73     if (fd < 0) {
 74         printf("open failed\n");
 75         return 0;
 76     }
 77     memset(buff, 0, sizeof(buff));
 78     
 79     /* 写入横轴 */
 80     strcpy(buff, "温度℃,");
 81     write(fd, buff, strlen(buff));
 82     for (k = 0; k < 10; k++) {
 83         sprintf(buff, "%f,", k*step);
 84         write(fd, buff, strlen(buff));
 85     }
 86     write(fd, "\r\n", 2);
 87 
 88     for (i = min_t; i <= 0; i += 10 * step) {
 89         sprintf(buff, "%f,", i);
 90         write(fd, buff, strlen(buff));
 91         for (j = 0; j < 10; j += step) {
 92             if (!strcmp(RES_TYPE, "CU50")) {
 93                 result = R0 * (1 + A * (i - j) + B * (i - j) * (i - j - 100) + C * (i - j - 100) * (i - j) * (i - j));
 94             } else {
 95                 //result = R0 * (1 + A * (i - j) + B * pow((i - j), 2) + C * (i - j - 100) * pow((i - j), 3));
 96                 result = R0 * (1 + A * (i - j) + B * (i - j) * (i - j) + C * (i - j - 100) * (i - j) * (i - j) * (i - j));
 97             }
 98             sprintf(buff, acc, result);
 99             write(fd, buff, strlen(buff));
100             if (i == min_t) {
101                 break;
102             }
103         }
104         write(fd, "\r\n", 2);
105     }
106     for (i = 0; i <= max_t; i += 10 * step) {
107         sprintf(buff, "%f,", i);
108         write(fd, buff, strlen(buff));
109         for (j = 0; j < 10; j += step) {
110             if (!strcmp(RES_TYPE, "CU50")) {
111                 result = R0 * (1 + A * (i + j) + B * (i + j) * (i + j - 100) + C * (i + j - 100) * (i + j) * (i + j));
112             } else {
113                 //result = R0 * (1 + A * (i + j) + B * pow((i + j), 2));
114                 result = R0 * (1 + A * (i + j) + B * (i + j) * (i + j));
115             }
116             sprintf(buff, acc, result);
117             write(fd, buff, strlen(buff));
118             if (i == max_t) {
119                 break;
120             }
121         }
122         write(fd, "\r\n", 2);
123     }
124 
125     close(fd);
126 
127     return 0;
128 }

  有几个需要注意的点:

  1. 因为浮点数存在截断误差,所以通过这个程序计算出来的值,与真实值略有出入(可以忽略);

  2. 通过这个方法计算出来的PT100和CU50的表与网上的其他表一致,但是PT1000不一致(差别很小),经过验证发现网上的PT1000的分度表实际上是用PT100的参数计算出来的,我简直呵呵了,公式都摆在那,那些人都不自己算一遍的吗。

3. PT100和PT1000精度比较

  通过上一节算出来,当温度从0℃增加到1℃时,PT100的电阻增加0.39Ω,PT1000的电阻增加3.862Ω(网上的表是3.908Ω),可见PT1000增加的电阻是PT100的10倍,是不是意味着PT1000精度是PT100的10倍呢?从第1节的计算结果得出,当电阻值越大时,惠斯通电桥对电阻的变化越不敏感,它们是一个反比例函数的关系。

  假设我们需要测量的温度不会大于150℃,此时PT100的阻值是157.33欧姆,PT1000的阻值是1564.651Ω,根据第1节算出来的电阻选取规则,使用PT100时,其他电阻选用56Ω比较合适,使用PT1000时其他电阻选用560Ω比较合适。

  假设PT100的电阻是k,那么相同温度下PT1000的电阻就为10k,Vo的值用下面的公式计算:

  

   这时就发现一个问题,Vo的值是一模一样的。也就是说,如果使用惠斯通电桥测温度,PT100和PT1000在精度上没有任何差别

4. 放大倍数及电路确定

  以PT100为例,固定电阻为56Ω,假设使用温度范围为-20℃~150℃,PT100的阻值变化范围为92.16Ω~157.33Ω,Vo的值范围为305mV~594mV(取绝对值)。而一般的ADC能采集0~3.3V的电压(单端电压),因此为了提高精度,可以将电压放大5倍(需要选用差分放大器),这样电压范围会变为1.525V~2.97V,更好的利用的ADC的采集范围,以此提高精度。

  可以使用INA128U对信号进行放大,INA128U的放大倍数为1+50K/RG,取RG为12.5k,那么放大倍数就是5,仿真如下图:

  

  其中INA128U的6号引脚输出电压是经过放大后的电压值再加上5号引脚的电压,因此,如果想要继续提示精度,可以算出温度变化范围内电压的差值,为594-305=289mV,为了尽可能达到3.3V的满量程,可以将放大倍数调整到11倍,同时在5号引脚施加一个偏置电压,让INA128U的输出电压落在0~3.3V的区间内,按照下图所示方法连接,当温度达到最大值150℃时,放大器输出最小值(-0.594*11)+6.6=0.066V,当温度达到最小值-20℃时,放大器输出(-0.305*11)+6.6=3.245V

   仿真结果与计算结果基本一致:

  

  

 5. 使用惠斯通电桥与电阻分压测电阻的优点分析

5.1 从计算方法考虑

  热敏电阻使用3线制接法,先看直接分压的情况,如下图:

 Vo的计算公式为:

   可见Vo是Rx的反比例函数。随着Rx的增加,Vo的变化会越来越不明显。

  再看惠斯通电桥的情况:

  

   Vo的计算公式为:

  

   这与电阻直接分压的算法差不多,只不过是括号里多减了个1/2,而且它们的导数是相同的,并且它们受到线上电阻a的影响是一样的,这意味着从计算方法上看,惠斯通电桥法与电阻分压法是完全一样的。

5.2 从特殊情况考虑

  我们知道惠斯通电桥有一种平衡状态,就是Vo为0的情况,此时有一个特性,就是:

   一般让R2,R3,R4都相等,记作R,此时

  化简之后得到Rx=R,此时式子里没有a,也就是说当电桥平衡时,即Vo=0时,惠斯通电桥可以完全消除线上电阻的影响,得到的结果是最精确的。

  但是电阻分压法就不能有这个优点吗?

  电阻分压法的特殊情况是Vo=1/2Vs,此时Rx+a=R2+a,Rx=R2,同样消除了线上电阻的影响。

  但是!当惠斯通电桥达到平衡状态时,不需要考虑参考电压Vs,无论Vs的值为多少,Vo的值都是0,而电阻分压法的平衡状态是Vo=1/2Vs,Vo的值会受Vs的影响。所以惠斯通电桥真正的优点是:在平衡状态时消除了参考电源的影响

   不过话又说回来,因为被测电阻是变化的,要使惠斯通电桥达到平衡状态,需要改变其他3个电阻的值,在实际情况下这是不现实的。

6. 推荐使用方法(使用运算放大器)

  既然惠斯通电桥的优点那么不明显,那就直接用简单的电阻分压法吧。

  将PT100串联一个56Ω的电阻测量2个电阻之间的电压,当温度变化范围为-20℃~150℃时,PT100的阻值变化范围为92.16Ω~157.33Ω,Vo的值范围为656mV~945mV,假设ADC的采样范围为0~3.3V,那么可以将电压放大3倍,得到的电压范围为1.968V~2.835V,这样虽然将采样精度提高了3倍,但是0~1.968V这个区域浪费了。最好的情况就是656mV~945mV这个范围刚好能对应上0~3.3V的范围,这时就要用运算放大器了,将其作为一个减法器放大。具体接法如下图:

   必须用电压跟随,否则Ux的值会随着放大倍数的改变而改变。

  Ux的值最小为657mV,那么就在另一端造一个657mV出来,如下图:

  

   为了留点余量,这里造出来的电压是639mV。然后将这两个电压接到减法器里,如下图:

 

 根据运放的特性,得到以下2个式子:

   联立化简得到如下式子:

   现在认为制造一种特殊情况,就是R1=R2,R3=R4,那么上面的式子就可以化简为:

   

   如果再让R3=R1,那么此时Uo=Ux-Ua,这就是减法器。

  但是我们还是要利用一个R3/R1这个数,因为Ua是我们造出来的电压,它等于Ux的最小值,此时Uo的值为0,而当,Ux变化到945mV时,我们希望Uo的值尽可能接近3.3V,那么就可以取R3=11R1,此时放大倍数为11倍,最大输出电压为3.179V,尽可能的利用了ADC的采样范围。

   而实际情况需要留一些余量,按照上面的接法,让Ua的值为639mV,比Ux的最小值再小一点,放大倍数设为10倍,理论上输出电压值范围在180mV~3.06V之间,尽可能的利用了ADC的采样范围。

补充:

  虽然理想运放最大输出电压接近电源电压,但是要根据实际情况而定,比如我使用的LM324,手册上说的是:Large Output Voltage Swing: 0V to VCC-1.5V,因此他的输入电源要大于3.3+1.5=4.8V,取5V比较合适。