Практика. Мигание светодиодом с заданной частотой.

Давайте возьмем за основу примеры Blink и DigitalReadBtnSerial из библиотеки VBCoreG4, их можно найти в File->Examples->VBCoreG4_arduino_system, и напишем свою программу, которая после загрузки которой, на плате будет мигать светодиод на определенной частоте. По нажатию на кнопку мигание прекращается, а частота мигание задается через Serial порт.

Для начала подключим библиотеку и определим нужные нам пины. На схеме платы можно увидеть, что светодиод соединен с выводом PA5, а пользовательская кнопка - с PC13. В библиотеке они уже определены как LED2 и USR_BTN, но если мы об этом не помним, можно определить еще раз или присвоить выводам PA5 и PC13 любые другие имена. Делается это с помощью #define.

#include <VBCoreG4_arduino_system.h>

#define LED2 PA5
#define USR_BTN PC13

Далее нам понадобятся несколько переменных - частота мигания светодиода, которую мы будем задавать через Serial порт. Пусть по умолчанию она равна 1 Гц. Нужна переменная, которая покажет выключен ли режим мигания светодиодом - если выключен, то светодиодом не мигаем, переменная, в которую будет записано текущее состояние кнопки и переменная, в которую будет записано предыдущее состояние кнопки. И последнее, что нам понадобится в программе - это таймер, который будет задавать прерывания с заданной частотой.

double freq = 1; //частота в Гц
int is_off = LOW; // переменная, определяющая выключен ли режим мигания
int prev_btnSt; // предыдущее состояние кнопки
int buttonState; // текущее состояние кнопки
HardwareTimer *timer = new HardwareTimer(TIM3); // таймер

В функции setup() устанавливаем пины PA5 и PC13 в режимы OUTPUT и INPUT_PULLUP, определяем переменную prev_btnSt, настраиваем таймер, по умолчанию светодиод мигает один раз в секунду.

Подробнее о том, как работать с таймерами и прерываниями можно почитать здесь.

void setup() {
  Serial.begin(115200);
  pinMode(USR_BTN, INPUT_PULLUP);
  pinMode(LED2, OUTPUT);
  prev_btnSt = digitalRead(USR_BTN);

  timer->pause();
  timer->setOverflow(1, HERTZ_FORMAT); // задаем частоту прерывания
  timer->attachInterrupt(blink); //функция мигания светодиодом, вызывается с указанной частатой
  timer->refresh();
  timer->resume();
}

В основном цикле мы проверяем нажата ли кнопка, а также, если пользователь в Serial порт отправил число, мы задаем новую частоту. Обратите внимание, что частота мигания светодиода задается в Гц. Если она больше либо равна 1, мы можем использовать HERTZ_FORMAT, как второй параметр метода setOverflow. Если же требуемая частота меньше 1, то в качестве второго параметра задается формат MICROSEC_FORMAT. Предварительно на значение частоты нужно разделить 1000000*

*В 1 секунде 1000000 микросекунд. Чтобы задать частоту в 1 Гц - светодиод загорается раз в секунду, время цикла должно быть равно 1000000 микросекунд. Если мы хотим получить частоту в 0,5 Гц, то есть светодиод загорается 1 раз в 2 секунды, время цикла между загораниями увеличивается в два раза и равно 2 секунды = 2000000 микросекунд = 1000000/0,5. Если хотим частоту 1 Гц уменьшить в 4 раза до 0,25 Гц, то соответственно время между циклами с 1 секунды увеличивается в 4 раза до 4 секунд = 4000000 микросекунд = 1000000/0,25.

void loop() { 
  buttonState = digitalRead(USR_BTN); //читаем состояние кнопки
  if(buttonState == LOW && prev_btnSt == HIGH){ //если в предыдущем цикле она 
                                                //не была нажата, а сейчас на нее нажали
    is_off = !is_off;                          //режим мигания лампочки меняем на противоположный.
                                              //если светодиод мигал, то отключаем мигание, 
                                              //если нет - то, наоборот, включаем
    prev_btnSt = buttonState;              //предыдущему состоянию кнопки даем текущее значение
  }
  if(buttonState == HIGH) {prev_btnSt = buttonState;}//предыдущему состоянию кнопки даем текущее значение
  if (Serial.available() > 0) { // если в порте появились какие-то данные
    freq = Serial.readString().toDouble(); // считываем частоту, преобразуем в тип double
    if(freq>=1){timer->setOverflow(freq, HERTZ_FORMAT);} //если частота >= 1, то используем HERTZ_FORMAT
    else if (freq> 0 && freq<1){timer->setOverflow(1000000/freq, MICROSEC_FORMAT);} // иначе - MICROSEC_FORMAT
    else {Serial.println("incorrect value for frequency");} //в случае если частота задана в неверном формате, <=0
    timer->refresh(); //обнуляем таймер
    timer->resume(); //запускаем таймер
  }
}

И, самое последнее, что осталось - это написать функцию мигания светодиодом, которая будет вызываться с установленной частотой.

void blink(){
  if(is_off == LOW){ //если режим работы не выключен
    digitalWrite(LED2, !digitalRead(LED2));  //мигаем светододом
  }
  else{digitalWrite(LED2, LOW);} //иначе выключим светодиод
}

Вот и вся программа. Далее загружаем ее на плату и тестируем работу. С полным кодом можно ознакомиться ниже.

#include <VBCoreG4_arduino_system.h>

#define LED2 PA5
#define USR_BTN PC13

double freq = 1; //частота в Гц
int is_off = LOW; // переменная, определяющая выключен ли режим мигания
int prev_btnSt; // предыдущее состояние кнопки
int buttonState; // текущее состояние кнопки
HardwareTimer *timer = new HardwareTimer(TIM3); // таймер

void setup() {
  Serial.begin(115200);
  pinMode(USR_BTN, INPUT_PULLUP);
  pinMode(LED2, OUTPUT);
  prev_btnSt = digitalRead(USR_BTN);

  timer->pause();
  timer->setOverflow(1, HERTZ_FORMAT); // задаем частоту прерывания
  timer->attachInterrupt(blink); //функция мигания светодиодом, вызывается с указанной частотой
  timer->refresh();
  timer->resume();
}

void loop() { 
  buttonState = digitalRead(USR_BTN); //читаем состояние кнопки
  if(buttonState == LOW && prev_btnSt == HIGH){ //если в предыдущем цикле она 
                                                //не была нажата, а сейчас на нее нажали
    is_off = !is_off;                          //режим мигания лампочки меняем на противоположный.
                                              //если светодиод мигал, то отключаем мигание, 
                                              //если нет - то, наоборот, включаем
    prev_btnSt = buttonState;              //предыдущему состоянию кнопки даем текущее значение
  }
  if(buttonState == HIGH) {prev_btnSt = buttonState;}//предыдущему состоянию кнопки даем текущее значение
  if (Serial.available() > 0) { // если в порте появились какие-то данные
    freq = Serial.readString().toDouble(); // считываем частоту, преобразуем в тип double
    if(freq>=1){timer->setOverflow(freq, HERTZ_FORMAT);} //если частота >= 1, то используем HERTZ_FORMAT
    else if (freq> 0 && freq<1){timer->setOverflow(1000000/freq, MICROSEC_FORMAT);} // иначе - MICROSEC_FORMAT
    else {Serial.println("incorrect value for frequency");} //в случае если частота задана в неверном формате, <=0
    timer->refresh(); //обнуляем таймер
    timer->resume(); //запускаем таймер
  }
}

void blink(){
  if(is_off == LOW){ //если режим работы не выключен
    digitalWrite(LED2, !digitalRead(LED2));  //мигаем светододом
  }
  else{digitalWrite(LED2, LOW);} //иначе выключим светодиод
}

Last updated