Нестабильность из-за задержек
- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Demiurg, это всё классно, если вы проект ТС собираетесь сами и с нуля делать. А ТСу потребуется тонна времени на изучение что это такое и как это программируется. И начинать с нуля. Скорость создания проекта стремиться в бесконечность. Для такого простого проекта как у него надо тупо "blink without delay" допилить и всё.
- Реклама
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Показываю как пример. То, о чем просил ТС в конце корневого сообщения. Кнопка триггер. Нажимаем на кнопу, мигает один светодиод, загорается второй. Нажимаем на кнопу еще раз, оба светодиода гаснут.
Дальше сами, ручками. Могу скинуть архив этого проекта. Файлов протеуса нет и не будет. Не пользуюсь. Мой инструментарий симулятор авр студии.
Спойлер
Код: Выделить всё
//==================
#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 КБ) 108 скачиваний
- Сообщения: 23
- Зарегистрирован: Ср ноя 21, 2018 02:29:02
Искреннее спасибо всем участникам! Честно говоря, не думал,что такая вроде бы простенькая задача будет так сложно решаться. Demiurg, персонально 100 баллов в карму за конкретную помощь
- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Альтернативный и куда более простой в понимании вариант. Просто с миганием по таймеру. Писал в блокноте, не проверял, с нотацией 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 раз.
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Да не сложно на самом деле. Нужно просто почитать какую нибудь книгу по авр микроконтроллерам. И цикл статей Татарчевского. Чтобы понять суть. Когда понимаешь суть, понимаешь, что делать.
Добавлено after 8 minutes:
Можно и на флагах. Но код менее читабелен. И каждый флаг добавляет степень двойки состояний. А ещё неучтенные комбинации флагов, состояний. Конечные автоматы этого лишены. Там в принципе не может быть запрещённых состояний.
Добавлено after 8 minutes:
Можно и на флагах. Но код менее читабелен. И каждый флаг добавляет степень двойки состояний. А ещё неучтенные комбинации флагов, состояний. Конечные автоматы этого лишены. Там в принципе не может быть запрещённых состояний.
- Реклама
- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Ну да, мои 17 строк мигания куда менее читаемы, чем ваша "простыня" для примера ТС )Можно и на флагах. Но код менее читабелен.
Ничего не имею против КА как таковых (только предпочитаю табличные реализации, по мне куда "читаемее"), но еще раз - для примера ТС из пушки по воробьям. Вы взяли свою либу, к которой привыкли. Для всех остальных - с ней еще разобраться надо. Даже мне сходу на глаз вся реализация не сразу понятна. Надо читать пачку исходников, чтобы разобраться. А вы предлагаете ТС понять её? Ну-ну.
PS: Поглядел мельком ваш архив - ну у вас банально switch...case, обернутый просто для расширяемости удобной. Таблички переходов, со ссылками на функции обработчиков куда "читабельней" в итоге, но понять их механизм новичку будет еще сложнее.
Добавлено after 1 minute 37 seconds:
Или массив структур или полная таблица переходов, как в последнее время стал делать, если оперативки не жалко. Тут еще вкратце писал: https://www.radiokot.ru/forum/viewtopic ... 4#p3826024
Но это всё ТС нафиг не нужно пока что.
- Сообщения: 1759
- Зарегистрирован: Пт июн 01, 2018 07:28:45
А вот моя вариация на тему КА с диспетчером:
Инициализация машины и её первое состояние:
Можно даже несколько машин запустить.
Код: Выделить всё
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);- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Дело не в 17 строчках. Краткость не всегда полезна. При вашем подходе начнёшь что нибудь менять, утонешь в флагах. Программа дальше станет нечитабельной. Без малейших шансов адекватно править, менять логику.NStorm писал(а): Ну да, мои 17 строк мигания куда менее читаемы, чем ваша "простыня" для примера ТС )
Дело не в личной либе. И разбираться ТС-у в любом случае. Я дал ссылку на цикл статей. У меня на данном примере сделано практически по такому же подходу, как в статьях. Служба сообщений, в моем случае сообщения-события. При этом не очередь, из за которой свои нюансы всплывают. Программные таймеры. Обычный switch-case, никаких оберток. Ими я как раз не стал пугать ТС.NStorm писал(а): Вы взяли свою либу, к которой привыкли. Для всех остальных - с ней еще разобраться надо. Даже мне сходу на глаз вся реализация не сразу понятна. Надо читать пачку исходников, чтобы разобраться. А вы предлагаете ТС понять её? Ну-ну.
Табличный интерпретатор - неплохо. Тоже свои нюансы. Сначала, ТС пусть почитает, что такое КА вообще. Служба сообщений, событий - то есть, взаимодействие программных модулей. А это ключевой момент. Программные таймеры. Потом ТС сам уже будет решать, какими методами ему реализовать КА. А также табличные интерпретаторы.NStorm писал(а): Таблички переходов, со ссылками на функции обработчиков куда "читабельней" в итоге, но понять их механизм новичку будет еще сложнее.
Данные, структуры, алгоритмы. Чем больше данных, структур, тем меньше программа. И наоборот. В первом случае, в идеале, вся программа сводится к табличному интерпретатору. Таблицы, структуры хороши. Но и тут есть нюанс. Жёстко заданная логика. Универсальности нет, как ни бейся. Пройденный этап. Поэтому, компромиссы. Анализ проекта. Систематизация данных. Синтез подходов. Разные интерпретаторы. Разные таблицы. Есть ещё метод. Подглядел у одного эмбеддера. Делается одна большая таблица, и макросами делаются методы выборки данных под конкретный интерпретатор таблицы. X-Macro.
Добавлено after 9 minutes 36 seconds:
Выложите какой нибудь простой пример проект на вашем подходе. Архив с готовым, скомпилированным, рабочим проектом. Посмотрю на досуге.parovoZZ писал(а):А вот моя вариация на тему КА с диспетчером:
- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Всего-лишь добавить 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
};
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Вы сами прекрасно осознаете, что подход на флагах сложнее, нечитабельней, мало того, флаги чреваты неучтенными сочетаниями, состояниями.NStorm писал(а): Всего-лишь добавить enum для флагов и всё станет читаемей.
А что тут думать, сам активно таблицы применяю. MicroMenu, к примеру, собственной переработки. Но для ТС на данный момент это будет сложно. Работа с указателями, структурами. Если разберётся, гуд. Инфу мы ему предоставили, куда копать.NStorm писал(а): Вот и думайте, где большое гибкости )
- Сообщения: 2089
- Зарегистрирован: Вс июн 19, 2016 09:32:03
[uquote="NStorm",url="/forum/viewtopic.php?p=4016558#p4016558"]Одна и та же функция перехода trToggleBypass может быть вызвана из любой комбинации (текущее состояние, событие). Любой переход может вызвать функцию другого перехода, как делает trAcRestoration при наличии определенного условия. Есть обработчики переходов из любого события или независимо от текущего состояния (как в данном случае [ST_ANY] делает). Вот и думайте, где большое гибкости )[/uquote]
Я как-то по результатам одной темы про КА, там и Demiurg был, написал следующий класс:
Тут видно в таблице по одной лямбде, на самом деле указателей на функции для каждого состояния может быть два(action/guard), на 32-х битных мк они бы занимали 8 байт, плюс байт состояния(на M0 пришлось бы дополнять до 12 байт), но в данном случае сначала мы проходим по таблице и находим все функции, затем размешаем их в конце таблицы а вместо самих указателей подставится индекс(байт), т.е. на каждое состояние нужно всего 3 байта. Таблица естественно ложится во флеш. А самым большим недостатком оказалось то, что реально я это ни разу не использовал, всегда находятся более простые подходы 
Я как-то по результатам одной темы про КА, там и 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()- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Reflector, по ссылке выше что давал, я сначала делал таблицы с проходом. Памяти меньше расход, но больше циклов на проход таблицы для поиска. Компромисс между циклами и памятью. Если памяти хватает, мне указатели показались удобнее в использовании. Ну и речь о чистом Си.
Demiurg, это всё понятно, но я "вангую" что и с вашим вариантом даже ТС не разберется и дальше не допишет. Не тот уровень владения языком пока что еще, судя по его исходнику. Вариант на флаге без сомнения неудобен для развития дальнейшего. Но о развитии в посте ТС речи не шло. А его задачу это решает более просто, "в лоб" и должно быть в рамках возможности понять им смысл.
Demiurg, это всё понятно, но я "вангую" что и с вашим вариантом даже ТС не разберется и дальше не допишет. Не тот уровень владения языком пока что еще, судя по его исходнику. Вариант на флаге без сомнения неудобен для развития дальнейшего. Но о развитии в посте ТС речи не шло. А его задачу это решает более просто, "в лоб" и должно быть в рамках возможности понять им смысл.
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
Во полемику развели.
В CVAVR ни чего нет эффективнее кака потом в коде это очень просто, и код эффективен, без ваших автоматов, классов и т.п.
Хотите asm глянуть во что вот этопревращается?
В CVAVR ни чего нет эффективнее как
Код: Выделить всё
#define LED1 (PORTB.0)Код: Выделить всё
LED1 = 1;
LED1 = 0;Хотите asm глянуть во что вот это
Код: Выделить всё
if (!PIND.0) LED1 = 1; else LED1 = 0;Dimon456, вопрос не о том, как развести порты, а о том, как сделать "параллельно выполняемый" код, и чтоб эти параллельные ветви друг другу не мешали
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
"параллельно выполняемый" код возможен только в много поточных системах, как вариант DMA в stm32, даже windows у вас на компе не относится к "системе реального времени".
Остальное все - последовательно исполняемый код, как можно говорить о какой-то параллельности.
Вы просто завернули последовательность if else или switch case в красивую не понятную обертку.
Универсальности это не дает.
Остальное все - последовательно исполняемый код, как можно говорить о какой-то параллельности.
Вы просто завернули последовательность if else или switch case в красивую не понятную обертку.
Универсальности это не дает.
какие порты?Ivanoff-iv писал(а):как развести порты
- Сообщения: 1978
- Зарегистрирован: Ср июл 17, 2013 13:55:57
Dimon456, поэтому "параллельно выполняемый" видимо в кавычках и был. И DMA - это не "параллельно выполняемый". И параллельность и ОСРВ - совсем разные вещи. Что-то вы всё в кучу намешали.
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Псевдопараллельность. Те принципы которые применяются в диспетчерах, ртос. Дробление выполнения программных модулей на куски либо временными отрезками (вытеснение).
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
Если ваша псевдопараллельность уместится на 1 страничку, тогда давайте код в студию, обсудим.
у меня уместится
... код.... блин, код наверно только в понедельник.... 
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
"Dimon456". Мне не нравится ваша позиция. Одна страничка. Свой подход я обьяснял. Проект делится на логические модули. Если я распишу все в одной странице, я утону в этой странице. Если вам это не нравится, то не проецируйте этот одностраничный подход на мои сообщения. Это ваше личное предпочтение.
Вы одной вещи не понимаете. Главный модуль, пример которого я показал, он как раз уместился в страничку. И уместится, если ТС покажет полное ТЗ. Не суть. Готовь сани летом, телегу зимой. Приготовь свое рабочее пространство. И работай на одной страничке. Другие странички считайте ножовкой, болгаркой ну и так далее.
Вы одной вещи не понимаете. Главный модуль, пример которого я показал, он как раз уместился в страничку. И уместится, если ТС покажет полное ТЗ. Не суть. Готовь сани летом, телегу зимой. Приготовь свое рабочее пространство. И работай на одной страничке. Другие странички считайте ножовкой, болгаркой ну и так далее.


