LM324运算放大器,TLC1543 多通道模数转换器读取ADC值
- 传感器MF58-104F-3950:25 ℃ 100 kΩ,B=3950 K,玻璃封装,-40 … +250 ℃。
- 信号调理(单电源 5 V)采用“恒压分压 + 电压跟随 + 一阶低通”三件套,运放 LM324 单电源 5 V 供电即可。) 通道 1 做电压跟随(输入阻抗 >> 10 MΩ,输出阻抗 < 1 Ω)通道 2 做 2 阶 Sallen-Key 低通,截止 10 Hz,抑制 50 Hz 纹波运放输出直接送 TLC1543 A0;其余 10 路留空或接地。
- ADC 接口TLC1543 与 STC51 采用“软件 SPI”——3 线制(CS、CLK、DOUT),参考电压 REF+ = 5.00 V,REF- = 0 V。
二、ADC 驱动(C51)
TLC1543 10-bit 读时序(Mode-0 SPI):
/* ---------- tlc1543.h ---------- */
#ifndef _TLC1543_H_
#define _TLC1543_H_
#include <REG52.H>
sbit CS = P1^0;
sbit CLK = P1^1;
sbit DOUT = P1^2;
sbit DIN = P1^3;
/* 读取指定通道 0…10,返回 0…1023 */
unsigned int TLC1543_Read(uchar ch);
#endif
/* ---------- tlc1543.c ---------- */
#include "tlc1543.h"
#define DELAY() { _nop_(); _nop_(); } // 约 0.2 µs@22.1184 MHz
unsigned int TLC1543_Read(uchar ch)
{
uint dat = 0;
uchar i;
ch &= 0x0F;
CS = 1; CLK = 0; CS = 0; // 启动
/* 4 个地址位,MSB 先出 */
for(i=0;i<4;i++){
DIN = (ch >> (3-i)) & 1;
CLK = 1; DELAY(); CLK = 0; DELAY();
}
/* 再 6 个 dummy 时钟,把转换结果移出 */
for(i=0;i<6;i++){
CLK = 1; DELAY(); CLK = 0; DELAY();
}
/* 读 10 位 */
for(i=0;i<10;i++){
dat <<= 1;
if(DOUT) dat++;
CLK = 1; DELAY(); CLK = 0; DELAY();
}
CS = 1;
return dat >> 0; // 10-bit 有效
}
三、查表法温度转换
- 电阻-温度表生成用 Steinhart-Hart 方程(B 值版):R(T) = 100000·exp(3950·(1/(T+273.15) - 1/298.15))在 -40 … +125 ℃ 区间每 1 ℃ 计算一次阻值,得到 166 点。
- ADC 码 → 阻值 → 温度分压公式:Vadc = 5·Rtd/(R1+Rtd)ADC = 1023·Vadc/5 = 1023·Rtd/(R1+Rtd)反推:Rtd = R1·ADC/(1023 - ADC)拿到 Rtd 后,直接在数组里“二分查表”即可。
- 查表代码( ROM 占用 332 Byte)
/* ---------- ntc_table.h ---------- */
#ifndef _NTC_TABLE_H_
#define _NTC_TABLE_H_
#define R_FIX 100000L // 100 kΩ
#define NTC_POINTS 166 // -40…125 ℃
/* 放 16-bit 阻值(Ω), 索引 0 = -40 ℃ */
code uint16 ntc_r[NTC_POINTS] = {
1747900, 1645300, 1550900, 1463700, 1382700, 1307200, 1236800,
1170900, 1109200, 1051300, 996900, 945300, 897200, 852200,
810000 , 770300 , 733000 , 697900 , 664800 , 633500 , 603900 ,
575900 , 549300 , 524000 , 499900 , 476900 , 454900 , 433800 ,
413500 , 394000 , 375200 , 357000 , 339400 , 322300 , 305700 ,
289600 , 274000 , 258900 , 244200 , 230000 , 216200 , 202800 ,
189800 , 177200 , 165000 , 153200 , 141800 , 130800 , 120200 ,
110000 , 100200 , 90800 , 81700 , 73300 , 65500 , 58300 ,
51700 , 45600 , 40000 , 34900 , 30300 , 26200 , 22500 ,
19300 , 16400 , 13900 , 11700 , 9800 , 8200 , 6800 ,
5600 , 4600 , 3700 , 3000 , 2400 , 1900 , 1500 ,
1200 , 930 , 730 , 560 , 430 , 330 , 250 ,
190 , 140 , 100 , 75 , 55 , 40 , 29 ,
21 , 15 , 11 , 8 , 6 , 4 , 3
};
/* 返回温度(放大 10 倍,-400 表示 -40.0 ℃) */
int16 ADC2Temp(uint16 adc);
#endif
/* ---------- ntc_table.c ---------- */
#include "ntc_table.h"
int16 ADC2Temp(uint16 adc)
{
ulong rt; // 临时阻值
uint16 low = 0, high = NTC_POINTS-1, mid;
/* 1. ADC → 阻值 */
if(adc >= 1022) return 1250; // 超上限
rt = (ulong)R_FIX * adc / (1023 - adc);
/* 2. 二分查表 */
while(low <= high)
{
mid = (low+high)>>1;
if(rt >= ntc_r[mid]) low = mid + 1;
else high = mid - 1;
}
/* low-1 即为最近索引 */
if(low == 0) return -400;
/* 线性插值(可选) */
uint16 r1 = ntc_r[low-1];
uint16 r2 = ntc_r[low];
int16 t1 = -400 + (low-1)*10;
int16 t2 = t1 + 10;
return t1 + (int16)((int32)(t2-t1)*(r1 - rt)/(r1 - r2));
}
四、主程序框架
/* ---------- main.c ---------- */
#include <REG52.H>
#include "tlc1543.h"
#include "ntc_table.h"
#include "lcd1602.h" // 自己写的 1602 驱动
void main()
{
uint16 adc;
int16 temp; // 放大 10 倍
lcd_init();
lcd_puts("Temp: . C");
while(1)
{
adc = TLC1543_Read(0); // 通道 0
temp = ADC2Temp(adc); // 查表得温度
lcd_goto(6,0);
lcd_print_temp(temp); // 显示 xx.x
delay_ms(500);
}
}

开源社区
