Отговори на тема  [ 26 мнения ]  Отиди на страница Предишна  1, 2
Stop Loop 
Автор Съобщение
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 1:45 am
Мнения: 260
Мнение Re: Stop Loop
Защо са ни стейтове, като може да се изпълни с просто следене на фазите на бутона + таймери :)
Накратко: пазим старата стойност на бутона в нечетен бит, а новата - в четен, и ги четем по двойки (анд-ването с 3 в макросите GetPhaseButtonХ() по-долу). Така имаме общо 4 възможни фази, като 2 от тях се случват еднократно (PRESSED and RELEASED) за един цикъл натискане-отпускане; съответно те са и най-интересни.
Таймерите са 3-стейтни и винаги броят надолу. Удобни са, когато трябва да се реализира еднократно събитие (в случая 3 секунди импулс и 1 сек дилей).
Четенето на бутоните може да се извади извън периодичното изпълнение (if ((timeNow - Status.timers.lastCallTime) >= TASK_CALL_PERIOD_MS)...) за по-бърза реакция.

Код:
#define Button_Up      8
#define Button_Down    9
#define Relay_Up       2
#define Relay_Compr    3
#define Relay_Down     4
#define TASK_CALL_PERIOD_MS    2

enum BtnPhase_t {
    PHASE_LOW      = 0,
    PHASE_PRESSED  = 1,
    PHASE_HIGH     = 3,
    PHASE_RELEASED = 2
}

struct Status_t {
    uint8_t  buttonPhases;
    struct {
        uint16_t  relayUpPulse;
        uint16_t  relayDownDelay;
        uint32_t  lastCallTime;
    } timers;
};

static struct Status_t  Status;


uint8_t  RefreshButtonPhases(void)
{
    Status.buttonPhases = (Status.buttonPhases << 1) & ~((1 << 0) | (1 << 2));
    Status.buttonPhases |= (digitalRead(Button_Up)   << 0);
    Status.buttonPhases |= (digitalRead(Button_Down) << 2);
   
    return Status.buttonPhases;
}

#define GetPhaseButtonUp(phase)   ((phase) & 3)
#define GetPhaseButtonDown(phase) (((phase) >> 2) & 3)

void setup()
{
    pinMode(Button_Up, INPUT);
    pinMode(Button_Down, INPUT);
    pinMode(Relay_Up, OUTPUT);
    pinMode(Relay_Compr, OUTPUT);
    pinMode(Relay_Down, OUTPUT);

    digitalWrite(Relay_Up, LOW);
    digitalWrite(Relay_Compr, LOW);
    digitalWrite(Relay_Down, LOW);
   
    Status.timers.lastCallTime = 0;
}

void loop()
{
    uint32_t  timeNow = millis();
    if ((timeNow - Status.timers.lastCallTime) >= TASK_CALL_PERIOD_MS)
    {
        uint8_t  btnPhases    = RefreshButtonPhases();
        uint8_t  phaseBtnUp   = GetPhaseButtonUp(btnPhases);
        uint8_t  phaseBtnDown = GetPhaseButtonDown(btnPhases);
        Status.timers.lastCallTime = timeNow;
       
        switch (phaseBtnUp)
        {
            case PHASE_PRESSED:
                digitalWrite(Relay_Up, HIGH);
                break;
            case PHASE_HIGH:
                break;
            case PHASE_RELEASED:
                digitalWrite(Relay_Up, LOW);
                digitalWrite(Relay_Down, LOW);
                digitalWrite(Relay_Compr, LOW);
                break;
            default:
            {
                switch (phaseBtnDown)
                {
                    case PHASE_PRESSED:
                        Status.timers.relayUpPulse = (3000 / TASK_CALL_PERIOD_MS) + 1;
                        digitalWrite(Relay_Up, HIGH);
                        break;
                    case PHASE_RELEASED:
                        // Stop all timers
                        Status.timers.relayUpPulse = 0;
                        Status.timers.relayDownDelay = 0;
                       
                        // All relays off
                        digitalWrite(Relay_Up, LOW);
                        digitalWrite(Relay_Down, LOW);
                        digitalWrite(Relay_Compr, LOW);
                        break;
                    default:
                        break;
                }
                break;
            }
        }
   
        switch (Status.timers.relayUpPulse)
        {
            case 0: break;
            case 1:
            {
                Status.timers.relayUpPulse = 0;
                Status.timers.relayDownDelay = (1000 / TASK_CALL_PERIOD_MS) + 1;
               
                digitalWrite(Relay_Up, LOW);
                digitalWrite(Relay_Compr, HIGH);
                break;
            }
            default:
                Status.timers.relayUpPulse--;
                break;
        }
       
        switch (Status.timers.relayDownDelay)
        {
            case 0: break;
            case 1:
            {
                Status.timers.relayDownDelay = 0;
                digitalWrite(Relay_Down, HIGH);
                break;
            }
            default:
                Status.timers.relayDownDelay--;
                break;
        }
    }
}


Пон Авг 17, 2020 10:39 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 8:21 pm
Мнения: 27998
Местоположение: София
Мнение Re: Stop Loop
Е това което си дал какво е че не са стейтове :) А използването на таймери в един момент започва да става не рационално, като трябва да инкрементваш или декрементваш по един куп таймери .... иначе е по-производително, или може да бъде по-производително.


Пон Авг 17, 2020 10:30 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Сеп 28, 2011 9:04 am
Мнения: 38
Мнение Re: Stop Loop
tolstolob написа:
Защо са ни стейтове, като може да се изпълни с просто следене на фазите на бутона + таймери :)
Накратко: пазим старата стойност на бутона в нечетен бит, а новата - в четен, и ги четем по двойки (анд-ването с 3 в макросите GetPhaseButtonХ() по-долу). Така имаме общо 4 възможни фази, като 2 от тях се случват еднократно (PRESSED and RELEASED) за един цикъл натискане-отпускане; съответно те са и най-интересни.
Таймерите са 3-стейтни и винаги броят надолу. Удобни са, когато трябва да се реализира еднократно събитие (в случая 3 секунди импулс и 1 сек дилей).
Четенето на бутоните може да се извади извън периодичното изпълнение (if ((timeNow - Status.timers.lastCallTime) >= TASK_CALL_PERIOD_MS)...) за по-бърза реакция.

Защото до колкото разбрах от koko76bj Ардуино няма многозадачност. Или трябва да напишеш програма тип черва (абсолютно непрепоръчително), или да капсулираш всяко нещо в отделни модули като викаш определена loopback функция от модула при всеки loop.
Това обаче означава, че не е добре да имаш забавяне в тези функции. За това ти е стейт машината и избягване на използването на delay(x) в тялото на тези функции.

Аз нищо не разбирам от Ардуино (почти толкова и от C), просто се опитах да помогна на колегата да си свърши работа
но не зная за какви макроси говориш. До колкото видях Ардуино използва C++ а там се съм чувал за такова понятие (или поне исках да не съм чувал) . Какво имам в предвид
Код:
#define GetPhaseButtonDown(phase) (((phase) >> 2) & 3)

Това е сиснтаксис на C, не че не работи и в C++ но е много грозно като синтаксис при наличие на static inline функции това направо си изглежда кофти (недай си боже за някаква по-сложна функция).
има и една по-готина алтернатива като се нарича lambda
Код:
auto example()->void
{
   uint32_t  x = 4;
   
    auto lambda_func = [&xa = x, x = x+1]( uint32_t i)->int
    {
        xa += i;
        return x+i;
    }(3);
}


дето си пишеш "МАКРОСИ" директо в тялото на функцията ,но не зная до кой диалект на C++ поддържа адруино. Но мисля ,че е поне C++11 което поддържа такива "МАКРОСИ".
ако ти е интересно виж това https://en.cppreference.com/w/cpp/language/lambda
Един съвет: За да спестиш 1 байт RAM правиш "сериозни" врътки да съхраниш стейта на бутоните. Това наистина не е оправдано!

Много ми хареса ми подхода на Jack - софруерна имплемнтация на базата на хардуерна логика :) Готино

_________________
Оставете човек в самолет и той ще летне за един ден.
Хвърлете човек от самолета и той лети до края на живота си.


Пон Авг 17, 2020 11:23 pm
Профил ICQ
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 1:45 am
Мнения: 260
Мнение Re: Stop Loop
ToHu написа:
Е това което си дал какво е че не са стейтове :) А използването на таймери в един момент започва да става не рационално, като трябва да инкрементваш или декрементваш по един куп таймери .... иначе е по-производително, или може да бъде по-производително.

Е, в крайна сметка е така, то какво иначе да бъде :) Аз тригерирах по-скоро заради понятията: 'таймер' и 'фаза на бутон' са максимално близо до текста на заданието. Щото, 'state1' и т.н. до 'stateN' не ми е никак лесно за мапване към заданието.
@panchev68, критиките към твоето решение са (заради което беше и моя пост):
- Да ползваш FreeRTOS за такава задача, е като да трепеш мухи с лазерно оръдие. Съответно кода, който съм дал ще върви директно и на въшлив PIC10, но РТОС - едва ли.
- Ако квалифицираш побитови операции като 'врътки', може би трябва да знаеш, че такива инструкции има дори и в цитирания по-горе пик, използването им е добре за 'пърформанса'. Веднага личи, че основната ти дейност не са контролерите.
- Не знам как е по-елегантно да ползваш отделен хвърчащ байт за стария стейт на бутона, вместо целия ти стейт да стои само в един, но вкусове всякакви. Това е и любимия подход на индийците - предпочитат да има максимално много хвърчащи променливи със загадъчни имена и дълги черва от рода на
Код:
if (state == 1 && old == 0) ...
else if (state == 0 && old == 1) ...
else if (...) ...


Вто Авг 18, 2020 10:25 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Сеп 28, 2011 9:04 am
Мнения: 38
Мнение Re: Stop Loop
tolstolob написа:
@panchev68, критиките към твоето решение са (заради което беше и моя пост):
- Да ползваш FreeRTOS за такава задача, е като да трепеш мухи с лазерно оръдие. Съответно кода, който съм дал ще върви директно и на въшлив PIC10, но РТОС - едва ли.
- Ако квалифицираш побитови операции като 'врътки', може би трябва да знаеш, че такива инструкции има дори и в цитирания по-горе пик, използването им е добре за 'пърформанса'. Веднага личи, че основната ти дейност не са контролерите.
- Не знам как е по-елегантно да ползваш отделен хвърчащ байт за стария стейт на бутона, вместо целия ти стейт да стои само в един, но вкусове всякакви. Това е и любимия подход на индийците - предпочитат да има максимално много хвърчащи променливи със загадъчни имена и дълги черва от рода на


Да със сигурност аруино не ми е интересно. Ако това визираш за среда за разработка на фирмуер за контролери ми е много тъжно за теб. На ATmega328P - 32К flash и 2 K RAM / на 20 MHz 8-битов процесор - не зная какви контролери правиш - дано ти се получава.
Ако правиш управления за детски играчки или да мигат полседователно 2 светодиода това е OK .
Все още не мога да разбера идеята ти да кодираш стейтовите в 1 общ стейт и на следващият ред да ги декодираш. Като толкова държих да са в 1 стейт защо не използваш union - пърформанса ще ти е в пъти. с цената на +1 байт в RAM-a. Както каза всеки има право да няма вкус.
Не зная какво е pic10 и ptoc и "хвърчащ байт" , Това което си пуснал като пример си е жива стейт машина която по някой път се налага , все пак не всеки обича switch/case няма никаква връзка с капсулиране за което говорих.
За FreeRTOS: 1-во никога няма да се хвана с подобна задача, 2. Не ми се занимаваще да търся командите на ардуино за да помогна на koko76bj и му пратих това с което ме е най-познато и му писах къде да търси.
Поздрави.

_________________
Оставете човек в самолет и той ще летне за един ден.
Хвърлете човек от самолета и той лети до края на живота си.


Вто Авг 18, 2020 11:58 am
Профил ICQ
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 1:45 am
Мнения: 260
Мнение Re: Stop Loop
panchev68 написа:
...
Нямах намерение да пиша повече, но няма да оставя ad hominem подмятанията без отговор. Като вземем предвид следните бисери:
- Пише "Аз нищо не разбирам от Ардуино (почти толкова и от C)" и "не зная за какви макроси говориш". Мисли, че макросите идват чак в С++11...
- Бърка callback с loopback...
- Бърка юниън с битфийлд... Ми и битфийлд да беше, нямаше да е "в пъти по-бърз" от маскиране и шифтване (конкретно 8-битови атмеги/пикове), щото отдолу генерирания асемблер е същия... Сега, че е по-четливо с бит фийлд, съгласен съм.
- още не може да разбере идеята да "кодираш стейтовите в 1 общ стейт и на следващият ред да ги декодираш". Жокер: имаш едновременно ефективност (малка консумация РАМ, в един байт можеш да обработваш до 4 бутона и по-малко генерирани бранч инструкции, заради по-простите сравнения) + четливост. Може и вместо switch конструкции, да ползваш if-else черва, печалбата е 0.
- Нарича Ардуино API-то "команди"
- Прави грешни предположения за уменията/качествата на съфорумци, единствено защото му критикуват кода.
Предвид изброеното по-горе, аз лично бих бил много скептичен към съветите на такъв 'специалист'.
Айде със здраве.


Вто Авг 18, 2020 3:08 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Сеп 28, 2011 9:04 am
Мнения: 38
Мнение Re: Stop Loop
офф отвори си учебника за 1-ви клас по C
Код:
union
{
      uint16_t U16;
      uint8_t U8[2];
}State;

auto example()->void
{
        State.U8[0] = readPin(1);
        State.U8[1] = readPin(1);
}


"колегата" бърка lambda с неговите макроси - Мисли, че макросите идват чак в С++11... хаха по голяма тъпотия не бях чувал !!!
"битфийлд" пак не зная какво е това
ако имаш в предвид "Bit Fields"
Код:
struct
{
  bool B1:1;
  bool B1:2;
};

не е опция !!! има много по темата

има си стандартен клас в C++ std::vector<bool>

хаха а за уменията не коментирам нищо. Само ми е мъчно :D
Поздрави

_________________
Оставете човек в самолет и той ще летне за един ден.
Хвърлете човек от самолета и той лети до края на живота си.


Вто Авг 18, 2020 3:51 pm
Профил ICQ
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 1:45 am
Мнения: 260
Мнение Re: Stop Loop
Keep them coming :mrgreen: Кажи сега за loopback-а, дето се вика циклично на всеки loop 8)
Трябва с Карадев да направите стартъп - той ще прави multidrop RS-232, ти ще плющиш луупбеци, unicorn най-много до месец :mrgreen:
https://en.wikipedia.org/wiki/Unicorn_(finance)


Вто Авг 18, 2020 4:24 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 10:22 pm
Мнения: 3074
Мнение Re: Stop Loop
Момчета,
сипете си по една бира,
ако трябва - разделете си я....жегаво много.

Ако може простичко да ми обясните какво е "ламбда", в кои диалекти го има.
Това
auto example()->void
как се разшифрова?

Гледам, че ви се пише,пък аз съм любопитко :D


Вто Авг 18, 2020 5:45 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Сря Юли 11, 2007 9:16 am
Мнения: 1705
Мнение Re: Stop Loop
stefan63 написа:
Момчета,
сипете си по една бира,
ако трябва - разделете си я....жегаво много.

Ако може простичко да ми обясните какво е "ламбда", в кои диалекти го има.
Това
auto example()->void
как се разшифрова?

Гледам, че ви се пише,пък аз съм любопитко :D


Ламбдата е анонимна функция. В примера по-горе е използвана тотално не на място и затова може би не ти е станало ясно.
А за другият ти въпрос - като
Код:
void example() { ... }
:D
Ако няма причина да описвам типа на резултата по този начин (със стрелкичката), не бих го ползвал.


Сря Авг 19, 2020 8:16 am
Профил
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Чет Авг 20, 2020 7:17 am
Мнения: 7
Местоположение: Пловдив
Мнение Re: Stop Loop
stefan63 написа:
Момчета,
сипете си по една бира,
ако трябва - разделете си я....жегаво много.

Ако може простичко да ми обясните какво е "ламбда", в кои диалекти го има.
Това
auto example()->void
как се разшифрова?

Гледам, че ви се пише,пък аз съм любопитко :D


Lambda (closures) е функция, която можете да я напишете инлайн във вашия изходен код на функция (функция в функцията)

auto example()->void

при писане на c++ , когато в header(.hpp) файла имаш даден клас , много по-удобно е използването на този синтаксис в .cpp файла.

panchev68 е в грешка
Function-like мacros не заменят static inline и lambda
function-like macros заместватват директо кода , докато другите 2 имат физическо изражение (тоест можеш да вземеш указател или референция към тях).
static inline function е по-рационалният подход пред function-like macros от гледна точка на оптимизация . Другото предимство е че може да се изпълняваш стъпка по-стъпка в debug. Аз поне никога няма да използвам сложни function-like макроси. Това е предпоставка за трудно откриваеми грешки.


Чет Авг 20, 2020 8:00 am
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 26 мнения ]  Отиди на страница Предишна  1, 2

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 5 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни