Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
292 views8 pages

Parola A Do Z

Download as doc, pdf, or txt
Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1/ 8

Arduino++

Arduino, CNC, software and other ramblings

Parola A to Z Text Animation


On February 10, 2017 By marco_cIn Arduino, Parola, softwareLeave a comment

The key function of the Parola library is to display text using different
animations. These are built around a core supporting framework and largely follow the same
patterns. This article explores how Parola animations are constructed so that advanced users of
the library have enough information to be able to write (and contribute!) their own new
animations.
Arduino++
Arduino, CNC, software and other ramblings

Parola A to Z Text Animation


On February 10, 2017 By marco_cIn Arduino, Parola, software

The key function of the Parola library is to display text using different
animations. These are built around a core supporting framework and largely follow the same
patterns. This article explores how Parola animations are constructed so that advanced users of
the library have enough information to be able to write (and contribute!) their own new
animations.

What is Animation?

Animation is a series of still images (frames) that follow each other which, through a persistence
of vision effect, we see as moving in a continuous and smooth manner. The frame rate
(expressed in frames per second or FPS) is the frequency at which consecutive frames are shown
in an animated display.

For the Parola library, an animation is broken up into 3 parts

1. A text effect while entering the display.


2. A pause to allow reading the message.

3. A text effect when leaving the display.

The frame rate is governed by the speed setting, which determines how often the animation code
is invoked, and entry and exit effects can be different.

A crucial part of the animation is the pause in the middle. The text position at this point is
identical for all animations, based on a combination of the text displayed and the justification
(left, center or right) selected. This rule allows the selection of different entry and exit effects, as
the starting point for the exit sequence is the same and the ending point for the entry sequencer in
all text effects. Specifically, the common location is where the commonPrint() method displays
the text.

Creating a Text Effect

An effect can be created in one of 2 ways. Which is used depends on the coder and the
complexity of the effect:

Rewind/Play: Using this method the text is initially placed in the display
buffer using the commonPrint() method. For the entry effect the text is then
rewound and, conversely, for an exit effect it is played, to where it would be
in the current frame. Most animations are coded using this straightforward
algorithm.
Frame-by-Frame: Using this method the frames are incrementally built up
column by column, using the font management functions getFirstChar() and
getNextChar() described in this previous blog. Only a few text effects use this
method as the code can be much more complex. SLICE and SCROLLING are
examples of frame-by-frame animation.

Each text effect is implemented as a standalone private method containing a finite state machine
(FSM) in 2 parts. One part implements the text move into the display (parameter bIn is true) and
the other the text move out of the display (bIn is false). Because the entry and exit effects can be
different for a display cycle, the code cannot assume that the either separate part was ever called.
The FSM can use a number of defined states:

INITIALISE: A one time initialization of for text entry effect. The exit effect
can be initialized when the state is PAUSE and bIn is false.
GET_FIRST_CHAR: Get and display the first character. Any character related
initialization (eg, reset displayed column count) should be done here as well.

GET_NEXT_CHAR: Any character other than the first. In many animations


only one of GET_FIRST_CHAR and GET_NEXT_CHAR is needed.

PUT_CHAR: In the middle of placing a character on the display. Typically this


is displaying columns of the character on the display in frame-by-frame
animations.

PUT_FILLER: The method should be placing filler (blank) columns into the
display. This is often not implemented by the text effect.

PAUSE: Set by the text effect when the text has reached the pause location
and the first phase of the animation is completed. The library will then delay
the exit effect by the specified pause time.

END: set by the FSM when the exit effect has completed and the display cycle
has completed.

The general flow within the FSM is the entry phase starting with _fsmState set to INITIALISE
and ending when the state is set to PAUSE within the effect method. The exit phase starts from
the PAUSE state and ends when the state is set to END by the method. Aside from the
INITIALISE state, which is set by the displayReset(), all other states are set by the method itself.
Additionally all states, except PAUSE and END, only have local meaning.

Delays between frames and the pause between entry and exit are handled by the main library
code.

Global variables within the class are used to track the status for the current text effect to avoid
static declarations (and wasted memory) in the text effect.

_fsmState holds the state set during the last invocation.


_limitLeft and _limitRight are the text column limits for the pause position of
the text.

_nextPos, _posOffset, _startPos, and _endPos are available for the text effect
to maintain counters and status between calls.

Integrating an Effect into Library

Integrating a new text effect is relatively straightforward:

1. Choose a name for the effect. The convention is effect for the method
located in a source file called MD_Parola_.
2. Add the identifier for the text effect to the textEffect_t enumerated type.

3. Add the function prototype for the new effect to the MD_PZone class definition
in the MD_Parola.h file.

4. Modify the zoneAnimate() method in MD_PZone.cpp to invoke the new


method from the scheduler.

5. Clone an existing method and modify it according to what the effect needs to
do. This is the hardest part!

The Simplest Example the PRINT effect

The simplest text effect is PRINT, shown below. The entry is the text being printed and the exit is
the display cleared.

This example shows the basic layout of the in and out sections, which is common to every other
text effect. Note _fsmState is also set to PAUSE and END to signal the end of each animation
phase.

void MD_PZone::effectPrint(bool bIn)


// Just print the message in the justification selected
{
if (bIn) // incoming
{
commonPrint();
_fsmState = PAUSE;
}
else //exiting
{
zoneClear();
_fsmState = END;
}
}

More Complexity the FADE Effect

For the FADE effect, entry is a display intensity increase from 0 to the current intensity setting.
The exit text effect is the same thing in reverse.

This example implements a strategy similar to Rewind/Play without the added complexity of
moving or masking the text bitmap whilst still using more FSM cases.

INITIALISE is used to set the class variable to the start and end intensity of the fade sequence
before clearing the display, as we start from no test being displayed. The next call (with
_fsmState == GET_FIRST_CHAR), the intensity is increased and the text printed using
commonPrint(). Subsequent calls (_fsmState == PUT_CHAR) only change the intensity as the
text is already displayed. The FSM sets the PAUSE state when it has reached the last intensity
setting.
void MD_PZone::effectFade(bool bIn)
// Fade the display in and out.
// If the overall intensity is changed while the animation is running, the
// intensity at the start of the animation will be restored at the end,
overriding
// any user code changes.
{
if (bIn) // incoming
{
switch (_fsmState)
{
case INITIALISE:
_nextPos = 0;
_endPos = getIntensity();
zoneClear();
_fsmState = GET_FIRST_CHAR;
break;

case GET_FIRST_CHAR:
setIntensity(_nextPos++);
commonPrint();
_fsmState = PUT_CHAR;
break;

case PUT_CHAR:
// check if we have finished
if (_nextPos > _endPos)
_fsmState = PAUSE;
else
setIntensity(_nextPos++);
break;

default:
_fsmState = PAUSE;
}
}
else // exiting
{
switch (_fsmState)
{
case PAUSE:
_nextPos = _endPos = getIntensity();
setIntensity(_nextPos);
commonPrint();
_fsmState = PUT_CHAR;
break;

case PUT_CHAR:
// check if we have finished
if (_nextPos < 0)
{
setIntensity(_endPos); // set to original conditions
zoneClear(); // display nothing - we are currently at 0
_fsmState = END;
}
else
setIntensity(_nextPos--);
break;

default:
_fsmState = END;
}
}
}

Full Complexity SCAN_HORIZ Effect

The SCAN_HORIZ text entry and exit effects display the text as a single column scanning end to
end. At fast frame rates, persistence of vision creates the impression of a vertical letterbox slit
moving over the text.

This effect is of the Rewind/Play type. INITIALISE sets up the global variable through a helper
function that initializes:

_startPos = _nextPos = (_textAlignment == PA_RIGHT ? _limitRight :


_limitLeft);
_endPos = (_textAlignment == PA_RIGHT ? _limitLeft : _limitRight);
_posOffset = (_textAlignment == PA_RIGHT ? 1 : -1);

Each subsequent call to the FSM loads entire text into the display buffer using
commonPrint() and all the columns except the currently scanned column are then removed
PAUSE is reached when the last text column is scanned.

The exit effect is identical except the display is left with no text at the end.

void MD_PZone::effectHScan(bool bIn)


// Scan the message over with a new one
// Print up the whole message and then remove the parts we
// don't need in order to do the animation.
{
if (bIn) // incoming
{
switch (_fsmState)
{
case INITIALISE:
setInitialEffectConditions();
_fsmState = PUT_CHAR;
// fall through to next state

case PUT_CHAR:
commonPrint();
// check if we have finished
if (_nextPos == _endPos)
{
_fsmState = PAUSE;
break;
}

// blank out the part of the display we don't need


for (uint8_t i=_startPos; i != _endPos+_posOffset; i += _posOffset)
{
if (i != _nextPos)
_MX->setColumn(i, EMPTY_BAR);
}
_nextPos += _posOffset; // for the next time around
break;

default:
_fsmState = PAUSE;
}
}
else // exiting
{
switch (_fsmState)
{
case PAUSE:
setInitialEffectConditions();
_fsmState = PUT_CHAR;
// fall through to next state

case PUT_CHAR:
commonPrint();

// blank out the part of the display we don't need


for (uint8_t i=_startPos; i != _endPos+_posOffset; i += _posOffset)
{
if (i != _nextPos)
_MX->setColumn(i, EMPTY_BAR);
}

// check if we have finished


if (_nextPos == _endPos)
_fsmState = END;
_nextPos += _posOffset; // for the next time around
break;

default:
_fsmState = END;
break;
}
}
}

Frame-by-frame animations are considerably more complex that the Rewind/Play type, because
many more things need to be tracked during the animation, but in principle they work the same
way.

You might also like