
to make your sketch more professional
Real time operating system
A real-time operating system (RTOS) is an operating system (OS) intended to serve real-time application requests. It must be able to process data as it comes in, typically without buffering delays. Processing time requirements (including any OS delay) are measured in tenths of seconds or shorter.
It’s not a secret that the Arduino has small system resources. Is it possible to run RTOS at Arduino? Fortunately, yes! There is some RTOS which can run at Arduino. We have used some of them and our choice is ChibiOS.
ChibiOS/RT is designed for deeply embedded real time applications where execution efficiency and compact code are important requirements. This RTOS is characterized by its high portability, compact size and, mainly, by its architecture optimized for extremely efficient context switching.
What plus we get when use RTOS
All examples which you see when study Arduino or KSduino is a Linear program. The basic part of program are placed to Loop function and run from its begin to the end. There is a delay at the end of loop when our Arduino does nothing. This kind of program for similar tasks, for example: we read some sensors one time per second. What should we do if we need read light sensor every ten milliseconds and read temperature sensor one time per five seconds. We can write this program in standard loop using millis function and much if which will perform this task. This program will work but the loops code will very long with much conditions. Programs like this is not readable, heavily modified and may contain difficult to debug errors.
When we use RTOS we can create separate processes (threads). Each of the processes looks like separate loop function. So we can create a program with much loops each of they will execute its separate task. In our example the first process will read light sensor with quick delay the second process will read temperature sensors with long delay. Both of this process will send information to KSduino.
Setup RTOS and create sketches
How the RTOS for Arduino looks and what we will use to create programs? The ChibiOS is a simple library which should be copied to your Arduinos library folder. And the program is simple Arduino sketch created in Arduino IDE.
OK, Let us download ChibiOS and create your first ChibiOS Arduino sketch!
We get the ChibiOS from http://code.google.com/p/rtoslibs/ page. This page contain information about other RTOS and link for official ChibiOS website.
There is direct download link, we use version ChibiOS20130208:
http://ksdu.in/o/45
You can download also this archive from the KSduino website:
http://ksduino.org/downloads/ChibiOS20130208.zip
The ChibiOS and KSduino example
We modify example from previous article: Pseudo multitasking. Using timer in Arduino sketch
In this example we create process:
- Thread 1 for sending parameters to KSduino
- Thread 2 for calculate DS18b20 temperature
- Thread 3 for read KSduino answers
To synchronize KSduino tasks we use semafor so in one time moment only one KSduino task can run.
// Includes
#include "SPI.h"
#include "EthernetUdp.h"
#include "OneWire.h" // one wire library to connect ds18b20
#include "ksDS18B20.h" // subclass to read ds18b20 values
#include "KSduino.h" // KSduino Library
#include "ChibiOS_AVR.h" // ChibiOS library
// DS18B20 address
uint8_t devAddr1[] = { 0x28, 0x16, 0x05, 0xB2, 0x03, 0x00, 0x00, 0x00 };
// Define OneWire, DS18B20 & Timer classes
OneWire ds(7); // OneWire on pin 7
ksDS18B20 ds18b20_1 (&ds, devAddr1);
// KSduino User definition -----------------------------------------
// This Arduino ID and Password
// Change this values to yours
unsigned int deviceID = 0000; // set your Device ID
unsigned int devicePwd = 1111; // set your Device Password
// This Arduino MAC, IP,DNS, Gateway and port
// Change this values to yours
byte mac[] = { 0x74,0x69,0x69,0x2D,0x00,0x00 };
byte ip[] = { 192, 168, 1, 222 };
//byte dns[] = { 192, 168, 1, 1 };
//byte gateway [] = { 192, 168, 1, 1 };
//byte subnet [] = { 255, 255, 255, 0 };
unsigned int port = 40000 + deviceID;
// KSduino Server definition ----------------------------------------
// Server address & port
byte serverIp[] = { 178,63,53,233 }; // Global IP address
unsigned int serverPort = 9930; // Port number
// ----------------------------------------------------------------
// Define KSduino class
KSduino ksd (deviceID, devicePwd, serverIp, serverPort);
// Define some KSduino parameters with KSduinoParameter class
KSduinoParameter d1 (&ksd, "d1", 0.5, 15*60);
KSduinoParameter f1 (&ksd, "f1", 0.5, 15*60);
// Semaphore to trigger context switch
Semaphore sem;
// Idle time counter
volatile uint32_t count = 0;
//------------------------------------------------------------------
void setup()
{
ksd.begin(mac, ip, port); // start KSduino
// ksd.begin(mac, ip, dns, gateway, port);
// ksd.begin(mac, ip, dns, gateway, subnet, port);
// Setup ChibiOS
chBegin(mainThread);
}
//------------------------------------------------------------------------------
// thread 1 - this task send KSduino parameters
// 160 byte stack for KSduino task, beyond task switch and interrupt needs
static WORKING_AREA (waThread1, 160);
static msg_t Thread1(void *arg)
{
#define WAIT_FOR_ANSWER 2
for (;;)
{
// Create D1 test value
int d1_generator = random(1,1000);
byte d1_value = d1_generator < 10 ? 1 : 0; // will high ones per second
// Send values to KSduino if something changed
if (d1.check (d1_value) || ds18b20_1.getTemp () && f1.check(ds18b20_1.celsius))
{
chSemWait(&sem); // only one KSduino task should run at this moment
ksd.beginPacket ();
d1.addParameter (d1_value);
f1.addParameter( ds18b20_1.celsius);
ksd.endPacket (WAIT_FOR_ANSWER);
chSemSignal(&sem);
}
chThdSleepMilliseconds(10);
}
return 0;
}
//------------------------------------------------------------------------------
// thread 2 - calqulate DS18b20 thermometer every second
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA (waThread2, 64);
static msg_t Thread2(void *arg)
{
for (;;)
{
ds18b20_1.readTermometer();
chThdSleepMilliseconds(1000);
}
return 0;
}
//------------------------------------------------------------------------------
// thread 3 - KSduino update
// 160 byte stack for KSduino task, beyond task switch and interrupt needs
static WORKING_AREA(waThread3, 160);
static msg_t Thread3 (void *arg)
{
for (;;)
{
chSemWait(&sem); // only one KSduino task should run at this moment
ksd.update ();
chSemSignal(&sem);
chThdSleepMilliseconds(5);
}
return 0;
}
//------------------------------------------------------------------------------
void mainThread() {
// initialize semaphore
chSemInit(&sem, 1);
// start blink thread
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO + 1, Thread1, NULL);
// start print thread
chThdCreateStatic(waThread2, sizeof(waThread2),
NORMALPRIO + 1, Thread2, NULL);
// start ksduino send thread
chThdCreateStatic(waThread3, sizeof(waThread3),
NORMALPRIO + 1, Thread3, NULL);
// Main thread (iadle thread) loop
for (;;)
{
// must insure increment is atomic
// in case of context switch for print
noInterrupts();
count++;
interrupts();
}
}
//------------------------------------------------------------------
void loop()
{
// not used
}
To use this example you need one DS18b20 sensor:
https://ksdu.in/o/3h
This sketch is using ksDS18B20 class. You can download this example with ksDS18B20 class at:
http://ksdu.in/o/46Best regards,
Kirill Scherba
The founder and main developer of
KSduino project.
Sea also:
How to skip repeated parameter values?Pseudo multitasking. Using timer in Arduino sketch