Що спричиняє припинення роботи моєї світлодіодної програми мікроконтролера?


11

Отже, я ПОПОВНЕНИЙ і зовсім початківець у програмуванні. Я зробив деякі основні речі на Arduinos (буквально перемикаючи світлодіоди і щось показуючи на РК), і я намагаюся самостійно навчити себе програмувати в C. Я інженер-апаратник по торгівлі, але це турбує мене, що я не можу зробіть будь-яку сторону мікропрограмного забезпечення та програмного забезпечення, і немає вечірніх курсів, щоб викладати це, і я хотів би продовжити свої варіанти кар’єри. Я намагаюся зрозуміти, як деякі з цих команд поєднуються і виникли проблеми, які я просто не можу зрозуміти, чому це не працює.

Отже, у мене є вхід і вихід. Мій вихід перемикає ворота FET, який вмикає світлодіод. Вхід надходить з воріт І. Отже, мій світлодіод завжди вмикається, і коли я отримую вхідний сигнал із воріт AND (2 умови були виконані), я хочу, щоб вихід (тумблер світлодіода) йшов НИЗКО (вимкніть світлодіод. Оскільки вихід також підключений до один із входів AND, це також перетворить вхідний сигнал НИЗКО.

Що я хочу зробити: я просто хочу прочитати вхід як "умови, що виконуються" та вимкнути світлодіод. Потім він повинен вимкнутись на 1 секунду і знову увімкнути. Якщо вхід знову стає ВИСОКИМ, процес повторюється. Я використовую простий поштовх, щоб зробити перемикач, як інший вхід І-воріт, і виміряв, що вихід (MCU-вхід) стає високим при натисканні кнопки, але світлодіодне перемикання (вихід) не вимкнеться. Мій код (я думаю) досить чортово простий, але явно я щось неправильно не розумію, оскільки він просто не працює.

Отже, це код, який я використовую:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

І мені це здається логічним. У звичайному стані вихід є ВИСОКИМ. Якщо на вхід надходить сигнал із воріт І, світлодіод вимкнеться на 1 секунду, а потім знову увімкнеться.

Що це я зробив не так, як це виглядає як логічний спосіб зробити це, і я просто не можу зрозуміти, чому це не працює?

Якщо це допомагає, я використовую Nucleo F103RB. Коли я використовую код "блимати" і просто вмикаю світлодіод таким чином, він працює чудово, саме тоді, коли я додаю твердження "якщо", воно піде не так.

Це спрощена схема:

схематичний

імітувати цю схему - Схематично створено за допомогою CircuitLab

PS Я знаю, що я не додав їх у схему, але на воротах AND є резистори, що випадають, на входах та виходах.


Чи спрацьовує це, якщо ви вводите "виконані умови" безпосередньо в IN?
Транзистор

Це не. Я натиснув кнопку прямо на IN і досі не працював
Цікаво

1
Це гарна ідея позначити вхідні змінні як мінливі, або компілятор може зробити деякі дивні оптимізації, вважаючи, що він не змінюється за межами коду.
Дірк Брюер

3
@DirkBruere: Ви сподіваєтесь, що визначення DigitalInвже включає volatile.
MSalters

3
Лише натяк на наступний раз: Спробуйте утримувати кнопку під час увімкнення (або скидання) ЦП (або мікроконтролера). Тепер що відбувається?
CVn

Відповіді:


26

Я б подумав, що вам знадобиться цикл навколо коду -

while(1)
{

    if (ip == 1){
       op = 0;
       wait (1.0);
       op = 1;}
    else {
       op = 1;}
}

Перш ніж ви матимете шанс натиснути кнопку, яку ви будете завершені та випущені. Вам потрібно певний час, щоб оператор if повторно працював.


Що відрізняє моє? Я бачу "поки", але що це робить? Вибачте за всі питання, але я дійсно починаю з нульових знань!
Цікаво

1
@curious Перш ніж ви матимете можливість натиснути кнопку, яку ви кодуєте, буде закінчено і вийде. Вам потрібно певний час, щоб оператор if повторно працював. Це звичайно так, якщо не є щось інше щодо мікроконтролера, який ви програмуєте.
HandyHowie

9
"Чи можете ви пояснити, чому це спрацювало?" - цикл все повторюється, поки умова не вирішиться до нуля. Яка умова, ви можете запитати; це частина в круглих дужках після ключового слова "while", і як ви бачите, умова встановлюється на 1, тому вона ніколи не дорівнює нулю, і тому повторюється нескінченно. Без циклу "час" код виконується лише один раз, після чого програмне забезпечення припиняється, але з циклом "час" код виконується повторно, доки ви не вмикаєте обладнання.
Jurgy

14
Моя помилка, ймовірно, пов’язана з поїздкою в Ардуїно до mbed. В Arduino ви зазвичай вводите код своєї програми loop(), але рамка Arduino додає код, який приблизно так поводиться int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0

1
@Curious Ваші справді спрацювали. На жаль, він працював точно один раз, відразу, коли ви включили його. Пробігла, можливо, одна мікросекунда, і це було все. Якщо ви хочете, щоб він продовжував перевіряти вхід і встановлювати вихід, вам потрібно сказати, щоб він продовжував це робити. "while (some_condition)" працює так довго, як "true_condition" є істинним, що на мові C означає ненульовий. Тож "while (1)" продовжує перевіряти вхід назавжди або принаймні на той час, поки воно все одно працює.
Грем

21
#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
    // and now the program ends? What to do?
}

Процесор виконує інструкції послідовно . Він починається з переходу до main()коду ініціалізації бібліотеки mbed DigitalInі DigitalOut.
Потім виконує порівняння ip == 0, виконує інструкцію в межах, {}а потім main()закінчує ... більше не буде інструкцій ... Що це робить?

Він може скинутись через пошук незаконних операндів у порожній флеш-пам'яті. Або він може зависнути у виправнику несправностей і блимати SOS, як це роблять mbeds. Це залежить від того, як це реалізовано, і, ймовірно, зараз вийде за вас.
Але якщо вам цікаво, ви можете дослідити поводження з помилками ARM або дізнатися, звідки main()насправді викликано.

Тепер, як це виправити?

int main() {
    // Add a while(1) infinite loop
    while(1){
        if (ip == 1){
            op = 0;
            wait (1.0);
            op = 1;
        }else{
            op = 1;
        }
    }
    // Program never gets here
}

Дуже дякую за пояснення. Цикл while дозволив йому працювати. На жаль, я не можу дати тобі ще +1, оскільки моя репліка занадто низька, але я дуже вдячний у відповідь та пояснення
цікаво

Ага! Ця третя пропозиція щодо мого запитання дозволила мені проголосувати вашу відповідь! Ще раз дякую
Цікаво

1
@Curious Якщо ви хочете, щоб це було вам зрозуміліше, програміст, ви можете написати щось на зразок, while(1 == 1)а не просто while(1). Останній є ідіоматичним С, але перший є більш очевидним для людини, оскільки "завжди оцінюватиметься правдою". Будь-який гідний компілятор повинен створити однаковий двійковий код для обох варіантів.
CVn

2
@ MichaelKjörling Я б не погодився, що це більш очевидно для людини. Так само, як ваш мозок читає слова за формою, а не за характером, досвідченому програмісту ці ідіоми перекладають безпосередньо на поняття, а не інтерпретують те, що робить кожне окреме твердження. Відходячи від ідіоматичних конструкцій, ви змушуєте людей займатися вашим кодом нижчим рівнем, ніж це необхідно для розуміння; який над великою базою кодів додає до багато непотрібної розумової роботи.
Чуу

1
@Chuu "людиною [хто не досвідчений програміст]"
користувач253751

2

Як правильно зазначають інші, цикл дозволив би повторно запускати ваш код. Однак існує вбудований спосіб зробити це для Arduino без необхідності whileциклу. Це робиться loopфункцією - її застосовність до вашої проблеми залежить від того, чи використовуєте ви ID Arduino IDE.

Це має виглядати приблизно так:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

void setup() {
    // any code before loop is run
}

void loop() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

Ваша основна функція тепер прихована і додається до вашої програми лише при компіляції. Ось хороша дискусія з цього приводу: http://forum.arduino.cc/index.php?topic=379368.0


Так. Я спочатку робив справи на ардуїно, включаючи це, тому при переході на ядро ​​та IDE mbed я не міг зрозуміти, чому це не працює!
Цікаво

1
Ця відповідь спирається на використання системи Arduino. mbed - це інша система / набір бібліотек, а функції loop()та setup()функції Arduino не використовуються в більшості систем. Для довідки Ардуїно просто визначає main()щось подібне:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Камерон Таклінд

0

Якщо ви схожі на збірку, це може бути трохи більше у вашій зоні комфорту:

int main () {

//A label or function similar to assembly

label:

    if (ip == 1){

        op = 0;

        wait (1.0);

        op = 1;

    }else{

        op = 1;

    }

// Goto used same as "jmp" in assembly

goto label;

// Program never gets here

}


3
Будь ласка , не використовуйте goto будь-якою мовою, що знаходиться вище монтажу.
Jeroen3

Я зовсім не знайомий зі складанням, боюся!
Цікаво

Я знаю про це, але це про це!
Цікаво

@ Jeroen3 На питання, на яке ви посилаєтесь, відповідає "goto's доречно в декількох місцях", "З Goto немає нічого поганого, якщо воно використовується належним чином" і "Немає нічого поганого в тому, щоб goto в собі". Я погоджуюсь, що в мовах, що мають винятки, goto є зайвим, але особливо в C він має свої вживання.
glglgl

@glglgl: Як згадувалося Чуу, код повинен бути читабельним. goto** настійно ** пропонує «магія відбувається тут», можливо, за винятком goto cleanup;. У прикладі тут читачеві залишиться неприємне запитання "що таке особливе, що ви не використовувалиwhile(1) { } тут ???".
MSalters
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.