как срастить два кода в один

AndreyTU
Offline
Зарегистрирован: 24.03.2018

Прошу помощи. Я еще новичок в программировании.

Задача: при помощи квадратурного энкодера изменять частоту таймера, создающего последовательность импульсов с различными длительностью и паузами. Например, азбука Морзе и т.п.

Нашел два работающих кода: отдельно Enсoder с защитой от дребезга, и отдельно Таймер последовательности имп.

Вопрос тривиальный: как срастить эти два кода в один?

Код Enсoder 

// Объявляем переменные

int pinA = 2; // Пины прерываний
int pinB = 3; // Пины прерываний

volatile long pause    = 50;  // Пауза для борьбы с дребезгом
volatile long lastTurn = 0;   // Переменная для хранения времени последнего изменения

volatile int count = 0;       // Счетчик оборотов
int actualcount    = 0;       // Временная переменная определяющая изменение основного счетчика

volatile int state = 0;       // Статус одного шага - от 0 до 4 в одну сторону, от 0 до -4 - в другую

volatile int pinAValue = 0;   // Переменные хранящие состояние пина, для экономии времени
volatile int pinBValue = 0;   // Переменные хранящие состояние пина, для экономии времени


void setup()
{
  pinMode(pinA, INPUT);           // Пины в режим приема INPUT
  pinMode(pinB, INPUT);           // Пины в режим приема INPUT
  digitalWrite(pinA, HIGH);       // Задействуем встроенные подтягивающие резисторы
  digitalWrite(pinB, HIGH);       // Задействуем встроенные подтягивающие резисторы
  
  attachInterrupt(0, A, CHANGE);  // Настраиваем обработчик прерываний по изменению сигнала
  attachInterrupt(1, B, CHANGE);  // Настраиваем обработчик прерываний по изменению сигнала

  Serial.begin(9600);             // Включаем Serial
}

void loop()
{
  if (actualcount != count) {     // Чтобы не загружать ненужным выводом в Serial, выводим состояние
    actualcount = count;          // счетчика только в момент изменения
    Serial.println(actualcount);
  }
}

void A()
{
  if (micros() - lastTurn < pause) return;  // Если с момента последнего изменения состояния не прошло
  // достаточно времени - выходим из прерывания
  pinAValue = digitalRead(pinA);            // Получаем состояние пинов A и B
  pinBValue = digitalRead(pinB);

  cli();    // Запрещаем обработку прерываний, чтобы не отвлекаться
  if (state == 0  && !pinAValue &&  pinBValue || state == 2  && pinAValue && !pinBValue) {
    state += 1; // Если выполняется условие, наращиваем переменную state
    lastTurn = micros();
  }
  if (state == -1 && !pinAValue && !pinBValue || state == -3 && pinAValue &&  pinBValue) {
    state -= 1; // Если выполняется условие, наращиваем в минус переменную state
    lastTurn = micros();
  }
  setCount(state); // Проверяем не было ли полного шага из 4 изменений сигналов (2 импульсов)
  sei(); // Разрешаем обработку прерываний

  if (pinAValue && pinBValue && state != 0) state = 0; // Если что-то пошло не так, возвращаем статус  в исходное состояние
}
void B()
{
  if (micros() - lastTurn < pause) return;
  pinAValue = digitalRead(pinA);
  pinBValue = digitalRead(pinB);

  cli();
  if (state == 1 && !pinAValue && !pinBValue || state == 3 && pinAValue && pinBValue) {
    state += 1; // Если выполняется условие, наращиваем переменную state
    lastTurn = micros();
  }
  if (state == 0 && pinAValue && !pinBValue || state == -2 && !pinAValue && pinBValue) {
    state -= 1; // Если выполняется условие, наращиваем в минус переменную state
    lastTurn = micros();
  }
  setCount(state); // Проверяем не было ли полного шага из 4 изменений сигналов (2 импульсов)
  sei();
  
  if (pinAValue && pinBValue && state != 0) state = 0; // Если что-то пошло не так, возвращаем статус  в исходное состояние
}

void setCount(int state) {          // Устанавливаем значение счетчика
  if (state == 4 || state == -4) {  // Если переменная state приняла заданное значение приращения
    count += (int)(state / 4);      // Увеличиваем/уменьшаем счетчик
    lastTurn = micros();            // Запоминаем последнее изменение
  }
}

Код Таймера

/* Пример 1.3
  мигание светодиода с определеной последовательностью
*/
//---------------классы---------
//класс Cl_LED просто светодиод мигает с полупериодом time
const int time[] = {200, 200, 500, 500, 1000, 1000, 300, 300};
const byte num_time = 8; //количество чисел в time[]
class Cl_LED {
    uint32_t past; // время послед переключения
    byte i_time;//номер в последовательности мигания
    bool led; // состояние на светодиоде
    byte pin;//нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      i_time = 0; //устанавливаем послед мигания в начало
      digitalWrite(pin, led = 1);
      past = millis();
    }
    // метод loop()
    void loop() {
      if (millis() - past >= time[i_time]) {
        ++i_time; // переход на след шаг последовательности
        if (i_time >= num_time)i_time = 0;//если послед закончилась,начать с начала
        digitalWrite(pin, led = !led);//<--- переключаем светодиод
        past = millis(); //<--- сохраняем время переключения
      }
    }
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

AndreyTU пишет:
как срастить эти два кода в один?

Знаешь как приготовить коктейль «Зима в России»?

1. Берёшь 50% водки
2. Добавляешь ещё 50% водки
3. Тщательно перемешиваешь
4. Перед употреблением добавляешь водку по вкусу.

Вот и со скетчами надо примерно также.

AndreyTU
Offline
Зарегистрирован: 24.03.2018

С водкой-то я еще справляюсь, а вот с кодом ...

sadman41
Offline
Зарегистрирован: 19.10.2016

Призывайте в пост Квона. Судя по стилю - это его классы в кашу заварены. Вот теперь пусть ея и расхлебывает.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Так вопрос только в тщательности перемешивания.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:

Призывайте в пост Квона. 

Хреново, что лички нет. Вот как его пригласить? разве что в заголовке темы его упомянуть.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Срастить то можно. Но 1 - зачем? 2 - и что должно вообще получится. 

AndreyTU
Offline
Зарегистрирован: 24.03.2018

Задача: при помощи энкодера изменять множитель частоты таймера

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А разьве энкодер это может. 1 - нужен код обслуживающий энкодер 2 - нужен код в котором можно менять частоту мигания 3- нужен код который позвляет пользователю понимать что нужно делать и что получилось . Программирование это не механическое сливания жидкостей и смотреть что получилось . 

AndreyTU
Offline
Зарегистрирован: 24.03.2018

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

Однако, нашел подходящий код (ну не умею пока самостоятельно составить код с нуля), http://cyber-place.ru/showthread.php?t=2703. Чуть-чуть подредактировал под свои задачи, все работает как необходимо, только джиттер довольно сильный на высоких частотах. Как я понял, джиттер простыми средствами не устранить. Код стробоскопа (регулировка энкодером частоты и скважности), может кому и сгодится.

//Скетч от Cyber-Place.ru

// Выводы ЭНКОДЕРА
#define CLK 3  // Clock Подключаем к INT1, нельзя переназначать
#define DT 4  // второй вывод энкодера
#define SW 5  // switch кнопка энкодера

#define Min 66 // минимальное значение 
#define Max 1134 //максимальное значение
#define led_pin 13        // подключен светодиод


#define step_freq 66.667       // шаг изменения частоты 
volatile uint32_t freq = 1133.3; // нач. частота в Гц
volatile uint32_t paus, time_light; // время свечения светодиода в мкс
uint32_t oldcount;
boolean DT_last; // последнее состояние энкодера

void setup()
{
  pinMode(CLK, INPUT_PULLUP); // Clock Подключаем к INT1, нельзя переназначать
  pinMode(DT, INPUT_PULLUP); // второй вывод энкодера
  pinMode(SW, INPUT_PULLUP); // кнопка энкодера
  pinMode(led_pin, OUTPUT);    // управление симистором

  attachInterrupt(1, encoderTick, CHANGE); // прерывания от Энкодера

  DT_last = digitalRead(CLK);         // считываем положение CLK
}

void loop()
{
  time_light = (54398 / freq);
  paus = 17.375 * time_light;

  digitalWrite(led_pin, 1);

  oldcount = micros();
  while ( (micros() - oldcount) < time_light) {} // длительность импульса светодиода

  digitalWrite(led_pin, 0);

  while ( (micros() - oldcount) < paus) {} // положительный полупериод
  oldcount = micros();

  digitalWrite(led_pin, 1);

  oldcount = micros();
  while ( (micros() - oldcount) < time_light) {} // длительность импульса светодиода

  digitalWrite(led_pin, 0);

  while ( (micros() - oldcount) < paus) {} // положительный полупериод
  oldcount = micros();
  digitalWrite(led_pin, 1);

  oldcount = micros();
  while ( (micros() - oldcount) < time_light) {} // длительность импульса светодиода

  digitalWrite(led_pin, 0);

  while ( (micros() - oldcount) < paus * 0.6) {} // положительный полупериод
  oldcount = micros();
  digitalWrite(led_pin, 1);

  oldcount = micros();
  while ( (micros() - oldcount) < time_light * 6.) {} // длительность импульса светодиода

  digitalWrite(led_pin, 0);

  while ( (micros() - oldcount) < paus*1.25) {} // положительный полупериод
  oldcount = micros();
}

//********************обработчики прерываний Энкодера*******************************
void encoderTick()     // Обратка прерываний от Энкодера
{
  uint8_t DT_now = digitalRead(CLK);       // считываем текущее положение CLK

  if (DT_now != DT_last && digitalRead(SW))   // если предыдущее и текущее положение не равны, значит был поворот
  {
    if (digitalRead(DT) != DT_now)    // если DT не равен CLK, значит вращение по часовой стрелке
    {
      if ( freq < Max ) freq += step_freq;   // прибавить
    } else {                                   // если DT равен CLK, значит вращение против часовой
      if ( freq > Min ) freq -= step_freq; // убавить
    }
  }
}