PT100恆流源測溫電路【一】
自從想要做一個PT100的測溫電路,實驗了很多方法,包括恆流源,電橋。最後決定使用恆流源,而恆流源採用壓控恆流源,電壓基準採用LM285,輸出電壓1.235V。
此恆流源的輸出電流取決於LM285的輸出電壓,和R1的阻值,為了得到精確的輸出電流,R1最好採用高精度,低溫漂的電阻。如果需要更高的精度,則需要使用更高的電壓基準晶片,比如REF5025,LM399等。
PT100採用四線制接法,通過J2輸入,放大器採用AD623儀表放大器,當然使用普通運放構成差分放大器也是可以的,只是使用現成的儀表放大器比較方便,只需要一個外部電阻R15即可設定放大增益,公式為G=100KΩ/R15+1,這個電路設定的放大增益G=11。另外U8、C7、C8、R17、R18構成二階有源低通濾波器,這裡設定的截止頻率f≈5Hz。濾波後的訊號接ADC到微控制器的模數轉換引腳,當然也可以通過跳線JP1接到專用16位AD轉換晶片ADS1110,將電壓轉換為數字訊號然後交由微控制器處理。
本電路因為採用單電源供電,而AD623需要使用一個負電壓,所以使用了一個電壓反轉晶片MAX660,但也可以使用LM2662替代,而事實上在實際的電路中,我使用的就是LM2662
這是微控制器電路的原理圖,使用的是 STC的STC12C5A16S2,LQFP44封裝。其中KEY,DATA,CLK,CS是用來控制數碼管,用於顯示測量溫度,在這個環節中,使用了一片HD7279晶片,用於動態顯示數碼管,為什麼使用這個晶片而不是使用微控制器直接驅動數碼管呢。這個是出於節省CPU資源的考慮,因為程式中使用了一些濾波演算法比較耗費CPU,而且考慮到可能需要使用485通訊,萬一等待時間過長,擔心因此造成數碼管閃爍,所以使用了一片HD7279。
這個是核心板輸出介面電路
關於這個晶片的使用方法就不多說了,datasheet上寫的非常清楚了。
當然,顯示部分的電路是和核心電路分開的,在另外一塊PCB上。下面是核心板的PCB
以下是標定資料,“溫度計”項代表使用標準水銀溫度計的測量值;“PT100“代表以上裝置測量得出的值;”誤差“為”PT100“-”溫度計“的值;”多項式“是採用多項式擬合後的到的值;”擬合後誤差”為”多項式“-”溫度計“的值;
溫度計 | PT100 | 誤差 |
多項式 | 擬合後誤差 |
2 | 6 | -4 | 2.3 | 0.3 |
2.7 | 6.7 | -4 | 3.1 | 0.4 |
3 | 7 | -4 | 3.5 | 0.5 |
4 | 8 | -4 | 4.7 | 0.7 |
7 | 10 | -3 | 7.2 | 0.2 |
8.9 | 11.1 | -2.2 | 8.5 | -0.4 |
9 | 12 | -3 | 9.6 | 0.6 |
9.2 | 11.3 | -2.1 | 8.8 | -0.4 |
9.2 | 12.4 | -3.2 | 10.1 | 0.9 |
9.5 | 11.4 | -1.9 | 8.9 | -0.6 |
10 | 11.7 | -1.7 | 9.3 | -0.7 |
10 | 12.8 | -2.8 | 10.6 | 0.6 |
10.2 | 12.2 | -2 | 9.9 | -0.3 |
11.2 | 12.8 | -1.6 | 10.6 | -0.6 |
11.5 | 14.2 | -2.7 | 12.3 | 0.8 |
12 | 13 | -1 | 10.8 | -1.2 |
12 | 14 | -2 | 12.0 | 0.0 |
12.2 | 13.9 | -1.7 | 11.9 | -0.3 |
13 | 15 | -2 | 13.2 | 0.2 |
13.5 | 15.2 | -1.7 | 13.5 | 0.0 |
14 | 16 | -2 | 14.4 | 0.4 |
14 | 15.6 | -1.6 | 14.0 | 0.0 |
14.2 | 15.1 | -0.9 | 13.4 | -0.8 |
22.5 | 22.3 | 0.2 | 21.9 | -0.6 |
23 | 22.7 | 0.3 | 22.3 | -0.7 |
23.5 | 22.9 | 0.6 | 22.6 | -0.9 |
24 | 23.3 | 0.7 | 23.0 | -1.0 |
24.5 | 24.9 | -0.4 | 24.9 | 0.4 |
24.5 | 23.8 | 0.7 | 23.6 | -0.9 |
25 | 25.2 | -0.2 | 25.2 | 0.2 |
25 | 24.3 | 0.7 | 24.2 | -0.8 |
25.5 | 25.7 | -0.2 | 25.8 | 0.3 |
26 | 26.2 | -0.2 | 26.4 | 0.4 |
26.5 | 26.6 | -0.1 | 26.9 | 0.4 |
27 | 27.1 | -0.1 | 27.4 | 0.4 |
27.5 | 27.4 | 0.1 | 27.8 | 0.3 |
28 | 27.8 | 0.2 | 28.2 | 0.2 |
28.5 | 28.2 | 0.3 | 28.7 | 0.2 |
29 | 28.7 | 0.3 | 29.3 | 0.3 |
29.5 | 29 | 0.5 | 29.6 | 0.1 |
30 | 29.5 | 0.5 | 30.2 | 0.2 |
30.7 | 30 | 0.7 | 30.7 | 0.0 |
31 | 30.3 | 0.7 | 31.1 | 0.1 |
31.5 | 30.7 | 0.8 | 31.5 | 0.0 |
32 | 31 | 1 | 31.9 | -0.1 |
32 | 31.2 | 0.8 | 32.1 | 0.1 |
32.5 | 32.6 | -0.1 | 33.7 | 1.2 |
32.5 | 31.6 | 0.9 | 32.5 | 0.0 |
33 | 32.1 | 0.9 | 33.1 | 0.1 |
34 | 33 | 1 | 34.1 | 0.1 |
34.5 | 33.4 | 1.1 | 34.5 | 0.0 |
38 | 36.2 | 1.8 | 37.7 | -0.3 |
39 | 37 | 2 | 38.5 | -0.5 |
40 | 38 | 2 | 39.6 | -0.4 |
41 | 39 | 2 | 40.7 | -0.3 |
42 | 40.5 | 1.5 | 42.4 | 0.4 |
44 | 41.7 | 2.3 | 43.6 | -0.4 |
45 | 42.6 | 2.4 | 44.6 | -0.4 |
46 | 43.5 | 2.5 | 45.6 | -0.4 |
47 | 44.6 | 2.4 | 46.8 | -0.2 |
48 | 45.6 | 2.4 | 47.8 | -0.2 |
49 | 46.5 | 2.5 | 48.8 | -0.2 |
50 | 47.6 | 2.4 | 49.9 | -0.1 |
51 | 48.5 | 2.5 | 50.9 | -0.1 |
54 | 51.5 | 2.5 | 54.0 | 0.0 |
55 | 52.5 | 2.5 | 55.0 | 0.0 |
56 | 53.5 | 2.5 | 56.0 | 0.0 |
58 | 55.5 | 2.5 | 58.1 | 0.1 |
59.2 | 56.5 | 2.7 | 59.1 | -0.1 |
60 | 57.5 | 2.5 | 60.1 | 0.1 |
61 | 58.3 | 2.7 | 60.9 | -0.1 |
62 | 59.4 | 2.6 | 62.0 | 0.0 |
63 | 60.5 | 2.5 | 63.1 | 0.1 |
64 | 61.5 | 2.5 | 64.1 | 0.1 |
65.2 | 62.5 | 2.7 | 65.1 | -0.1 |
66 | 63.5 | 2.5 | 66.0 | 0.0 |
67.2 | 64.5 | 2.7 | 67.0 | -0.2 |
68 | 65.5 | 2.5 | 68.0 | 0.0 |
70 | 67.6 | 2.4 | 70.0 | 0.0 |
71 | 68.2 | 2.8 | 70.6 | -0.4 |
72 | 69.4 | 2.6 | 71.7 | -0.3 |
73 | 70.5 | 2.5 | 72.8 | -0.2 |
74 | 71.5 | 2.5 | 73.7 | -0.3 |
75 | 72 | 3 | 74.2 | -0.8 |
76 | 74 | 2 | 76.0 | 0.0 |
77.5 | 74.9 | 2.6 | 76.9 | -0.6 |
78 | 76 | 2 | 77.9 | -0.1 |
上圖中X軸為PT100的值,Y軸為溫度計的值,可以看出多項式擬合的效果更好一些
以下是實物效果:
下面是程式程式碼:
#include <intrins.h>
#include <STC12C5A60S2.H>
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short WORD;
float code RTD_TAB_PT100[151] = // 表格是以1度為一步,即-20, -19, -18.....
{
88.22, 88.62 ,88.62, 89.40, 89.80, 90.19, 90.59, 90.98, 91.37, 91.77, // -30 ~ -21
92.16, 92.55, 92.95, 93.34, 93.73, 94.12, 94.52, 94.91, 95.30, 95.69, // -20 ~ -11
96.09, 96.48, 96.87, 97.26, 97.65, 98.04, 98.44, 98.83, 99.22, 99.61, // -10 ~ -1
100.00,100.39,100.78,101.17,101.56,101.95,102.34,102.73,103.13,103.51, // 0 ~ 9
103.90,104.29,104.68,105.07,105.46,105.85,106.24,106.63,107.02,107.49, // 10 ~ 19
107.79,108.18,108.57,108.96,109.35,109.73,110.12,110.51,110.90,111.28, // 20 ~ 29
111.67,112.06,112.45,112.83,113.22,113.61,113.99,114.38,114.77,115.15, // 30 ~ 39
115.54,115.93,116.31,116.70,117.08,117.47,117.86,118.24,118.62,119.01, // 40 ~ 49
119.40,119.78,120.16,120.55,120.93,121.32,121.70,122.09,122.47,122.86, // 50 ~ 59
123.24,123.62,124.01,124.39,124.77,125.16,125.54,125.92,126.31,126.69, // 60 ~ 69
127.07,127.45,127.84,128.22,128.60,128.98,129.37,129.75,130.13,130.51, // 70 ~ 79
130.89,131.27,131.66,132.04,132.42,132.80,133.18,133.56,133.94,134.32, // 80 ~ 89
134.70,135.08,135.46,135.84,136.22,136.60,136.98,137.36,137.74,138.12, // 90 ~ 99
138.50,138.88,139.26,139.64,140.02,140.39,140.77,141.15,141.53,141.91, // 100 ~ 109
142.29,142.66,143.04,143.42,143.80,144.17,144.55,144.93,145.31,145.68, // 110 ~ 119
146.06 // 120
};
sbit beep = P3^5;
//----------------ADS1110地址、配置字-----------------//
#define ADS1110_WR_ADDRESS 0x92 // 1001 001 0 寫
#define ADS1110_RD_ADDRESS 0x93 // 1001 001 1 讀
#define ADS1110_CONFIG_REG 0x8C // 連續轉換模式,16bit精度,PGA=1
sbit ADS1110_SDA = P1^5; // 模擬I2C資料傳輸位
sbit ADS1110_CLK = P1^6; // 模擬I2C時鐘控制位
//uchar TMR_H, TMR_L; // AD轉換高8位,和低8位
uint AD_Result[25];
unsigned long nTmp;
//*** HD7279 函式定義 ***
void long_delay(void); // 長延時
void short_delay(void); // 短暫延時
void delay10ms(unsigned char); // 延時10MS
void write7279(uchar, uchar); // 寫入到HD7279
uchar read7279(uchar); // 從HD7279讀出
void send_byte(uchar); // 傳送一個位元組
uchar receive_byte(void); // 接收一個位元組
sbit cs =P0^7; // cs at P1.4
sbit clk=P0^6; // clk 連線於 P1.5
sbit dat=P0^5; // dat 連線於 P1.2
sbit key=P0^4; // key 連線於 P1.3
sbit Hight_LED = P4^6;
sbit Low_LED = P4^1;
//****** HD7279A 指令 ******
#define CMD_RESET 0xa4
#define CMD_TEST 0xbf
#define DECODE0 0x80
#define DECODE1 0xc8
#define CMD_READ 0x15
#define UNDECODE 0x90
#define RTL_CYCLE 0xa3
#define RTR_CYCLE 0xa2
#define RTL_UNCYL 0xa1
#define RTR_UNCYL 0xa0
#define ACTCTL 0x98
#define SEGON 0xe0
#define SEGOFF 0xc0
#define BLINKCTL 0x88
//-------- AT24C04 變數宣告 ---------
sbit _24C02_SCL = P2^6; //AT24C04的時鐘
sbit _24C02_SDA = P2^5; //AT24C04的資料
uchar BUF[16]; //資料快取區
uint code nDefaultDATA[] =
{// nLowTMP nHightTMP nTMPAdj
480, 650, 0 // 預設設定
};
uint nSettingDATA[3] = {0, 0, 0}; // 當前設定
void Delay5us();
void AT24C04_Start();
void AT24C04_Stop();
void AT24C04_SendACK(bit ack);
bit AT24C04_RecvACK();
void AT24C04_SendByte(uchar dat);
uchar AT24C04_RecvByte();
void AT24C04_ReadPage();
void AT24C04_WritePage();
//****** 紅外接收 ******
sbit IRIN = P3^3; //紅外接收器資料線
uchar IRCOM[7];
uchar nFlag = 0;
uchar nMode = 1; // nMode 0 1 2 3
// mean NULL nLowTMP nHightTMP nTMPAdj
uint nLowTMP = 480; // 最低溫度設定
uint nHightTMP = 650; // 最高溫度設定
char nTMPAdj = 0; // 溫度修正
void send_ad_result(uchar temp);
/***********************************************************************************
************************************************************************************
////////////////////////////////HD 7279 函式////////////////////////////////////////
************************************************************************************
************************************************************************************/
void write7279(uchar cmd, uchar dta)
{
cs = 0;
send_byte (cmd);
send_byte (dta);
cs = 1;
}
uchar read7279(uchar command)
{
cs = 0;
send_byte(command);
return(receive_byte());
cs = 1;
}
void send_byte( uchar out_byte)
{
uchar i;
cs=0;
long_delay();
for (i=0;i<8;i++)
{
if (out_byte&0x80)
{
dat=1;
}
else
{
dat=0;
}
clk=1;
short_delay();
clk=0;
short_delay();
out_byte=out_byte*2;
}
dat=0;
}
uchar receive_byte(void)
{
uchar i, in_byte;
dat=1; // set to input mode
long_delay();
for (i=0;i<8;i++)
{
clk=1;
short_delay();
in_byte=in_byte*2;
if (dat)
{
in_byte=in_byte|0x01;
}
clk=0;
short_delay();
}
dat=0;
return (in_byte);
}
void delay10ms(uint time) //誤差 -0.000000000001us
{
uchar a,b,c;
uint i;
for (i=0;i<time;i++)
{
for(c=7;c>0;c--)
for(b=168;b>0;b--)
for(a=24;a>0;a--);
}
}
void long_delay(void)
{
unsigned char i;
for (i=0;i<0x30;i++);
}
void short_delay(void)
{
unsigned char i;
for (i=0;i<8;i++);
}
/***********************************************************************************
************************************************************************************
////////////////////////////////HD 7279 函式 END////////////////////////////////////////
************************************************************************************
************************************************************************************/
//--------------------- 模組延時程式_1ms -------------------------
void delay1ms(uint delay1ms) //STC11F60XE,延時1ms
{
uchar a,b;
// 12M
// for(;delay1ms>0;delay1ms--)
// for(b=222;b>0;b--)
// for(a=12;a>0;a--);
// 11.0592M
for( ; delay1ms > 0; delay1ms--)
for(b = 21; b > 0; b--)
for(a = 130; a > 0; a--);
}
void Delay5us() // 晶振11.0592M 誤差 -0.026765046296us
{
uchar a;
for(a=12;a>0;a--);
_nop_();
}
void delay(uint delay) //STC11F60XE,12M,延時170us
{
uchar a,b;
// 12M
// for(;delay>0;delay--)
// for(b=78;b>0;b--)
// for(a=5;a>0;a--);
// 11.0592M
for( ; delay > 0; delay--)
for( b = 2; b > 0; b--)
for( a = 232; a > 0; a--);
}
//--------------------- 數碼管顯示函式 -------------------------
void Display_TMP(uint nTmp1)
{
//send_byte(CMD_RESET);
write7279(DECODE0,nTmp1/100%100);
delay1ms(2);
write7279(DECODE0+1,nTmp1/10%10);
delay1ms(2);
write7279(SEGON,15);
delay1ms(2);
write7279(DECODE0+2,nTmp1%10);
delay1ms(2);
write7279(SEGON,63);
delay1ms(2);
write7279(SEGON,62);
delay1ms(2);
write7279(SEGON,61);
delay1ms(2);
write7279(SEGON,60);
delay1ms(2);
write7279(SEGON,59);
delay1ms(2);
//delay10ms(1000);
//send_byte(CMD_RESET);
}
void Display_SETTMP(uint nTmp2)
{
//send_byte(CMD_RESET);
write7279(DECODE0+4,nTmp2/100%100);
delay1ms(2);
write7279(DECODE0+5,nTmp2/10%10);
delay1ms(2);
write7279(SEGON,47);
delay1ms(2);
write7279(DECODE0+6,nTmp2%10);
delay1ms(2);
write7279(SEGON,31);
delay1ms(2);
write7279(SEGON,30);
delay1ms(2);
write7279(SEGON,29);
delay1ms(2);
write7279(SEGON,28);
delay1ms(2);
write7279(SEGON,27);
delay1ms(2);
//delay10ms(1000);
//send_byte(CMD_RESET);
}
void Display_SET()
{
send_byte(CMD_RESET);
if (nMode == 1) // set nLowTMP
{
write7279(SEGON,1);
delay1ms(2);
write7279(SEGON,2);
delay1ms(2);
write7279(SEGON,3);
delay1ms(2);
write7279(DECODE0+4,nLowTMP/100%100);
delay1ms(2);
write7279(DECODE0+5,nLowTMP/10%10);
delay1ms(2);
write7279(SEGON,47);
delay1ms(2);
write7279(DECODE0+6,nLowTMP%10);
}
if (nMode == 2) // set nHightTMP
{
write7279(SEGON,0);
delay1ms(2);
write7279(SEGON,1);
delay1ms(2);
write7279(SEGON,2);
delay1ms(2);
write7279(SEGON,4);
delay1ms(2);
write7279(SEGON,5);
delay1ms(2);
write7279(DECODE0+4,nHightTMP/100%100);
delay1ms(2);
write7279(DECODE0+5,nHightTMP/10%10);
delay1ms(2);
write7279(SEGON,47);
delay1ms(2);
write7279(DECODE0+6,nHightTMP%10);
}
if (nMode == 2) // set nTMPAdj
{
write7279(SEGON,0);
delay1ms(2);
write7279(SEGON,1);
delay1ms(2);
write7279(SEGON,2);
delay1ms(2);
write7279(SEGON,4);
delay1ms(2);
write7279(SEGON,5);
delay1ms(2);
write7279(SEGON,6);
delay1ms(2);
if (nTMPAdj < 0)
{
write7279(SEGON,32);
delay1ms(2);
write7279(DECODE0+5,(0-nTMPAdj)/10%10);
delay1ms(2);
write7279(DECODE0+6,(0-nTMPAdj)%10);
}
if (nTMPAdj > 0)
{
write7279(DECODE0+5,nTMPAdj/10%10);
delay1ms(2);
write7279(DECODE0+6,nTMPAdj%10);
}
}
}
/***********************************************************************************
************************************************************************************
////////////////////////////////紅外解碼 函式-BEGIN/////////////////////////////////
************************************************************************************
************************************************************************************/
void IR_IN() interrupt 2 using 0
{
return ;
}
/***********************************************************************************
////////////////////////////////紅外解碼 函式 END////////////////////////////////////
************************************************************************************/
/***********************************************************************************
************************************************************************************
////////////////////////////////AD1110 轉換 -BEGIN/////////////////////////////////
************************************************************************************
************************************************************************************/
/*******************************************************************************
名稱:ads1110Start(void)
功能:ADS1110 I2C Start
********************************************************************************/
void ads1110Start(void)
{
ADS1110_SDA = 1;
_nop_(); _nop_(); _nop_();_nop_(); _nop_();
ADS1110_CLK = 1;
_nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
ADS1110_SDA = 0;
_nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
}
/*******************************************************************************
名稱:ads1110Stop(void)
功能:ADS1110 I2C Stop
********************************************************************************/
void ads1110Stop(void)
{
ADS1110_SDA = 0;
_nop_(); _nop_();_nop_(); _nop_();_nop_(); _nop_();
ADS1110_CLK = 1; // -----------結束I2C匯流排.
_nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();_nop_(); _nop_();
ADS1110_SDA = 1;
_nop_(); _nop_(); _nop_();
}
/*******************************************************************************
名稱:waitAck(void)
功能:ADS1110 I2C 等待ack
********************************************************************************/
uchar waitAck(void)
{
uint i = 0;
ADS1110_CLK = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
while((ADS1110_SDA==1)&&(i<500))
i++;
ADS1110_CLK = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
return 0x00;
}
/*******************************************************************************
名稱:void sendAck(void)
功能:向ADS1110 I2C 傳送 ack
********************************************************************************/
void sendAck(void)
{
ADS1110_SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
ADS1110_CLK=1;
_nop_();
_nop_();
_nop_();
_nop_();
ADS1110_CLK=0;
}
/*******************************************************************************
名稱:void sendNotAck(void)
功能:向ADS1110 I2C 不傳送 ack
********************************************************************************/
void sendNotAck(void)
{
ADS1110_SDA=1;
_nop_();
_nop_();
_nop_();
_nop_();
ADS1110_CLK=1;
_nop_();
_nop_();
_nop_();
_nop_();
ADS1110_CLK=0;
}
/*******************************************************************************
名稱:void ads1110SendByte(uchar sendData)
功能:向ADS1110 I2C 傳送1個位元組
********************************************************************************/
void ads1110SendByte(uchar sendData)
{
uchar i,temp;
temp = sendData;
for(i=0;i<8;i++)
{
temp = temp << 1;
ADS1110_CLK = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); _nop_();
ADS1110_SDA = CY;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
ADS1110_CLK = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}
ADS1110_CLK = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
ADS1110_SDA = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}
/*******************************************************************************
名稱:uchar ads1110ReceiveByte(void)
功能:ADS1110 I2C 接收1個位元組
********************************************************************************/
uchar ads1110ReceiveByte(void)
{
uchar i,k;
ADS1110_CLK = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); _nop_();
ADS1110_SDA = 1;
_nop_(); _nop_();_nop_(); _nop_();_nop_(); _nop_();
for(i=0;i<8;i++)
{
ADS1110_CLK = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
k= (k << 1)| ADS1110_SDA;
ADS1110_CLK = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
return k;
}
/*******************************************************************************
名稱:ads1110Config(void)
功能:對ADS1110進行配置
********************************************************************************/
void ads1110Config(void)
{
ads1110Start();
ads1110SendByte(ADS1110_WR_ADDRESS);
waitAck();
ads1110SendByte(ADS1110_CONFIG_REG);
waitAck();
ads1110Stop();
}
/*******************************************************************************
名稱:讀取ADS1100資料子程式
功能:
********************************************************************************/
uint RD_ADS()
{
uchar temp;
uint W_B1byte_high, W_B1byte_low, W_B1_word;
ads1110Start();
ads1110SendByte(ADS1110_RD_ADDRESS);
temp = waitAck();
if(!temp)
{
W_B1byte_high /*= TMR_H*/ = ads1110ReceiveByte();
sendAck();
W_B1byte_low /*= TMR_L*/ = ads1110ReceiveByte();
sendAck();
temp = ads1110ReceiveByte();
ads1110Stop();
W_B1_word = (W_B1byte_high << 8)+ W_B1byte_low;
if (W_B1_word > 0x7fff)
W_B1_word = 0;
return W_B1_word;
}
else
return 0x0000;
}
/*******************************************************************************
名稱: 取AD結果函式
功能: 它是16位AD轉換,連續去制25次,去掉3最大值和3個最小值,剩下19個取平均值
返回: 平均取值
********************************************************************************/
uint get_ad_result()
{
uchar i,j;
uint temp;
nTmp = 0;
for(i = 0; i < 25; i++) // 連續取值25次
{
AD_Result[i] = RD_ADS();
delay1ms(10);
}
for(i = 1; i< 25; i++) // 插入法對取的25個值進行排序
{
temp = AD_Result[i]; //store the original sorted array in temp
for(j=i ; j>0 && temp < AD_Result[j-1] ; j--) //compare the new array with temp
{
AD_Result[j] = AD_Result[j-1]; //all larger elements are moved one pot to the right
}
AD_Result[j] = temp;
}
// for(i = 3; i < 22; i++) // 去掉3最大值和3個最小值,餘下19個值求和
// {
// nTmp = nTmp + AD_Result[i];
// }
return AD_Result[12]; //nTmp / 19; // 取剩下19個數平均值
//ad_average_result=ad_average_result*4*5000/1024;
}
/*******************************************************************************
名稱: 串列埠傳送函式
功能: 取AD結果函式傳送到串列埠,方便除錯
返回: 無
********************************************************************************/
void send_ad_result(uchar temp)
{
SBUF = temp;
while(TI == 0) ;
TI = 0;
delay1ms(100);
//SBUF=R>>4;
}
/*******************************************************************************
名稱: 初始化函式
功能: 設定串列埠相關暫存器值,波特率取9600, 12T模式
返回: 無
********************************************************************************/
void _initiate() //初始化函式
{
EA = 1;
ES = 0;
TMOD = 0x20; // 定時計數器方式控制暫存器,"自動重灌,16位計數器".
SCON = 0x50; // 序列控制暫存器,方便在串列埠助手那觀察
// 12M
// TH1 = 0xF3; // 定時器初值高8位設定
// TL1 = 0xF3; // 定時器初值低8位設定
// 11.0592M 波特率 9600
TH1 = 0xFD; // 定時器初值高8位設定
TL1 = TH1; // 定時器初值低8位設定
PCON = 0x00;
TR1 = 1;
// IE = 0x84; // 允許總中斷中斷,使能 INT1 外部中斷
EX1 = 1;
// TCON = 0x10; // 觸發方式為脈衝負邊沿觸發
}
/*******************************************************************************
名稱: 蜂鳴器函式
功能: 設定蜂鳴器鳴響
返回: 無
********************************************************************************/
void Beep(uchar nSet)
{
}
/****************************************/
/****************************************/
//------------ AT24C04 驅動函式 --------------
/**************************************
向AT24C04寫1頁(16位元組)資料
將TESTDATA開始的16個測試資料寫如裝置的00~0F地址中
**************************************/
void AT24C04_WritePage()
{
uchar i;
AT24C04_Start(); //起始訊號
AT24C04_SendByte(0xa0); //傳送裝置地址+寫訊號
AT24C04_SendByte(0x00); //傳送儲存單元地址
for (i=0; i<3; i++)
{
AT24C04_SendByte(nSettingDATA[i]);
}
AT24C04_Stop(); //停止訊號
}
/**************************************
從AT24C04讀取1頁(16位元組)資料
將裝置的00~0F地址中的資料讀出存放在DATA區的BUF中
**************************************/
void AT24C04_ReadPage()
{
uchar i;
AT24C04_Start(); //起始訊號
AT24C04_SendByte(0xa0); //傳送裝置地址+寫訊號
AT24C04_SendByte(0x00); //傳送儲存單元地址
AT24C04_Start(); //起始訊號
AT24C04_SendByte(0xa1); //傳送裝置地址+讀訊號
for (i=0; i<16; i++)
{
BUF[i] = AT24C04_RecvByte();
if (i == 15)
{
AT24C04_SendACK(1); //最後一個數據需要會NAK
}
else
{
AT24C04_SendACK(0); //迴應ACK
}
}
AT24C04_Stop(); //停止訊號
}
/**************************************
起始訊號
**************************************/
void AT24C04_Start()
{
_24C02_SDA = 1; //拉高資料線
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
_24C02_SDA = 0; //產生下降沿
Delay5us(); //延時
_24C02_SCL = 0; //拉低時鐘線
}
/**************************************
停止訊號
**************************************/
void AT24C04_Stop()
{
_24C02_SDA = 0; //拉低資料線
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
_24C02_SDA = 1; //產生上升沿
Delay5us(); //延時
}
/**************************************
傳送應答訊號
入口引數:ack (0:ACK 1:NAK)
**************************************/
void AT24C04_SendACK(bit ack)
{
_24C02_SDA = ack; //寫應答訊號
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
_24C02_SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
/**************************************
接收應答訊號
**************************************/
bit AT24C04_RecvACK()
{
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
CY = _24C02_SDA; //讀應答訊號
_24C02_SCL = 0; //拉低時鐘線
Delay5us(); //延時
return CY;
}
/**************************************
向IIC匯流排傳送一個位元組資料
**************************************/
void AT24C04_SendByte(uchar dat)
{
uchar i;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1; //移出資料的最高位
_24C02_SDA = CY; //送資料口
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
_24C02_SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
AT24C04_RecvACK();
}
/**************************************
從IIC匯流排接收一個位元組資料
**************************************/
uchar AT24C04_RecvByte()
{
uchar i;
uchar dat = 0;
_24C02_SDA = 1; //使能內部上拉,準備讀取資料
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1;
_24C02_SCL = 1; //拉高時鐘線
Delay5us(); //延時
dat |= _24C02_SDA; //讀資料
_24C02_SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
return dat;
}
/***********************************************************************
*FunName: float CalculateTemperature(float fR)
*
*In: fR -> PT100的電阻值。
*
*Out: fTem -> 測得的溫度值。
*
*Discription: 將電阻值查表算出溫度值。
*
*Notes: 採用2分查詢法。
*
************************************************************************/
float CalculateTemperature(float fR)
{
float fTem;
float fLowRValue;
float fHighRValue;
int iTem;
uchar i;
uchar cBottom, cTop;
if (fR < RTD_TAB_PT100[0]) // 電阻值小於表格最小值,低於量程下限。
{
return 210;
}
if (fR > RTD_TAB_PT100[150]) // 電阻值大於表格最大值,超出量程上限。
{
return 211;
}
cBottom = 0;
cTop = 150;
for (i=75; (cTop-cBottom)!=1; ) // 2分法查表。
{
if (fR < RTD_TAB_PT100[i])
{
cTop = i;
i = (cTop + cBottom) / 2;
}
else if (fR > RTD_TAB_PT100[i])
{
cBottom = i;
i = (cTop + cBottom) / 2;
}
else
{
iTem = (uint)i - 30;
fTem = (float)iTem;
return fTem;
}
}
iTem = (uint)i - 30;
send_ad_result(0x00);
fLowRValue = RTD_TAB_PT100[cBottom];
fHighRValue = RTD_TAB_PT100[cTop];
send_ad_result(cBottom);
send_ad_result(cTop);
fTem = ( (fR - fLowRValue) / (fHighRValue - fLowRValue) ) + iTem; // 表格是以5度為一步的。
// 兩點內插進行運算。
return fTem;
}
/*******************************************************************************
名稱: main
功能: 主函式
返回: 無
********************************************************************************/
void main()
{
uint result,tmr,nResult_TMP;
uchar TMR_H, TMR_L, nTemp_1,nTemp_2,nTemp_3;
float fTMP;
nTemp_1 = 2;
nTemp_2 = 3;
nTemp_3 = 0;
// 設定看門狗 EN_WDT = 1,CLR_WDT = 1,IDLE_WDT = 1, PS2 = 1,PS1 = 1,PS0 = 1
WDT_CONTR = 0x3f;
IRIN=1;
_initiate(); // 初始化
ads1110Config(); // 配置ADS1110,採用連續轉換模式,16bit精度,PGA=1
// 則取樣電壓值為 V = (OutCode * 2.048) / 32768
P1M0 |= 0x00; // 設P1_7為高阻模式 如: P1_0= #00000000B
P1M1 |= 0x80;
//AT24C04_ReadPage();
delay(10);
for (tmr=0; tmr<0x2000; tmr++); // 上電延時
send_byte(CMD_RESET); // 復位HD7279A
delay1ms(5);
Display_TMP(230); // 設定初始值23.0℃
delay1ms(5);
Display_SETTMP(550); // 設定初始值55.0℃
while(1)
{
result = get_ad_result(); // ADC取樣,25次,中值濾波法
TMR_H = (result >> 8) & 0xff; // 取高八位
TMR_L = result & 0xff; // 取低八位
//send_ad_result(TMR_H);
//send_ad_result(TMR_L);
//lTmp = result
fTMP = ((result*2.048)/32768 + 0.0029) / 11 / 0.001021; // 用ADC轉換的電壓值計算電阻
//send_ad_result(0x00);
delay1ms(10);
fTMP = CalculateTemperature(fTMP); // 查表法轉換溫度值
// 根據實際標定結果進行資料擬合,得到公式-----實際溫度 = -0.0023*測量溫度*測量溫度 + 1.2692*測量溫度 - 5.2778
nResult_TMP = (uint)(10*(-0.0023*fTMP*fTMP + 1.2692*fTMP - 5.2778)) + nTMPAdj;
if (nTemp_1 != (nResult_TMP/100%100))
{
write7279(DECODE0,nResult_TMP/100%100);
nTemp_1 = nResult_TMP/100%100;
}
if (nTemp_2 != (nResult_TMP/10%10))
{
write7279(DECODE0+1,(nResult_TMP/10%10)|0x80);
nTemp_2 = nResult_TMP/10%10;
}
if (nTemp_3 != (nResult_TMP%100))
{
write7279(DECODE0+2,nResult_TMP%10);
nTemp_3 = nResult_TMP%10;
}
TMR_H = (nResult_TMP >> 8) & 0xff; // 取高八位
TMR_L = nResult_TMP & 0xff; // 取低八位
send_ad_result(TMR_H);
send_ad_result(TMR_L);
WDT_CONTR = 0x3f; // 喂狗 間隔9.1022s
}
}
執行視訊可以到以下地址觀看:
https://v.youku.com/v_show/id_XMTc0OTg0NjUyOA==.html?spm=a2hzp.8244740.0.0