Analog & Digital I/O Tutorial

The Blinking LED Tutorial demonstrates how to use a Timer in combination with an LED object. In this tutorial we want explore further I/O mechanisms. The HUB-GM100 device has several analog inputs and digital I/Os which we want to integrate in this tutorial. You should prepare a current source which provides a configurable current in the range of 4…20 mA and connect it to the first analog input of the device.

The first analog input can be accessed through an AnalogInput object which we configure as a 4…20 mA analog input:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
    }
}

The application so far consists of the analog input definition only and does nothing. Next we want to print the current measured by the analog input on the console whenever it changes:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        onCurrentChanged: console.log(current)
    }
}

This application does nothing since the AnalogInput object needs to be told when to actually read a new value from the underlying (12 bit) ADC. This is where the Polling object comes into play. It allows polling special polled properties such as AnalogInput.value:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        onCurrentChanged: console.log(current)
        Polling on value { }
    }
}

Run this program, play with the current of your source and observe the output.

Per default the Polling object polls its target property every 1000 milliseconds. This can be changed easily by setting the Polling.interval property:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        onCurrentChanged: console.log(current)
        Polling on value { interval: 200 }
    }
}

This version polls the analog input value every 200 milliseconds and prints the converted current on the console whenever it changes.

Instead of just printing a value we can use it for threshold detection. In the most simple case the red LED of the HUB-GM100 can be switched on if a certain threshold is exceeded:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        id: ain1
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        Polling on value { interval: 200 }
    }
    LED {
        index: LED.StatusRed
        value: ain1.current > 10
    }
}

This application makes the red LED flash whenever the analog input exceeds 10 mA. The code demonstrates how to link two objects in a declarative manner and should give you an initial idea of how QML works. In traditional microcontroller programs you have to implement a timer routine, trigger an ADC conversion, compare the result imperatively and turn on or off the LED manually. Here all magic happens by simply using a Polling object and binding the QML expression ain1.current > 10 to the LED.value property. All expressions are re-evaluated whenever parts of it change or are updated, e.g. object properties or variables.

Changing the code to control a digital output instead of an LED is quite simple:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        id: ain1
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        Polling on value { interval: 200 }
    }
    DigitalIO {
        index: DigitalIO.IO1
        direction: DigitalIO.Output
        value: ain1.current > 10
    }
}

The last challenge in this tutorial is to implement a time-controlled threshold detection, i.e. only switch on the digital output if the threshold is exceeded for longer than 3 seconds. We already know Timer from the first tutorial. Therefor we could add two non-repeating Timer objects and restart them whenever the AIN value goes below or above the threshold:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        id: ain1
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        Polling on value { interval: 200 }
    }
    DigitalIO {
        id: dout1
        index: DigitalIO.IO1
        direction: DigitalIO.Output
    }
    Timer {
        id: startTimer
        running: ain1.current > 10
        interval: 3000
        repeat: false
        onTriggered: dout1.value = true
    }
    Timer {
        id: stopTimer
        running: ain1.current <= 10
        interval: 3000
        repeat: false
        onTriggered: dout1.value = false
    }
}

This initial version works but is not very QML-like since it contains similar redundant property initializations and even requires two signal handler functions. Anyway we can do better thanks to the Comparator object:

import InCore.Foundation 2.2
import InCore.IO 2.2

Application {
    AnalogInput {
        id: ain1
        index: AnalogInput.AIN1
        mode: AnalogInput.Mode20mA
        Polling on value { interval: 200 }
    }
    Comparator {
        id: comp
        input: ain1.current
        thresholdValueOn: 10
        timerIntervalOn: 3000
    }
    DigitalIO {
        id: dout1
        index: DigitalIO.IO1
        direction: DigitalIO.Output
        value: comp.output
    }
}

The comparator changes its output to true if the input value exceeds the on-threshold for longer than Comparator.timerIntervalOn milliseconds. The output of the comparator finally is bound to the DigitalIO.value property.