Sample Routines for the OWC #190 Controller

coyright, Peter H Anderson, Baltimore, MD, Sept, '07


Introduction.

The following routines are presented to illustrate various applications of interfacing the OWC #190 with a PC.

All routines were written using the Bloodshed DevC++ Compiler which is free. I have been impressed with this compiler and each semester give all of my students a CD with the Bloodshed Compiler.

In each of the routines, I attempt to provide simple examples of various application, using and RS232 Com Port, timing, interfacing with a DS18B20 temperature sensors, a DS2438 temperature and A/D, a DS2423 dual counter, a DS2450 Quad 16-bit A/D, measuring temperature using a NTC thermistor, reading parameters from a text file, logging data to a file, timing a process, etc.

I was educated as an EE and although I do indeed teach an introductory C course, I really perceive myself as a novice when it comes to process control using a PC. Please recognize I wrote and tested the routines. However, I would be pompous to offer that I have not made an error or two. In addition, good programming demands that the programmer anticipate and deal with every possible error condition. I can't do that as there are not enough hours in the day and a 300 line program might grow to several times that size. But, hopefully, this offers ideas and helps some realize their creativity.

Serial Port Routines.

This discussion has not been completed.

p>

Program DS18B20_1.CPP.

In this program, three DS18B20 temperature sensors are connected to OWC #190 channels "0", "1" and "2". LEDs are connected to OWC #190 channels "3", "4" and "5". The LEDs might be alarms, heaters and cooling fans or similar. In this example, allarm outputs 3, 4 and 5 are associated with temperature sensors 0, 1 and 2, respectively.

The high and low trip points and the polarity are specified in a file c:\settings.txt. This is a file you prepare to define the operation of your system as opposed to hard coding the trip points in your program.

Consder the file;

23.0 27.0 1
3.0 7.0 0
30.0 35.0 1
The first line might be used to control an air conditioner in a living area. When the temperature is above 27.0, turn on the LED (air conditioner) and leave it on until the temperature falls below 23.0 degrees C. Note that I define this a polarity of 1.

The second might be near an exposed water pipe in a cool climate. If ther temperature falls below 3.0 degrees C, turn on a heater until the temperature rises above the high trip point of 7.0 degrees C. Note that the polarity is identified as 0.

The third might be used to control a ventilation fan in an attic. When the temperatures rises above 35.0, turn on the fan, and leave it on until the temperature falls below 30 degrees C.

Note that I have included the implementation of the RS232 functions in

// DS18B20_2.CPP (Bloodshed DevCpp)
//
// Illustrates an interface with three DS18B20 temperature sensors on
// OWC #190 channel 0, 1, 2.  Each temperature is measured and compared
// with high and low trip points.  Corresponding relays (or LEDs) on
// OWC #190 channels 3, 4 and 5 are either operated or released.
//
// The measurment sequence is repeated every minute.
//
// copyright, Peter H Anderson, Sept 20, '07
//
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <string.h>

#define COM_PORT 3 // <<<<<<<<<<<< Modify as required.

#define DEBUG

int meas_DS18B20(int ch, float *p_Tc);
int output_state(int ch, int state);

// RS232 Routines
HANDLE rs_initialise (const long int BaudRate,
                      const char parity, const char data);
void rs_flush(void);
void rs_terminate(void);
char rs_getch(void);
int rs_getline(char line[], clock_t timeout);
void rs_putch(int txchar);
void rs_putstr(const char *string);

// delay_routines
void delay_ms(clock_t millis);

HANDLE hCom;           //handle for serial port I/O
int io_port;

#define FAILURE 0
#define SUCCESS !FAILURE

int main()
{
    FILE *fr;
    clock_t timeout;
	float Tc[3], Tc_high_trip[3], Tc_low_trip[3];
	int n, channel, pol[3];

	io_port = COM_PORT;
    if(!rs_initialise(9600, '8', 'N')) // open the COM port
    {
         printf("Opening Port Failed\n");
         delay_ms(5000);
         exit(1);
    }

    if ((fr = fopen("c:\\settings.txt", "rt")) == NULL)
    {
         printf("Error opening thermostat settings file\n");
         delay_ms(5000);
         exit(1);
    }
    // else

    for (n=0; n<3; n++)
    {
        if (fscanf(fr, "%f %f %d",
                       &Tc_high_trip[n], &Tc_low_trip[n], &pol[n]) != 3)
        {
            printf("Error reading from thermostat settings file\n");
            exit(1);
        }

        else
        {
            printf("%f\t%f\t%d\n", Tc_high_trip[n], Tc_low_trip[n], pol[n]);
        }
    }

    // now proceed to measure
    timeout = clock() + 60000;  // every 60 secs
    while(1) // forever
    {
       for (channel = 0; channel<3; channel++)
       {
         if (meas_DS18B20(channel, &Tc[channel]) == FAILURE) // perform a temperature meas
                                              // on CH n
         {
             printf("CH %1d, Error\n", channel);
         }
         else
         {
             printf("CH %1d, Tc = %.2f\n", channel, Tc[channel]);
         }

         if (pol[channel] == 1)
         {
             if (Tc[channel] > Tc_high_trip[channel])
             {
                output_state(channel + 3, 1);
             }
             if (Tc[channel] < Tc_low_trip[channel])
             {
                 output_state(channel + 3, 0);
             }
         }
         else // pol = 0
         {
             if (Tc[channel] > Tc_high_trip[channel])
             {
                 output_state(channel + 3, 0);
             }
             if (Tc[channel] < Tc_low_trip[channel])
             {
                 output_state(channel + 3, 1);
             }
         }
       } // end of for loop

       while(clock() < timeout) // wait for the balance of the 60 seconds
       {
       }
       timeout = timeout + 60000; // new timeout value
    }
    // as written, the program never really gets to this point
    rs_terminate();
    while(getchar() != 'x')
    {
    }
    return 0;
}

int meas_DS18B20(int ch, float *p_Tc)
{
    char s[25], line[25];
    int num_chars, high, low, word;
    float Tc;

    sprintf(s, "P%1dW%1dccS%1d44", ch, ch, ch);
                // presence, 0xcc, 0x44 followed by one second of strong pullup

    rs_putstr(s);
    delay_ms(1200);


    sprintf(s, "P%1dW%1dccW%1dbe", ch, ch, ch);
              // presence, 0xcc, 0xbe
    rs_putstr(s);
    delay_ms(200);

    rs_flush(); // flush the buffer
    sprintf(s, "R%1d", ch);

    rs_putstr(s);
    delay_ms(50);
    if ((num_chars = rs_getline(line, 100)) == 0) // probably no device
    {
        return(FAILURE);
    }
    // printf("%s\n", line); // used for debugging
    // else
    sscanf(line, "%x", &low);

    rs_flush();  // flush buffer
    sprintf(s, "R%1d", ch);
    rs_putstr(s);

    delay_ms(50);
    if ((num_chars = rs_getline(line, 100)) == 0)
    {
        return(FAILURE);
    }
    // printf("%s\n", line);
    // else
    sscanf(line, "%x", &high);

    word = (high << 8) | low;
    // printf("....%x %x %x\n", high, low, word); // for debugging
    if (word & 0x8000)
    {
        word = (word ^ 0xffff) + 1;
        Tc = -0.0625 * (float) word;
    }
    else
    {
         Tc = 0.0625 * (float) word;
    }
    *p_Tc = Tc;
    return(SUCCESS);
}

int output_state(int ch, int state)
{
    char s[25], line[25];
    int num_chars, relay_state;
    rs_flush();

    if (state == 1)
    {
        sprintf(s, "H%1d", ch);  // H followed by the channel
    }
    else
    {
        sprintf(s, "L%1d", ch); // L followed by the channel
    }

    rs_putstr(s);

    num_chars = rs_getline(line, 250);
    sscanf(line, "%d", &relay_state);
    return(relay_state);
}

void delay_ms(clock_t millis)
{
   clock_t endtime;
   endtime = millis + clock();
   while( endtime > clock() )        ;

}

// RS232 routines
HANDLE rs_initialise (const long int BaudRate, const char parity, const char data)
{
    BOOL bPortReady;
    DCB dcb;
	COMMTIMEOUTS CommTimeouts;

    char ComPortName[5]="COM ";
    ComPortName[3]='0'+ io_port;
    hCom = CreateFile(ComPortName, GENERIC_READ | GENERIC_WRITE,
                                  0,            // exclusive access
                                  NULL,         // no security
                                  OPEN_EXISTING,
                                  0,            // no overlapped I/O
                                  NULL);        // null template


    if ((int)hCom <= 0)
    {
        printf("serial port COM%d connect fail %s error %d\n\r", io_port, ComPortName, GetLastError());
        return 0;
    }
    //else                printf(" serial port COM%d connect OK \n\r", io_port);

    bPortReady = SetupComm(hCom, 128, 128); // set buffer sizes
    if (!bPortReady )
    {
        printf("serial port COM%d SetupComm fail  %d\n\r", io_port,  GetLastError());
        return 0;
    }
    //else                printf(" serial port COM%d connect OK \n\r", io_port);

    bPortReady = GetCommState(hCom, &dcb);
    if (!bPortReady )
    {
        printf("serial port COM%d  GetCommState fail  %d\n\r", io_port,  GetLastError());
        return 0;
    }
    //  else                printf(" serial port COM%d connect OK \n\r", io_port);
    dcb.BaudRate = BaudRate;
    if( data == '7') dcb.ByteSize = 7;
    else             dcb.ByteSize = 8;
    if( parity == 'E') dcb.Parity = EVENPARITY;
    if( parity == 'O') dcb.Parity = ODDPARITY;
    else               dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.fAbortOnError = TRUE;

    // set XON/XOFF
    dcb.fOutX = FALSE;                       // XON/XOFF off for transmit
    dcb.fInX = FALSE;                        // XON/XOFF off for receive
    // set RTSCTS
    dcb.fOutxCtsFlow = FALSE;               // turn off CTS flow control
    dcb.fRtsControl = FALSE;                // RTS_CONTROL_HANDSHAKE; //
    // set DSRDTR
    dcb.fOutxDsrFlow = FALSE;               // turn off DSR flow control
    //dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR handshake
    dcb.fDtrControl = DTR_CONTROL_DISABLE;  //
    // dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; //

    bPortReady = SetCommState(hCom, &dcb);
    if (!bPortReady )
    {
        printf("serial port COM%d  SetCommState fail  %d\n\r", io_port,  GetLastError());
        return 0;
    }

    // Communication timeouts
    //COMMTIMEOUTS CommTimeouts;
    bPortReady = GetCommTimeouts (hCom, &CommTimeouts);
    CommTimeouts.ReadIntervalTimeout = 5 ;
    CommTimeouts.ReadTotalTimeoutConstant = 5 ;
    CommTimeouts.ReadTotalTimeoutMultiplier = 1 ;
    CommTimeouts.WriteTotalTimeoutConstant = 5 ;
    CommTimeouts.WriteTotalTimeoutMultiplier = 1 ;
    bPortReady = SetCommTimeouts (hCom, &CommTimeouts);
    if (!bPortReady )
    {
        printf("serial port COM%d SetCommTimeouts fail  %d\n\r", io_port,  GetLastError());
        return 0;
    }
    else
    {
        printf(" serial port COM%d connect OK \n\r", io_port);
    }
    return (hCom);
}

void rs_terminate(void)
{
   CloseHandle(hCom);
}

char rs_getch(void)
{
    char rxchar;
    BOOL bReadRC;
    static DWORD iBytesRead;
    bReadRC = ReadFile(hCom, &rxchar, 1, &iBytesRead, NULL);
    if (iBytesRead)
    {
        return rxchar;
    }
    else
    {
        return 0;         // return 0 if no character read
    }
}

void rs_flush(void)
{
    while(rs_getch()!=0)   ;
}

int rs_getline(char line[], clock_t timeout)
{
    int num_chars = 0;
    char ch;
    clock_t endtime;
    endtime = timeout + clock();
    //printf("%ld %ld\n", clock(), endtime);
    while(endtime > clock())
    {
        //printf("!");
        ch = rs_getch();
        //printf("%d ", ch);
        if (ch != 0)
        {
            //printf("%c", ch);
            if ((ch == 10) || (ch == 13))
            {
                line[num_chars] = '\0'; // terminate the string
                return(num_chars);
            }

            else
            {
                line[num_chars] = ch;
                ++num_chars;
            }
        }

    } // end of while
    line[num_chars] = '\0';
    return(-1);  // timeout
}

void rs_putch(int txchar)
{
    BOOL bWriteRC;
    static DWORD iBytesWritten;
    bWriteRC = WriteFile(hCom, &txchar, 1, &iBytesWritten,NULL);
    return;
}

void rs_putstr(const char *string)
{
#ifdef DEBUG
    printf("%s\n", string);
#endif
    while (*string != '\0')
    {
        delay_ms(5);
        rs_putch(*string++);
    }
}


DS2438_1.CPP

This program illustrates an interface with the DS2438 Smart Battery monitor which includes the capability for measuring temperature, for measuring one external voltage and the voltage of the supply to the DS2438. (The DS2438 also has another A/D to measure the current though a sensing resistor and measuring elapsed time. I have not used these capabilities.

This routine measures and displays the temperature, the voltage on the A/D and the supply voltage. This is repeated every minute.

A Honeywell HIH-4000 is connected to the A/D of the DS2438 and the relative humidity is calculated and adjusted for the measured temperature.

Note that I have an RH #166 unit which uses a DS2438 and a Honeywell HIH-4000 to measure temperature and relative humidity and in fact used one to test this routine.

The primary functions;

int meas_DS2438(int ch, float *p_Tc, float *p_Vad, float *p_Vd);
Note that the temperature, Vad and Vdd are passed by reference and the return integer is used for error handling. As noted above, I did very little with error handling.
int meas_DS2438_temp(int ch, float *p_Tc);
int meas_DS2438_voltage(int ch, int source, float *p_V);
The function meas_DS2438_voltage is used to measure either the Vad or the Vdd by passing soource as either a zero or a one.
float calc_RH(float Tc, float Vad, float Vdd);
This function uses Vad, Vdd and the temperature to calculate the relative humidity corrected for temperature.

From the Honeywell data sheet,

      Vout = Vsource (0.00062 * RH_raw + 0.16)
Rerranging to express RH as a function of Vout and Vsource;
      RH_raw = 161.3 * Vad / Vdd - 25.8;
This value is corrected for temperature;
      RH_corrected = RH_raw / (1.0305 + 0.000044 * Tc - 0.0000011 * Tc^2)

Note that in the following, the implementations the the RS232 functions has been ommitted fro brevity. You can simply cut and paste these from the DS18B20 routine which appears above.

// DS2438_1.CPP (Bloodshed DevCpp)  for the OWC #190
//
// Illustrates an interface with a DS2438 temperature and A/D IC.  A Honeywell
// HIH-4000 is connected to the A/D input.
//
// Measures and displays temperature, Vad and Vdd.
//
// Calculates and displays relative humidity.
//
// copyright, Peter H Anderson, Sept 26, '07
//
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <string.h>

#define COM_PORT 3 // <<<<<<<<<<<< Modify as required.

#define DEBUG

int meas_DS2438(int ch, float *p_Tc, float *p_Vad, float *p_Vd);
int meas_DS2438_temp(int ch, float *p_Tc);
int meas_DS2438_voltage(int ch, int source, float *p_V);
float calc_RH(float Tc, float Vad, float Vdd);

int output_state(int ch, int state);

// RS232 Routines
HANDLE rs_initialise (const long int BaudRate,
                      const char parity, const char data);
void rs_flush(void);
void rs_terminate(void);
char rs_getch(void);
int rs_getline(char line[], clock_t timeout);
void rs_putch(int txchar);
void rs_putstr(const char *string);

// delay_routines
void delay_ms(clock_t millis);

HANDLE hCom;           //handle for serial port I/O
int io_port;

#define FAILURE 0
#define SUCCESS !FAILURE

int main()
{
    io_port = COM_PORT;
    clock_t timeout;
	float Tc, Vad, Vdd, RH;
	int channel, n;

    if(!rs_initialise(9600, '8', 'N')) // open the COM port
    {
         printf("Opening Port Failed");
         delay_ms(5000);
         exit(1);
    }

    timeout = clock() + 60000;  // every 60 secs
    channel = 1;

    while(1) // forever
    {
         if (meas_DS2438(channel, &Tc, &Vad, &Vdd) == FAILURE)
                   // perform a temperature meas and two A/D on specified
                   // channel
         {
             printf("CH %1d, Error\n", channel);
         }
         else
         {
             RH = calc_RH(Tc, Vad, Vdd);
             printf("CH %1d, Tc = %.2f, Vad = %.2f, Vdd = %.2f, RH = %.2f\n",
                     channel, Tc, Vad, Vdd, RH);
         }

         while(clock() < timeout) // wait for the balance of the 60 seconds
         {
         }
         timeout = timeout + 60000; // new timeout value
    }
    // as written, the program never really gets to this point
    rs_terminate();
    while(getchar() != 'x')
    {
    }
    return 0;
}

int meas_DS2438(int ch, float *p_Tc, float *p_Vad, float *p_Vd)
{
    if (meas_DS2438_temp(ch, p_Tc) == FAILURE)
    {
       return(FAILURE);
    }
    if (meas_DS2438_voltage(ch, 0, p_Vad) == FAILURE)
    {
        return(FAILURE);
    }
    if (meas_DS2438_voltage(ch, 1, p_Vd) == FAILURE)
    {
        return(FAILURE);
    }
}

int meas_DS2438_temp(int ch, float *p_Tc)
{
    char s[25], line[25];
    int num_chars, high, low, word_val, sign_bit;
    float Tc;

    sprintf(s, "P%1dW%1dccW%1d44", ch, ch, ch, ch);
              // presence, CC, 44 - perform temperature measurement
    rs_putstr(s);

    delay_ms(1100);  // allow time for temperature meas to complete

    sprintf(s, "P%1dW%1dccW%1db8W%1d00", ch, ch, ch, ch);
              // presence, CC, B8, 00 - recall to scratchpad
    rs_putstr(s);

    sprintf(s, "P%1dW%1dccW%1dbeW%1d00", ch, ch, ch, ch);
              // presence, CC, BE, 00 - read scratchpad
    rs_putstr(s);

    rs_flush();  // skip byte 0
    sprintf(s, "R%1d", ch);
    rs_putstr(s);
    delay_ms(100);

    rs_flush();
    sprintf(s, "R%1d", ch);
    rs_putstr(s);
    delay_ms(100);

    if ((num_chars = rs_getline(line, 100)) == 0)
    {
        return(FAILURE);
    }

    // else
    sscanf(line, "%x", &low);
    rs_flush();  // flush buffer
    sprintf(s, "R%1d", ch);
    rs_putstr(s);
    delay_ms(100);

    if ((num_chars = rs_getline(line, 100)) == 0)
    {
        return(FAILURE);
    }

    // else
    sscanf(line, "%x", &high);

    printf("%x %x\n", high, low); // used for debugging

    word_val = (unsigned int) high * 256 + low;
    sign_bit = word_val & 0x8000;

    if (sign_bit)
    {
         word_val = word_val ^ 0xffff + 1; // take the twos comp
    }
    word_val = word_val / 8;
    Tc = 0.03125 * (float) word_val;

    if (sign_bit)
    {
        Tc = -Tc;
    }

    *p_Tc = Tc;
    return(SUCCESS);
}

int meas_DS2438_voltage(int ch, int source, float *p_V)
{
    char s[25], line[25];
    int num_chars, word_val, n, a[9];
    float Tc;

    if (source == 0) // V_ad
    {
        sprintf(s, "P%1dW%1dccW%1d4eW%1d00W%1d00", ch, ch, ch, ch, ch);
               // presence, CC, 4E, 00, 00 for Vad
        rs_putstr(s);
    }
    else //  Vdd
    {
        sprintf(s, "P%1dW%1dccW%1d4eW%1d00W%1d08", ch, ch, ch, ch, ch);
              // presence, CC, 4E, 00, 08 for Vdd
        rs_putstr(s);
    }

    sprintf(s, "P%1dW%1dccW%1db4", ch, ch, ch);
              // presence, CC, 44 - perform A/D measurement
    rs_putstr(s);

    delay_ms(1200);

    sprintf(s, "P%1dW%1dccW%1db8W%1d00", ch, ch, ch, ch);
              // presence, CC, B8, 00 - recall to scratchpad
    rs_putstr(s);

    sprintf(s, "P%1dW%1dccW%1dbeW%1d00", ch, ch, ch, ch);
              // presence, CC, BE, 00 - read scratchpad
    rs_putstr(s);

    for (n=0; n<9; n++)
    {
        rs_flush();  // flush buffer
        sprintf(s, "R%1d", ch);
        rs_putstr(s);
        if ((num_chars = rs_getline(line, 100)) == 0)
        {
            return(FAILURE);
        }

        // else
        sscanf(line, "%x", &a[n]);
        // printf("....%d\n", high);
    }

    word_val = a[4] * 256 + a[3];
    *p_V = 0.01 * (float) word_val;
    return(SUCCESS);
}

float calc_RH(float Tc, float Vad, float Vdd)
{
   float RH_raw, RH_corrected;

   RH_raw = 161.3 * Vad / Vdd - 25.8;
   RH_corrected = RH_raw / (1.0305 + 0.000044 * Tc - 0.0000011 * Tc * Tc);
   printf("RH_raw = %.2f  RH_corrected = %.2f\n", RH_raw, RH_corrected);
   return(RH_corrected);
}

void delay_ms(clock_t millis)
{
   clock_t endtime;
   endtime = millis + clock();
   while( endtime > clock() )        ;

}


// Include the implementations of the RS232 functions here.


DS2423.CPP

// description

// DS2423_1.CPP (Bloodshed Dev-Cpp) OWC #190
//
// Illustrates an interface with a DS2423 dual 32-bit counter.
//
// copyright, Peter H Anderson, Sept 29, '07
//
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <string.h>

#define COM_PORT 3 // <<<<<<<<<<<< Modify as required.

#define DEBUG

int meas_DS2423(int ch, long *p_count_0, long *p_count_1);

// RS232 Routines
HANDLE rs_initialise (const long int BaudRate,
                      const char parity, const char data);
void rs_flush(void);
void rs_terminate(void);
char rs_getch(void);
int rs_getline(char line[], clock_t timeout);
void rs_putch(int txchar);
void rs_putstr(const char *string);

// delay_routines
void delay_ms(clock_t millis);

HANDLE hCom;           //handle for serial port I/O
int io_port;

#define FAILURE 0
#define SUCCESS !FAILURE

int main()
{
    clock_t timeout;
	long count_0, count_1;

    io_port = COM_PORT;

    if(!rs_initialise(9600, '8', 'N')) // open the COM port
    {
         printf("Opening Port Failed");
         delay_ms(5000);
         exit(1);
    }

    timeout = clock() + 60000;  // every 60 secs
    while(1) // forever
    {
		 if (meas_DS2423(0, &count_0, &count_1) == FAILURE)

         {
             printf("CH 2, Error\n");
         }
         else
         {
             printf("CH 2, Count_0 = = %lx, Count_1 = %lx\n", count_0, count_1);
         }

         while(clock() < timeout) // wait for the balance of the 60 seconds
         {
         }
         timeout = timeout + 60000; // new timeout value
    }
    // as written, the program never really gets to this point
    rs_terminate();
    while(getchar() != 'x')
    {
    }
    return 0;
}

int meas_DS2423(int ch, long *p_count_0, long *p_count_1)
{
    char s[25], line[25];
    int num_chars, counter_num, n, a[4] = {0, 0, 0, 0};
    unsigned long count;

    rs_putstr(s);

    for (counter_num=0; counter_num<=1; counter_num++)
    {
        if (counter_num == 0)
        {
            sprintf(s, "P%1dW%1dccW%1da5W%1dc0W%1d01", ch, ch, ch, ch, ch);
              // presence, CC, A5, C0, 01
            rs_putstr(s);
        }
        else
        {
            sprintf(s, "P%1dW%1dccW%1da5W%1de0W%1d01", ch, ch, ch, ch, ch);
            rs_putstr(s);
              // presence, CC, A5, E0, 01
        }

        // now 32 reads and throw away the data

        for (n=0; n<32; n++)
        {
            rs_flush();  // flush buffer
            sprintf(s, "R%1d", ch);
            rs_putstr(s);
            if ((num_chars = rs_getline(line, 100)) == 0)
            {
                return(FAILURE);
            }
            delay_ms(5);
        }

        // read the four data bytes

        for (n=0; n<4; n++)
        {
            rs_flush();  // flush buffer
            sprintf(s, "R%1d", ch);
            rs_putstr(s);
            if ((num_chars = rs_getline(line, 100)) == 0)
            {
                return(FAILURE);
            }
            // else
            sscanf(line, "%x", &a[n]);
        }

        count = a[3];
        count = count * 256 + a[2];
        count = count * 256 + a[1];
        count = count * 256 + a[0];

        printf("....%lx\n", count);
        if (counter_num == 0)
        {
            *p_count_0 = count;
        }
        else
        {
            *p_count_1 = count;
        }
    }
    return(SUCCESS);
}

void delay_ms(clock_t millis)
{
   clock_t endtime;
   endtime = millis + clock();
   while( endtime > clock() )        ;
}

// insert implementations of RS232 routines here