Home > Other >Special Application Circuits > How to create a digital watch using YAKINDU Statechart Tools

How to create a digital watch using YAKINDU Statechart Tools

Source: InternetPublisher:萌面大虾 Keywords: lcd watch Arduino Updated: 2024/12/24

Create a digital watch using the YAKINDU statechart tool for the 16x2 LCD Keypad Shield.

I will show you how to create a digital watch using YAKINDU Statechart Tools and run it on an Arduino using the LCD Keypad Shield .

The original model of the digital watch was taken from David Harrell. He previously published a paper on "Extensive Extensions of the Traditional Form of State Machines and Statecharts". In the paper, he used the digital watch as an example. Inspired by this, I rebuilt the watch using YAKINDU Statechart Tools (a tool for creating state machine graphical models and generating C/C++ code with it) and brought it back to life on Arduino.

How digital watches work

Let's start by defining how a digital watch should work.

Basically, it's a configurable watch with different modes. The main one is to show the current time, but there are some other features. As inputs you have an on/off, a mode and a settings button. Also, it's possible to turn the light on and off.

With the mode button you can distinguish between modes and activate/deactivate clock functions:

Display time (clock)

Display date (date)

Set alarm (Alarm 1, Alarm 2)

Enable/disable ringtone (Set Ringtone)

Using the stopwatch (Stopwatch)

In the menu you can configure the mode using the on/off button. The settings button allows you to set the time - like a clock or alarm. The stopwatch can be controlled by using the light on and light off buttons - start and stop. You can also use the integrated lap counter.

In addition, there is a chime that rings every hour and a controllable backlight is integrated. However, in the first step, I did not connect them to the Arduino.

State Machine

poYBAGL98dGAbCURAAHXWlSlR2I169.png

I don't want to explain this example in detail. It's not because it's too complex, it's just a bit too big. But I will try to explain the basic idea of ​​how it works. Either look at the model or download and simulate it. Some parts of the state machine are summarized in sub-areas, such as the time area of ​​the settings. This ensures that the state machine is readable.

The model is divided into two parts - graphic and text.

In the text section, events, variables, etc. will be defined.

In the graphical part - the state diagram - the logical execution of the model is specified.

To create a state machine that satisfies the specified behavior, some input events are needed, which can be used in the model: onoff, set, mode, light, and light_r. An internal event is used in the definition part, which increments the time value every 100 milliseconds:

every 100 ms / time += 1

Based on a 100 millisecond step, the current time will be calculated in HH:MM:SS format:

display.first = (time / 36000) % 24;
display.second = (time / 600) % 60;
display.third = (time / 10) % 60;

Each time the state machine is called, these values ​​will be connected to the LCD display by using the updateLCD operation:

display.updateLCD(display.first, display.second, display.third, display.text)

The basic execution of the state machine has been defined in the "How a digital watch works" section. In this tool, I used some "special" modeling elements such as CompositeState, History , Sub-Diag rams, ExitNodes, etc.

LCD Keypad Shield
LCD Keypad Shield is very cool for simple projects that need a visual screen and some buttons as inputs - a typical simple HMI (Human Machine Interface). LCD Keypad Shield contains five user buttons and one button for reset. The five buttons are connected together to the A0 pin of the Arduino. Each of them is connected to a voltage divider that can distinguish the buttons.

You can use analogRead (0) to find a specific value, which of course may vary from manufacturer to manufacturer. This simple project displays the current value on an LCD:

#include
#include

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
 lcd.begin(16, 2);
 lcd.setCursor(0,0);
 lcd.write("Measured Value");
}

void loop() {
 lcd.setCursor(0,1);
 lcd.print("  ");
 lcd.setCursor(0,1);
 lcd.print(analogRead(0));
 delay(200);
}

These are my measurements:

None: 1023

Selection: 640

Left: 411

Down: 257

Upper: 100

Right: 0

poYBAGL98dqAC3pYAAVKAnDIS8U703.png

The buttons can be read using these thresholds:

#define NONE 0
#define SELECT 1
#define LEFT 2
#define DOWN 3
#define UP 4
#define RIGHT 5

static int readButton() {
 int result = 0;
 result = analogRead(0);
 if (result < 50) {
return RIGHT;
 }
 if (result < 150) {
return UP;
 }
 if (result < 300) {
return DOWN;
 }
 if (result < 550) {
return LEFT;
 }
 if (result < 850) {
return SELECT;
 }
 return NONE;
}

Connecting the State Machine
The C++ code generated by the state machine provides interfaces that must be implemented to control the state machine. The first step is to connect the in events with the keys of the Keypad Shield. I have already shown how to read the buttons, but in order to connect them to the state machine, the buttons need to be debounced. Otherwise the events will be raised multiple times, resulting in unpredictable behavior. The concept of software debounce is not new.

In my implementation, I detect a falling edge (button release). I read the value of the button, wait 80 milliseconds, save the result and read the new value. If oldResult is not NONE (not pressed) and new result is NONE, then I know that the button was pressed before and now it has been released. After that, the corresponding input event of the state machine can be raised.

int oldState = NONE;
static void raiseEvents() {
 int buttonPressed = readButton();
 delay(80);
 oldState = buttonPressed;
 if (oldState != NONE && readButton() == NONE) {
switch (oldState) {
 case SELECT: {
stateMachine->getSCI_Button()->raise_mode();
break;
 }
 case LEFT: {
stateMachine->getSCI_Button()->raise_set();
break;
 }
 case DOWN: {
stateMachine->getSCI_Button()->raise_light();
break;
 }
 case UP: {
stateMachine->getSCI_Button()->raise_light_r();
break;
 }
 case RIGHT: {
stateMachine->getSCI_Button()->raise_onoff();
break;
 }
 default: {
break;
 }
}
 }
}

The connection
main program uses three parts:

State Machine

Timer

Display handler (typically lcd.print(...))

DigitalWatch* stateMachine = new DigitalWatch();
CPPTimerInterface* timer_sct = new CPPTimerInterface();
DisplayHandler* displayHandler = new DisplayHandler();

The state machine uses the display handler and gets a timer that will be updated to control the timed events. After that, the state machine is initialized and entered.

void setup() {
 stateMachine->setSCI_Display_OCB(displayHandler);
 stateMachine->setTimer(timer_sct);
 stateMachine->init();
 stateMachine->enter();
}

The loop does three things:

Raise input event

Calculate elapsed time and update the timer

Calling state machine

long current_time = 0;
long last_cycle_time = 0;
void loop() {
 raiseEvents();
 last_cycle_time = current_time;
 current_time = millis();
 timer_sct->updateActiveTimer(stateMachine,
current_time - last_cycle_time);
 stateMachine->runCycle();
}

Add Example

To add the examples to a running IDE:

File->New->Example->YAKINDU Statechart Example->Next->Arduino - Digital Watch (C++)

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号