#include <Arduino_FreeRTOS.h>
#include <semphr.h> // add the FreeRTOS functions for Semaphores (or Flags).
#include <Servo.h> // Servo Library *Gutus
Servo myservo; // create servo object to control a servo
// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only one Task is accessing this resource at any time.
SemaphoreHandle_t xSerialSemaphore;
int sensorValue = 0;
int servoValue = 0;
bool SelenoidNC = false;
// define two Tasks for DigitalRead & AnalogRead Sub routine
void TaskDigitalRead( void *pvParameters );
void TaskAnalogRead( void *pvParameters );
void displayMonitor( void *pvParameters);
void servoTask( void *pvParameters);
// the setup function runs once when you press reset or power the board
void setup() {
// Servo initialization
myservo.attach(9); // no 9 for servo
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
}
// Semaphores are useful to stop a Task proceeding, where it should be paused to wait,
// because it is sharing a resource, such as the Serial port.
// Semaphores should only be used whilst the scheduler is running, but we can set it up here.
if ( xSerialSemaphore == NULL ) // Check to confirm that the Serial Semaphore has not already been created.
{
xSerialSemaphore = xSemaphoreCreateMutex(); // Create a mutex semaphore we will use to manage the Serial Port
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive( ( xSerialSemaphore ) ); // Make the Serial Port available for use, by "Giving" the Semaphore.
}
// Now set up two Tasks to run independently.
xTaskCreate(
TaskDigitalRead
, "DigitalRead - Emergency Button" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL //Parameters for the task
, 1 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL ); //Task Handle
xTaskCreate(
TaskAnalogRead
, "AnalogRead - Flow Meter" // A name just for humans
, 128 // Stack size
, NULL //Parameters for the task
, 2 // Priority
, NULL ); //Task Handle
xTaskCreate(displayMonitor, "Display - Monitoring", 128, NULL, 4, NULL);
xTaskCreate(servoTask, "Display - Monitoring", 128, NULL, 3, NULL);
// Now the Task scheduler, which takes over control of scheduling individual Tasks, is automatically started.
}
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskDigitalRead( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
/*
DigitalReadSerial
Reads a digital input on pin 2, prints the result to the serial monitor
This example code is in the public domain.
*/
// digital pin 2 has a pushbutton attached to it. Give it a name:
uint8_t pushButton = 0;
// make the pushbutton's pin an input:
pinMode(pushButton, INPUT);
for (;;) // A Task shall never return or exit.
{
// read the input pin:
int buttonState = digitalRead(pushButton);
// See if we can obtain or "Take" the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks of the Scheduler to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
if (buttonState == LOW){
SelenoidNC = !SelenoidNC;
vTaskDelay(100);
}
// We were able to obtain or "Take" the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
// print out the state of the button:
xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}
vTaskDelay(10); // one tick delay (15ms) in between reads for stability
}
}
void TaskAnalogRead( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
for (;;)
{
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
sensorValue = map(sensorValue, 0, 1024, 0, 101);// map sensorValue to 0-1024 as 1-100 percentage
xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}
vTaskDelay(10); // one tick delay (15ms) in between reads for stability
}
}
void servoTask( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
for (;;)
{
int K = 1; //initial K=1 for Direct Acting, and K= -1 for Reverse Acting
servoValue = sensorValue * K; //Equation to dertermina servoValue
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
servoValue = map(servoValue, 0, 1024, 0, 181);// map servoValue to 0-100% as 1-180 degree
myservo.write(servoValue); //output sensorValue as servoValue
if(SelenoidNC == true){
myservo.write(0);
}
xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}
vTaskDelay(10); // one tick delay (15ms) in between reads for stability
}
}
void displayMonitor( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
for(;;)
{
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
if (!SelenoidNC){
Serial.print("Emergency Status : ");
Serial.println(" SAFE");
Serial.print("Flow Meter Value (%):\t");
Serial.print(sensorValue);// print Flow Meter Value
Serial.print(" Servo Value (deg):\t");
Serial.println(servoValue); //print Servo Degree Value
}else{
Serial.print("Emergency Status :\t");
Serial.println("ALERT!!!");
}
xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}
vTaskDelay(pdMS_TO_TICKS(1000)); // one tick delay (15ms) in between reads for stability
}
}