С возрастанием уровня технического развития возникает необходимость повышения функциональности электронных изделий. Для это требуется организовать одновременное выполнение большого количества независимых процессов с одной стороны, и низкую стоимость всей системы – с другой. Конечно. удешевить стоимость можно за счет оптимизации схемотехники системы, исключив ряд её компонентов и используя более низкостоимостную элементную базу, но в связи с этим возрастет функциональная нагрузка на оставшиеся компоненты системы, и, в частности – на управляющий микропроцессор. Но даже в таком случае часто себестоимость выходит слишком высокой. Выходом из положения является замена дорогостоящих микропроцессоров на более дешёвую их альтернативу – микроконтроллеры. И тогда на первый план выходит проблема построения эффективных сложносоставных систем на основе микроконтроллеров.
Основной задачей сложносоставных систем является оптимальное распределение машинного времени управляющего микроконтроллера между компонентами системы, что, в свою очередь, требует реализации некоторого количества одновременно выполняющихся участков кода управляющей программы, для обеспечения чего необходимо учитывать имеющиеся в распоряжении ресурсы микроконтроллера и распределять их между процессами в соответствии с приоритетами этих процессов[1]. С увеличением числа задач усложняется алгоритм распределения ресурсов, что требует дополнительного времени при разработке многофункциональных систем.
Для обеспечения эффективного функционирования современной системы управляющему микроконтроллеру необходимо одновременно производить математическую обработку данных и осуществлять постоянный контроль и управление несколькими периферийными блоками системы (интерфейс пользователя, опрос датчиков, приёмо-передача данных и т.п.)[2]. В общем случае каждая из этих задач реализуется посредством выполнения индивидуального алгоритма, имеющего собственный набор параметров, к числу которых относятся требуемая скорость смены шагов алгоритма и величины временных задержек. При классическом подходе совмещённая организация подобных операций на одном микроконтроллере достигается за счёт специальных приёмов, существенно усложняющих структуру программы введением многоуровневой системы машинных состояний, характерных для совмещаемых процессов (ввод псевдопараллельного выполнения) [3].
Существует множество решений глобального распараллеливания задач для производственных микроконтроллеров, от использования диспетчеров задач до операционных систем реального времени. Но, что если ресурсы ограничены, а задачи, хоть и просты, все же требуют параллельного выполнения? Конечно, в таком случае громоздкие модули неприменимы. Выход прост – использование псевдопараллельного программирования. С помощью его приемов можно создать нетребовательную к ресурсам, с понятным кодом программу для выполнения относительно простых задач, зато обеспечивающую надежность перехода из режима в режим[4].
Далее приведен пример двух частей программы, разработанной для микроконтроллера STM32R100RB. Первая часть реализует мигание светодиодом, с использованием системных часов реального времени для задания частоты мигания. Вторая часть реализовывает интуитивное меню на основе трех кнопок. Обе части выполняются постоянно и последовательно, но, благодаря разделению частей кода, отвечающих за отдельные состояния процесса, создается эффект параллельного выполнения[5].
Рассмотрим пример более подробно. На рис. №1 отображена диаграмма состояний и переходов для второй части: примера Меню.
Рисунок №1 – Диаграмма состояний и переходов Меню
В процессе работы программа находится в одном из состояний и при наличии условия перехода его меняет. То же и для первой части примера.
Мигание светодиодом (псевдопараллельное выполнение).
void modIndication_Run(void){
unsigned char nextState;
unsigned char status;
unsigned char i = 0;
unsigned long delayTime = 0;
switch (blinkState){
// Начальное состояние (выполняемый код ограничен «скобками» case-break) светодиод загорается
case BLINK_STATE_ON :
BlinkPhase = 1;
nextState = BLINK_STATE_DELAY_ON;
saveOldTime = modSysClock_getCurrentTime();
break;
// Второе состояние, контроллер просто проверяет пришло ли время менять состояние. Такой прием не забирает время контроллера, в отличие от функции delay(); или задержки счетом большого числа.
case BLINK_STATE_DELAY_ON :
saveNewTime = modSysClock_getCurrentTime();
delayTime = saveNewTime – saveOldTime;
if (modSysClock_isTimesUp(delayTime, 250)){
nextState = BLINK_STATE_OFF;
}
else{
nextState = BLINK_STATE_DELAY_ON;
}
break;
// Третье состояние. Светодиод гаснет. Автоматический переход в четвертое состояние.
case BLINK_STATE_OFF :
BlinkPhase = 0;
nextState = BLINK_STATE_DELAY_OFF;
//saveTime = modSysClock_getCurrentTime();
saveOldTime = modSysClock_getCurrentTime();
break;
// Четвертое состояние. Тот же принцип, что и во втором состоянии
case BLINK_STATE_DELAY_OFF :
saveNewTime = modSysClock_getCurrentTime();
delayTime = saveNewTime – saveOldTime;
if (modSysClock_isTimesUp(delayTime, 250)){
nextState = BLINK_STATE_ON;
}
else{
nextState = BLINK_STATE_DELAY_OFF;
}
break;
}
blinkState = nextState; [5]
Меню настройки количества горящих светодиодов на основе трех кнопок (псевдопараллельное выполнение)
void BusinessLogic_Run(void){
unsigned char i = 0;
unsigned char nextLevel;
unsigned char error = 0;
unsigned char addData = 1;
unsigned char next = 1;
unsigned long delayTime = 0;
switch (Menulevel){
// Первое состояние. Ожидание сигналов от кнопок. Выполняемый код ограничен «скобками» case-break.
case WaitForEnter :
if (modKeyboard_GetState(BUTTON_1,buttonStateHold)){
nextLevel = AllLedsBlink;
} else {
nextLevel = WaitForEnter;
}
break;
// Второе состояние. Вход в режим меню изменение количества светодиодов. Переход в состояние ожидания сигналов кнопок «больше», «меньше».
case AllLedsBlink :
Stack_LEDS[i] = Stack_Previous_LEDS[i];
for(i=0; i<STACK_SIZE10; i++){
if (Stack_LEDS[i] == 1){
modIndication_SetLedMode(i,LED_MODE_BLINK);
}}
saveOldTime = modSysClock_getCurrentTime();
nextLevel = WaitForChange;
break;
// Третье состояние. Состояние ожидания сигналов кнопок «больше», «меньше». Если Сигналов нет преход в состояние возврата предыдущих настроек.
case WaitForChange :
saveNewTime = modSysClock_getCurrentTime();
delayTime = saveNewTime – saveOldTime;
if (modSysClock_isTimesUp(delayTime, 7000)){
next = TIME;
}
if (modKeyboard_GetState(BUTTON_2, buttonStateReleased)){
next = MORE;
}
if (modKeyboard_GetState(BUTTON_3, buttonStateReleased)){
next = LESS;
}
if (modKeyboard_GetState(BUTTON_1,buttonStateHold)){
next = EXIT;
}
switch (next){
case MORE :
nextLevel = SetMoreLeds;
break;
case LESS :
nextLevel = SetLessLeds;
break;
case EXIT :
nextLevel = SaveChangesAndGo;
break;
case TIME :
nextLevel = DisagreeChanges;
break;
default :
nextLevel = WaitForChange;
break;
}
break;
// Четвертое состояние. Увеличить количество горящих светодиодов на 1.
case SetMoreLeds :
if (!error) {
error = StackPush(Stack_LEDS, &Stack_LEDS_CurrentSize, STACK_SIZE10, addData);
}
for(i=0; i<STACK_SIZE10; i++){
if (Stack_LEDS[i] == 1){
modIndication_SetLedMode(i,LED_MODE_BLINK);
} else {
modIndication_SetLedMode(i,LED_MODE_OFF);
}
}
saveOldTime = modSysClock_getCurrentTime();
nextLevel = WaitForChange;
break;
// Пятое состояние. Уменьшить количество горящих светодиодов на 1.
case SetLessLeds :
if (!error) {
error = StackPop(Stack_LEDS, &Stack_LEDS_CurrentSize, &addData);
}
for(i=0; i<STACK_SIZE10; i++){
if (Stack_LEDS[i] == 1){
modIndication_SetLedMode(i,LED_MODE_BLINK);
} else {
modIndication_SetLedMode(i,LED_MODE_OFF);
}
}
saveOldTime = modSysClock_getCurrentTime();
nextLevel = WaitForChange;
break;
// Шестое состояние. Сохранить изменения и зажечь светодиоды.
case SaveChangesAndGo :
for(i=0; i<STACK_SIZE10; i++){
Stack_Previous_LEDS[i] = Stack_LEDS[i];
}
for(i=0; i<STACK_SIZE10; i++){
if (Stack_LEDS[i] == 1){
modIndication_SetLedMode(i,LED_MODE_ON);
}}
nextLevel = WaitForEnter;
break;
// Седьмое состояние. Возврат к предыдущим настройкам.
case DisagreeChanges :
for(i=0; i<STACK_SIZE10; i++){
Stack_LEDS[i] = Stack_Previous_LEDS[i];
}
for(i=0; i<STACK_SIZE10; i++){
if (Stack_LEDS[i] == 1){
modIndication_SetLedMode(i,LED_MODE_ON);
}}
nextLevel = WaitForEnter;
break;
}// end switch (Menulevel)
Menulevel = nextLevel; [5]
Библиографический список
- «Введение в распараллеливание алгоритмов и программ» В. Е. Карпов, Московский физико-технический институт, Компьютерные исследования и моделирование 2010г., Т. 2 № 3, С. 231–272
- «Многозадачность на микроконтроллере», ресурс «Встраиваемая электроника» [http://www.velect.ru/articles.html]
- Real-time Software Design – Ian Sommerville, ресурс: [http://ifs.host.cs.st-andrews.ac.uk/Books/SE7/Presentations/PDF/ch15.pdf]
- Introduction of Real-Time Embedded System Design, Gang Quan, Chet Kagel FMTC, Orlando Office, ресурс [http://web.cecs.pdx.edu/~mperkows/temp/real-time-embedded-systems.pdf]
- Материалы практических работ курса «Программирование на МК» ОВЕН-Campus, ООО «ВО ОВЕН».
Количество просмотров публикации: Please wait