Digital pH MeterWichit Sirichote, kswichit@kmitl.ac.th
Build a digital readout instrument for displaying pH scale from mV output of the pH glass electrode using the 8051 microcontroller.
Abstract: A prototype of the digital readout instrument designed for pH glass electrode has been developed. The instrument has two circuit boards, i.e. main board and display board. The main board is built with the 89V51RD2, 64kB Flash microcontroller, two channels digit digital voltmeter chips, ICL7135, and the Femtoampere input high precision amplifier, LMP7721. The display board is built with MAX7219, 7-segment display controller. The input DC potential range is +/-1.0000V with 100 mV sensitivity. The potential from glass electrode is converted to pH scale using Nernst equation. Temperature correction for the pH reading is computed by using the built-in temperature sensor, LM35 or manual set at 25.0C. Calibration of the pH probe uses 3-point standard buffers i.e. pH 4.00, pH 7.00 and pH 10.00. In addition, the meter also provides RS232 port for interfacing to the PC.
Figure 1: The prototype of Digital pH Meter and pH probe. A simplified block diagram of the digital pH meter is shown in Figure 2. A digital pH meter measures the potential difference (in mV) then converts it to pH scale with temperature correction. The pH probe is made of glass electrode. Its characteristic is a very high internal resistance (>10^8 Ohms). To feed the signal from the glass electrode to the analog-to-digital converter thus needs a very high input resistance buffer amplifier. The DC signal produced from the electrode is +/-414.0mV. The analog-to-digital converter (ADC) converts analog voltage to digital data. The microcontroller reads the digital data, performs digital filtering and converts it to pH scale using Nernst equation. The pH readings will then be displayed by the display board.
Figure 2: Block diagram. Hardware descriptions: The complete schematic for the main board is shown in Figure 3. The MCU is 8051 compatible, NXP89V51RD2, 64kB Flash microcontroller. The ADC is ICL7135, integrating type analog to digital converter. The first ADC is used to digitize the output from pH glass probe and the second ADC is for LM35 temperature sensor. Interfacing between ADC and MCU is done by 4-bit BCD reading. The very high impedance opamp, LMP7721 is used to buffer between pH probe and ADC's input. The high precision reference voltage is LM4140. The I2C EEPROM, 24C16 is for parameters settings.
Figure 3: Hardware schematic of the main board(click to enlarge). Figure 4 shows the display board schematic using MAX7219. Each chip drives 8-digit 7-sement LED. The serial data out from the 1st MAX7219 is tied to data in of the 2nd MAX7219. This configuration forms the 32-bit shift register (the control byte and data byte is 16-bit word).
Figure 4: Hardware schematic of the display board(click to enlarge). The circuit is built using double sides PCB, Figure 5 shows the component placement on the TOP layer. The pH probe connector is BNC type with teflon insulation.
Figure 5: Components placement. The source code listing is shown in Figure 6. The main program is forever loop reading the BCD output from the ICL7135 continuously.
/*
Digital pH meter ProjectInput buffer amplifier LMP7721 femtoampere precision amplifier
input signal max +/- 1.0000V 100 uV sensitivity
pH display 0.00 to 14.00
Built-in temperature sensor LM35
calibration mode: 3-point using standard buffer 4.00 7.00 and 10.00
Serial interface: RS232C 9600 8n1
Power Supply: 220VAC 5VACopyright(c) 2012 Faculty of Science, King Mongkut's Institute of Technology Ladkrabang
Bangkok THAILAND
programmer: Wichit Sirichote,kswichit@kmitl.ac.th, September 5, 2011
9 September 2011 add serial commands for setting printing interval
21 September 2011 adjust printable fro mat for event with entry command
25 October 2012 Test NXP 89V51RD2 with IAP by serial boot loader
28 October 2012 test displaying pH reading with 59.16mV/pH
pH = EMF/59.16 + 7 (@25C)
3 November 2012 using 768 bytes expanded RAM with xdata modifier
the EXTRAM bit is 0 by default after reset thus the expanded RAM
can be accessed easily via xdata modifier7 November 2012 check ADC's clock, 125kHz app reared at pin1 of the MCU
25 December 2012 -test with dry cell input 0-1.2V with 25 turns POT voltage divider circuit
change biasing resistor at LM385 from 10k to 1k. This provides +/-1.2V
power supply for the LMP7721
27 December 2012 compute pH reading from Nernst equation
E = E0 - RT/F ln(Q)
R = 8.314472(15) JK-1 mol-1
F = 9.64853399(24)ื10^4 Cmol-1
T = absolute temperature in K 273.15 (0C)
convert from net ural log to common log factor is 2.30258E = E0 - [(8.314472 [273.15+C])/9.64853399(24)ื10^4]*2.30258
@25C
E = E0 - 59.16 pH
28 December 2012
sensitivity= 1.984212002*(273.15+temperature(C))30 December 2012 add calibration mode using 3-point standard buffer
4.00, 7.00 and 10.00
The linear regression method has been used for determining
the equation.- test EEPROM coding
31 December 2012 EEPROM needs small delay after write
save calibrated A and b to EEPROM
Y = A + bXA and b are converted to 32-bit long number by multiplying with 1E6
longA= A*1E6;
longb= b*1E6;On the next reset, these parameters are then restored
-provide command to program the value of 3-point standard buffer
the values of each standard buffer, i.e. 4.00, 7.00, and 10.00 will be
programmed into the eeprom13 January 2013 test pH probe bought from ebay
*/
#include <stdlib.h>
#include "AT89X52.H"
#include "stdio.h"#define Voffset 0 // offset voltage
sbit SCL = P1^3;
sbit SDA = P1^4;sbit CLK= P1^7;
sbit DIN= P1^6;
sbit LOAD= P1^5;sbit D5 = P0^4;
sbit P2D5 = P2^4;int digit=5;
int digit2=5;
xdata char sbuffer[8];
xdata char sbuffer2[8];
xdata unsigned char buffer[16];
char command;
int i;char bdata flag=0;
char bdata flag1=0;
char bdata flag2=0;
char bdata flag3=0;sbit ready = flag^0;
sbit ready2 = flag^1;
sbit terminal = flag^2;
sbit pol = flag^3;
sbit ov = flag^4;
sbit pol2 = flag^5;
sbit ov2 = flag^6;
sbit fire = flag^7;sbit once = flag1^0;
sbit key1_press = flag2^0;
sbit channel1_display = flag2^1;sbit key3_press = flag2^2;
sbit manual_auto = flag2^3;sbit calibrate_mode = flag2^4;
sbit key4_press = flag2^5;
sbit key2_press = flag2^6;
sbit calibrated = flag2^7; // set when the meter has been calibratedsbit clear_display = flag3^0;
sbit disable_key4 = flag3^1;int V1=0;
int V2=0;
int tV1,tV2,tV3;
//unsigned int temp16;float pH;
float temperature;unsigned long temp32=0;
sbit RUN = P1^1;
code char convert[10] = {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b};
code char title[]="\n\rDigital pH Meter V1.1 (? help)";/* 7-segment pattern converting array
a
__ register data
f |__| b D7 D6 D5 D4 D3 D2 D1 D0
e |__| c.DP DP a b c d e f g
d
*/char code prompt[] = "\n\r>";
char mode='a';short tick;
int second=0;
int interval=1;unsigned int sample=1;
//short fire=0;
xdata char xbuffer[32]; // try the expanded RAM of the RD2 chip
sbit key1 = P3^4;
sbit key2 = P3^5;
sbit key3 = P3^6;
sbit key4 = P3^7;xdata unsigned int x[5],y[3];
xdata timer3=0;xdata long time_up=0;
xdata int set_temperature=250; // set temperature manually, default = 25.0C
xdata float temp,mVpH;
xdata char calibrate_point=0;// variables for linear curve fitting
xdata float sumXY,sumXX,sumYY;xdata float X1[3],Y1[3];
xdata float sumX,sumY;
xdata long XY[3],XX[3],YY[3];
xdata float d1,d2,d3,d4,d5;
xdata float A=0.0;
xdata float b=0.0;xdata char time_over=0;
xdata long longA,longb;xdata long sbuffer4;
xdata long sbuffer7;
xdata long sbuffer10;
// function prototype declaration
void get_key();
void write24c16long(unsigned int address, unsigned long ddata);
#define POLARITY 0x20
#define OVERRANGE 0x40#define buffer4 700 //400
#define buffer7 900 //700
#define buffer10 1400 //1000
// EEPROM address definition
#define eeprom_calibrated 0
#define eeprom_longA 2 // four bytes reserved
#define eeprom_longb 6 // four bytes reserved#define eeprom_buffer4 10
#define eeprom_buffer7 14
#define eeprom_buffer10 18
// driver for MAX7219 display controller
// shift 32-bit data to 7219 seriallyshift(long n)
{
char j;CLK = LOAD = 0;
for(j=0; j<32; j++)
{
DIN = n&0x80000000; // send data to 7219
CLK =1; // pulse CLK
CLK =0;
n<<=1; // shift left one bit
}
LOAD =1; // pulse LOAD
LOAD =0;
}init7219()
{
shift(0x0a010a01); /* intensity (middle) */
shift(0x0b070b07); /* scan limit 8 digits */
shift(0x09000900); /* no decode mode */
shift(0x0f000f00); /* disable test mode */
shift(0x0c010c01); /* normal operation */
}update7219()
{
init7219(); /* reinitialize everytime entering to this function */
temp32=0;
temp32 |= buffer[8];
temp32<<=16;
temp32|= buffer[0];
shift(0x01000100|temp32);temp32=0;
temp32 |= buffer[9];
temp32<<=16;
temp32|= buffer[1];
shift(0x02000200|temp32);
temp32=0;
temp32 |= buffer[10];
temp32<<=16;
temp32|= buffer[2];
shift(0x03000300|temp32);
temp32=0;
temp32 |= buffer[11]; // put decimal point
temp32<<=16;
temp32|= buffer[3];
shift(0x04000400|temp32);temp32=0;
temp32 |= buffer[12];
temp32<<=16;
temp32|= buffer[4];
shift(0x05000500|temp32);temp32=0;
temp32 |= buffer[13];
temp32<<=16;
temp32|= buffer[5];
shift(0x06000600|temp32);
temp32=0;
temp32 |= buffer[14];
temp32<<=16;
temp32|= buffer[6];
shift(0x07000700|temp32);
temp32=0;
temp32 |= buffer[15];
temp32<<=16;
temp32|= buffer[7];
shift(0x08000800|temp32);
}
void timer0_isr (void) interrupt 1 using 3
{
TH0 |= 0xdc;timer3++;
if(++tick>100)
{
tick=0;
if(++second>=interval)
{
second=0;
fire=1;}
}
}
void ex0_isr (void) interrupt 0 using 1
{
if(D5) digit=5;
sbuffer[digit]= P0&0x0F;
// buffer[8-digit]=convert[sbuffer[digit]];
digit--;
if(digit==0) ready=1;
// read polarity, over range and under range
if(P0&POLARITY) pol=1;
else pol=0;
if(P0&OVERRANGE) ov=1;
else ov=0;
}void ex1_isr (void) interrupt 2 using 2
{
if(P2D5) digit2=5;
sbuffer2[digit2]= P2&0x0F;
// buffer[16-digit2]=convert[sbuffer2[digit2]];
digit2--;
if(digit2==0) ready2=1;
// read polarity, over range and under range
if(P2&POLARITY) pol2=1;
else pol2=0;
if(P2&OVERRANGE) ov2=1;
else ov2=0;
}
void over_display()
{
buffer[3]=0x7E;
buffer[4]=0x0E;
buffer[5]=0;
buffer[6]=0;
buffer[7]=0;
}void over_display2()
{
buffer[11]=0x7E;
buffer[12]=0x0E;
buffer[13]=0;
buffer[14]=0;
buffer[15]=0;
}// print pH probe input
void print_channel1()
{
// float temp;
if(ready)
{
// ready=0;
V2=0;
V2 = sbuffer[5]*10000;
V2 += sbuffer[4]*1000;
V2 += sbuffer[3]*100;
V2 += sbuffer[2]*10;
V2 += sbuffer[1];// perform 5-point moving average
x[4]= x[3];
x[3]=x[2];
x[2]=x[1];
x[1]=x[0];
x[0]=V2;V2 = (x[0]+x[1]+x[2]+x[3]+x[4])/5;
// printf("\n%d",V1);
//RUN=0;
// display on LED
//V2= 12345;
//if(pol==0) buffer[2]= 0x00; // put minus sign
//else buffer[2]=0x00;//buffer[4] |=0x80; // put dot to buffer[3]
//buffer[7] = 0xff;if(ov) over_display();
//update7219();// also send to PC via serial port 9600 8n1
if(pol==0) V2*=-1;
tV1= V2;
// printf("\n%.4f,",temp);if(channel1_display==0)
{mVpH= -1.984212002*(273.15+temperature/10);
pH= (tV1/(mVpH)) + 7;
pH *=100;if(calibrated)
{
pH = A + b*pH;
}
//pH = abs(pH);
sprintf(xbuffer,"%04.0f",pH);buffer[4]=convert[xbuffer[0]-0x30];
buffer[5]=convert[xbuffer[1]-0x30];
buffer[6]=convert[xbuffer[2]-0x30];
buffer[7]=convert[xbuffer[3]-0x30];
buffer[5] |=0x80; // put dot to buffer[3]if(buffer[4]==0x7e) buffer[4]=0; // turn off zero
if(calibrate_mode==0) buffer[3] = 0; // used for 3-point calibartion counting
else
{
buffer[3]= convert[calibrate_point];
if(buffer[3]== 0x7e) buffer[3]=0; // begin with 1-2-3
if(buffer[3]== 0x33) buffer[3]=0; // remove 4 as well
}
if(calibrate_mode==0)
{
buffer[0]= 0x67; // show pH
buffer[1]= 0x37;
if(calibrated) buffer[1]|=0x80; // shows pH. indicating meter has been calibrated
buffer[2]= 0;
}
else // calibrate mode
{if(calibrated==0 && clear_display==0)
{
buffer[0]= 0x4e; // show CAL
buffer[1]= 0x77;
buffer[2]= 0x0e;
}
if(calibrated==0 && clear_display==1)
{
buffer[0]= 0x4e; // show CLr
buffer[1]= 0x0e;
buffer[2]= 0x05;
}
}
}
else
{
if(calibrate_mode==0)
{
if(tV1<0)
{
tV3=abs(tV1);
buffer[2]=1; // addd minus sign
}else
{
tV3= tV1;
buffer[2]=0; // remove minus sign
}
}
sprintf(xbuffer,"%05d",tV3);buffer[3]=convert[xbuffer[0]-0x30];
buffer[4]=convert[xbuffer[1]-0x30];
buffer[5]=convert[xbuffer[2]-0x30];
buffer[6]=convert[xbuffer[3]-0x30];
buffer[7]=convert[xbuffer[4]-0x30];// off MSD
if(buffer[3]== 0x7e)
{
buffer[3]=0; // off MSD
if(buffer[4]==0x7e)
{
buffer[4]=0;
if(buffer[5]==0x7e)
{
buffer[5]=0;
}
}
}
buffer[6] |=0x80; // put dot to buffer[3]buffer[0]= 0x15; // display mV
buffer[1]= 0x3e;}
update7219();
}
}// print LM35 temperature sensor
void print_channel2()
{
// float temp;
if(ready2)
{
// ready2=0;
V1=0;
V1 = sbuffer2[5]*10000;
V1 += sbuffer2[4]*1000;
V1 += sbuffer2[3]*100;
V1 += sbuffer2[2]*10;
V1 += sbuffer2[1];
// three point moving average for temperature input
y[2]=y[1];
y[1]=y[0];
y[0]=V1;V1 = (y[0]+y[1]+y[2])/3;
//RUN=0;
// display on LED
if(pol2==0) buffer[10]= 0x01; // put minus sign
else buffer[10]=0x00;
buffer[11] |=0x80; // put dot to buffer[3]if(ov2) over_display2();
//update7219();// also send to PC via serial port 9600 8n1
if(pol2==0) V1*=-1;
tV2= V1;
temperature = V1/10;
if(manual_auto==0) temperature= set_temperature;
sprintf(xbuffer,"%03.0f",temperature);buffer[12]=convert[xbuffer[0]-0x30];
buffer[13]=convert[xbuffer[1]-0x30];
buffer[14]=convert[xbuffer[2]-0x30];
//buffer[14]=convert[xbuffer[3]-0x30];buffer[13] |=0x80; // put dot to buffer[13]
buffer[11]=0;
buffer[15]=0x4e; // put unit C
if(manual_auto) buffer[8]=0x77; // display Auto ot manual mode
else buffer[8]= 0x15;
update7219();
}
}void pause()
{
unsigned int i;
for(i=0; i<30000;i++)
continue;
}void print_7135()
{
for(i=0; i<16; i++)
buffer[i]=0xff; // test display all segments
update7219();
pause(); // wait for a while
buffer[0]=0;
buffer[1]=0;
buffer[8]=0;
buffer[9]=0;
}void print_terminal()
{if(ready&&ready2&&terminal&&fire)
{
ready=0;
ready2=0;
fire=0;mVpH= -1.984212002*(273.15+temperature/10);
pH= (tV1/(mVpH)) + 7;
pH*=100;
if(calibrated)
{
pH = A + b*pH;
}pH/=100;
time_up+=interval;
//sprintf(xbuffer,"%.0f",pH);
printf("\n%d,%ld,%dE-4,%dE-4,pH=%.2f",sample++,time_up,tV2,tV1,pH);
//printf("%s",xbuffer);
}
}
char getchr(void)
{
while(!RI);
RI =0;
return SBUF; // no echo for command write
}
// send ASCII string to screen, the string must be stored in code memory
putstr(char *s)
{
char i=0;
char c;
while((c=*(s+(i++)))!= 0) putchar(c); // while byte is not terminator, keep sending
}sendprompt()
{
putstr(prompt);
}
void getcommand()
{
if (RI) command = getchr(); //
else command = -1; /* no cammand has entered */
}void escape_command()
{
if(command== 0x1B)
{
terminal=0; // enter command mode
sendprompt();
}
}void help_menu()
{
if(command=='?')
{
//putstr(help);
putstr("\n\r a automatic print readings");
putstr("\n\r i set interval(s)");
putstr("\n\r m mV/pH");
putstr("\n\r b set standard buffer");
putstr("\n\r SP manual entry");
sendprompt();}
}
void mVpHdisplay()
{if(command=='m')
{printf("%0.3f %0.1fC",mVpH/10,temperature/10);
printf(" Y= %0.3f + %0.3f *X",A,b);
sendprompt();}
}
void interval_command()
{
if(command== 'i')
{
EA=0; // stop all interrupts
putstr("enter interval(s)=");
gets(buffer,sizeof(buffer-1));
interval=atoi(buffer);
//printf("\n %d", interval);
buffer[0] = convert[2];
buffer[8] = convert[1];
buffer[1] = 0;
EA=1;
}
}
prompting()
{
if (command == 0x0d && terminal==0) // send title and prompt when get ENTER key
{
putstr(title);
sendprompt();
sample=1;
once=0;
}
}void command_auto()
{if(command=='a')
{
putstr("press ESC to exit");
terminal=1;
sample=1;
tick=0;
second=0;}
}
void command_terminal_trigger()
{
if(command==' ' && terminal==0)
{
if(ready&&ready2)
{
ready=0;
ready2=0;
if(once==0)
{putstr("\n");
once=1;
}
printf("%d,%dE-4,%dE-4,",sample++,tV2,tV1);
gets(buffer,sizeof(buffer-1));
buffer[0] = convert[2];
buffer[8] = convert[1];
buffer[1] = 0;
}
}
}void command_set_buffer()
{
if(command=='b')
{
EA=0;
putstr("\n\renter standard buffer pH 4.00>");
gets(buffer,sizeof(buffer-1));
sbuffer4=atof(buffer)*100;
write24c16long(eeprom_buffer4,sbuffer4);
putstr("\\n\renter standard buffer pH 7.00>");
gets(buffer,sizeof(buffer-1));
sbuffer7=atof(buffer)*100;
write24c16long(eeprom_buffer7,sbuffer7);putstr("\\n\renter standard buffer pH 10.00>");
gets(buffer,sizeof(buffer-1));
sbuffer10=atof(buffer)*100;
write24c16long(eeprom_buffer10,sbuffer10);// printf("%ld, %ld, %ld",sbuffer4,sbuffer7,sbuffer10);
sendprompt();
EA=1;
}
}
#define slave_address 0xA0 // write command 0xA0, read command 0xA1
void dly (unsigned char CNT)
{unsigned char i;
while (CNT--!=0)
for (i=100;i!=0;i--);
}
void wait(void)
{
unsigned char i=50;
for(i=0;i<8;i++);
}
void start_bit(void)
{
SCL=1;wait();
SDA=0;wait();
SCL=0;wait();
}
void stop_bit(void)
{
SDA=0;wait();
SCL=1;wait();
SDA=1;wait();
SCL=0;wait();
}
void write_8bit(unsigned char ch)
{
unsigned i=8;
for(i=0;i<8;i++)
{if(ch & 0x80) SDA=1;
else SDA=0;
ch=(ch<<1);
SCL = 1;
wait();
SCL=0;
wait();
}
SDA=1;
wait();
SCL = 1 ;
wait();
SCL=0;
wait();
}
char rd8bit()
{char i=8,j;
for(i=0;i<8;i++)
{
j<<=1;
SCL=1;wait();
if(SDA)j |= 1;
SCL=0;
wait();
}
SDA=1;
wait();
return(j);
}
void write24c16(unsigned int address,unsigned char ddata)
{
start_bit();
write_8bit(0xA0);
write_8bit(address);
write_8bit(ddata);
stop_bit();
}
unsigned char read24c16(unsigned int address)
{
unsigned char rdata;
start_bit();
write_8bit(0xA0);
write_8bit(address);
start_bit();
write_8bit(0xA1);
rdata=rd8bit();
stop_bit();
return(rdata);
}void write24c16long(unsigned int address, unsigned long ddata)
{
unsigned int n=0;
n= ddata&0xff;
write24c16(address,n);
dly(50);
ddata>>=8;
n= ddata&0xff;
write24c16(address+1,n);
dly(50);
ddata>>=8;
n= ddata&0xff;
write24c16(address+2,n);
dly(50);
ddata>>=8;
n= ddata&0xff;
write24c16(address+3,n);
dly(50);
}long read24c16long(unsigned int address)
{
unsigned long n;
n=0;
n|=read24c16(address+3);
n<<=8;
n|=read24c16(address+2);
n<<=8;
n|=read24c16(address+1);
n<<=8;
n|=read24c16(address);
return n;
}
#define xy_number 3
void linear_regression()
{
sumX=0;
sumY=0;
sumXY=0;
sumXX=0;
sumYY=0;
// copy data to input array// X1[0]= 412;
// X1[1]= 755;
// X1[2]= 1026;
Y1[0]= read24c16long(eeprom_buffer4); // standard buffer 400
Y1[1]= read24c16long(eeprom_buffer7); // standard buffer 700
Y1[2]= read24c16long(eeprom_buffer10); // standard buffer 1000printf("%0.1f %0.1f %0.1f",Y1[0],Y1[1],Y1[2]);
for(i=0; i<3; i++)
{
XY[i]=X1[i]*Y1[i];
XX[i]=X1[i]*X1[i];
YY[i]=Y1[i]*Y1[i];
}
for(i=0; i<3; i++)
{
sumX+=X1[i];
sumY+=Y1[i];
sumXY+=XY[i];
sumXX+=XX[i];
sumYY+=YY[i];
}
d1=sumXY*xy_number; // for n = 3
d2=sumX*sumY;
d3=sumXX*xy_number;
d4=sumX*sumX;
b=d1-d2;b/=(d3-d4); // get B slope
A=(sumY-(b*sumX))/xy_number; // get intercept
printf(" Y=%.6f + %.6fX",A,b);
longA= A*1E6;
longb= b*1E6;printf(" %ld %ld",longA,longb);
if(b>.85 && b <1.20)
{
sprintf(xbuffer,"%3.0f",b*1000);buffer[0]=convert[xbuffer[0]-0x30];
buffer[1]=convert[xbuffer[1]-0x30];
if(b<1.0) buffer[1]|=0x80; // put decimal point if slope <100%
buffer[2]=convert[xbuffer[2]-0x30];
}
else // display failed
{buffer[0]=1; // ---- failed display
buffer[1]=1;
buffer[2]=1;
}
calibrated=1;
write24c16(eeprom_calibrated,1); // save calibrated bit to eeprom
dly(100);
write24c16long(eeprom_longA,longA); // save A
write24c16long(eeprom_longb, longb); // save b
}
//------------------ front keypad input functions --------------------
void read_key1()
{
if(key1==0 && key1_press==0 && calibrated==0) // after calibrated, no change allowed
{
key1_press=1;
channel1_display^=1;
}
}key1_release()
{if(key1 && key1_press)
key1_press=0;
}key2_release()
{if(key2 && key2_press)
key2_press=0;
}
void read_key2()
{
if(key2==0&& key2_press==0)
{
key2_press=1;
calibrate_mode^=1; // calibrate mode =1 pH mode =0;
//buffer[0]=convert[2];
if(calibrate_mode)
{calibrate_point=0;
// calibrated=0; // clear calibrated flag to zero for new calibration
}
}}
void read_key3()
{
if(key3==0 && key3_press==0)
{
key3_press=1;
manual_auto ^=1; // toggle between manual and automatic temperature reading
}}
key3_release()
{
if(key3&&key3_press)
key3_press=0;
}key4_release()
{
if(key4&&key4_press) key4_press=0;}
void read_key4()
{
if(key4==0 && key4_press==0 && disable_key4==0)
{
key4_press=1;
// buffer[0]=convert[4];
X1[calibrate_point]= pH;
++calibrate_point;
if(calibrate_point==4)
{
linear_regression();
}
if(calibrate_point==5)
{
calibrate_point=0;
clear_display=0;
calibrate_mode=0;
buffer[0]= 0x67; // show pH
buffer[1]= 0x37;
//if(calibrated) buffer[1]|=0x80; // shows pH. indicating meter has been calibrated
buffer[2]= 0;
disable_key4=1;
}}
}// read keypad every 300ms
void get_key()
{
if(timer3>30)
{
timer3=0;
read_key1();
read_key2();
read_key3();
read_key4();key1_release();
key2_release();
key3_release();
key4_release();
}
}
//----------------------- end front keypad functions ---------------------
void restore_parameters()
{if(read24c16(eeprom_calibrated))
{
calibrated=1;
longA= read24c16long(eeprom_longA);
longb=read24c16long(eeprom_longb);
A = longA*1E-6;
b = longb*1E-6;
}
else calibrated =0;}
//press key3 while power on, clear calibrated parameters
void clear_memory()
{
if(key3==0)
{
EA=0;
for(i=0; i<16; i++)
buffer[i]=0;
while(key3==0)
{
buffer[0]= 0x4e; // show CLEAr
buffer[1]= 0x0e;
buffer[2]= 0x4f;
buffer[3]= 0x77;
buffer[4]= 0x05;update7219();
}
write24c16(eeprom_calibrated,0);
dly(100);
EA=1;
}}
void main (void)
{
SCON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
TMOD = 0x21; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xfd; /* TH1: reload value for 9600 baud */
TR1 = 1; /* TR1: timer 1 run */
TI = 1; /* TI: set TI to send first char of UART */
TR0 = 1; // timer0 produces 10ms tickT2CON = 0x00; // timer 2 is used to produce 120KHz for 60Hz and 125kHz for 50Hz
T2MOD |= 0x02;
TR2 =1;
RCAP2H= 0xFF;
RCAP2L= 0xEA; // E9 for 120kHz, EA for 125kHz
IT0 = 1; // Configure interrupt 0 for falling edge on /INT0 (P3.2)
IT1 =1; // falling edge of INT1
EX0 = 1; // Enable EX0 Interrupt
EX1 = 1; // enable EX1 interrupt
ET0 = 1; // run timer0
EA = 1; // Enable Global Interrupt Flag
RUN=1; // run the 7135init7219();
putstr(title);
sendprompt();
print_7135();//buffer[0] = convert[2];
//buffer[8]= convert[1];
clear_memory();
restore_parameters();
//write24c16(2,3);
//dly(10);
//printf(" byte read = %bX",read24c16(2));
// write24c16long(2,-123459087);
//dly(100);// printf("\n A= %ld b=%ld",read24c16long(eeprom_longA),read24c16long(eeprom_longb));
while(1)
{
getcommand();
escape_command();
help_menu();
prompting();
interval_command();
command_auto();
command_terminal_trigger();
mVpHdisplay();
command_set_buffer();print_channel1();
print_channel2();
print_terminal();
get_key();
}
}Figure 5: Source code listing.
Download Schematic main board ,Schematic display board ,Source code, HEX file , Technical report
22 July 2013