Статья
Версия для печати
Обсудить на форуме
Многозадачность во встроенном приложении

© Dale, 02.01.2012 — 02.01.2012.

Начало: часть 1, часть 2.

Часть 3

Оглавление


Модель приложения на инструментальной системе

В статье «Hello World!» в embedded-исполнении мы уже применяли метод моделирования приложения на инструментальной системе. Это дает возможность убедиться в работоспособности будущей системы, не дожидаясь готовности ее аппаратной части. Поступим так же и в этот раз.

Модуль симуляции аппаратных средств системы

На этот раз, помимо таймера и источника света, которые были у нас в упомянутой статье, в новой системе появился также датчик освещенности, который также не мешало бы симулировать. Я решил использовать для управления его состояниями клавиатуру, а для отображения текущего состояния — консольный вывод, как и ранее.
Поскольку консольная строка отображает теперь состояние двух независимых устройств (а в перспективе, как мы увидим, их будет больше), имеет смысл сосредоточить средства симуляции в отдельном модуле.
Датчик освещенности будет симулироваться следующим образом: нажатие клавиши D (в любом регистре) будет переключать текущее состояние датчика в «день» (Day), а нажатие клавиши N (также в любом регистре) — в «ночь» (Night). Между нажатиями клавиш датчик будет сохранять свое состояние.
Для отображения состояния системы будет использоваться строка консоли. Первая литера строки будет отображать текущее состояние датчика освещенности (D/N — «день/ночь» соответственно). Вторая литера будет отображать состояние красного прожектора — R, если он включен, и пробел, если выключен.
Интерфейс симулятора выглядит следующим образом:

Код: (C) Simulation.h
#ifndef _SIMULATION_H
#define _SIMULATION_H

/** @file
 * @brief Симуляция устройства.
 *
 * Симулируются следующие периферийные устройства:
 * \li датчик освещенности;
 * \li красный прожектор.
 *
 * На консоль выводится строка следующего вида:
 * \li первая литера - состояние датчика освещенности: D(Day)/N(Night);
 * \li вторая литера - R (если красный прожектор включен) либо пробел.
 *
 * Смена состояния датчика освещенности симулируется нажатиями клавиш D и N на любом регистре.
 */


 /**
 * @brief Симуляция состояния датчика освещенности.
 *
 * Симулирует текущее состояние датчика освещенности. Переключение состояния производится нажатием клавиш D (DFay) и N (Night) на консоли.
 *
 * @return Состояние датчика освещенности.
 * @retval 0 Ночь.
 * @retval 1 День.
 */

_Bool Simulation_getDayLightSensor_isDay(void);

 /**
 * @brief Симуляция состояния красного прожектора.
 *
 * Симулирует текущее состояние красного прожектора.
 * @param val 0 - выключен, 1 - включен.
 */

void Simulation_setRedLightSwitch(_Bool val);

 /**
 * @brief Итерация симуляции.
 */

void Simulation_run(void);

#endif // _SIMULATION_H

Реализация:

Код: (C) Simulation.c
#include "Simulation.h"
#include <conio.h>
#include <ctype.h>
#include <stdio.h>

static _Bool isDayFlag = 0;

_Bool Simulation_getDayLightSensor_isDay(void)
{
    char c;
    if (_kbhit())
    {
        c = toupper(_getch());
        if (c == 'D')
            isDayFlag = 1;
        else if (c == 'N')
            isDayFlag = 0;
    }

    return isDayFlag;
}

static _Bool redLightSwitchState = 0;

void Simulation_setRedLightSwitch(_Bool val)
{
    redLightSwitchState = val;
}

static char showDayFlag(void)
{
    return isDayFlag ? 'D' : 'N';
}

static char showRedLightSwitchState(void)
{
    return redLightSwitchState ? 'R' : ' ';
}

void Simulation_run(void)
{
    printf("%c%c\r", showDayFlag(), showRedLightSwitchState());
}

Симулятор красного прожектора

Код: (C) RedLightSwitch.c
#include "RedLightSwitch.h"
#include "Simulation.h"

void RedLightSwitch_init(void)
{
    Simulation_setRedLightSwitch(0);
}

void RedLightSwitch_off(void)
{
    Simulation_setRedLightSwitch(0);
}

void RedLightSwitch_on(void)
{
    Simulation_setRedLightSwitch(1);
}

Симулятор датчика освещенности

Код: (C) DayLightSensor.c
#include "DayLightSensor.h"
#include "Simulation.h"

void DayLightSensor_init(void)
{
}

_Bool DayLightSensor_isDay(void)
{
    return Simulation_getDayLightSensor_isDay();
}

Симулятор таймера

Симуляция таймера несколько отличается от предыдущей версии. На этот раз мы не можем позволить себе зациклить управление до тех пор, пока будет выдержана необходимая пауза. Вместо этого мы вычислим конечную метку времени, а затем будем проверять, достигнута она или еще нет.

Код: (C) IntervalTimer.c
#include "IntervalTimer.h"
#include <time.h>

static clock_t finishMark;  // конечная временная метка интервала

void IntervalTimer_init(void)
{
    finishMark = 0;
}

void IntervalTimer_start(uint16_t interval)
{
    finishMark = clock() + (interval * CLOCKS_PER_SEC / 1000);
}

_Bool IntervalTimer_isElapsed(void)
{
    return (clock() >= finishMark);
}


Вспомогательная версия модуля Application

Для целей симуляции нам придется слегка модифицировать реализацию модуля Application:

Код: (C) ApplicationSim.c
#include "Application.h"
#include "RedChannelAuto.h"
#include "Simulation.h"

void Application_init(void)
{
    RedChannelAuto_init();
}

void Application_run(void)
{
    RedChannelAuto_run();
    Simulation_run();
}

По сравнению с базовой версией в функцию Application_run() добавлен вызов Simulation_run(), посредством которого производится отображение выходной информации для симуляции устройства на инструментальной системе.



Увидеть результат симуляции можно, загрузив и запустив соответствующее приложение. Напоминаю, что в процессе симуляции можно использовать клавиши D и N для имитации дневного и ночного режимов датчика освещенности.
Архив с текущим состоянием проекта находится во вложении.

Продолжение.
Версия для печати
Обсудить на форуме