NStorm писал(а):но логика работы мне всё-равно сильно не нравится
согласен. вы явно не делаете скридку на то, что топикстартер - начинающий. какие там указатели?! его надо научить стройно излагать свои мысли скудными средствами языка, а вы сразу к указателям... извините, но вся тема явно заведет
sergo80zxc в тупик.
для чего ему насоветовали для задержек применять прерывания?! ну блин, в первом классе говорят: нельзя от меньшего отнимать более! НЕЛЬЗЯ - и точка. а в пятом классе говорят - а на самом деле МОЖНО. но в пятом! по мере того, как растут навыки, расширяется и круг тем, которые стоит предлагать к восприятию. если в первом классе огорошить задачей "У Пети было 3 яблока, а Вася забрал у него 5 яблок. Сколько осталось у Пети яблок?" и ответом на нее "осталось МИНУС 2 яблока", то первоклассник нахрен убежит из дому и будет в лесу среди волков жить, как маугли - там у него точно из имеющихся 3 никто 5 не отнимет...
sergo80zxc, я вам настоятельно рекомендую почитать мою статью:
https://simple-devices.ru/articles/7-so ... 0-16-40-05 к моему глубочайшему сожалению, владелец сайта забил на модуль врезки кода, и потому примеры кода в статье выглядят ужасно, но если читать буквы внимательно, то смысл статьи будет понятен. если будут вопросы - готов ответить.
ваша задача сводится к следующей: необходимо узнавать, какая кнопка нажата, и в зависимости от этого включать и выключать разные нагрузки по принципу кнопки с фиксацией. итак, задача состоит из трех действий: определение нажатой кнопки, выбора по ней нужной нагрузки и управлению этой нагрузкой "триггерным" способом.запишем это прямо сразу так, как только что было по-русски, но в переводе на язык Си, т.е. подбирая обычным словам наиболее подходящие аналогии из Си:
Код: Выделить всё
while(1){ // главный цикл - никуда не деться, т.к. управление кнопками непрерывное
button = get_pressed_buttons(); // считаем, что у нас есть готовая функция, которая вернет нам нажатую кнопку
// при этом не напрягаемся тем, что такой функции еще нет - мы её сделаем позже
switch(button){ // это наиболее удбный способ анализировать какое-то число в Си
case BTN_1 : trigger_load(LOAD1); break; // точно так же считаем, что у нас есть готовая функция для управления нагрузкой
case BTN_2 : trigger_load(LOAD2); break; // и эта функция просто должна получить нагрузку, которой она будет управлять
// вариантов нажатых кнопок может быть сколько угодно, включая и одновременное нажатие
case BTN_1_AND_BTN_2: trigger_load(LOAD3);
}
}
посмотрите на получившийся код: он
РЕШАЕТ ВАШУ ЗАДАЧУ! в нем есть абсолютно все, что вы хотели! более того, он построен так, что просто произнеся написанное (на каком-то гибриде русско-английского языка), вы получите точное описание того, что вы изначально излагали в качестве постановки задачи!
получается, это уже есть готовый код, который вы и хотели получить. только надо добавить в него все то, чего еще нет, в частности, описать, что такое BTN_1, BTN_2, LOAD1 и т.д. - то есть описать все переменные и константы. если с этим затруднения - можно сделать так же, как с нашими несуществующими функциями, т.е. написать что-то так, как будто они описаны уже и правильно (для этого использовать комментарии):
Код: Выделить всё
#define BTN_0 // BTN_1 - код кнопки 1, возвращаемый функцией get_pressed_buttons(), если кнопка нажата
#define BTN_1 1 // BTN_2 - код кнопки 2, возвращаемый функцией get_pressed_buttons(), если кнопка нажата
#define BTN_1_AND_BTN_2 2 // BTN_1_AND_BTN_2 - код, возвращаемый функцией get_pressed_buttons(), если нажаты сразу обе кнопки 1 и 2
// значения всех констант пока можно задавать любыми, лишь бы были - потом можно будет уточнить всегда, по мере понимания процесса
// нагрузки определяем точно так же - лишь бы были
#define LOAD1 0 // нагрузка 1
#define LOAD2 0 // нагрузка 2
#define LOAD3 0 // нагрузка 3
// заводим переменную для хранения кода кнопки
int button;
// и описываем наши функции
// возвращает код нажатых кнопок
int get_pressed_buttons(void);
// переключает указанную нагрузку
void trigger_load(int load);
если объединить эти оба участка кода, то получится вполне компилируемый код, который только сообщит, что отсутствуют 2 упомянутые функции.
давайте начнем с переключателя нагрузок.
нагрузка у нас - это определенный порт и пин, так? триггерность будет обеспечена простой инверсией состояния этого пина в нужном порту.
поэтому можно было бы описывать нагрузку именно парой порт-пин, например PORTB, PB0 - согласны?
если мы решим, что так удобно, придется переделать то, что только что сделали, а именно переделать определения нагрузок и функцию trigger_load в макрос trigger_load - внешне они будут одинаковы, но макрос боле вольно обращается со своими параметрами:
Код: Выделить всё
// описываем нагрузки теперь так
#define LOAD1 PORTB, PB0 // нагрузка 1
#define LOAD2 PORTB, PB1 // нагрузка 2
#define LOAD3 PORTB, PB2 // нагрузка 3
// строчку void trigger_load(int load); удаляем, а вместо неё пишем так
#define trigger_load(x,y) x ^= (1<<(y))
если вы затрудняетесь с пониманием этой записи, разъясняю:
в коде у нас было trigger_load(LOAD1);
при подстановке макроса LOAD1 получится такая запись: trigger_load(PORTB, PB0);
у нашего макроса triger_load два параметра: первый х, второй y
поэтому наш макрос превратится в PORTB ^= (1<<(PB0))
эта запись по сути означает именно инверсию указанного бита в указанном порту - что и было надо.
итак, изначальная функция trigger_load в ходе нашего погружения в код превратилась в макрос, но основной код (главный цикл) никак не изменился! то есть ГОТОВОЕ РЕШЕНИЕ задачи не поменялось от того, что В НЮАНСИКАХ произошли изменения! более того, со временем вам захочется управлять нагрузкой дистанционно - вы снова превратите trigger_load в функцию (конечно, скорее всего и макросы LOAD1...LOADn наверняка тоже придется подправить), а внутри этой функции реализуете отправку команд по интернету в Южную Америку - и основной код начнет управлять нагрузками на другом конце океана... красиво?

теперь беремся за функцию определения кодов нажатых кнопок. как должна эта функция работать? начинаем действовать точно так же, как и при решении основной задачи: описываем предельно кратко, но точно, что эта функция должна делать: опросить порт, убедиться, что нет дребезга, разобрать битовое состояние порта и вернуть коды кнопок по состояниям битов. теперь точно так же записываем это "на языке Си", заменяя, при необходимости, сложные действия обращением к функциям или макросам (который считаем, как и ранее, у нас есть)... и не бойтесь задержек! задержка в 10 мс достаточна, чтобы гарантировать подавление дребезга, и абсолютно незаметна при решении вашей задачи! у вас получится что-то типа такого кода:
Код: Выделить всё
int get_pressed_buttons(void){
int code; // переменная для сохранения состояния порта
code = ! BTN_PIN; // BTN_PIN - это макрос для регистра пинов порта с кнопками
// кнопки наверняка будут "гасить" подтяжки на землю, поэтому код будет инвертироваться - потому и знак !
_delay_ms(10); // задержка для подавления дребезга 10 мс (магическое число - лучше превратить в макрос)
// теперь проверяем, поменялось ли состояние пинов
if (code == (! BTN_PIN)){
// не поменялось: надо обработать код
switch(code){
case 0b00000001: return BTN_1; // магическое число лучше заменить на макрос
// я не буду расписывать, как вернуть остальные коды - это ведь и так понятно?
}
} else {
// поменялось:
return NO_BUTTON; // вернем код отсутствия нажатых кнопок
}
}
теперь, когда заготовка функции готова, надо дополнить её макросами и т.п. - как и ранее.
вот и все.
почти

потому что в нашем коде нет одного важного момента: когда мы ставили задачу, мы забыли важный момент:
изменять состояние нагрузок надо
только тогда,
когда состояние кнопки поменялось, а когда состояние кнопки осталось неизменным, переключать нагрузку не надо! сейчас наш код будет моргать нагрузкой все время, пока мы держим кнопку нажатой! то есть в коде главного цикла нам надо добавить участок, который сравнит полученный код нажатой кнопки с тем кодом, который был в прошлый раз, и, если оба кода одинаковы, не будет ничего анализировать.
но, надеюсь, теперь это вы сможете сделать и самостоятельно.
извините, что почти пересказал рекомендованную к прочтению статью... но, надеюсь, способ решения задачи ОТ ОБЩЕГО К ЧАСТНОМУ вы уловили. выливается он в такой цикл разработки:
подумал, изложил, написал, подумал, скорректировал написанное, подумал, изложил, написал, подумал, скорректировал написанное...трудоемкий процесс, но для начинающего - самое то! хорошая тренировка. рекомендую!
