Artikel ini adalah pengembangan dari artikel “Lampu Kedip Dengan Model Finite State Machine“. Pada artikel tersebut pewaktuan 1 detik menggunakan fungsi delay() dari Arduino. Pada artikel ini digunakan vTaskDelay pada sistem operasi real time FreeROTS untuk mendapatkan perioda 1 detik untuk eksekusi Finite State Machine (FSM).
Spesifikasi
Sistem yang dibuat adalah lampu kedip, dengan perioda 2 detik.
Perangkat Keras
Perangkat lunak dengan Arduino Nano ATmega328. Output dengan LED yang diseri dengan resistor pembatas arus. Nilai resistor tidak kritis. Pada percobaan ini dipakai nilai resistor 1000 ohm. LED disambung ke port D3 pada Arduino Nano.
Model Sistem
Model FSM untuk lampu kedip adalah sebagai berikut.
Perangkat Lunak
Pada sistem ini diperlukan pewaktuan (timing) agar lampu berkedip dengan frekuensi 0,5 Hz. Untuk itu diperlukan FSM yang dihitung/dipanggil setiap 1 detik. Untuk membuat pemanggilan periodik seperti ini dapat dilakukan dengan beberapa cara sebagai berikut:
- delay pada Arduino atau library lain
- interupsi timer
- delay pada Real Time Operating System misal FreeRTOS
Pada implementasi ini yang dibuat adalah menggunakan FreeRTOS. Delay menggunakan fungsi vTaskDelay() pada FreeRTOS. Penjelasan tentang FreeRTOS di Arduino dapat dibaca di artikel https://www.arduino.cc/reference/en/libraries/freertos/
Model diagram alir (flowchart) perangkat lunak adalah sebagai berikut.
Aplikasi memiliki 2 super loop. Super loop pertama ada di main program, tidak berisi apa-apa. Super loop kedua ada di Task FSM.
Kode lengkap dapat dilihat di repository https://github.com/waskita/embedded/blob/master/kedip/nano-fsm-freertos/nano-fsm-freertos.ino
Bagian Awal
#include "Arduino_FreeRTOS.h"
#define ON 100
#define OFF 101
#define LED_OUTPUT 3
int state = OFF;
TaskHandle_t xHandle1 = NULL;
Inisialisasi Sistem
void setup() {
int output = 0;
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_OUTPUT, OUTPUT);
Serial.begin(115200);
Serial.print("portTICK_PERIOD_MS: ");
Serial.print(portTICK_PERIOD_MS);
Serial.println();
fsm_init(&state);
fsm_output(output);
xTaskCreate(
TaskFSM
, "TaskFSM" // A name just for humans
, 100 // stacksize
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, &xHandle1 );
}
Implementasi Inisialisasi Finite State Machine
Implementasi ini serupa dengan di artikel “Lampu Kedip Dengan Model Finite State Machine“
void fsm_init(int *state, int *out) {
*state = OFF;
*out = 0;
}
Implementasi Finite State Machine
Implementasi ini serupa dengan di artikel “Lampu Kedip Dengan Model Finite State Machine“
void fsm(int *state, int *out) {
switch (*state) {
case ON: {
*state = OFF;
*out = 0;
break;
}
case OFF: {
*state = ON;
*out = 1; // nyalakan output
break;
}
}
}
Implementasi Output FSM
Implementasi ini serupa dengan di artikel “Lampu Kedip Dengan Model Finite State Machine“
void fsm_output(int output_value) {
if (output_value == 1) {
digitalWrite(LED_OUTPUT, HIGH);
} else {
digitalWrite(LED_OUTPUT, LOW);
}
}
Implementasi Task / Thread
static void TaskFSM(void *pvParameters)
{
TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialised with the current tick
count. Note that this is the only time we access this variable. From this
point on xLastWakeTime is managed automatically by the vTaskDelayUntil()
API function. */
xLastWakeTime = xTaskGetTickCount();
while (1)
{
int output = 0;
fsm(&state, &output);
if (output == 1) {
digitalWrite(LED_OUTPUT, HIGH);
} else {
digitalWrite(LED_OUTPUT, LOW);
}
Serial.print("state: ");
Serial.print(state);
Serial.print(" output: ");
Serial.print( output);
Serial.println();
vTaskDelayUntil( &xLastWakeTime, ( 1000 / portTICK_PERIOD_MS ) ); // perioda 1 detik
}
}
Pengujian
Pengujian dilakukan dengan menjalankan program, kemudian mengamati kedipan lampu dan output ke port serial.
Pada output serial akan muncul tampilan seperti berikut ini:
16:23:36.204 -> state: 100 output: 1
16:23:37.280 -> state: 101 output: 0
16:23:38.302 -> state: 100 output: 1
16:23:39.324 -> state: 101 output: 0
16:23:40.390 -> state: 100 output: 1
16:23:41.415 -> state: 101 output: 0
16:23:42.427 -> state: 100 output: 1
16:23:43.466 -> state: 101 output: 0
16:23:44.534 -> state: 100 output: 1
16:23:45.557 -> state: 101 output: 0
16:23:46.581 -> state: 100 output: 1
16:23:47.652 -> state: 101 output: 0
16:23:48.674 -> state: 100 output: 1
Dari output serial tersebut nampak perubahan state dan output terjadi sesuai rancangan.
Waktu perubahan tidak tepat 1 detik, terlihat bergeser sedikit. Penyebabnya kemungkinan karena implementasi timer tick pada FreeRTOS Arduino menggunakan Watchdog Timer, bukan Timer 0, Timer 1 ataupun Timer 2. Watchdog Timer pada Arduino menggunakan osilator RC yang tidak setepat osilator kristal.