Прерывает arduino, прерывая последовательную связь

У меня проблемы со связью VB.Net-Arduino.

Кажется, прерывание приостановило мою последовательную линию связи в void loop() { ... }. Я не знаю, что делать, и я не могу стереть строку прерываний, так как я получил этот код с другого сайта, и он сказал, что прерывания играют важную роль в этом коде.

Итак, есть ли другой способ сохранить прерывания, например создать новую пустоту в коде? Не могли бы вы мне помочь, пожалуйста?

вот код:

//Для MEGA 2560

int i = 0;
int j = 0;
int k = 0;

int x = 0;
int y = 0;
int z = 0;

int OK = 0;
int OK1 = 0;
int OK2 = 0;
int OK3 = 0;
int OK4 = 0;

int sinPWM[] = {
    0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22,
    23, 24, 26, 27, 28, 29, 31, 32, 33, 34, 36, 37, 38, 39, 40, 42, 43,
    44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 64,
    65, 66, 67, 68, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 82, 83, 84,
    85, 86, 87, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102,
    104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117,
    118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131,
    132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
    145, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157,
    158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
    171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 179, 180, 181,
    182, 183, 184, 185, 185, 186, 187, 188, 189, 189, 190, 191, 192,
    193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202,
    203, 203, 204, 205, 205, 206, 207, 208, 208, 209, 210, 210, 211,
    212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 219, 219,
    220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226,
    227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
    233, 234, 234, 234, 235, 235, 236, 236, 237, 237, 237, 238, 238,
    238, 239, 239, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242,
    243, 243, 243, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246,
    246, 246, 246, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248,
    248, 248, 248, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
    249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
    249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
    248, 248, 248, 248, 248, 248, 248, 247, 247, 247, 247, 247, 247,
    246, 246, 246, 246, 246, 245, 245, 245, 245, 244, 244, 244, 244,
    243, 243, 243, 242, 242, 242, 241, 241, 241, 241, 240, 240, 240,
    239, 239, 238, 238, 238, 237, 237, 237, 236, 236, 235, 235, 234,
    234, 234, 233, 233, 232, 232, 231, 231, 230, 230, 229, 229, 228,
    228, 227, 227, 226, 226, 225, 225, 224, 224, 223, 223, 222, 221,
    221, 220, 220, 219, 219, 218, 217, 217, 216, 215, 215, 214, 214,
    213, 212, 212, 211, 210, 210, 209, 208, 208, 207, 206, 205, 205,
    204, 203, 203, 202, 201, 200, 200, 199, 198, 197, 197, 196, 195,
    194, 193, 193, 192, 191, 190, 189, 189, 188, 187, 186, 185, 185,
    184, 183, 182, 181, 180, 179, 179, 178, 177, 176, 175, 174, 173,
    172, 171, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161,
    160, 159, 158, 157, 156, 155, 154, 153, 152, 152, 151, 150, 149,
    148, 147, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135,
    134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 123, 122, 121,
    120, 119, 118, 117, 116, 115, 114, 112, 111, 110, 109, 108, 107,
    106, 105, 104, 102, 101, 100, 99, 98, 97, 96, 94, 93, 92, 91, 90,
    89, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 74, 73, 72, 71, 70,
    68, 67, 66, 65, 64, 62, 61, 60, 59, 58, 56, 55, 54, 53, 52, 50, 49,
    48, 47, 45, 44, 43, 42, 40, 39, 38, 37, 36, 34, 33, 32, 31, 29, 28,
    27, 26, 24, 23, 22, 21, 19, 18, 17, 16, 14, 13, 12, 11, 9, 8, 7, 6,
    4, 3, 2, 1, 0
};

#define toggle 7

int sw;
int nilaiVB;
int potvolt = A1;                // Пенгатур Теганган
int potfreq = A2;                // Частота Пенгатура

float potvoltval;
float potfreqval;
float DataVolt;
float DataFreq;
float A;
float F;

String inputString = "";         // строка для хранения входящих данных
boolean stringComplete = false;  // завершена ли строка
String In_1;
String In_2;

int Val1 = 0;
int Val2 = 0;

void setup() {
    Serial.begin(9600);
    inputString.reserve(200);

    pinMode(4, OUTPUT);
    pinMode(13, OUTPUT);
    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(5, OUTPUT);

    cli();                            // остановить прерывания
    TCCR0A = 0;                       //сбросить значение
    TCCR0B = 0;                       //сбросить значение
    TCNT0 = 0;                        //сбросить значение
    //0b : записать биты в двоичном формате
    TCCR0A = 0b10100001;              // фазовый правильный режим ШИМ
    TCCR0B = 0b00000001;              // нет прескалеров

    TCCR2A = 0;                       //сбросить значение
    TCCR2B = 0;                       //сбросить значение
    TCNT2 = 0;                        //сбросить значение
    //0b : записать биты в двоичном формате
    TCCR2A = 0b10100001;              // фазовый правильный режим ШИМ
    TCCR2B = 0b00000001;              // нет прескалеров

    TCCR3A = 0;                       //сбросить значение
    TCCR3B = 0;                       //сбросить значение
    TCNT3 = 0;                        //сбросить значение
    //0b : записать биты в двоичном формате
    TCCR3A = 0b10100001;              // фазовый правильный режим ШИМ
    TCCR3B = 0b00000001;              // нет прескалеров

    TCCR1A = 0;                       //сбросить значение
    TCCR1B = 0;                       //сбросить значение
    TCNT1 = 0;                        //сбросить значение
    OCR1A = 509;                      // сравнить значения соответствия
    TCCR1B = 0b00001001;  //Бит WGM12 равен 1 для режима CTC и без предделителя

    TIMSK1 |= (1 << OCIE1A);          // запускаем прерывания

    sei();                            // разрешаем прерывания
}

// прерывание начинается, когда таймер 1 соответствует OCR1A
ISR(TIMER1_COMPA_vect) {

    //=======================Фаза A============== ======== ===//

    if (i > 629 && OK == 0) {   // окончательное значение выборки для контакта 13
        i = 0;                  // начинаем с начального значения выборки
        OK = 1;                 // включить контакт 4
    }

    if (i > 629 && OK == 1) {   // окончательное значение выборки для контакта 4
        i = 0;                  // начинаем с начального значения выборки
        OK = 0;                 // включить контакт 13
    }

    x = round(A*sinPWM[i]); // значение x взято из выборки, а i имеет индекс 0
    i = i+F;                    // на следующую позицию выборки
    if (OK == 0) {
        OCR0B = 0;                      //контакты 4 0
        OCR0A = x; //pin 13 начинает чтение образца
    }

    if (OK == 1) {
        OCR0A = 0;                      // контакты 13 0
        OCR0B = x; // контакт 4 начинает чтение образца
    }

    // если значение i достигнет 209, то начнется вторая фаза
    if ((i >= 418) || OK1 == 1) {
        OK1 = 1;                  // поддерживать функцию if

        //=========================Фаза B==================== = =======//

        if (j > 629 && OK2 == 0) {  // окончательное значение выборки для контакта 10
            j = 0;                  // начинаем с начального значения выборки
            OK2 = 1;                // включить контакт 9
        }

        if (j > 629 && OK2 == 1) {  // окончательное значение выборки для контакта 9
            j = 0;                  //начнем с начального значения выборки
            OK2 = 0;                // включить контакт 10
        }

        y = round(A*sinPWM[j]); // значение y взято из выборки, а i имеет индекс 0
        j = j+F;                    // на следующую позицию выборки
        if (OK2 == 0) {
            OCR2B = 0;              // контакты 9 0
            OCR2A = y;              // контакт 10 начинает чтение образца
        }

        if (OK2 == 1) {
            OCR2A = 0;              // контакты 10 0
            OCR2B = y;              // контакт 9 начинает чтение образца
        }
    }

    // если значение j достигнет 209, то начнется третья фаза
    if ((j>= 418) || OK3 == 1) {
        OK3 = 1;                    // сохраняем функцию if

        //=======================Фаза C============== =======/ /

        if (k > 629 && OK4 == 0) {  // окончательное значение выборки для контакта 5
            k = 0;                  // начинаем с начального значения выборки
            OK4 = 1;                // включить контакт 2
        }

        if (k > 629 && OK4 == 1) {  // окончательное значение выборки для вывода 2
            k = 0;                  // начинаем с начального значения выборки
            OK4 = 0;                // включить контакт 5
        }

        z = round(A*sinPWM[k]); // значение z взято из выборки, а i имеет индекс 0
        k = k+F;                    // на следующую позицию выборки
        if (OK4 == 0) {
            OCR3B = 0;              // контакты 2 0
            OCR3A = z;              // контакт 5 начинает чтение образца
        }

        if (OK4 == 1) {
            OCR3A = 0;              // контакт 5 0
            OCR3B = z;              // штифт 2 memulai pembacaan образец
        }
    }
}

void loop() {
    sw = digitalRead(toggle);

    if (sw == 0) { // ВБ
        if (stringComplete) {
            if (inputString.substring(0, 4) == "VOLT") {
                In_1 = inputString.substring(4);
                Val1 = In_1.toInt();
                A = Val1/1023; // Формула Пенгонтролана Тегангана
                Serial.println(Val1);
            }
            if (inputString.substring(0, 4) == "FREQ") {
                In_2 = inputString.substring(4);
                Val2 = In_2.toInt();
                F = map(Val2, 1023, 0, 0, 50);//Формула управления частотой
            }

            inputString = "";
            stringComplete = false;
        }
    }
    else if (sw == 1) { // Потенциометр
        potvoltval = analogRead(potvolt);
        A = potvoltval/1023; // Формула управления напряжением

        potfreqval = analogRead(potfreq);
        F = map(potfreqval, 1023, 0, 0, 50);//Формула управления частотой
    }
}

void serialEvent() {
    while (Serial.available()) {
        // получаем новый байт:
        char inChar = (char) Serial.read();
        // добавляем его в inputString:
        inputString += inChar;
        // если входящий символ является новой строкой, установите флаг, чтобы
        // основной цикл может что-то с этим сделать:
        if (inChar == '\n') {
            stringComplete = true;
        }
    }
}

А вот положение прерываний: Прерывания

Я получил код с этого сайта.

А вот и мой код VB

Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Try
        Me.CenterToParent()
        SerialPort1.PortName = "COM4"
        SerialPort1.BaudRate = 9600
        SerialPort1.Open()
        Timer1.Start()
        SerialPort1.Write("VOLT" & TrackBar1.Value & Chr(10))
        SerialPort1.Write("FREQ" & TrackBar2.Value & Chr(10))
    Catch ex As Exception
        MsgBox(ex.Message, MessageBoxIcon.Error, "Error Message")
        Me.Close()
    End Try
End Sub

Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
    SerialPort1.Close()
End Sub

Private Sub TrackBar1_Scroll(sender As Object, e As EventArgs) Handles TrackBar1.Scroll
    Try
        SerialPort1.Write("VOLT" & TrackBar1.Value & Chr(10))
    Catch ex As Exception
        MsgBox(ex.Message, MessageBoxIcon.Error, "Error Message")
    End Try
End Sub

Private Sub TrackBar2_Scroll(sender As Object, e As EventArgs) Handles TrackBar2.Scroll
    Try
        SerialPort1.Write("FREQ" & TrackBar2.Value & Chr(10))
    Catch ex As Exception
        MsgBox(ex.Message, MessageBoxIcon.Error, "Error Message")
    End Try
End Sub
End Class

И дизайн тожеDesign

, 👍0

Обсуждение

Вы неправильно диагностировали проблему. Эти вызовы cli() и sei() безвредны. Пожалуйста, объясните, в чем ваша настоящая проблема., @Edgar Bonet

cli() и sei() используются только при установке, они не являются проблемой. Возможно, ваш ISR таймера занимает слишком много времени. Вы можете сделать его короче, выполняя больше действий в цикле. Но, пожалуйста, опишите далее, какое нежелательное поведение вы видите с этим кодом., @chrisl

прерывание выполняется каждые 509 тактовых импульсов (без предделителя), а обработчик длинный. нет времени ни на что другое, @Juraj

Разработчики сказали: «Чтобы убедиться, что с прерываниями нет проблем, мы будем использовать cli() (остановить прерывания) и sei() (разрешить прерывания). Пожалуйста, убедитесь, что прерывания по таймеру работают! Как работает ШИМ! Попробуйте отключить простой светодиод или что-то еще, чтобы диагностировать вашу проблему., @abu-ahmed al-khatiri

Что вы хотите, чтобы ваша программа делала в целом. Чего вы пытаетесь достичь? Тогда расскажи нам, какие проблемы ты видишь? Что он делает неправильно?, @sa_leinad

@EdgarBonet .. Я работаю над инвертором VFD, управляемым VB.Net. Таким образом, выходным напряжением и частотой можно управлять с помощью VB.Net. Теперь проблема в том, что я не могу контролировать вывод, и я предполагаю, что что-то не так с моим прерыванием. Ну, люди здесь сказали мне, что ISR слишком длинный, я думаю, что это тоже правильно. Теперь я не знаю, что делать с сокращением ISR., @Fitrah Hidayat

@chrisl.. Когда я спросил кого-то еще, он также упомянул, что ISR слишком длинный. Есть ли у вас какие-либо советы, чтобы сделать ISR короче? Что касается нежелательного поведения, когда я запускаю VB.Net и прокручиваю панель управления напряжением, с выводом моего проекта ничего не происходит. Я ожидаю, что выходное напряжение может варьироваться с помощью трекбара в VB.Net. Но когда я использую потенциометр, он работает., @Fitrah Hidayat

@Juraj .. Не могли бы вы сказать мне, что мне тогда делать, пожалуйста?, @Fitrah Hidayat

@sa_leinad.. Как вы можете видеть в моих комментариях, я намерен контролировать напряжение и частоту через VB.Net. Проблема в том, что я не могу отправить данные из VB в Arduino. Я действительно не знаю, что случилось. Но я предполагаю, что это связано с прерыванием или ISR. Есть ли у вас какие-либо советы по поводу кода?, @Fitrah Hidayat

Откуда вы знаете значение OCR1A = 509, и вы даете i > 629? Но вместо этого ваша ссылка основана на «OCR1A = 509» и значении переменной «i <313». Для примера, где таймер 0 предназначен для прерывания, я использовал ту же формулу OCR1A=(fclk/fOC1A*N)-1, где вместо OCR1A появляется OCR0A., @abu-ahmed al-khatiri

Чтобы увидеть, связано ли это с прерываниями, вы можете обернуть цикл while (Serial.available()) в serialEvent() в разделе ATOMIC_BLOCK. Чтобы сократить ISR, просто установите flag, а затем в loop(): if(flag) // вызовите ISR как функцию и очистите флаг. Еще кое-что: переменные, используемые в ISR **и** вашей программе (например, F), должны быть объявлены volatile'. Вы должны отфильтровать аналоговый выход аппаратно, так как analogWrite()` создает не аналоговое напряжение, а ШИМ., @Sim Son

@ abu-ahmedal-khatiri, 629 - это конечная переменная векторной таблицы, поскольку автор сказал, что таблица генерирует только 50 Гц, я удвоил ее. По моей логике, если 50 Гц состоит из 314 переменных, я думал, что для 100 Гц требуется 629 переменных., @Fitrah Hidayat

@SimSon.. Спасибо за совет. И не могли бы вы рассказать мне простой код о том, как установить флаг? Я не могу найти ни одного примера об этом., @Fitrah Hidayat

@SimSon .. я нашел кое-что о флаге в этой [ссылке](https://www.baldengineer.com/flag-variables-are-not-evil-for-microcontrollers.html). Но я не уверен, как поместить это в мой код. Не могли бы вы сказать mw, что делать в первую очередь ??, @Fitrah Hidayat


1 ответ


Лучший ответ:

0

Поскольку кажется, что ваша основная проблема заключается в слишком длинном ISR, я рассмотрю возможность установки флага в ISR. См. этот пример кода (который не является полным компилируемым примером, только код, демонстрирующий принцип):

volatile byte flag = 0;

ISR(TIMER1_COMPA_vect) {
    flag = 1;
}

void loop(){
    if(flag){
        flag = 0; // сброс флага для следующего выполнения
        // здесь выполняем код, который ранее был в ISR
    }
}

Сначала переменная флага объявляется как volatile. Это сообщает компилятору, что значение этой переменной может измениться в любое время и что компилятор не может оптимизировать ее с помощью кэшированного значения или других оптимизаций. Это требуется всегда, когда вы обращаетесь к переменной как в ISR, так и в обычном коде.

В реальном ISR этот флаг просто установлен в 1. Это занимает очень короткое время, так что никакое другое прерывание (например, для Serial) не будет заблокировано им.

Затем в нашем void loop() мы проверяем, имеет ли флаг значение, отличное от нуля (каждое значение, отличное от нуля, будет оцениваться как true, поэтому нам не нужен оператор сравнения здесь). Если да, мы сначала сбрасываем флаг в ноль, чтобы другое прерывание могло снова установить его в 1. Затем мы выполняем другой код, который ранее был в вашем ISR. Поскольку теперь он работает в обычном коде, он не будет блокировать последовательные прерывания.


"ISR слишком длинный" также может означать, что это происходит слишком часто. Юрай уже заявил в своем комментарии, что прерывание происходит «каждые 509 тактов». Это не очень много. Вы можете увеличить время между двумя последовательными прерываниями таймера, используя предварительный делитель. Поскольку выполнение только этого уменьшит частоту вашей выходной синусоидальной волны, вам нужно будет выполнить некоторые вычисления, возможно, только используя каждый четвертый или около того элемент массива синусоидальной волны. При этом вы теряете точность во времени, но получаете больше вычислительного времени для других задач.


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

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

,

Спасибо за Ваш ответ. Я обязательно попробую это., @Fitrah Hidayat