Обсуждаем контроллеры компании Atmel.
Ответить

Re: Нестабильность из-за задержек

Чт апр 15, 2021 17:43:20

Demiurg, это всё классно, если вы проект ТС собираетесь сами и с нуля делать. А ТСу потребуется тонна времени на изучение что это такое и как это программируется. И начинать с нуля. Скорость создания проекта стремиться в бесконечность. Для такого простого проекта как у него надо тупо "blink without delay" допилить и всё.

Re: Нестабильность из-за задержек

Чт апр 15, 2021 18:49:25

Показываю как пример. То, о чем просил ТС в конце корневого сообщения. Кнопка триггер. Нажимаем на кнопу, мигает один светодиод, загорается второй. Нажимаем на кнопу еще раз, оба светодиода гаснут.
Спойлер
Код:
//==================
#ifndef PROC_DEVICE_H
#define PROC_DEVICE_H

#include "proc_device.h"
#include "main_def_func.h"
//==================

//==================
#define LED_1_PORT PORTD
#define LED_1_DDR  DDRD
#define LED_1_PIN  PIND
#define LED_1      PD2

#define LED_2_PORT PORTD
#define LED_2_DDR  DDRD
#define LED_2_PIN  PIND
#define LED_2      PD3
//==================

//==================
#ifdef __PROJECT_MODE_WORK__
#define LED_1_DELAY_BLINK 500
#endif

#ifdef __PROJECT_MODE_DEBUG__
#define LED_1_DELAY_BLINK 1
#endif
//==================

//==================
void proc_device (void);
//==================

//==================
void led_1_on (void);
void led_1_off (void);
void led_1_switch (void);

void set_proc_led_1_blink_on (void);
void set_proc_led_1_blink_off (void);
void proc_led_1_blink (void);

void led_2_on (void);
void led_2_off (void);
void led_2_switch (void);
//==================

#endif


Спойлер
Код:
//==================
#include "proc_device.h"
//==================

//==================
void proc_device (void)
{
   static u08 _proc_device;

   switch (_proc_device)
   {
      case 0:
         set_bit (LED_1_DDR, LED_1); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         set_bit (LED_2_DDR, LED_2); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         _proc_device = 1;
         break;

      case 1:
         if (Get_Event (EV_ID_KEY_PRESSED))
         {
            switch (GetKeyCode ())
            {
               case KEY_PLUS_COD:
                  set_proc_led_1_blink_on ();
                  led_2_on ();
                  _proc_device = 2;
                  break;

               case KEY_MINUS_COD:
                  break;
            }
         }

//         _proc_device = 2;
         break;

      case 2:
         if (Get_Event (EV_ID_KEY_PRESSED))
         {
            switch (GetKeyCode ())
            {
               case KEY_PLUS_COD:
                  set_proc_led_1_blink_off ();
                  led_2_off ();
                  _proc_device = 1;
                  break;

               case KEY_MINUS_COD:
                  break;
            }
         }

//         _proc_device = 2;
         break;

      default:
         break;
   }

   proc_led_1_blink ();
}
//==================

//==================
void led_1_on (void)
{
   set_bit (LED_1_PORT, LED_1);
}

void led_1_off (void)
{
   clr_bit (LED_1_PORT, LED_1);
}

void led_1_switch (void)
{
   switch_bit (LED_1_PORT, LED_1);
}
//==================

//==================
static u08 _proc_led_1_blink;

void set_proc_led_1_blink_on (void)
{
   _proc_led_1_blink = 1;
}

void set_proc_led_1_blink_off (void)
{
   _proc_led_1_blink = 0;
   led_1_off ();
}

void proc_led_1_blink (void)
{
   static soft_timer ST_PROC_LED_1_BLINK;

   switch (_proc_led_1_blink)
   {
      case 0:
         break;

      case 1:
         set_bit (LED_1_DDR, LED_1); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         led_1_on ();
         set_soft_timer (ST_PROC_LED_1_BLINK, 0, LED_1_DELAY_BLINK);

         _proc_led_1_blink = 2;
         break;

      case 2:
         if (handle_soft_timer (ST_PROC_LED_1_BLINK))
         {
            led_1_switch ();
         }
         break;

      default:
         break;
   }
}
//==================

//==================
void led_2_on (void)
{
   set_bit (LED_2_PORT, LED_2);
}

void led_2_off (void)
{
   clr_bit (LED_2_PORT, LED_2);
}

void led_2_switch (void)
{
   switch_bit (LED_2_PORT, LED_2);
}
//==================


Дальше сами, ручками. Могу скинуть архив этого проекта. Файлов протеуса нет и не будет. Не пользуюсь. Мой инструментарий симулятор авр студии.
Вложения
Light.rar
(431.15 KiB) Скачиваний: 90

Re: Нестабильность из-за задержек

Чт апр 15, 2021 19:15:00

Искреннее спасибо всем участникам! Честно говоря, не думал,что такая вроде бы простенькая задача будет так сложно решаться. Demiurg, персонально 100 баллов в карму за конкретную помощь

Re: Нестабильность из-за задержек

Чт апр 15, 2021 19:30:30

Альтернативный и куда более простой в понимании вариант. Просто с миганием по таймеру. Писал в блокноте, не проверял, с нотацией CVAVR не знаком:
Спойлер
Код:
#include <mega8.h>
#include <delay.h>

#define T0VAL = 195 // переполнение на 195 тиках ~ 200мс

char flag;

void main(void) {
  DDRD = 0x00;
  PORTD = 0xFF;
  DDRB = 0xFF;
  PORTB = 0x00;
  DDRC.0 = 0xFF;
  PORTC.0 = 0x00;
  DDRC.1 = 0xFF;
  PORTC.1 = 0x00;
  DDRC.2 = 0x00;
  DDRC.3 = 0x00;
  DDRC.4 = 0x00;
  DDRC.5 = 0x00;
  PORTC.2 = 0xFF;
  PORTC.3 = 0xFF;
  PORTC.4 = 0xFF;
  PORTC.5 = 0xFF;
  PORTB.0 = 1;
  PORTB.4 = 1;
 
  while (1) {
    // кнопка-триггер нажимается, пока просто запоминаем включение у нас (флаг = 1) или выключение (флаг = 3)
    if (!PINC.2 && flag == 0)
      flag = 1;
    else if (!PINC.2 && flag == 2)
      flag = 3;

    // кнопку-триггер отжали, теперь можно переключать состояние
   if (PINC.2 && flag == 1) {
     TCCR0 = (1 << CS02) | (1 << CS00); // Timer0 запуск, предделитель = /1024
     PORTC.0 = 1; // Включаем d9
      flag = 2;
   }
    else if (PINC.2 && flag == 3) {
     PORTC.0 = 0; // Включаем d9
     PORTC.1 = 0; // и d10 тоже (а вдруг он был включен)
      flag = 0; // возвращаемся к "состоянию 0"
     TCCR0 = 0; // Stop Timer0
   }
   
   if (flag >= 2 && TCNT0 >= T0VAL) { // если у включеное состояние "триггера" и таймер0 досчитал до 195 (200мс), то мигаем d10
     PORTC.1 ^= PORTC.1; // инвертируем состояние PC1
     TCNT0 = 0; // Сбросить счетчик таймера
   }

    //// 1-ая группа кнопок
    if (!PIND.0) {
      PORTB.0 = 1;
      PORTB.1 = 0;
      PORTB.2 = 0;
      PORTB.3 = 0;
    }
    if (!PIND.1) {
      PORTB.1 = 1;
      PORTB.0 = 0;
      PORTB.2 = 0;
      PORTB.3 = 0;
    }
    if (!PIND.2) {
      PORTB.2 = 1;
      PORTB.0 = 0;
      PORTB.1 = 0;
      PORTB.3 = 0;
    }
    if (!PINC.5) {
      PORTB.5 = 1;
      PORTB.0 = 0;
      PORTB.1 = 0;
      PORTB.3 = 0;
    }
    if (!PIND.3) {
      PORTB.3 = 1;
      PORTB.0 = 0;
      PORTB.1 = 0;
      PORTB.2 = 0;
    }
    /////////   2-ая   группа кнопок
    if (!PIND.4) {
      PORTB.4 = 1;
      PORTB.5 = 0;
      PORTB.6 = 0;
      PORTB.7 = 0;
    }
    if (!PIND.5) {
      PORTB.5 = 1;
      PORTB.6 = 0;
      PORTB.7 = 0;
      PORTB.4 = 0;
    }
    if (!PIND.6) {
      PORTB.6 = 1;
      PORTB.4 = 0;
      PORTB.5 = 0;
      PORTB.7 = 0;
    }
    if (!PIND.7) {
      PORTB.7 = 1;
      PORTB.4 = 0;
      PORTB.5 = 0;
      PORTB.6 = 0;
    }
  }
}
Последний раз редактировалось NStorm Чт апр 15, 2021 19:32:16, всего редактировалось 1 раз.

Re: Нестабильность из-за задержек

Чт апр 15, 2021 19:39:31

Да не сложно на самом деле. Нужно просто почитать какую нибудь книгу по авр микроконтроллерам. И цикл статей Татарчевского. Чтобы понять суть. Когда понимаешь суть, понимаешь, что делать.

Добавлено after 8 minutes:
Можно и на флагах. Но код менее читабелен. И каждый флаг добавляет степень двойки состояний. А ещё неучтенные комбинации флагов, состояний. Конечные автоматы этого лишены. Там в принципе не может быть запрещённых состояний.

Re: Нестабильность из-за задержек

Чт апр 15, 2021 20:28:14

Можно и на флагах. Но код менее читабелен.

Ну да, мои 17 строк мигания куда менее читаемы, чем ваша "простыня" для примера ТС )
Ничего не имею против КА как таковых (только предпочитаю табличные реализации, по мне куда "читаемее"), но еще раз - для примера ТС из пушки по воробьям. Вы взяли свою либу, к которой привыкли. Для всех остальных - с ней еще разобраться надо. Даже мне сходу на глаз вся реализация не сразу понятна. Надо читать пачку исходников, чтобы разобраться. А вы предлагаете ТС понять её? Ну-ну.

PS: Поглядел мельком ваш архив - ну у вас банально switch...case, обернутый просто для расширяемости удобной. Таблички переходов, со ссылками на функции обработчиков куда "читабельней" в итоге, но понять их механизм новичку будет еще сложнее.

Добавлено after 1 minute 37 seconds:
Или массив структур или полная таблица переходов, как в последнее время стал делать, если оперативки не жалко. Тут еще вкратце писал: https://www.radiokot.ru/forum/viewtopic ... 4#p3826024
Но это всё ТС нафиг не нужно пока что.

Re: Нестабильность из-за задержек

Чт апр 15, 2021 21:37:04

А вот моя вариация на тему КА с диспетчером:

Код:
void Example_State_SM (dSM_Handler_t m)
{
   
    switch (m->Signal)
    {
        case DSM_SIGNAL_ENTRY:
            // Здесь код при первом входе в состояние после его смены.
            // Например, инициализация таймеров, структур, выделение памяти и пр.
       
            break;
       
        case DSM_SIGNAL_NONE:
            // Здесь код, вызываемый циклически диспетчером
            break;

        case DSM_SIGNAL_EXIT:
            // Здесь код, когда состояние сменилось
            // Можно освободить память, остановить таймеры и пр.

            break;

        default:
            break;
     }
}


Инициализация машины и её первое состояние:
Код:
dStateMashine_Setup(&SM, Example_State_SM);


Можно даже несколько машин запустить.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 04:46:59

NStorm писал(а):Ну да, мои 17 строк мигания куда менее читаемы, чем ваша "простыня" для примера ТС )

Дело не в 17 строчках. Краткость не всегда полезна. При вашем подходе начнёшь что нибудь менять, утонешь в флагах. Программа дальше станет нечитабельной. Без малейших шансов адекватно править, менять логику.

NStorm писал(а):Вы взяли свою либу, к которой привыкли. Для всех остальных - с ней еще разобраться надо. Даже мне сходу на глаз вся реализация не сразу понятна. Надо читать пачку исходников, чтобы разобраться. А вы предлагаете ТС понять её? Ну-ну.

Дело не в личной либе. И разбираться ТС-у в любом случае. Я дал ссылку на цикл статей. У меня на данном примере сделано практически по такому же подходу, как в статьях. Служба сообщений, в моем случае сообщения-события. При этом не очередь, из за которой свои нюансы всплывают. Программные таймеры. Обычный switch-case, никаких оберток. Ими я как раз не стал пугать ТС.

NStorm писал(а):Таблички переходов, со ссылками на функции обработчиков куда "читабельней" в итоге, но понять их механизм новичку будет еще сложнее.

Табличный интерпретатор - неплохо. Тоже свои нюансы. Сначала, ТС пусть почитает, что такое КА вообще. Служба сообщений, событий - то есть, взаимодействие программных модулей. А это ключевой момент. Программные таймеры. Потом ТС сам уже будет решать, какими методами ему реализовать КА. А также табличные интерпретаторы.

Данные, структуры, алгоритмы. Чем больше данных, структур, тем меньше программа. И наоборот. В первом случае, в идеале, вся программа сводится к табличному интерпретатору. Таблицы, структуры хороши. Но и тут есть нюанс. Жёстко заданная логика. Универсальности нет, как ни бейся. Пройденный этап. Поэтому, компромиссы. Анализ проекта. Систематизация данных. Синтез подходов. Разные интерпретаторы. Разные таблицы. Есть ещё метод. Подглядел у одного эмбеддера. Делается одна большая таблица, и макросами делаются методы выборки данных под конкретный интерпретатор таблицы. X-Macro.

Добавлено after 9 minutes 36 seconds:
parovoZZ писал(а):А вот моя вариация на тему КА с диспетчером:

Выложите какой нибудь простой пример проект на вашем подходе. Архив с готовым, скомпилированным, рабочим проектом. Посмотрю на досуге.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 07:17:12

При вашем подходе начнёшь что нибудь менять, утонешь в флагах. Программа дальше станет нечитабельной.

Всего-лишь добавить enum для флагов и всё станет читаемей.

Таблицы, структуры хороши. Но и тут есть нюанс. Жёстко заданная логика. Универсальности нет, как ни бейся

Поглядите по ссылке. У меня таблица лишь задает связь (текущее состояние, событие) => переход. Переход - это функция, там можно как угодно обрабатывать ситуацию и потом вернуть любое новое состояние. В т.ч. переход сам может вызвать другой переход и т.д. Универсальности даже больше, чем внутри case'а.

Добавлено after 4 minutes 45 seconds:
Простой пример:
Спойлер
Код:
eState trToggleBypass() {
...
}

eState trAcRestoration() {
    if (state.v1_state != VST_CLOSED)
        return trToggleBypass();
    else
        return ST_NORMAL;
}

// Transition table type
typedef eState (*trans_t[ST_LAST][EV_LAST])(void);

// Transition table
trans_t trans = {
    [ST_NORMAL][EV_BTN_SHORT] = trToggleBypass,
    [ST_BYPASS][EV_AC_RESTORATION] = trAcRestoration,
    [ST_WATER_CLOSED][EV_BTN_SHORT] = trToggleBypass,
    [ST_ANY][EV_VALVE_TIMEOUT] = trError
};

Одна и та же функция перехода trToggleBypass может быть вызвана из любой комбинации (текущее состояние, событие). Любой переход может вызвать функцию другого перехода, как делает trAcRestoration при наличии определенного условия. Есть обработчики переходов из любого события или независимо от текущего состояния (как в данном случае [ST_ANY] делает). Вот и думайте, где большое гибкости )

Re: Нестабильность из-за задержек

Пт апр 16, 2021 07:35:14

NStorm писал(а):Всего-лишь добавить enum для флагов и всё станет читаемей.

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

NStorm писал(а):Вот и думайте, где большое гибкости )

А что тут думать, сам активно таблицы применяю. MicroMenu, к примеру, собственной переработки. Но для ТС на данный момент это будет сложно. Работа с указателями, структурами. Если разберётся, гуд. Инфу мы ему предоставили, куда копать.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 07:58:47

Одна и та же функция перехода trToggleBypass может быть вызвана из любой комбинации (текущее состояние, событие). Любой переход может вызвать функцию другого перехода, как делает trAcRestoration при наличии определенного условия. Есть обработчики переходов из любого события или независимо от текущего состояния (как в данном случае [ST_ANY] делает). Вот и думайте, где большое гибкости )

Я как-то по результатам одной темы про КА, там и Demiurg был, написал следующий класс:
Спойлер
Код:
enum class State : uint8_t { _, A, AC, ACD, ACDA, AB, ABA, ABAD, ABADC };
enum class Event : uint8_t { PressA, PressB, PressC, PressD };

constexpr Transition<State, Event> transitions[] =
{
    { State::_,     Event::PressA, State::A },
    { State::A,     Event::PressC, State::AC },
    { State::AC,    Event::PressD, State::ACD },
    { State::ACD,   Event::PressA, State::ACDA, [] { greenLed.toggle(); } },
   
    { State::A,     Event::PressB, State::AB },
    { State::AB,    Event::PressA, State::ABA },
    { State::ABA,   Event::PressD, State::ABAD },
    { State::ABAD,  Event::PressC, State::ABADC, [] { redLed.toggle(); } }
};

StateMachine<transitions> sm;
sm.process(Event::PressB);
sm.process(Event::PressD);
sm.process(Event::PressA);   // A
sm.process(Event::PressC);   // AC
sm.process(Event::PressD);   // ACD
sm.process(Event::PressA);   // ACDA -> greenLed.toggle()

Тут видно в таблице по одной лямбде, на самом деле указателей на функции для каждого состояния может быть два(action/guard), на 32-х битных мк они бы занимали 8 байт, плюс байт состояния(на M0 пришлось бы дополнять до 12 байт), но в данном случае сначала мы проходим по таблице и находим все функции, затем размешаем их в конце таблицы а вместо самих указателей подставится индекс(байт), т.е. на каждое состояние нужно всего 3 байта. Таблица естественно ложится во флеш. А самым большим недостатком оказалось то, что реально я это ни разу не использовал, всегда находятся более простые подходы :)

Re: Нестабильность из-за задержек

Пт апр 16, 2021 08:05:37

Reflector, по ссылке выше что давал, я сначала делал таблицы с проходом. Памяти меньше расход, но больше циклов на проход таблицы для поиска. Компромисс между циклами и памятью. Если памяти хватает, мне указатели показались удобнее в использовании. Ну и речь о чистом Си.

Demiurg, это всё понятно, но я "вангую" что и с вашим вариантом даже ТС не разберется и дальше не допишет. Не тот уровень владения языком пока что еще, судя по его исходнику. Вариант на флаге без сомнения неудобен для развития дальнейшего. Но о развитии в посте ТС речи не шло. А его задачу это решает более просто, "в лоб" и должно быть в рамках возможности понять им смысл.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 09:14:58

Во полемику развели.
В CVAVR ни чего нет эффективнее как
Код:
#define LED1 (PORTB.0)
а потом в коде
Код:
        LED1 = 1;
        LED1 = 0;
это очень просто, и код эффективен, без ваших автоматов, классов и т.п.
Хотите asm глянуть во что вот это
Код:
        if (!PIND.0) LED1 = 1; else LED1 = 0;
превращается?

Re: Нестабильность из-за задержек

Пт апр 16, 2021 09:22:24

Dimon456, вопрос не о том, как развести порты, а о том, как сделать "параллельно выполняемый" код, и чтоб эти параллельные ветви друг другу не мешали

Re: Нестабильность из-за задержек

Пт апр 16, 2021 10:09:34

"параллельно выполняемый" код возможен только в много поточных системах, как вариант DMA в stm32, даже windows у вас на компе не относится к "системе реального времени".
Остальное все - последовательно исполняемый код, как можно говорить о какой-то параллельности.

Вы просто завернули последовательность if else или switch case в красивую не понятную обертку.
Универсальности это не дает.

Ivanoff-iv писал(а):как развести порты
какие порты?

Re: Нестабильность из-за задержек

Пт апр 16, 2021 10:14:33

Dimon456, поэтому "параллельно выполняемый" видимо в кавычках и был. И DMA - это не "параллельно выполняемый". И параллельность и ОСРВ - совсем разные вещи. Что-то вы всё в кучу намешали.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 10:32:16

Псевдопараллельность. Те принципы которые применяются в диспетчерах, ртос. Дробление выполнения программных модулей на куски либо временными отрезками (вытеснение).

Re: Нестабильность из-за задержек

Пт апр 16, 2021 14:00:14

Если ваша псевдопараллельность уместится на 1 страничку, тогда давайте код в студию, обсудим.

Re: Нестабильность из-за задержек

Пт апр 16, 2021 14:21:26

у меня уместится :) ... код.... блин, код наверно только в понедельник.... :(

Re: Нестабильность из-за задержек

Пт апр 16, 2021 14:23:36

"Dimon456". Мне не нравится ваша позиция. Одна страничка. Свой подход я обьяснял. Проект делится на логические модули. Если я распишу все в одной странице, я утону в этой странице. Если вам это не нравится, то не проецируйте этот одностраничный подход на мои сообщения. Это ваше личное предпочтение.
Вы одной вещи не понимаете. Главный модуль, пример которого я показал, он как раз уместился в страничку. И уместится, если ТС покажет полное ТЗ. Не суть. Готовь сани летом, телегу зимой. Приготовь свое рабочее пространство. И работай на одной страничке. Другие странички считайте ножовкой, болгаркой ну и так далее.
Ответить