Почему этот конечный автомат не поддерживает свое состояние?

Привет, StackOverflow!

В следующем коде у меня есть простой конечный автомат, который изменяет работу некоторого внешнего устройства освещения (как следует из комментариев). Состояние изменяется нажатием кнопки, подключенной к GP1. Схема, подключенная к GP1, является схемой подавления дребезга компаратора, которая сравнивает VDD с 0,6VDD (я также пробовал схему триггера RC/диода/Шмитта), которая затем вызывает сигнал LO. На прицеле мы видим чистую прямоугольную волну при быстром нажатии на кнопку.

Текущее (и нежелательное) поведение PIC10F200 выглядит следующим образом:

  1. Переключатель нажат (состояние = 0)
  2. Приращения переменной конечного автомата (состояние = 1)
  3. Освещение переходит в корпус 1 и включается
  4. Освещение остается включенным не менее секунды
  5. Освещение выключается
  6. Система остается в этом состоянии до тех пор, пока кнопка не будет снова нажата или питание не будет выключено.

Вопрос: почему это так? И как, если возможно, исправить это так, чтобы одно нажатие кнопки равнялось одному приращению состояния, которое PIC затем поддерживает до тех пор, пока как система запитана и кнопка снова не нажимается?

#define SYS_FREQ        8000000L
#define FCY             SYS_FREQ/4
#define _XTAL_FREQ      4000000

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/


/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/

__CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC);

void main(void)
{
    TRIS = 0b111110;

    unsigned char state = 0;

    while(1)
    {
        switch (state)
        {
            case 0: // IDLE/OFF
                if (GPIObits.GP0) GPIObits.GP0 = 0;
                break;
            case 1: // ON
                if (!GPIObits.GP0) GPIObits.GP0 = 1;
                break;
            case 2: // BLINK (slow)
                GPIObits.GP0 = !GPIObits.GP0;
                __delay_ms(100);
                break;
            case 3: // BLINK (fast)
                GPIObits.GP0 = !GPIObits.GP0;
                __delay_ms(50);
                break;
            case 4: // BEAT DETECT
                GPIObits.GP0 = GPIObits.GP2;
                break;
            default:
                state = 0;
                break;
        }

        if (!GPIObits.GP1)
        {
            __delay_ms(250);
            state++;
        }
    }
}

ОБНОВЛЕНИЕ: так как есть небольшая путаница в отношении того, что я пытаюсь сделать с помощью этого кода/системы, давайте предоставим полный контекст. Этот микроконтроллер, PIC10F200, является частью общей конструкции платы для электролюминесцентного (EL) драйвера проводов. Микроконтроллер просто контролирует, включена ли схема драйвера, подключая GP0 к порту EN микросхемы драйвера. Система имеет четыре режима работы, провод горит постоянно, провод мигает, провод мигает быстрее, и провод мигает при обнаружении низкочастотного биения (другая цепь в системе ). Переход из этих режимов работы управляется кнопочным переключателем (кратковременно включенным), который должен быть установлен на печатной плате. Это требует, чтобы state в приведенном выше коде оставался стабильным между нажатиями кнопки. В настоящее время он этого не делает и ведет себя так, как описано в исходной части этого поста. Как указано в заголовке вопроса, почему state в настоящее время не работает стабильно и как мне это сделать?

ОБНОВЛЕНИЕ (08.03.2014): решение

Необходимо установить следующие настройки, предполагая, что GP0 — это выход, GP2 — ваш T0CKI, и у вас есть переключатель, который переводит сигнал в состояние LO при срабатывании.

TRIS = 0b111110;
OPTION = 0b11101111;

Вопрос о том, действительно ли имеют значение биты 0-3 для OPTION, зависит от того, решите ли вы использовать модуль WDT.

Кроме того, реализация обнаружения отпускания кнопки представляет собой простой механизм счетчика, который сбрасывается, когда GP2 становится LO в любой момент во время счета.

if (TMR0 > 0)
{
    while (count < 20)
    {
        if (!GPIObits.GP2) count = 0;
        __delay_ms(10);
        count++;
    }
    TMR0 = 0;
    state++;
}

person James Lui    schedule 05.03.2014    source источник
comment
Итак, gp1 — это кнопка, gp0 — светодиод, а gp2 — что? И как работает кнопка? Один щелчок (нажмите и отпустите) дает 1, а другой 0?   -  person γηράσκω δ' αεί πο    schedule 05.03.2014
comment
Да, GP1 подключен к кнопке, GP0 — к EN-порту драйвера светодиода/электропровода (в конечном итоге), GP2 — это вход схемы обнаружения низких частот (басы от... громкой музыки), который пока не подключен, т.к. Я даже не могу заставить конечный автомат работать должным образом. Кнопка мгновенного включения, подобная самой простой, которую вы найдете в большинстве дешевых электронных устройств. Поэтому, когда он нажат, контакты замыкаются, и VDD подключается к схеме компаратора (операционный усилитель LM324N).   -  person James Lui    schedule 05.03.2014
comment
почему вы пытаетесь сделать это с состояниями. То, чего вы пытаетесь достичь, легко. Вам не нужно усложнять код.   -  person γηράσκω δ' αεί πο    schedule 05.03.2014
comment
С помощью state я пытаюсь просто переключаться между режимами работы устройства, которые помечены в коде. С моим нынешним знанием PIC, как работает XC8 и C, это самый простой способ, который я мог придумать для выполнения этой задачи. Я полностью готов попробовать разные подходы, за исключением любого решения на ассемблере, потому что изменение языка не только не решает проблему, но и усложняет реализацию и поддержку.   -  person James Lui    schedule 05.03.2014
comment
То, что вы описываете, является одним состоянием. При нажатии кнопки. В будущем вы можете добавить что-то еще, но сейчас это одно состояние. if (!GPIObits.GP1){GPIObits.GP0 = 1; __delay_ms(1000); GPIObits.GP0 = 0;}   -  person γηράσκω δ' αεί πο    schedule 05.03.2014
comment
То, что я описал в вопросе и в комментариях, - это то, как система ведет себя в настоящее время. Моя проблема в том, что это нежелательно. Система должна вести себя так, как указано в коде: ПУСК -> холостой ход -> срабатывание выключателя -> ВКЛ -> выключатель -> более медленное мигание -> выключатель -> более быстрое мигание -> выключатель -> схема обнаружения низких частот (GP2) -> выключатель -> ПРАЗДНЫЙ. Я назвал эту последовательность событий в контексте всей системы простым конечным автоматом для простоты. Я знаю, что это не самое сложное использование конечного автомата, но именно оно представляет систему, которую я пытаюсь реализовать. построить.   -  person James Lui    schedule 06.03.2014


Ответы (3)


У вас проблема с аппаратным/программным обеспечением!

  1. Когда ваша программа находится в цикле задержки, ваша ключевая кнопка не проверяется!
  2. Вы проверяете только событие нажатия клавиши, но вы также должны отпустить клавишу.

Моя цель состоит в том, чтобы вы могли использовать контакт GP2 (T0CKI) вместо GP1 для ключа. Этот вывод имеет вход триггера Шмитта, если он используется как вход счетчика TMR0. После этого настройте MCPU TMR0 как счетчик с внешними часами на выводе GP2 (T0CKI). Вы также должны установить бит T0SE, чтобы настроить счетчик, который будет увеличиваться при переходе от высокого уровня к низкому на выводе T0CKI. В программе после любого цикла проверьте содержимое TMR0, если клавиша была нажата больше 0. Подождите несколько мс и проверьте, был ли освобожден ключ, если он был освобожден, чем увеличьте переменную state и очистите содержимое TMR0.

person GJ.    schedule 06.03.2014
comment
Вы совершенно правы в своем первом пункте (+1). Мой код заботится только о втором. Если у светодиода большой интервал, то у вас проблема с магором. Ваше решение интересное, но ортодоксальное. Способ, которым вы решаете такого рода проблемы, заключается в использовании таймера. Проверьте таймер (случай 2 и 3 без задержек), если время истекло, затем светодиод (включится или выключится) и сбросьте таймер. - person γηράσκω δ' αεί πο; 06.03.2014
comment
Спасибо! На самом деле я говорю о таймере TMR0, сконфигурированном как счетчик, запускаемый через контакт GP2 (T0CKI), поэтому вы должны нажать кнопку 256 раз, чтобы счетчик обнулился. Но возможен и ваш способ! - person GJ.; 06.03.2014
comment
@GJ: Итак, OPTION = 0b11111111; прямо сейчас, согласно документации, T0CS правильно для использования GP2/T0CKI, T0SE подвергается операции XOR с GP2 для получения ввода в MUX. Таким образом, для перехода HI -> LO целесообразно, чтобы T0SE равнялось 1, а GP2 нажимало HI для подачи на MUX LO. Уместны ли здесь настройки прескалера? - person James Lui; 06.03.2014
comment
@James Lui: Вы также можете включить блок праскейлера, если очистите бит PSA в регистре option, но в этом нет необходимости! Используйте pracaler, назначенный WDT, в этом случае вы можете использовать WDT для более длительных интервалов времени, когда вы ожидаете в цикле задержки. - person GJ.; 06.03.2014
comment
Оооо, мы уже очень близко. Я установил OPTION = 0b1110111;, который, кажется, производит стабильные изменения состояния, однако, если я слишком сильно нажимаю кнопку, программа зависает. Поскольку это простая программа, есть две возможности. 1) Он зависает внутри части кода, который я использую для проверки того, что GP2 является HI последовательно, прежде чем сбрасывать TMR0 и увеличивать состояние. или 2) я непреднамеренно остановил переходы между состояниями, и программа застряла на IDLE, что маловероятно. @GJ и @valter: наша диалектика здесь и оба ваших предложения в совокупности привели нас сюда, спасибо! - person James Lui; 08.03.2014

двигай

if (!GPIObits.GP1){
    if(isPressed == false){
        //__delay_ms(250); //you dont need the delay
        state++;
        if(state == 5){state = 0;}
        isPressed = true;
    }
}
else{isPressed = false;}

перед оператором switch. char isPressed = false; перед циклом while

Вальтер

person γηράσκω δ' αεί πο    schedule 05.03.2014
comment
Нет необходимости использовать дополнительную переменную isPressed, мое решение достаточно хорошее, и если state больше 4, то предложение по умолчанию должно установить его равным 0. - person GJ.; 06.03.2014
comment
@GJ. должен установить его на 0 и если кнопка нажата, он сделает его равным единице. Таким образом, вы теряете нулевое состояние. Другое дело, что в микроконтроллерах вы не используете задержки в 250 мс, чтобы проверить, нажата ли кнопка. У вас есть schmitt trigger, чтобы позаботиться об этом. - person γηράσκω δ' αεί πο; 06.03.2014
comment
Нет, вы не потеряете состояние 0. Когда переменная state увеличивается до 5, тогда предложение по умолчанию должно установить ее в 0, а после этого следующий цикл должен установить GP0 в 0 и выключить светодиод. - person GJ.; 06.03.2014
comment
@GJ. Вы не поняли мою мысль. Допустим, кнопка нажата (GPIObits.GP1 = 0) и state = 5. Переключатель переходит в значение по умолчанию и устанавливает state = 0, а затем if statement становится true и увеличивает состояние до 1. Следующая итерация не перейдет к 0, а к 1. Также это не |, а ||. - person γηράσκω δ' αεί πο; 06.03.2014
comment
Нет необходимости переходить к 0, потому что это должно отключить GP0 и светодиод, но следующий цикл снова установит его в 1. Спасибо за неправильный или oparator! - person GJ.; 06.03.2014
comment
@GJ. Вы упускаете суть. Дело в том, что у вашего кода есть проблема в этом конкретном сценарии, а не в том случае, если эта проблема не видна. Если позже он решит вставить задержку в нулевое состояние, что произойдет? В любом случае, если вы читаете его последний комментарий (в исходном сообщении), он хочет менять состояния каждый раз, когда нажимается кнопка, а ваш код этого не делает. - person γηράσκω δ' αεί πο; 06.03.2014
comment
@valter: Однако ваше решение более или менее то, что уже есть в коде, поскольку в любом случае предложение по умолчанию с set state возвращается к 0. Я пробовал это решение раньше, чтобы зафиксировать нажатое состояние и попытаться удерживать его так, чтобы система не считала, что кнопка была нажата, но система по-прежнему ведет себя так, как я описал в ОП. @GJ: я не пытаюсь прокрутить все состояния одновременно, я хочу перейти в состояние = 1, оставаться там, пока я снова не нажму переключатель, в вашем коде state != 0 в основном будет верно для каждого состояния, кроме 0, что означает ни одно государство никогда не бывает стабильным. - person James Lui; 06.03.2014
comment
Можете ли вы еще раз описать свой алгоритм, но с более подробной информацией в основном посте? - person GJ.; 06.03.2014
comment
@JamesLui Нет. Код, который я разместил, имеет два основных отличия: 1. что произойдет, если GPIObits.GP1 останется равным 0 дольше 250 мс? Это изменит состояние, которое является ложным флагом (я исправил его) 2. То, что я говорил с gj (я поместил оператор if перед оператором switch). Если вы все еще считаете, что мой код такой же, как ваш, не стесняйтесь и используйте свой. - person γηράσκω δ' αεί πο; 06.03.2014
comment
@valter: я не пытаюсь вам противоречить, я просто говорю, что я пробовал ваш код, который я написал раньше, когда я обдумывал идеи для решения этой проблемы. А теперь я дословно копирую ваш код и помещаю его туда, куда вы мне сказали, над оператором switch, и в результате поведение системы остается таким же. Следовательно, нам нужно альтернативное решение. - person James Lui; 06.03.2014
comment
@JamesLui Код работает как надо. Проблема в вашей схеме подключения кнопки к gp1. Это не обеспечивает чистую паузу. Вот почему вы должны использовать schmitt trigger. Я делал это миллион раз - person γηράσκω δ' αεί πο; 06.03.2014

__delay_ms(250); <-- too small delay

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

Обновить

Вы должны запускать PIC с отключенным WDT (сторожевым таймером), иначе он сбросит изображение через несколько секунд. Это похоже на ваше наблюдение. Вы можете мигать светодиодом в начале основной функции, чтобы проверить, произошло ли это, или вы можете инициализировать unsigned char state = 1; и затем посмотреть поведение.

Попробуйте это __CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC & WDT_OFF);

person rmi    schedule 05.03.2014
comment
Я пробовал это раньше, система все равно ведет себя так же, даже если я установил что-то сколь угодно большое, например... 10000 мс, все так же, он загорается, это длится секунду, а затем выключается и остается туда... - person James Lui; 05.03.2014
comment
Я подозреваю, что изображение сбрасывается, когда оно загорается. Как вы включаете свет. Свет потребляет много энергии или вызывает какие-либо сбои или помехи, или есть ли какие-либо реле? Вы используете хороший блок питания для рис. - person rmi; 05.03.2014
comment
Что ж, для тестирования я использую светодиод... который должен потреблять очень... очень... небольшой ток. Схема, которую в конечном итоге активирует выход, будет потреблять еще меньше. Блок питания в основном USB (5 В, 500 мА). - person James Lui; 05.03.2014
comment
Вы подключили подтягивающий резистор для GP1, чтобы он не плавал? Попробуйте напрямую подключить кнопку к GP1, минуя схему подавления дребезга компаратора. Здесь не требуется устранение дребезга, так как вы используете задержку 250 мс. - person rmi; 05.03.2014
comment
Я предполагаю, что ваш выход компаратора активен на низком уровне. Вы проверили это? - person rmi; 05.03.2014
comment
PIC10F200 - это PIC самого низкого уровня, доступный от Microchip, у него нет модуля компаратора (который на самом деле был бы полезен для устранения дребезга =()... Если вы имеете в виду аналоговый компаратор, который я построил вне PIC, да , когда V+ > V-, Vout падает до 0, что указывает на то, что кнопка нажата... но я проверяю !GPIObits.GP1, так что это не должно быть проблемой... - person James Lui; 05.03.2014
comment
Что ж, схема устранения дребезга была задумана только потому, что вход от кнопки был шумным до такой степени, что 250 мс на самом деле было недостаточно для задержки, однако подключение кнопки напрямую ничего не меняет в поведении системы, спасибо за все эти предложения. кстати, я не пробовал их, я уверен, что это просто какая-то случайная деталь о том, как работает PIC10F, которую я не понимаю... - person James Lui; 05.03.2014
comment
Для LM324, когда V+ > V-, Vout переходит на VDD. Ваш конечный автомат ожидает LOW, поэтому используется !GP1. - person rmi; 05.03.2014
comment
Вы уверены, что GP1 становится НИЗКИМ при нажатии кнопки? - person rmi; 05.03.2014
comment
Да, определенно работает на прицеле, со светодиодом (от включения до выключения) и четко через GP1 по мере изменения состояния, просто проблема в том, что происходит потом. - person James Lui; 05.03.2014
comment
1. Отключен ли сторожевой таймер? 2. Держите осциллограф подключенным к GP1, чтобы увидеть, не возникнут ли какие-либо сбои при возникновении неисправности. - person rmi; 05.03.2014
comment
Сторожевой таймер, я не знаю, компилятор не распознает макрос WDT_OFF в функции __CONFIG(). Что, мягко говоря, беспокоит, есть ли регистр CONFIG, который я мог бы установить напрямую? - person James Lui; 06.03.2014
comment
После небольшого поиска в Google макрос WDT_OFF теперь WDTE_OFF соответствует имени регистра в документации. - person James Lui; 06.03.2014
comment
Это не так, в настоящее время я изучаю решение GJ TMR0, чтобы увидеть, может ли оно решить проблему нестабильности ввода с кнопки. До сих пор я даже не смог заставить кнопку загореться... - person James Lui; 07.03.2014
comment
Вы уверены, что изображение не сбрасывается каким-либо образом? Я бы хотел, чтобы вы моргали светодиодом, когда начинается рис. Если он время от времени сбрасывается, поведение несколько объяснимо. - person rmi; 07.03.2014
comment
Вы правильно вытащили штифт MCLR? - person rmi; 07.03.2014
comment
В настоящее время к плате прикреплен программатор, который в документации предусматривает подтягивание вывода MCLR, что и было сделано. Я протестировал случай сброса, переписав код для постоянного включения светодиода и еще один сценарий, в котором светодиод напрямую связан со входом. PIC никогда не сбрасывался ни в одном из этих сценариев, также я подключил область ко всем контактам, чтобы отслеживать состояние устройства. Никогда не видел, чтобы линия MCLR менялась, кроме случаев, когда это утверждал программист. - person James Lui; 07.03.2014
comment
Теперь проблема сужается: область не может увидеть изменение GP1, но программа обнаруживает, что GP1 становится низким! Как насчет использования другого чипа pic. - person rmi; 07.03.2014
comment
Это мой третий чип. У меня есть тюбик из 10... Но теперь вы можете видеть мое недовольство этой проблемой, верно? Я буквально понятия не имею, почему PIC ведет себя так, как он есть, и нет никакой документации любого рода от тех, кто сталкивался с подобными проблемами. Так что либо никто никогда не пытался использовать PIC10F200 для этой цели, либо никто никогда не сталкивался с этой проблемой, либо я делаю что-то действительно очень неправильно. Я надеюсь, что это последний, потому что тогда есть хотя бы надежда на решение. Я обновлю эту тему, когда попробую последнее предложенное решение GJ. - person James Lui; 07.03.2014