Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/21: Рейтинг темы: голосов - 21, средняя оценка - 4.57
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
1

FreeRTOS и опрос кнопок и передача в таск

11.10.2017, 11:22. Показов 3890. Ответов 12
Метки нет (Все метки)

Не могу придумать в голове как передать состояние кнопок из одной задачи в другую. Задачу ставлю так: есть таск который опрашивает 6 кнопок, с этим не проблема. Есть второй таск, который крутит менюшку на LCD дисплее. Проблема в том, как передать состояние кнопок в другой таск? Создать по семафору на каждую кнопку, и по семафору отрабатывать нажатия кнопок? Очередь не очень понятно как прикрутить ибо кнопка нажимается любая, как потом из очереди узнать какая именно кнопка была нажата(если передавать именно состояния 1/0)? Либо заводить на каждую кнопку свой ID и метать его в очередь при нажатии, а в другой функции принимать очередь и через switch определять что за кнопка была нажата по ID. Как думаете?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.10.2017, 11:22
Ответы с готовыми решениями:

опрос 96 кнопок
Добрый день! Не могу определиться с реализацией задачи: Необходимо опрашивать 96 кнопок, которые...

Опрос кнопок и индикация.
Помогите пожайлуста. Пишу на Си. Пытаюсь на порт (не важно какой) повесить кнопку и динамическую...

Опрос кнопок (PIC16F877)
Здравствуйте, недавно начал заниматься программированием платы PIC16F877. Написал программу по...

Периодический опрос кнопок на MCS-51
Если ДД1=1 и ДД2=1, то ДСИ=0 и ДСИ2=0, если ДД1=0 и ДД2=0, то ДСИ1=1, ДСИ2=1, если ДД1 ≠ДД2,...

12
Модератор
Эксперт по электронике
8381 / 6225 / 837
Регистрация: 14.02.2011
Сообщений: 21,616
11.10.2017, 12:24 2
Цитата Сообщение от _SayHello Посмотреть сообщение
Очередь не очень понятно как прикрутить ибо кнопка нажимается любая, как потом из очереди узнать какая именно кнопка была нажата(если передавать именно состояния 1/0)?
создай перемененную типа uint8_t state
где первый бит отвечает за первую кнопку, второй за вторую ну и так далее
а потом
C++
1
2
3
4
5
6
7
8
9
10
11
12
if(state &0x01)
 // нажата первая кнопка
else
 //отжата
if(state&0x02)
  // нажата вторая кнопка
else
 //отжата
if(state&0x04)
 // нажата третья кнопка
else
 //отжата
а еще потом или передавай через очередь или сделай переменную глобальной
1
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
11.10.2017, 12:38  [ТС] 3
ValeryS, Т.е. опрос делаем, что то вроде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
     if(!GPIO_ReadInputDataBit(GPIOE, Button1)
          state |= (1 << 1);
     else
          state &= ~(1 << 1);
    if(!GPIO_ReadInputDataBit(GPIOE, Button2)
          state |= (1 << 2);
     else
          state &= ~(1 << 2);
.
.
.
.
    xStatus = xQueueSendToBack( xQueue, &State, 0 );
.
.
.
}
У меня просто "0" это нажатие "1" отпущено
0
Эксперт .NET
7538 / 5028 / 1198
Регистрация: 25.05.2015
Сообщений: 15,317
Записей в блоге: 14
11.10.2017, 12:42 4
Во FreeRTOS возможно ли выставить флаг в событии, которое будет получено другой задачей?
Типа сообщаем о кнопке (из прерывания или задачи) так:
C++
1
tn_eventgrp_imodify(&this->mEventGrp, TN_EVENTGRP_OP_SET, static_cast<TN_UWord>(button_bits));
А в другой задаче ждём так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
TN_RCode res = events.wait(TN_WAIT_INFINITE);
 
if (res == TN_RC_OK) {
  if (events.isSet(Defs::Event::UINavigateUp, false)) {
    ...
    break;
  }
 
  if (events.isSet(Defs::Event::UINavigateDown, false)) {
    ...
    break;
  }
   ...
}
0
Модератор
Эксперт по электронике
8381 / 6225 / 837
Регистрация: 14.02.2011
Сообщений: 21,616
11.10.2017, 12:43 5
Цитата Сообщение от _SayHello Посмотреть сообщение
Т.е. опрос делаем, что то вроде:
может проще

C
1
2
3
state= GPIO_ReadInputDataBit(GPIOE, Button1)<<0 |
          GPIO_ReadInputDataBit(GPIOE, Button2)<<1|
          GPIO_ReadInputDataBit(GPIOE, Button3)<<2 ......
смотря что возвращает GPIO_ReadInputDataBit если 0/1, то такой подход допустим, если нет то можно как и у тебя,
а можно использовать битовые поля
1
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
11.10.2017, 12:46  [ТС] 6
Rius, я пока в плюсовый стиль не особо могу, только как хобби учу. На Си орудую)
0
Модератор
Эксперт по электронике
8381 / 6225 / 837
Регистрация: 14.02.2011
Сообщений: 21,616
11.10.2017, 12:47 7
Цитата Сообщение от Rius Посмотреть сообщение
Во FreeRTOS возможно ли выставить флаг в событии, которое будет получено другой задачей?
что то непонятно что имеешь в виду
вот как я вижу
есть событие( сиречь нажатие кнопки) шлем в очередь, если нет то соответственно не шлем
а в другой задаче проверяем очередь если не пуста то считываем иначе ждем-с
0
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
11.10.2017, 12:47  [ТС] 8
ValeryS, Опробуем) Результаты выложу, посмотрим как менюшка бегает.
0
Эксперт .NET
7538 / 5028 / 1198
Регистрация: 25.05.2015
Сообщений: 15,317
Записей в блоге: 14
11.10.2017, 12:50 9
Цитата Сообщение от _SayHello Посмотреть сообщение
я пока в плюсовый стиль не особо могу, только как хобби учу
От плюсов там только namespace и static_cast, это для вас не важно и легко удаляется.

Добавлено через 1 минуту
Цитата Сообщение от ValeryS Посмотреть сообщение
есть событие( сиречь нажатие кнопки) шлем в очередь, если нет то соответственно не шлем
а в другой задаче проверяем очередь если не пуста то считываем иначе ждем-с
Да, то же самое имею в виду. Только очереди не использую. Место хранения этих событий - одно.
0
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
13.10.2017, 12:36  [ТС] 10
Как и обещал, выкладываю получившийся проектик по реализации меню на FreeRTOS.
Для меню использовал OLED дисплей WEH002004 на 4 строки. Меню двухуровневое с прокруткой по дисплею (для теста взял 6 пунктов в основном меню и по три потомка каждому). Контроллер stm32f303vct6.
Начнем с основного :
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "stm32f30x_conf.h"
#include "Hardware.h" // Здесь настройка тактирования / входов кнопок
#include "Utils.h"  // Там аппаратная задержка таймером
#include "FreeRTOS.h"
#include "task.h" // для тасков
#include "queue.h"  /для очереди
#include "semphr.h" //для мютекса
#include "lcd_WEH002004.h" //библиотечка дисплея с русским языком
#include "stdio.h" // для snprintf(..,)
 
 
//Структура меню - четырехсвязный список 
typedef struct menuItem
{
    int id;            //пока не использую, определяет ID каждого пункта/подпункта можно будет прикрутить клавишу ОК и 
выполнять чтонибудь по ее нажатию и ID
    char *name; //имя пункта
    char select;  // для личных нужд
    struct menuItem *up; // предыдущий узел
    struct menuItem *right; //потомок
    struct menuItem *left; //родитель
    struct menuItem *down; //следующий узел
} menuItem;
 
 
 
/*Потоки FreeRTOS*/
void vCheckButtons(void * pvParameters); //опрос клавишь
void vDisplay(void * pvParameters); //вывод на дисплей
void vMenu(void * pvParameters); //обработка меню
 
xQueueHandle xButtonsQueue; //объявляем очередь для состояния кнопок
xSemaphoreHandle xLCDMutex; // определяем мютекс для пользования массивом дисплея
 
char LCD_Buf[4][21]; // массив дисплея 4 строки 20 символов (21 под /0)
int main(void)
{
    //Инициализируем очередь на 1 элемент int и создаем мьютекс
    xButtonsQueue = xQueueCreate(1, sizeof(int));
    xLCDMutex = xSemaphoreCreateMutex();
   
    Init_DelayTIM(); //таймер на задержку
    InitHardware(); // инициализируем железо
    InitLCD(); //инициализируем LCD
  while(1)
  {
    // cоздаем таски и погнали
    xTaskCreate(vCheckButtons, "CheckButtons" , configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, NULL);
    xTaskCreate(vDisplay, "Display", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, NULL);
    xTaskCreate(vMenu, "Menu", configMINIMAL_STACK_SIZE+256, NULL, tskIDLE_PRIORITY+1, NULL);
   
    vTaskStartScheduler();
  }
}


Тут вроде все просто мьютекс решил запилить так как две задачи обращаются к одному массиву, vMenu наполняет его, vDisplay выводит. В принципе и без него было все ок потому что приоритета дисплею больше дал, а задачи "псевдосинхронны", дальше покажу почему. Но для порядка мьютекс использую. Покажу как. Для Меню пришлось выделить больше памяти для стека, так как там идет большое кол-во структур меню/подменю. Выделял на глаз, можно посчитать и выставить точно.


Теперь отдельно по задачам:
1) задача опроса кнопок
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void vCheckButtons(void * pvParameters)
{
    //делаем периодическую задачу
    portTickType xLastWakenTime; 
    xLastWakenTime = xTaskGetTickCount();
    int State = 0; //состояние кнопок
    while(1)
    {
        //у меня признак нажатия - 0 на ноге, поэтому по нулю забиваем биты на каждую клавишу, на 1 очищаем
        if(!GPIO_ReadInputDataBit(GPIOE, LEFT))
          State |= (1 << 0);
        else
          State &= ~(1 << 0);
        if(!GPIO_ReadInputDataBit(GPIOE, DOWN))
          State |= (1 << 1);
        else
          State &= ~(1 << 1);
        if(!GPIO_ReadInputDataBit(GPIOE, UP))
          State |= (1 << 2);
        else
          State &= ~(1 << 2);
        if(!GPIO_ReadInputDataBit(GPIOE, RIGHT))
          State |= (1 << 3);
        else
          State &= ~(1 << 3);
        //толкаем в очередь без ожидания очистки (время 0)
        xQueueSendToBack(xButtonsQueue, &State, 0);
        //период 150 мс
        vTaskDelayUntil(&xLastWakenTime, 150);
    }
}

Достаточно просто. Ничего сложного.
0
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
13.10.2017, 12:39  [ТС] 11
2) Задача меню (тут будет дохрена (относительно))

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
void vMenu(void * pvParameters)
{
          //создаем массив структур главных пунктов меню (я для проверки взял 6) и инициализируем их
          menuItem m[6] = { { 1, "  Методики", 0, NULL, NULL, NULL, NULL },
                     {  2, "  Параметры", 0, NULL, NULL, NULL, NULL },
                     {  3, "  Время", 0, NULL, NULL, NULL, NULL },
                     {  4, "  Menu 4", 0, NULL, NULL, NULL, NULL },
                     {  5, "  Menu 5", 0, NULL, NULL, NULL, NULL },
                     {  6, "  Menu 6", 0, NULL, NULL, NULL, NULL } };
         //второй уровень подпункты пункта 1
     menuItem m1[3] = {{ 11, "  Методика 1", 1, NULL, NULL, NULL, NULL },
                      { 12, "  Методика 2", 1, NULL, NULL, NULL, NULL },
                      { 13, "  Методика 3", 1, NULL, NULL, NULL, NULL }};
 
 
            //второй уровень подпункты пункта 2
     menuItem m2[3] = { { 21, "  Датчик", 1, NULL, NULL, NULL, NULL },
                       { 22, "  Магнетроны", 1, NULL, NULL, NULL, NULL },
                       { 23, "  Индикация", 1, NULL, NULL, NULL, NULL } };
         //второй уровень подпункты пункта 3   и т.д.
     menuItem m3[3] = { { 31, "  Текущее время", 1, NULL, NULL, NULL, NULL },
                       { 32, "  Текущая дата", 1, NULL, NULL, NULL, NULL },
                       { 33, "  Настройка", 1, NULL, NULL, NULL, NULL } };
 
     menuItem m4[3] = { { 41, "  Menu 4-1", 1, NULL, NULL, NULL, NULL },
                       { 42, "  Menu 4-2", 1, NULL, NULL, NULL, NULL },
                       { 43, "  Menu 4-3", 1, NULL, NULL, NULL, NULL } };
 
     menuItem m5[3] = { { 51, "  Menu 5-1", 1, NULL, NULL, NULL, NULL },
                       { 52, "  Menu 5-2", 1, NULL, NULL, NULL, NULL },
                       { 53, "  Menu 5-3", 1, NULL, NULL, NULL, NULL } };
 
     menuItem m6[3] = { { 61, "  Menu 6-1", 1, NULL, NULL, NULL, NULL },
                       { 62, "  Menu 6-2", 1, NULL, NULL, NULL, NULL },
                       { 63, "  Menu 6-3", 1, NULL, NULL, NULL, NULL } };
 
         //Определяем родственные связи основных пунктов=)
        //Из первого пунта дорога только вниз и направо
        m[0].down = &m[1];
    m[0].right = &m1[0];
    //Из второго вверх, вниз, вправо
    m[1].up = &m[0];
    m[1].right = &m2[0];
    m[1].down = &m[2];
             и.т.д.
    m[2].up = &m[1];
    m[2].right = &m3[0];
    m[2].down = &m[3];
 
    m[3].up = &m[2];
    m[3].right = &m4[0];
    m[3].down = &m[4];
 
    m[4].up = &m[3];
    m[4].right = &m5[0];
    m[4].down = &m[5];
 
    m[5].up = &m[4];
    m[5].right = &m6[0];
 
        //Теперь узлы второго уровня подменю 
       
    m1[0].left = &m[0];
    m1[0].down = &m1[1];
    // Настройка М12
    m1[1].up = &m1[0];
    m1[1].down = &m1[2];
    m1[1].left = &m[0];
    // Настройка М13
    m1[2].up = &m1[1];
    m1[2].left = &m[0];
 
    // Второй уровень меню M2
    // Настройка М21
    m2[0].left = &m[0];
    m2[0].down = &m2[1];
    // Настройка М22
    m2[1].up = &m2[0];
    m2[1].down = &m2[2];
    m2[1].left = &m[0];
    // Настройка М23
    m2[2].up = &m2[1];
    m2[2].left = &m[0];
 
    // Второй уровень меню M3
    // Настройка М31
    m3[0].left = &m[0];
    m3[0].down = &m3[1];
    // Настройка М32
    m3[1].up = &m3[0];
    m3[1].down = &m3[2];
    m3[1].left = &m[0];
    // Настройка М33
    m3[2].up = &m3[1];
    m3[2].left = &m[0];
 
    // Второй уровень меню M4
    // Настройка М41
    m4[0].left = &m[0];
    m4[0].down = &m4[1];
    // Настройка М42
    m4[1].up = &m4[0];
    m4[1].down = &m4[2];
    m4[1].left = &m[0];
    // Настройка М43
    m4[2].up = &m4[1];
    m4[2].left = &m[0];
 
    // Второй уровень меню M5
    // Настройка М51
    m5[0].left = &m[0];
    m5[0].down = &m5[1];
    // Настройка М52
    m5[1].up = &m5[0];
    m5[1].down = &m5[2];
    m5[1].left = &m[0];
    // Настройка М53
    m5[2].up = &m5[1];
    m5[2].left = &m[0];
 
    // Второй уровень меню M6
    // Настройка М61
    m6[0].left = &m[0];
    m6[0].down = &m6[1];
    // Настройка М62
    m6[1].up = &m6[0];
    m6[1].down = &m6[2];
    m6[1].left = &m[0];
    // Настройка М63
    m6[2].up = &m6[1];
    m6[2].left = &m[0];
 
    /Начальный вывод на дисплей - основное меню и указатель на первую позицию
    snprintf(LCD_Buf[0], 21, "Menu                           ");
    snprintf(LCD_Buf[1], 21, "%s                             ", m[0].name);
    snprintf(LCD_Buf[2], 21, "%s                             ", m[1].name);
    snprintf(LCD_Buf[3], 21, "%s                             ", m[2].name);
    LCD_Buf[1][0] = '>';
 
    menuItem *curItem = &m[0];    // Тут мы будем хранить указатель на текущее меню
 
    int max_draw_num = 3; //максимальное количество элементов меню на дисплее
    int select_draw_num = 1; //текущий выбранный элемент
    int first_draw_num = 1;  //элемент меню в первой строке для прокрутки
    int max_menu_count = 6; // максимальное кол-во элементов меню
    int max_menu_depth = 2; //максимальная глубина (читай количество уровней)
    int cur_menu_depth = 1; // текущая глубина
    portBASE_TYPE xStatus; //статус приема очереди
    int StatusRecieved; // принятое состояние кнопок
    while(1)
    {  
        //проверяем, если очередь не пустая, забираем и погнали обрабатывать
        xStatus = xQueueReceive( xButtonsQueue, &StatusRecieved, portMAX_DELAY);
        if(xStatus == pdPASS)
        { 
            // забираем мьютекс для работы с массивом
            xSemaphoreTake(xLCDMutex, portMAX_DELAY);
            //проверяем состояние кнопок
            switch (StatusRecieved)
            {
            //если была нажата вверх
            case 4:
                //и есть куда идти
                if (curItem->up)
                {
                    // переопределяем текущий пункт
                    curItem = curItem->up;
                    //если текущей пункт не уперся вверх двигаем указатель
                    if (select_draw_num > 1)
                    {
                        LCD_Buf[select_draw_num - first_draw_num + 1][0] = ' ';
                        select_draw_num--;
                        LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                    }
                     // тут передвигаем  начальные строки по дисплею и указатель
                    if (select_draw_num > 2)
                    {
                        first_draw_num--;
                        snprintf(LCD_Buf[1], 21, "%s                          ", m[first_draw_num - 1].name);
                        snprintf(LCD_Buf[2], 21, "%s                          ", m[first_draw_num].name);
                        snprintf(LCD_Buf[3], 21, "%s                          ", m[first_draw_num + 1].name);
                        LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                    }
 
                }
                else
                {
                    NULL;
                }
                break;
            case 8:
                //если вправо
                if (curItem->right)
                {
                    curItem = curItem->right;
                    //передвигаем глубину и устанавливаем на первую позицию
                    if (cur_menu_depth < max_menu_depth)
                    {
                        cur_menu_depth++;
                        first_draw_num = 1;
                    }
                    //в зависимости с какого пункта меню ушли в подменю выводим нужные строки
                    switch (select_draw_num)
                    {
                        case 1:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[0].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m1[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m1[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m1[first_draw_num + 1].name);
                            LCD_Buf[1][0] = '>';
                            break;
                        case 2:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[1].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m2[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m2[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m2[first_draw_num + 1].name);
                            LCD_Buf[1][0] = '>';
                            break;
                        case 3:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[2].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m3[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m3[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m3[first_draw_num + 1].name);
                            LCD_Buf[1][0] = '>';
                            break;
                        case 4:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[3].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m4[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m4[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m4[first_draw_num + 1].name);
                            LCD_Buf[1][0] = '>';
                            break;
                        case 5:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[4].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m5[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m5[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m5[first_draw_num + 1].name);
                            LCD_Buf[1][0] = '>';
                            break;
                        case 6:
                            snprintf(LCD_Buf[0], 21, "%s                          ", m[5].name+2);
                            snprintf(LCD_Buf[1], 21, "%s                          ", m6[first_draw_num - 1].name);
                            snprintf(LCD_Buf[2], 21, "%s                          ", m6[first_draw_num].name);
                            snprintf(LCD_Buf[3], 21, "%s                          ", m6[first_draw_num + 1].name);
                            LCD_Buf[ 1][0] = '>';
                            break;
                    }
                    select_draw_num = 1;
                }
                else
                {
                    NULL;
                }
                break;
            case 1:
                /*если влево
                if (curItem->left)
                {
                    curItem = curItem->left;
                    /*если в подменю, меняем глубину
                    if (cur_menu_depth > 1)
                    {
                        cur_menu_depth--;
                    }
                    first_draw_num = 1;
                    snprintf(LCD_Buf[0], 21, "Menu                          ");
                    snprintf(LCD_Buf[1], 21, "%s                          ", m[first_draw_num - 1].name);
                    snprintf(LCD_Buf[2], 21, "%s                          ", m[first_draw_num].name);
                    snprintf(LCD_Buf[3], 21, "%s                          ", m[first_draw_num + 1].name);
                    LCD_Buf[1][0] = '>';
                    select_draw_num = 1;
                }
                else
                {
                    NULL;
                }
                break;
            case 2:
                //если вниз
                if (curItem->down)
                {
                    curItem = curItem->down;
                    //пока не уперлись вниз меняем текущее положение
                    if (select_draw_num < max_menu_count)
                    {
                        //двигаем указатель
                        if (select_draw_num < max_draw_num)
                        {
                            LCD_Buf[select_draw_num - first_draw_num + 1][0] = ' ';
                            select_draw_num++;
                            LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                        }
                        else
                        {
                            select_draw_num++;
                        }
                    }
                    //если текущий пункт больше максимального кол-ва выводимых пунктов, листаем меню
                    if (select_draw_num > max_draw_num)
                    {
                        first_draw_num++;
                        snprintf(LCD_Buf[1], 21, "%s                          ", m[first_draw_num - 1].name);
                        snprintf(LCD_Buf[2], 21, "%s                          ", m[first_draw_num].name);
                        snprintf(LCD_Buf[3], 21, "%s                          ", m[first_draw_num + 1].name);
                        LCD_Buf[max_draw_num][0] = '>';
                    }
                }
                else
                {
                    NULL;
                }
                break;
            }
            //отдаем семафор обратно
            xSemaphoreGive(xLCDMutex);
        }
    }
}

Вот такая портянка, возможно нужно причесать. Проблема в том, что портянка немного не универсальна. Хочешь добавить пункт правь портянку. Но мне для баловства и пробы достаточно.
Три строки для пунктов использую, так как в первой будет шапка с названием уровня в котором нахожусь, для перового уровня это "Меню" , для второго уровня - имя родителя.

3) Ну и на сладкое таск вывода на дисплей:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void vDisplay(void * pvParameters)
{
    portTickType xLastWakenTime;
    xLastWakenTime = xTaskGetTickCount();
    ClearLCD();
    while(1)
    {
        SetCursor(1,0);
        PrintStr(LCD_Buf[0]);
        SetCursor(2,0);
        PrintStr(LCD_Buf[1]);
        SetCursor(3,0);
        PrintStr(LCD_Buf[2]);
        SetCursor(4,0);
        PrintStr(LCD_Buf[3]);
        vTaskDelayUntil(&xLastWakenTime, 500);
    }
}

Тут даже особо нечего комментировать , просто раз в 500 мс выплевывем данные массива на дисплей.
0
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
13.10.2017, 12:40  [ТС] 12
Для большего понимания работы меню, выкладываю некий эмулятор в консольной строке (я в VS 2017 запускаю)
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#include <iostream>
#include <cstring>
 
using namespace std;
 
 
typedef struct menuItem
{
    int id;
    char *name;
    char select;
    struct menuItem *up;
    struct menuItem *right;
    struct menuItem *left;
    struct menuItem *down;
} menuItem;
 
 
char LCD_Buf[4][20];
 
void showPosition(const menuItem *inputItem);
 
int main(void)
{
 
    menuItem m[6] = { { 1, "  Menu 1", 0, NULL, NULL, NULL, NULL },
                     {  2, "  Menu 2", 0, NULL, NULL, NULL, NULL },
                     {  3, "  Menu 3", 0, NULL, NULL, NULL, NULL },
                     {  4, "  Menu 4", 0, NULL, NULL, NULL, NULL },
                     {  5, "  Menu 5", 0, NULL, NULL, NULL, NULL },
                     {  6, "  Menu 6", 0, NULL, NULL, NULL, NULL } };
 
    menuItem m1[3] = {{ 11, "  Menu 1-1", 1, NULL, NULL, NULL, NULL },
                      { 12, "  Menu 1-2", 1, NULL, NULL, NULL, NULL },
                      { 13, "  Menu 1-3", 1, NULL, NULL, NULL, NULL }};
 
 
 
    menuItem m2[3] = { { 21, "  Menu 2-1", 1, NULL, NULL, NULL, NULL },
                       { 22, "  Menu 2-2", 1, NULL, NULL, NULL, NULL },
                       { 23, "  Menu 2-3", 1, NULL, NULL, NULL, NULL } };
 
    menuItem m3[3] = { { 31, "  Menu 3-1", 1, NULL, NULL, NULL, NULL },
                       { 32, "  Menu 3-2", 1, NULL, NULL, NULL, NULL },
                       { 33, "  Menu 3-3", 1, NULL, NULL, NULL, NULL } };
 
    menuItem m4[3] = { { 41, "  Menu 4-1", 1, NULL, NULL, NULL, NULL },
                       { 42, "  Menu 4-2", 1, NULL, NULL, NULL, NULL },
                       { 43, "  Menu 4-3", 1, NULL, NULL, NULL, NULL } };
 
    menuItem m5[3] = { { 51, "  Menu 5-1", 1, NULL, NULL, NULL, NULL },
                       { 52, "  Menu 5-2", 1, NULL, NULL, NULL, NULL },
                       { 53, "  Menu 5-3", 1, NULL, NULL, NULL, NULL } };
 
    menuItem m6[3] = { { 61, "  Menu 6-1", 1, NULL, NULL, NULL, NULL },
                       { 62, "  Menu 6-2", 1, NULL, NULL, NULL, NULL },
                       { 63, "  Menu 6-3", 1, NULL, NULL, NULL, NULL } };
 
    // Настройка М1
 
    m[0].down = &m[1];
    m[0].right = &m1[0];
    // Настройка М2
    m[1].up = &m[0];
    m[1].right = &m2[0];
    m[1].down = &m[2];
    // Настройка М3
    m[2].up = &m[1];
    m[2].right = &m3[0];
    m[2].down = &m[3];
    // Настройка М4
    m[3].up = &m[2];
    m[3].right = &m4[0];
    m[3].down = &m[4];
    // Настройка М5
    m[4].up = &m[3];
    m[4].right = &m5[0];
    m[4].down = &m[5];
    // Настройка М6
    m[5].up = &m[4];
    m[5].right = &m6[0];
 
 
 
    // Второй уровень меню M1
    // Настройка М11
    m1[0].left = &m[0];
    m1[0].down = &m1[1];
    // Настройка М12
    m1[1].up = &m1[0];
    m1[1].down = &m1[2];
    m1[1].left = &m[0];
    // Настройка М13
    m1[2].up = &m1[1];
    m1[2].left = &m[0];
 
    // Второй уровень меню M2
    // Настройка М21
    m2[0].left = &m[0];
    m2[0].down = &m2[1];
    // Настройка М22
    m2[1].up = &m2[0];
    m2[1].down = &m2[2];
    m2[1].left = &m[0];
    // Настройка М23
    m2[2].up = &m2[1];
    m2[2].left = &m[0];
 
    // Второй уровень меню M3
    // Настройка М31
    m3[0].left = &m[0];
    m3[0].down = &m3[1];
    // Настройка М32
    m3[1].up = &m3[0];
    m3[1].down = &m3[2];
    m3[1].left = &m[0];
    // Настройка М33
    m3[2].up = &m3[1];
    m3[2].left = &m[0];
 
    // Второй уровень меню M4
    // Настройка М41
    m4[0].left = &m[0];
    m4[0].down = &m4[1];
    // Настройка М42
    m4[1].up = &m4[0];
    m4[1].down = &m4[2];
    m4[1].left = &m[0];
    // Настройка М43
    m4[2].up = &m4[1];
    m4[2].left = &m[0];
 
    // Второй уровень меню M5
    // Настройка М51
    m5[0].left = &m[0];
    m5[0].down = &m5[1];
    // Настройка М52
    m5[1].up = &m5[0];
    m5[1].down = &m5[2];
    m5[1].left = &m[0];
    // Настройка М53
    m5[2].up = &m5[1];
    m5[2].left = &m[0];
 
    // Второй уровень меню M6
    // Настройка М61
    m6[0].left = &m[0];
    m6[0].down = &m6[1];
    // Настройка М62
    m6[1].up = &m6[0];
    m6[1].down = &m6[2];
    m6[1].left = &m[0];
    // Настройка М63
    m6[2].up = &m6[1];
    m6[2].left = &m[0];
 
    menuItem *curItem = &m[0];    // Тут мы будем хранить указатель на текущее меню
 
    char max_draw_num = 3;
    char select_draw_num = 1;
    char first_draw_num = 1;
    char max_menu_count = 6;
    char max_menu_depth = 2;
    char cur_menu_depth = 1;
 
    strcpy_s(LCD_Buf[0], "----Menu----");
    strcpy_s(LCD_Buf[1], m[0].name);
    strcpy_s(LCD_Buf[2], m[1].name);
    strcpy_s(LCD_Buf[3], m[2].name);
    LCD_Buf[first_draw_num][0] = '>';
 
    showPosition(curItem);
    char key = 0;
    while (std::cin >> key)
    {
        switch (key)
        {
        case 'w':
            if (curItem->up)
            {
                curItem = curItem->up;
                if (select_draw_num > 1)
                {
                    LCD_Buf[select_draw_num - first_draw_num + 1][0] = ' ';
                    select_draw_num--;
                    LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                }
                if (select_draw_num > 2)
                {
                    first_draw_num--;
                    strcpy_s(LCD_Buf[1], m[first_draw_num-1].name);
                    strcpy_s(LCD_Buf[2], m[first_draw_num].name);
                    strcpy_s(LCD_Buf[3], m[first_draw_num + 1].name);
                    LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                }
                    
            }
            else
            {
                NULL;
            }
            break;
        case 'd':
            if (curItem->right)
            {
                curItem = curItem->right;
                if (cur_menu_depth < max_menu_depth)
                {
                    cur_menu_depth++;
                    first_draw_num = 1;
                }
                switch (select_draw_num)
                {
                    case 1:
                        strcpy_s(LCD_Buf[0], m[0].name);
                        strcpy_s(LCD_Buf[1], m1[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m1[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m1[first_draw_num + 1].name);
                        LCD_Buf[1][0] = '>';
                        break;
                    case 2:
                        strcpy_s(LCD_Buf[0], m[1].name);
                        strcpy_s(LCD_Buf[1], m2[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m2[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m2[first_draw_num + 1].name);
                        LCD_Buf[1][0] = '>';
                        break;
                    case 3:
                        strcpy_s(LCD_Buf[0], m[2].name);
                        strcpy_s(LCD_Buf[1], m3[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m3[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m3[first_draw_num + 1].name);
                        LCD_Buf[1][0] = '>';
                        break;
                    case 4:
                        strcpy_s(LCD_Buf[0], m[3].name);
                        strcpy_s(LCD_Buf[1], m4[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m4[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m4[first_draw_num + 1].name);
                        LCD_Buf[1][0] = '>';
                        break;
                    case 5:
                        strcpy_s(LCD_Buf[0], m[4].name);
                        strcpy_s(LCD_Buf[1], m5[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m5[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m5[first_draw_num + 1].name);
                        LCD_Buf[1][0] = '>';
                        break;
                    case 6:
                        strcpy_s(LCD_Buf[0], m[5].name);
                        strcpy_s(LCD_Buf[1], m6[first_draw_num - 1].name);
                        strcpy_s(LCD_Buf[2], m6[first_draw_num].name);
                        strcpy_s(LCD_Buf[3], m6[first_draw_num + 1].name);
                        LCD_Buf[ 1][0] = '>';
                        break;
                }
                select_draw_num = 1;
            }
            else
            {
                NULL;
            }
            break;
        case 'a':
            if (curItem->left)
            {
                curItem = curItem->left;
                if (cur_menu_depth > 1)
                {
                    cur_menu_depth--;
                }   
                first_draw_num = 1;
                strcpy_s(LCD_Buf[0], "Menu");
                strcpy_s(LCD_Buf[1], m[first_draw_num - 1].name);
                strcpy_s(LCD_Buf[2], m[first_draw_num].name);
                strcpy_s(LCD_Buf[3], m[first_draw_num + 1].name);
                LCD_Buf[1][0] = '>';
                select_draw_num = 1;
 
            }
            else
            {
                NULL;
            }
            break;
        case 's':
            if (curItem->down)
            {
                curItem = curItem->down;
                if (select_draw_num < max_menu_count)
                {
                    
                    if (select_draw_num < max_draw_num)
                    {
                        LCD_Buf[select_draw_num - first_draw_num + 1][0] = ' ';
                        select_draw_num++;
                        LCD_Buf[select_draw_num - first_draw_num + 1][0] = '>';
                    }
                    else
                    {
                        
                        select_draw_num++;
                    }
                }
                if (select_draw_num > max_draw_num)
                {
                    first_draw_num++;
                    strcpy_s(LCD_Buf[1], m[first_draw_num - 1].name);
                    strcpy_s(LCD_Buf[2], m[first_draw_num].name);
                    strcpy_s(LCD_Buf[3], m[first_draw_num + 1].name);
                    LCD_Buf[max_draw_num][0] = '>';
                }
 
            }
            else
            {
                NULL;
            }
            break;
        default:
            {
                break;
            }
        }
 
 
        if (key == 'q') break;
        showPosition(curItem);
        cout << (int)select_draw_num << endl;
        cout << (int)first_draw_num << endl;
    }
}
 
void showPosition(const menuItem *inputItem)
{
    cout << "----------------------" << endl;
    cout << LCD_Buf[0] << endl;
    cout << LCD_Buf[1] << endl;
    cout << LCD_Buf[2] << endl;
    cout << LCD_Buf[3] << endl;
    cout << "----------------------" << endl;
}

Фотки прикладываю.
Если будут вопросы спрашивайте, отвечу.
0
Миниатюры
FreeRTOS и опрос кнопок и передача в таск   FreeRTOS и опрос кнопок и передача в таск   FreeRTOS и опрос кнопок и передача в таск  

FreeRTOS и опрос кнопок и передача в таск   FreeRTOS и опрос кнопок и передача в таск   FreeRTOS и опрос кнопок и передача в таск  

FreeRTOS и опрос кнопок и передача в таск  
855 / 525 / 172
Регистрация: 30.07.2015
Сообщений: 1,708
13.10.2017, 12:47  [ТС] 13
Можно ли подредактировать листинг обработки меню? Там в 256 комментарий /* оборваный
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.10.2017, 12:47

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Опрос клавиатуры (несколько нажатых кнопок сразу)
Подскажите как лучше сделать опрос клавиатуры, чтобы можно было отслеживать несколько одновременно...

Передача значений из массива кнопок
делаю калькулятор. сделала массив для кнопок операторов. но когда я выбираю какую-нибудь кнопку, то...

Передача индекса массива кнопок в обработчик событий
Проблема такая: у меня есть массив кнопок, созданные динамично for (k = 0; k &lt; 16; k++) ...

Передача параметров с разных кнопок через POST
У меня есть форма, в которой находится 2 разных кнопки. Как сделать так, чтобы параметры...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.