Разумеется данный кусок кода был придуман и выложен только лишь для примера.
Код реального проекта сложнее и запутаннее.
Он реализует через прерывания определение состояния, вычисление угловой позиции механизма и формирование управляющих воздействий.
В главном цикле содержится "медленный" алгоритм, который пропускает полученные данные через модель и корректирует управление. Также осуществляется связь с компьютером.
Данные о состоянии механизма записаны в структуре примерно следующего вида:
Код: Выделить всё
typedef struct{
volatile
uint8_t state_machine; // машина состояний
int16_t angle_cnt; // текущая угловая позиция
volatile
uint8_t event; // события
uint32_t rev_period_cnt; // счётчик периода оборота диска энкодера
volatile
uint32_t rev_period_latch; // период последнего полного оборота
uint32_t rev_period_pred; // предсказание периода следующего оборота
// и ещё десяток параметров
}ENGINE_PARAMS;
ENGINE_PARAMS engine_data;
Например переменная состояния state_machine используется как в конечном автомате в прерываниях, так и для управления из главного цикла.
Переменная rev_period_latch используется в прерываниях для вычисления ускорений, угловых и временных моментов управления. Она же используется в главном цикле для корректировки управления.
Такой доступ к данным получается не очень оптимальным. Я пока придумал 2 варианта.
Вариант 1.
Все поля структур какие надо объявляются как volatile.
Внутри функций они копируются во временные переменные, которым разрешена оптимизация. На выходе копируются обратно.
Например:
Код: Выделить всё
void proc_engine_state( void )
{
uint8_t sm = engine_data.state_machine;
// делать что-то с переменной sm
engine_data.state_machine = sm;
}
Вариант 2.
В структуре ENGINE_PARAMS все данные не volatile и из функций прерываний к ним идёт самый обычный доступ.
Код: Выделить всё
typedef struct{
uint8_t state_machine; // машина состояний
int16_t angle_cnt; // текущая угловая позиция
uint8_t event; // события
uint32_t rev_period_cnt; // счётчик периода оборота диска энкодера
uint32_t rev_period_latch; // период последнего полного оборота
uint32_t rev_period_pred; // предсказание периода следующего оборота
// и ещё десяток параметров
}ENGINE_PARAMS;
Но объявляется дополнительный указатель
через который получается volatile доступ к членам структуры из главного цикла:
Код: Выделить всё
ENGINE_PARAMS engine_data; // вот это используется только прерываниями
volatile ENGINE_PARAMS *p_engine_data;// а это для главного цикла
main()
{
p_engine_data->state_machine = STOP; // иниц значений
p_engine_data->angle_cnt = 0;
p_engine_data->rev_period_cnt = 0;
while(1)
{
if( p_engine_data->state_machine == WORK )
{
putsf("ENGINE WORK");
}else
{
putsf("ENGINE STOP");
}
if( p_engine_data->event == ERROR )
{
reinit_engine();
putsf("ERROR");
}
}
}
Вариант 2 похож на тот, о котором говорил в предыдущем сообщении.
Кто как решает подобные вопросы? Просто объявлять нужные поля структуры как volatile и не заморачиваться?
Да, компилятор ARMCC, но это наверно не имеет значения т.к. везде должно быть одинково.
Ещё. Есть специализированные DSP процессоры, в которых моя задача решена на аппаратном уровне. Но мне они пока недоступны.