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.