Real-time ASCEND/Data acquisition hardware
From ASCEND
←back to Real-time ASCEND.
Contributed by: Dipak Chirmade
Temperature data acquisition setup and other information
The following section describes the basic process, without discussion of how this data will be incorporated into ASCEND.
There are many micro controller hardware boards available that can do data acquisition over serial or usb cable for both analog or digital sensors. But we would like to recommend to use open-source as well as open-hardware boards like Arduino or Wiring etc. Since not only software but also hardware/circuits diagrams are open, one can customize the hardware according to the need.
This page describes basic steps to get Arduino board (Version: Duemilanove) ready for temperature data acquisition using SMT160-30 digital and LM35CZ analog temperature sensors.
Hardware specifications (Arduino Duemilanove V.2009)
| Hardware | Specification/s |
|---|---|
| Microcontroller | ATmega328 |
| Operating Voltage | 5V |
| Input Voltage (recommended) | 7-12V |
| Input Voltage (limits) | 6-20V |
| Digital I/O Pins | 14 (of which 6 provide PWM output) |
| Analog Input Pins | 6 |
| DC Current per I/O Pin | 40 mA |
| DC Current for 3.3V Pin | 50 mA |
| Flash Memory | 16 KB (ATmega168) or 32 KB (ATmega328) of which 2 KB used by bootloader |
| SRAM | 1 KB (ATmega168) or 2 KB (ATmega328) |
| EEPROM | 512 bytes (ATmega168) or 1 KB (ATmega328) |
| Clock Speed | 16 MHz |
Please visit http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove for other detailed specifications
Hardware Setup
Arduino board supports power over usb. Therefore you do not need extra power adapter. But in case if you're not acquiring data using standard computer then you might be needing extra conventional D.C. Power adapter (5.0 – 5.5V and 400-600mA).
Following are the pictures of USB-powered Arduino board.
Make a wiring according to +Vcc, Gnd and Out-put pin diagram by referring to the corresponding temperature sensor manuals. For example following picture shows SMT 160-30 wiring:
As you can see, always try to make a good isolation in between connectors so that possible short circuits may be avoided.
Similarly, other sensors are wired and isolated at both ends. And may be look like following picture
Arduino board has 6 analog inputs, 14 digital in-outputs, 3 GND, 1 Vin, 1 +Vcc (5V) and 1 AREF ports. You can plug your analog and digital temperature sensors in corresponding ports by referring to the temperature sensors manual. Running board with hooked two temperature sensors (1 analog + 1 digital) looks like in following picture.
Please note that first plug the temperature sensors to the Arduino board then power it ON. Otherwise Arduino board may hang in between.
For above setup, one may get feeds from DA hardware with time-stamping as
Sensor type :digital Sensor description :SMT16030 Sensor fuction :temperature Sensor status :active Sensor Event :notchanged Sensor EventType :optional Sensor Reading :23 Sensor Port :7 Sensor TimeStampHr :0 Sensor TimeStampMin :0 Sensor TimeStampSec :17 Sensor type :analog Sensor description :LM35CZ Sensor fuction :temperature Sensor status :active Sensor Event :changed Sensor EventType :compulsory Sensor Reading :24 Sensor Port :0 Sensor TimeStampHr :0 Sensor TimeStampMin :0 Sensor TimeStampSec :17
Currently supported sensors
Currently we're supporting 3 temperature sensors viz. SMT16030, LM35CZ and LM335AL743. (K-Type thermocouple wire and A2D converter sensor support (Beta) will be coming soon...)
You can use/re-use following code to test or to configure sensors according to your needs. dipak:models/dipak/SensorFirmware/RawCode
Noise Protection (RC filter)
The SMT16030 sensor is based on a free running oscillator. Periodic spikes on the power supply line may make the oscillator synchronise, resulting in a false temperature reading. To overcome this problem it is advised to put a filter in the power supply line of the sensor. It is suggested to use a low pass RC filter as given below. An additional advantage also is the power supply polarity protection of the sensor. The resistor of 220 Ohm limits the current through the sensor to about 25 mA. At this current the sensor will survive a possible wrong power supply polarity. The software can detect the presence of the output signal and therefore a proper connection of the sensor. See below for a suggested diagram.
Software Setup
- Download current version of Arduino programming tool kit from Arduino's website. Since Arduino is a java based application, procedure to run the software in MS windows or GNU/Linux doesn't differ much.
- Check if you have your modem handle plugged in properly. You might see /dev/<deviceHandle> on GNU/Linux or COM<deviceHandleNo>
- Arduino is well tested on almost all distribution based on GNU/linux so you might not be having much problem. Even though if you can not find or detect your device handle then try to do “dmesg” on terminal. Very last logs may show some information about your plugged in device. You can also give a try to FTDI USB drivers in rare case.
- Select appropriate board from Tools->Boards option.
- Finally select serial port on which Arduino is plugged-in.
- After compilation, one can upload the firmware to the board by just clicking Upload button. And at this point Arduino kit is ready to use.
Special Note: Please check if you have installed 'avr-g++' on your gnu/linux machine. Arduino needs 'gcc-avr' as well as 'avr-libc' to cross compile the firmware.
How to compile, burn/upload the firmware to DA Hardware
Compiling and burning the firmware for Arduino is a bit easy. As shown in following snap of Arduino IDE, Write your code in the text area. Hit round button with triangle in it for the compilation process. If every thing is good with your code, it shall generate .hex file. Upload the firmware image / hex file to flash by hitting button with arrow pointing towards right side of yours. And done!
Please see the following video for demonstration:
Limitations of a current (Arduino Auemilanove) DA hardware/Sensors
- Currently only general purpose temperature sensors are used. Therefore reading only between approximately -30° to +120°C range with +/-2°C tolerance is allowed.
- Though there are 6 analog and 12 digital ports, only one +5V DC (+Vcc) port is available. Thus it is little hard to connect multiple sensors without extending +Vcc while connecting the sensors etc
- If digit GPIO pin(s) is not connected to a digital sensor or if digital sensor malfunctions then 'pulseIn()' returns NULL/0 by which we can say that sensor is not working or connected. But if an analog GPIO pin(s) is not connected to an analog sensor or if an analog sensor malfuctions then 'analogRead()' doesn't return NULL but a valid stepping value (May be in between 0-1023) etc. Because of which it is not possible to detect if an analog sensor is connected or working properly.
- While writing firmware side code using Arduino IDE, if we make a mistake in syntax then Arduino complier doesn't point an error message to the point where we made the mistake but somewhere else. It is most of the time confusing and hard to debug error messages etc
An issue of accessing share memory of a DA-Hardware
Accessing shared memory of DA-hardware may be a good thing because by doing that real-time terminal data-reader can read the new data (or batch of data) without any delay. Delay may create some problem if time-stamping of available new data is done on ASCEND side.
But since we're accessing DA-hardware currently via SERIAL port (RS232), sharing memory will not work to access the data faster (or in batch ) as delay in serial communication exists in both cases. To test how fast we can fetch a data from DA-Hardware, I have performed a test dipak:models/dipak/SensorFirmware/DAHardwareShareMemCaseInvestigation. And I found following results.
Results: Logs from test can be found at
- For 1 second: dipak:models/dipak/SensorFirmware/DAHardwareShareMemCaseInvestigation/TerminalReader/OneSec.logs
- For 16 seconds:dipak:models/dipak/SensorFirmware/DAHardwareShareMemCaseInvestigation/TerminalReader/SixteenSecs.logs
Or graphically,
Summary:
- From results it can be seen that real-time terminal data-reader can read as fast as approximately 780 readings in a second from DA-Hardware.
- Delay introduced because of serial communication and it's effect on the time stamping for new data can be avoided if DA-Hardware itself sends the batch of readings with time-stamping etc (Please refer DA Communication)
- Mostly sensors don't show active change in reading if we try to fetch the reading with higher frequency.
- Current DA hardware (Arduino Duemilanove ATMEGA - 328) has Flash 16k bytes (of which 2k is used for the bootloader), SRAM 1024 bytes and EEPROM 512 bytes. Because of such a fair large SRAM there is no need to share memory so that we can reduce space complexity at the run time. Current implementation of firmware shows it is only using approximately 50% of SRAM under full load.
- Accessing shared memory via JTAG will involve a serious modification in Arduino code base but even though problem of delay in JTAG based communication remains the same.
Therefore it is feasible to continue without accessing shared memory of DA-Hardware for the time being.
Few DA-Hardware test cases
| | |
| DA-Haware setup for different baud rates e.g. (2400, 4800, 9600, 19200 etc) | Serial (RS232) communication worked at real-time data reader side when assigned the same baud rate as that of DA-Hardware. |
| User-button ('customised reset') pressed and released on DA-Hardware. | Feeds and time-stamps got reset with indication on-board user-LED. |
| No digital or analog sensor was connected to DA-Hardware and tried to fetch the reading | Got an event which indicated that sensors are inactive with NULL reading. |
| Memory leak test by 'memTest' function during run-time | Got confirmation of all dynamic allocated memory freed with no memory leaks. |
| Tried to fetch reading with and without pre-processing | Got corresponding feeds and crossed tested them with manual thermo-meter. |
Program snippets
Complete source code can be downloaded from dipak:models/dipak/SensorFirmware/RawCode
For Arduino firmware:
//Calculation of temperature from SMT160-30(079A) unsigned long CalculateTemperatureUsingSMT16930( unsigned long squareWaveHighTime = 0, //High time for the square wave unsigned long squareWaveLowTime = 0 //Low time for the square wave ){ unsigned long temperature = INCORRECTTEMPERATUREREADING;//Calculated temperature float dutyCycle = 0; //DutyCycle that need to calculate if((squareWaveHighTime + squareWaveLowTime)) //Wow! Just checked for Devide by Zero error while(true){ //Don't try to calculate DutyCyle in one line. It isn't supported! dutyCycle = squareWaveHighTime; //Calculate Duty Cycle for the square wave dutyCycle /= (squareWaveHighTime + squareWaveLowTime); //Add other code in future if nedded, break the loop to handle error codes //Error code -> break; //Compute temperature reading according to D.C. where D.C. = 0.320 + 0.00470 * T //Please read SMT160-30(079A) manual for formula used temperature = (dutyCycle - 0.320) / 0.00470; break; } //Handle Error code before returning to caller //Todo: Handle later if any return temperature; } //Calculation of temperature from LM35CZ unsigned long CalculateTemperatureUsingLM35CZ( unsigned int analogSampleValue = 0 //In between 0-1024 ){ unsigned long temperature = INCORRECTTEMPERATUREREADING;//Calculated temperature if(analogSampleValue) while(true){ //Add other code in future if nedded, break the loop to handle error codes //Error code -> break; //Calculate analog temperature. Please read LM35CZ manual for formula. temperature = (5.0 * analogSampleValue * 100.0) / 1024.0; break; } //Handle Error code before returning to caller //Todo: Handle later if any return temperature; } . . . //Fetch temperature feed from SMT16930 sensor tTemperature = CalculateTemperatureUsingSMT16930( pulseIn(DIGITALSENSORPIN_SMT16030, HIGH), //Read high time for square wave pulseIn(DIGITALSENSORPIN_SMT16030, LOW) //Read low time for square wave ); . . . //Fetch temperature feed from LM35CZ sensor tTemperature = CalculateTemperatureUsingLM35CZ( analogRead(ANALOGSENSORPIN_LM35CZ) //Read analog value ); . . .
For terminal client
#ifndef _TERMINAL_C #define _TERMINAL_C #include "terminal.h" /*Only once used so safe to declear as globle*/ struct termios oldTerminalSettings, newTerminalSettings; /*Terminal configuration info holder*/ /* Description: Open the terminal to perform I/O operations Arguments: Nothing Returns: INT, integer value */ int OpenTerminal(void) { return open(MODEMDEVICE, O_RDWR | O_NOCTTY); } /* Description: Save the old setting of terminal and configure the terminal according to new settings Arguments: INT, integer device handle number Returns: Nothing */ void ConfigureTheNewTerminal(int tDeviceHandle) { tcgetattr(tDeviceHandle,&oldTerminalSettings); /* Save current serial port settings */ bzero(&newTerminalSettings, sizeof(newTerminalSettings)); /* Clear\ struct for new port settings */ /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ newTerminalSettings.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ newTerminalSettings.c_iflag = IGNPAR | ICRNL; /* Raw output. */ newTerminalSettings.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ newTerminalSettings.c_lflag = ICANON; /* Initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newTerminalSettings.c_cc[VINTR] = 0; /* Ctrl-c */ newTerminalSettings.c_cc[VQUIT] = 0; /* Ctrl-\ */ newTerminalSettings.c_cc[VERASE] = 0; /* del */ newTerminalSettings.c_cc[VKILL] = 0; /* @ */ newTerminalSettings.c_cc[VEOF] = 4; /* Ctrl-d */ newTerminalSettings.c_cc[VTIME] = 0; /* inter-character timer unused */ newTerminalSettings.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ newTerminalSettings.c_cc[VSWTC] = 0; /* '\0' */ newTerminalSettings.c_cc[VSTART] = 0; /* Ctrl-q */ newTerminalSettings.c_cc[VSTOP] = 0; /* Ctrl-s */ newTerminalSettings.c_cc[VSUSP] = 0; /* Ctrl-z */ newTerminalSettings.c_cc[VEOL] = 0; /* '\0' */ newTerminalSettings.c_cc[VREPRINT] = 0; /* Ctrl-r */ newTerminalSettings.c_cc[VDISCARD] = 0; /* Ctrl-u */ newTerminalSettings.c_cc[VWERASE] = 0; /* Ctrl-w */ newTerminalSettings.c_cc[VLNEXT] = 0; /* Ctrl-v */ newTerminalSettings.c_cc[VEOL2] = 0; /* '\0' */ /* Now clean the modem line and activate the settings for the port */ tcflush(tDeviceHandle, TCIFLUSH); tcsetattr(tDeviceHandle,TCSANOW,&newTerminalSettings); return; } /* Description: Restore the terminal with old settings Arguments: INT, integer for opened device handle Returns: Nothing */ void ReconfigureTheTerminalForOldSettings(int tDeviceHandle) { tcflush(tDeviceHandle,TCIFLUSH); tcsetattr(tDeviceHandle,TCSANOW,&newTerminalSettings); return; }



