Accidental Science Accidental Science

Remotely displaying 8 Analog inputs

Display and analog reader
This project features a remote analog inputs reader, with data transmitted over a RS485 line. Based on event-driven functions and the NSC OS this run on ATmega32 MCUs.

Reading and displaying

This is apparently a simple project: its purpose is to display analog data coming from a remote unit that has eight analog inputs.
Remotely means that the two devices, the Display unit and the Reader unit, are apart at a distance that could be as far as almost a mile: 1200 m. I've said apparently because indeed it is rather complex as a system, as it is potentially able to transfer data over a network of 127 devices on a RS485 data bus. Also each unit runs a program that works in cooperation with an operating system that provides all the necessary support for network communication, event management and task management, antibouncing, and more.

This use case is a relatively simple application as it's actual purpose is to just display the voltage and current and analog settings of a power supply (so not even trasmitting data at a significative distance). But it comes as an handy example that may help showcase the potentials of the system.

Building the whole thing

This article is just an introduction. The code is written in C. To compile the code AVR GCC can be used. It can also be used also ICCAVR though unfortunately this compiler is no longer developed by the manufacturer. The physical devices can be purchased or you can build yourself, however I'll present them in more detail in a future article.

Description of the devices

Both units are powered by an Atmel/Microchip ATmega32a microcontroller. From now on, in the article I refer to the Reader unit simply as "Reader" and the Display unit simply as "Display". The Reader has four buffered logic inputs, four OC outputs, and eight analog inputs ...and more (see functional schematic below). Its core part is the ATmega32 microcontroller, a LM7805 voltage regulator, some transistors to buffer the inputs and outputs, a transceiver to send and receive data from the RS485 line, a yellow LED to provide basic status information, and some opamps to buffer the analog inputs and a noise generator as explained better later on.

The Display has three+four buffered inputs (four of them used to attach an optional keyboard), and two open-collector outputs, a one-wire input with a DS18S20 thermo sensor on board, voltage regulator, RS485 transceiver and of course a display.

Looking at the picture on top of the article you may notice that the Reader is kind of a prototype. I modified an existing board that has similar characteristics to carry the ADC inputs that otherwise were not used in the original board.

NSC 8A44 functional

Cross device processing

With reference to the drawing below, the Reader cyclically sends to the Display the values read from its analog inputs.
This is accomplished through a timer that fires an event after half a second, and inside this event routine remote procedures are called to drive an event inside the Display bringing there the respective analog values.
In the drawing these remote procedure calls (RPC) are shown with the violet and orange arrows, where the named RPCs are listed next to the arrows.

Display-reader
PSU Display and Reader

Inside the Display the public event (an event fired from a remote device through a remote procedure call) there is the code used to print the data on screen.

Here a code example shows how it is implemented:

The following code is located inside the Reader. /* This event is fired when the timer 0 expires. The OS offers up to eight timers with standard resolution of 1/10 of second or extended resolution down to 1/100 of second for selected OS timers. Note: this is not the MCU timer! Because inside the event we reload the timer, this timer continue to cyclically expire every half second. */ event Timer0(void) { setTimer(5, TIMER0); // reload timer, it will expire in 5 tenth of second. Second argument tells which timer is affected. RPC(PSUdisplay_newVoltage_VECTOR, READANALOG(0)); // call remote procedures, reading each analog channel. RPC(PSUdisplay_newCurrent_VECTOR, READANALOG(1)); RPC(PSUdisplay_currentSet_VECTOR, READANALOG(2)); RPC(PSUdisplay_limit2A_VECTOR, READANALOG(3)); } // This event is fired when one of the LOGIC input change. // IN: status of inputs; HIN: inputs that changed to high; LIN: inputs that changed to low. event input(unsigned int IN, unsigned int HIN, unsigned int LIN) { RPC(PSUdisplay_newStatus_VECTOR, IN); // call remote proc. sending the status of the inputs. }

The following code is an abstract from what is located inside the Display. event timer0(void) { setTimer(10, TIMER0); // reload timer, elapsing time: 1 second // Update ambient temperature - Because DS1820 returns temp. in half degrees and // we display it with one decimal, so we need to multiply by 10 and divide by two. textOut(0, sm_temperature, getIn(DGTDATA0)*10/2); // reprint status as it was received (see public event newStatus) newStatus(lastStatus, this); // force the display backlight to stay always on (otherwise it automatically turns off after a while) GLOWDISPLAYLAMP; } // This public event is fired when on another device a RP calls this public event. pubevent newVoltage(int volt, byte caller) { // Display voltage output update. The received data in 'volt' is converted // into decimal from hex as a 12 bits value. textOut(0, sm_Vout, convert10Bit2Decimal(volt, OPTCONVERT_12BITS)); } // As above this public event is fired when from the remote device it is invoked calling the RPC with a vector to this event. pubevent newStatus(int status, byte caller) { unsigned char r; if((lastStatus = status) & PSUalarm) { textOut(0, sm_AlarmMsg); } else { textOut(0, sm_noAlarm); // clear alarm SetInvert; if(status & outON) { r = TC_outStatus_outON; } else { r = TC_outStatus_outOFF; } textOut(0, gTextCollection[r]); // ... more code omitted ... } } ... more code omitted ...

Bidirectional calls

Because the Simple Field Bus Protocl (SFBP) allows multimaster networking, each device can transmit data to any other device at any time, provided no collision happens. SFBP specifications state that in case of collision up to five attempt should be made each one delayed by an increasing time.
So the Display can call back the Reader, or just send messages at any time. For example to drive Reader's outputs.
Changing remote outputs can be accomplished without even requiring to impement any code inside the recipient by simply using the OS's function setOut:

setOut(target_device, ON0, OFF2);

Creating the project

To create the required code stubs the NSC AppWizard can be used. Within this application (see image below) the device model is first selected. One can also define his/her own device. A name is given and the device is added to the project. Now options can be selected to include the required features, while not including unused features to reduce the final code size.
It is also possible select the desired events that should be implemented, and add public events the device will respond to.

Appwizard
NSC AppWizard screenshot. It works on Windows XP to Windows 11.

DisplayMaker to design pages and strings

If the selected device has a display through DisplayMaker it is possible to design pages and strings. Clicking the Edit strings... button on AppWizard, DisplayMaker pops up.
Simply entering the text and special commands and characters using the toolbar, strings and pages can be easily and swiftly created.
One interesting point is you can enter number placeholders with specific decimal and fixed digit formats, and references to other indexed strings.
Each string has an identifier name, in the image below it is possible to notice that some names are enclosed in brackets, indicating that those are indexed strings that will be accessible through the gTextCollection[] global array.
While they can be directly used, usually they are used as indexed strings that are automatically selected given an index argument to the function textOut. Similarly a command can be included to display indexed strings that are displayed as selectors, useful to show a menu and the current selected item simply giving the index of the current item.

DisplayMaker also offer the possibility to hold the current screen, and even add further overlapped texts to precisely position strings with ease.

DisplayMaker
DisplayMaker screenshot example.

After all the selections has been done and entered the desired strings for the device, more devices can be added to the project.
Once all devices has been configured as desired the project can be generated via menu Generate.
AppWizard generates the folders and files with code stubs that can be completed.
A devicename.evt.c.h module has the code stubs for the events, the devicename.prv-ini.c.h provide a place where your initialization code can go, devicename.prv.h for your global defines, function prototypes and declarations, and devicename.prv.c.h for your function implementations.

In this case for the Display into the PSUdisplay.pvr-ini.c.h file the initialization code to clear screen, print the main page and start the timer is placed.
While into PSUdisplay.evt.c.h the code for the selected events and pubevents is added.
The same is done for the Reader (devicename: PSUreader).
For the whole project I added about fourty lines of code!

events
Local events
pubevents
Public events are fired when a remote device calls a RPC

Summary of the NSC built-in Events and Functions

  • Events: Click, Longclick, Input, net, outchange, button, timer0...timer7, analog0, zeroencoder, encoder, interrupt0...interrupt2, scheduler, powerdown, powerup, keydetected, TChange.
  • Public events: as per user defined; function: RPC, setbusy, resetbusy, setsync, resetsync, wait, sendOK.
  • Local and Remote Methods and Functions: getIn, getOut, setOut, ResetAll, dimmer.
  • Local only Functions and Methods: read (eprom), write (eprom), yield, GLOWALARMLED, DARKALARMLED, OUT, setPWM, servo, setAnalogTrigger, encoder, setTimer, getTimer, setDatetime.
  • Scheduler functions: getSchedRecord, getSchedException, insertSched, deleteSched, freezeScheduler, ResetSched, readSched, writeSched.
  • Networking functions: send, SendCTRL, SendData.
  • Graphic methods: appendbuf, flashRead, drawbar, drawpixels, movecur, GLgotoX, GLgotoY, GLbitmapOut, _putchar, textOut, convert10Bit2Decimal, putnum, clearline, cls, showicon, drawicon, cpybuf, SetUnderline, SetDotsUnderline, SetBold, SetInvert, SetNormal
  • Error handling: try, catch, getErr, raiseException.

More to come

With this system all devices can communicate and call each other's public events. Complex distributed systems can be made, and have been made for building automation, control of industrial machineries, and even a laser game.
The system has some limitation of course, in particular tasks are cooperative, so no loop should be used inside events or function.
The AppWizard can also generate some special modules to handle cyclical functions at level of main task loop or at a millisecond pace.
Furthermore a module can be generated for special settings before and after interrupts are enabled at startup, while interrupts, if enabled are called as events.
Also it is possible to specify a private module for data communication replacing the included SFBP.

This is an evolution from an old project, as I designed the whole Network Shared Control operating system.
I'll put online the AppWizard setup that comes with the whole NSC SDK, though at the moment I writing this article it is not yet up.
If you are interested in this project, please let me know either contacting me through this site or on my page on Facebook or commenting on my videos on my YouTube channel.

Thanks for your interest.

Don't miss next post

Subscribe to stay up to date when new articles, videos or other contents are available.

RELATED ARTICLES

RECENT ARTICLES

Terms of use - Privacy - Legal information  |  Contacts  |  About  |  Subscribe [Valid Atom 1.0]  |  Sitemap

Powered by BlogManager™, Content Management for Static Websites