VP-EC-8AI Designing Analog Input Modules

Analog inputs can be mV, Volts, mili-Amps, Amps, AC, DC, or complex wave forms. Typical process controls applications take these measurements from sensors and transducers and convert them to 4 - 20 mA signal. There is still a huge infrastructure in most industries that support this. The 4 mA level represents a 0% measurement value, the 20 mA level represents the 100% measurement value. This provides an opportunity to signal a fault condition either intentionally by the transmitter or a unintentionally  by a cut cable for example.

This design is based on the MCP3208 8 channel 12 Bit Analog to Digital converter form Microchip.

PCB Assembly complete with PIC Processor Module:

Schematic:

 8AI-Schematic-Pg-1

Each analog input 0 to 20 mA signal is convert to a voltage across the 150 Ohm Load Resistor giving a 0 to 3.0 V input to the MCP3208.

 PCB Assembly with PIC Processor PCB detached:

Some of the design criteria was to have the module be compatible with the Raspberry Pi, have RS485 I/O, have MODBUS RTU communication and have protection for the input circuits.

Here is the full specification:

 

Specifications:

  • Power: 24 VDC
  • RS485  Jumper Selectable 9600 or 19.2K Baud, N81
  • Modbus RTU Protocol
  • Modbus ID: Dipswitch Selectable
  • Analog Inputs: 4-20 mA into 150 Ohm load, PTC Fuse Protection
  • Resolution: 12 Bit ADC
  • Calibration: Simple calibration via jumpers

Processor:

  • PIC18F45K20, c/w ICSP Port

Indicators:

  • Power On: BLUE LED
  • Analog Input: 1 thru 8: GREEN LED ON when input above 2mA
  • Heart Beat: AMBER LED (Flashes to indicate proper operation)
  • RS485: GREEN LED Rx, RED LED Tx.

Options:

  • DIN Rail Enclosure Bud Industries Model: DMB-4774

Schematic Page 2:

 8AI-Schematic-Pg-2

By removing the PIC PCB, the device now becomes Raspberry Pi Compatible:

For information regarding the PIC module, please see the post for the VP-EC-8KO.

 

Sample Source Code

This sample code uses the wiringPi library and the Geany C compiler. The code has been tested for:

    • Reading the Dipswitch
    • Reading the 8 channels of AD Counts from the MCP3208 AD Converter
    • 20 mA into a 150 Ohm load resistor = 3.0 VDC
    • MCP3208 uses the 3.3 VDC as a reference, therefore 20 mA = 3/3.3 * 4096 = 3723 AD Counts
    • A1 thru A8 LED driver using the 74HC595 Serial Shift Register



     /*

     * main.c
     *
     * Copyright 2016  <pi@raspberrypi>
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
     * MA 02110-1301, USA.
     *
     *
     */

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <stdlib.h>

    #include <wiringPi.h>
    #include <wiringPiSPI.h>

    // Define Pins RPi V2 Series B
    #define PIN_SW1 2
    #define PIN_SW2 3
    #define PIN_SW3 4
    #define PIN_SW4 17
    #define PIN_SW5 27
    #define PIN_SW6 22
    #define PIN_SW7 24
    #define PIN_SW8 23

    #define PIN_08 14     // Used for testing UART Leds Tx and Rx
    #define PIN_10 15

    #define PIN_EN_LED 18 // CS for LEDS (74HC595)
    #define PIN_EN_AD  7  // CS for Analog Inputs MCP3208

    #define mA_20  3723   // 20 mA * 150Ohms = 3 Vdc/3.3 Vdc full scale * 4096 Counts
    #define mA_Fault 372  // 2 mA Fault level in AD Counts

    // Function Prototypes
    void Initialize_Pi_Hardware(void);    
    int Read_Switch(void);
    void Update_Leds(void);
    unsigned int Update_Analog(unsigned char channel);

    // Variables
    unsigned int AN_AD[8];
    int Switch;

    int main(void) {

        int i;

        wiringPiSetupGpio();                   // Initialize the wiringPi GPIO
        Initialize_Pi_Hardware();              // Set the GPIO Bit directions
        digitalWrite(PIN_EN_LED, HIGH); // Set the EN LED CS HIGH
        digitalWrite(PIN_EN_AD, HIGH);   // Set the EN AD CS HIGH

        while(1)
        {
            Switch = Read_Switch();      // Read the 8 Point Dip Switch
            AN_AD[0] = Update_Analog(0); // Read Channel A0 AD Counts from MCP3208
            AN_AD[1] = Update_Analog(1);  // Read Channel A1 AD Counts
            AN_AD[2] = Update_Analog(2);  // Read Channel A2 AD Counts
            AN_AD[3] = Update_Analog(3);  // Read Channel A3 AD Counts
            AN_AD[4] = Update_Analog(4);  // Read Channel A4 AD Counts
            AN_AD[5] = Update_Analog(5);  // Read Channel A5 AD Counts
            AN_AD[6] = Update_Analog(6);  // Read Channel A6 AD Counts
            AN_AD[7] = Update_Analog(7);  // Read Channel A7 AD Counts

            printf("ID = %d \n", Switch); // Print the Data

            for(i = 0; i < 8; i++) {
                printf("Channel AN%d = %d ADC, %0.2f mA \n", (i+1), AN_AD[i], (float)AN_AD[i] * 20 / mA_20);
            }

            printf("\n");

            Update_Leds();        // Update AN1 thru A8 LEDs using the 74HC595
            delay(1000);          // Delay 1 Second loop
        }

        return 0;
    }

    // Update Analog Inputs using the MCP3208
    unsigned int Update_Analog(unsigned char channel) {

        unsigned int  adc, input;
        unsigned char buf[3];

        wiringPiSPISetup(1, 100000);
        input = 0x0600 | (channel << 6);
        buf[0] = (input >> 8) & 0xff;
        buf[1] = input & 0xff;
        buf[2] = 0;

        digitalWrite(PIN_EN_AD, LOW);
        wiringPiSPIDataRW(1,buf,3);
        adc = ((buf[1] & 0x0f ) << 8) | buf[2];
        digitalWrite(PIN_EN_AD, HIGH);

        return adc;

    }

    // Update the A1 thru A8 LEDs using the 74HC595
    // If the AD Counts are > than the AD Fault Counts, the respective Ax LED turns on 

       
    void Update_Leds(void) {

        unsigned char buf[2];
        unsigned char value;

        value = 0;

        if(AN_AD[0] > mA_Fault) {
            value |=  0x01;
        }
        if(AN_AD[1] > mA_Fault) {
            value |=  0x02;
        }
        if(AN_AD[2] > mA_Fault) {
            value |=  0x04;
        }
        if(AN_AD[3] > mA_Fault) {
            value |=  0x08;
        }
        if(AN_AD[4] > mA_Fault) {
            value |=  0x10;
        }
        if(AN_AD[5] > mA_Fault) {
            value |=  0x20;
        }
        if(AN_AD[6] > mA_Fault) {
            value |=  0x40;
        }
        if(AN_AD[7] > mA_Fault) {
            value |=  0x80;
        }

        buf[0] = value;
        wiringPiSPISetup(0, 100000);
        wiringPiSPIDataRW(0,buf,1);
        digitalWrite(PIN_EN_LED, LOW);
        delay(1);
        digitalWrite(PIN_EN_LED, HIGH);

    }

    // Read the Dipswitch as a value from 0 thru 255, to be used as the Modbus ID value


    int Read_Switch(void) {

        int value;
        value = 0;

        if(!digitalRead(PIN_SW1)) {
            value |= 0x01;
        }
        if(!digitalRead(PIN_SW2)) {
            value |= 0x02;
        }
        if(!digitalRead(PIN_SW3)) {
            value |= 0x04;
        }
        if(!digitalRead(PIN_SW4)) {
            value |= 0x08;
        }
        if(!digitalRead(PIN_SW5)) {
            value |= 0x10;
        }
        if(!digitalRead(PIN_SW6)) {
            value |= 0x20;
        }
        if(!digitalRead(PIN_SW7)) {
            value |= 0x40;
        }
        if(!digitalRead(PIN_SW8)) {
            value |= 0x80;
        }

        return value;
    }

    // Initialze the GPIO pin directions


    void Initialize_Pi_Hardware(void) {

        pinMode(PIN_08, OUTPUT);
        pinMode(PIN_10, OUTPUT);
        pinMode(PIN_EN_LED, OUTPUT);
        pinMode(PIN_EN_AD, OUTPUT);
        pinMode(PIN_SW1, INPUT);
        pinMode(PIN_SW2, INPUT);
        pinMode(PIN_SW3, INPUT);
        pinMode(PIN_SW4, INPUT);
        pinMode(PIN_SW5, INPUT);
        pinMode(PIN_SW6, INPUT);
        pinMode(PIN_SW7, INPUT);
        pinMode(PIN_SW8, INPUT);
    }














     

    SaveSave SaveSaveSave

    Leave a comment

    Please note, comments must be approved before they are published