Простой фэйлсэйф - помогите с программой

Vladimir_KVG
Offline
Зарегистрирован: 19.10.2015

Здравствуйте! Я хочу сделать на базе ардуино модуль для модели, выполняющий роль фэйл-сэйфа и инвертора одного серво-канала. Модуль будет работать с обычным р/у приемником, он будет промежуточным звеном между некоторыми сервами и приемником.

Я не программист, и решил сейчас  потренироваться и сделать программу, по которой ардуино будет просто копировать длительность серво импульса на другую ногу - восходящий фронт серво сигнала через прерывание ставит 1 в булевую переменную, нисходящий ставит 0, в основном цикле программа проверяет состояние переменной: если переменная равна 1 то ставит high на пин с серво, если 0 соответственно low. Моя китайская мега работает на 12мгц, то есть она вроде должна успевать все делать даже при самом коротком серво-импульсе, ведь и программа маленькая.

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

[code]
int pin0 = 2; //пин, на который идет сигнал с приемника
int pin1 = 7;//выходной сигнал на серву
boolean state = 0;//состояние выхода
void setup() {
  pinMode(pin0, INPUT);
  pinMode(pin1,  OUTPUT);
  attachInterrupt(pin0, get_rise, RISING);
  attachInterrupt(pin0, get_fall, FALLING);
}

void get_rise()
{
 state = 1;
}

void get_fall()
{
  state = 0;
}

void loop() {
  if(state == 0)
  pin1 = LOW;
  if(state == 1)
  pin1 = HIGH;
 }
[/code]

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

Я стараюсь писать максимально просто, потому что потом на эту мегу я хочу добавить гироскоп, чтобы одна из серв автоматически держала горизонт(в моем случае дифферент), а для этого судя по всему нужен будет пид -регулятор, не знаю пока, насколько он будет сложен в реализации, плюс еще на меге должен калман работать.

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

1. Переменные, которые изменяются в обработчике прерывания, должны быть объявлены с volatile. 

volatile boolean state = 0;//состояние выхода

2. Использование attachInterrupt неправильное. Указывать надо не номер пина, а номер прерывания (0 или 1). То, что они сидят на пине 2 и 3 указывать не надо. Поэтому строки 2 и 6 можно убрать. И как ниже написал коллега dimax, для одного внешнего прерывания (для одного пина) может быть только один обработчик. С одним из четырёх режимов: LOW, CHANGE, RISING, FALLING.

3. Вместо:

  void loop() {
  if(state == 0)
  pin1 = LOW;
  if(state == 1)
  pin1 = HIGH;
 }

Должно быть:

void loop() {
  if(state == 0)
  digitalWrite(pin1, LOW)
  if(state == 1)
  digitalWrite(pin1, HIGH)
 }

 

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Vladimir_KVG, код ужасный. Начиная от крупных косяков (типа 8 и 9 строка -должно быть что-то одно, либо райзин либо фоллин). Заканчивая вообще идеологией. Зачем применять МК там, где можно использовать один транзистор? :)

Vladimir_KVG
Offline
Зарегистрирован: 19.10.2015

Спасибо за ответы! Про volatile и только одно прерывание на порт я не знал, спасибо. Буду основательно все изучать :)

А фэйлсэйф будет работать по такому алгоритму:

-на вход с прерыванием по низкому уровню подается инвертированный (транзистором :) )  сигнал с приемника

-в прерывании выходной порт ставится в 1, обнуляется значение специальной переменной

-в основном цикле программа по таймеру инкрементирует значение переменной, и если оно достигнет определенного значения(из-за пропадания сигнала и, значит, прерываний, обнуляющих эту переменную) выполняет "фэйлсэйфовые" операции

Алгоритм, вроде, рабочий. Может можно как-то проще сделать?