Как принять сигнал с приемника в AVR (PWM|Digital)
ничего у меня не тряслость и работало четко
Извините, что вмешиваюсь: а у Вас “не тряслось” в “Протеусе” или Вы сервы подключали?
Вставлю и я пятачок 😃. Сразу оговорюсь, что в теме микроконтроллеров я недавно, поэтому тягаццо с мэтрами по части знания даташитов не буду. Но модельной электроникой я занимаюсь четверть века, поэтому представление о том, что должно получиться в результате, у меня присутствует.
В общем, у меня делается так:
- Обработка импульса ведется в прямом цикле, без таймеров и прерываний (для новичка это важно, помогает избежать гимора на этапе знакомства с железом).
- Первый-второй импульсы после включения пропускаются (они могут быть битыми и привести к неверной отработке устройства).
- Разрядность при обработке должна быть выше разрешающей способности сервы (у меня импульсу 1,5 мс соответствует 2000-2500 тиков), это избавит от дерганья сервы.
- Сам импульс должен сразу проверяться на пригодность к дальнейшей обработке (у меня это диапазон 0,8-2,2 мс).
- Если на выходе после обработки должен получаться дискретный сигнал, используется “защелка” с гистерезисом в 2-3 тика, это исключит ложные срабатывания вблизи точки переключения.
- Если на выходе после обработки должен получаться ШИМ, то “защелка” не нужна.
- Если на выходе должен быть какой-то результирующий сервоимпульс, то правила его формирования должны соответствовать п.п. 1 и 3., тактировать выходные импульсы лучше входными, обработку вести во время синхропаузы.
- Для обеспечения максимальной совместимости по уровням сигнала, импульс желательно обрабатывать на входе аналогового компаратора, но это не обязательно.
- Схема обязательно макетируется, только это гарантирует ее нормальную последующую работу на рабочей плате.
Данные советы на системах с ИИ не проверялись, но вполне пригодны в 90% случаев для простых модельных устройств типа сервореверсера, подкала, коллекторного регулятора оборотов и т.д.
Извините, что вмешиваюсь: а у Вас “не тряслось” в “Протеусе” или Вы сервы подключали?
Я протеусом не пользуюсь вообще, как при написании прог так и при проектировании и сборки железа. Прошивки проверяю на макете или на конструкторе или непосредственно на железе…
- Обработка импульса ведется в прямом цикле, без таймеров и прерываний (для новичка это важно, помогает избежать гимора на этапе знакомства с железом).
Вот именно это и достигается применением аппаратно-заточенных под ШИМ входов/выходов.
Иначе, даже выглядящие вполне прилично на осциллографе канальные импульсы, вызывают тряску серв 😦
Вот именно это и достигается применением аппаратно-заточенных под ШИМ входов/выходов.
Иначе, даже выглядящие вполне прилично на осциллографе канальные импульсы, вызывают тряску серв 😦
выглядящие вполне прилично на осциллографе импульсы, не могут вызывать тряску серв, повторяю - эта проблема решается правильно написаным софтом и установкой “подтяжек”…
И опять же, нету у контроллера аппаратно-заточеннх под ШИМ входов (не путать с выходами!)…
Ув. blade, разъясните мне пожалуйсто, что такое по Вашему “аппаратно-заточенный под ШИМ вход” и что за чудо схемотехника стоит за этим входом, что он носит гордое название “аппаратно-заточенный”?..
Вот, просто, любопытно, сколько занимаюсь контроллерами с детальным изучением даташитов и впервые вижу такое определение, просветите пожалуйсто)
ICP
ICP
ну извините меня, ICP в атмега8 это - 14 нога, а не названные выше, и она обозначает вход триггера захвата фронта таймера-счетчика 1. Им можно мерять импульсы, не спорю (правда там есть свои нюансы), но например в том же ардуино используется для этих целей нога с альтернативной функциеей - внешнее прерывание по изменению фронта, а почему? потому, что так проще код написать - через внешнее прерывание, и что освобождает процессор от всяких циклов с задержками для других задач…
У меня был такой проект, где в меге8 - был и сервотестер, и замерщик ШИМ-сигнала, для активаций оборудования, и слежения за линией питания, и вся телеметрия эта, передавалась по последовательной шине другому контроллеру. Все происходило в одно и тоже время, прошивка заняла 95% места в кристалле…
Окей, из приемника выходит PPM. мерять его по изменению фронта. это уже более-мение понятно.
Подскажите, чем вы эмулируете PPM в протеусе? там есть генираторы П импульсов - но как тестить? запустил с одной величиной - потом остановил - запустил с другой?
а тут же еще надо последовательность _П_I–I_ как получить вход, для отладки в протеусе?
Просто читая таймер по прерыванию имеем нестабильность на время входа в прерывание. Это как мин 4 такта проца, как макс. время окончания подпрограммы другого прерывания или просто по каким то причинам запрещены прерывания (запись в EEPROM итп). C ICR все железно, достаточно смотреть флаги и читать значения не реже времени строба или по тому же прерыванию. Для протеуса в качестве генератора PPM использовал Easy HDL, там пишется простейший луп с необходимыми длительностями. Для отладки вполне достаточно.
Просто читая таймер по прерыванию имеем нестабильность на время входа в прерывание. Это как мин 4 такта проца, как макс. время окончания подпрограммы другого прерывания или просто по каким то причинам запрещены прерывания (запись в EEPROM итп). C ICR все железно, достаточно смотреть флаги и читать значения не реже времени строба или по тому же прерыванию. Для протеуса в качестве генератора PPM использовал Easy HDL, там пишется простейший луп с необходимыми длительностями. Для отладки вполне достаточно.
Вас не затруднит примерчик такого скрипта опубликовать?
Да там все просто, что-то типа:
LBL_START:
REM CH1 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0011
REM CH2 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0011
REM CH3 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0011
REM CH4 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0011
REM CH5 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0011
REM CH6 -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0004
REM SYN -------------
OUT=0
SLEEP FOR 0.0004
OUT=1
SLEEP FOR 0.0026
GOTO LBL_START
Ээээ, то есть в каждый канал с приемника поступает вся пачка состояний каналов???
что-то я не понял…
или же только один канал выходит?
то есть
-
-
- 4,8-6 вольт с бека
- PPM посылка соответсвующая данному каналу, длинною в 2500мс из которой в первые 400 мс синхропауза, потом длина отклонения стика пропорциональна длине сигнала. но не больше 2100мс
я правильно понял?
Все разобрался, всем спасибо за разъяснения.
Теперь с помощью ардуины у меня есть БАНО.
4 режима:
- режим готовности, все выключено.
- режим стоянки, работают только стояночные огни (габориты).
- режим взлета и посадки, включается такси фонарь (передние фары) и стробы.
- полетный режим, работают габариты и строба. такси фонарь выключен.
код:
////////////////////////////////////////////////////////////////////
// BANO Arduino mini pro. 2,5 gramm. Channal for managment.
// Illia Golovatskyi mailto:
////////////////////////////////////////////////////////////////////
int ledTAXI = 2; // LED connected to digital pin 2 (4) Front of the plane.
int ledWHITE = 4; // LED connected to digital pin 4 (6) On the ruder.
int ledRED = 7; // LED connected to digital pin 7 (13) On the left console
int ledGREEN = 8; // LED connected to digital pin 8 (14) On the right console
int ledFLY = 10; // LED connected to PWM pin 10 (16) Strobe.
int pinInput = 3; // Input managment channel pin 3 (5)
volatile int Recv; // store RC signal pulse length
int Norm; // mapped value to be between 0-100
volatile long CH1PulseStartTicks;
int CH1Ready;
volatile int ParkFire = false;
volatile int TaxiFire = false;
volatile int FlyFire = false;
unsigned long FlyStartTicks;
unsigned long FlyTicks;
int BlinkFire = false;
int FadeLow = 25;
int FadeHigh = 255;
////////////////////////////////////////////////////////////////////
void test () {
digitalWrite(ledRED, HIGH); // set the LED on
digitalWrite(ledGREEN, HIGH); // set the LED on
digitalWrite(ledWHITE, HIGH); // set the LED on
digitalWrite(ledTAXI, HIGH); // set the LED on
analogWrite(ledFLY, 255); // set the LED on
delay(3000); // wait for a second
digitalWrite(ledRED, LOW); // set the LED off
digitalWrite(ledGREEN, LOW); // set the LED off
digitalWrite(ledWHITE, LOW); // set the LED off
digitalWrite(ledTAXI, LOW); // set the LED off
analogWrite(ledFLY, 0); // set the LED off
}
////////////////////////////////////////////////////////////////////
void setup() {
// nothing happens in setup
pinMode(ledRED, OUTPUT);
pinMode(ledGREEN, OUTPUT);
pinMode(ledWHITE, OUTPUT);
pinMode(ledTAXI, OUTPUT);
pinMode(pinInput, INPUT); //PPM inputs from RC receiver
attachInterrupt(1, ch1, CHANGE); // catch interrupt 1 (digital pin 3) going HIGH and send to rc1()
test();
}
////////////////////////////////////////////////////////////////////
void ch1()
{
if (digitalRead( pinInput ) == HIGH)// did the pin change to high or low?
{
CH1PulseStartTicks = micros();// store the current micros() value
}
else
{
// Pin transitioned low, calculate the duration of the pulse
Recv = micros() - CH1PulseStartTicks; // may glitch during timer wrap-around
// Set flag for main loop to process the pulse
CH1Ready = true;
}
}
////////////////////////////////////////////////////////////////////
void ParkLed(){
if (ParkFire) {
digitalWrite(ledRED, LOW); // set the LED off
digitalWrite(ledGREEN, LOW); // set the LED off
digitalWrite(ledWHITE, LOW); // set the LED off
ParkFire = false;
} else {
digitalWrite(ledRED, HIGH); // set the LED on
digitalWrite(ledGREEN, HIGH); // set the LED on
digitalWrite(ledWHITE, HIGH); // set the LED on
ParkFire = true;
}
}
////////////////////////////////////////////////////////////////////
void TaxiLed(){
if (TaxiFire) {
digitalWrite(ledTAXI, LOW); // set the LED off
TaxiFire = false;
} else {
digitalWrite(ledTAXI, HIGH); // set the LED on
TaxiFire = true;
}
}
////////////////////////////////////////////////////////////////////
void FlyLed(){
if (FlyFire) {
digitalWrite(ledFLY, LOW); // set the LED off
FlyFire = false;
} else {
digitalWrite(ledFLY, HIGH); // set the LED on
FlyFire = true;
FlyStartTicks = millis();
}
}
////////////////////////////////////////////////////////////////////
void loop(){
if (CH1Ready) {
CH1Ready = false; // reset input flag
// constrain and map the pulse length
Norm = map(constrain(Recv, 1000, 2000), 1000, 2000, 0, 100);
// Update LED
if (Norm < 10) { // All LED is off.
if (ParkFire == true) {ParkLed(); }
if (TaxiFire == true) {TaxiLed(); }
if (FlyFire == true) {FlyLed(); }
digitalWrite(ledTAXI, LOW); // set the LED off
} else if (Norm < 25) { // Park light is on. (Red on left console, Green on right console and White on ruder)
if (ParkFire == false) {ParkLed();}
if (TaxiFire == true) {TaxiLed(); }
if (FlyFire == true) {FlyLed(); }
} else if (Norm < 50) { // Landing mode: Park light + taxi + strobe LED is on.
if (ParkFire == false) {ParkLed();}
if (TaxiFire == false) {TaxiLed(); }
if (FlyFire == false) {FlyLed(); }
} else if (Norm < 75) { // Fly mode: Park light is on, strobe is blinking
if (ParkFire == false) {ParkLed();}
if (TaxiFire == true) {TaxiLed(); }
if (FlyFire == false) {FlyLed();}
}
}
if (FlyFire == true) {
FlyTicks = millis() - FlyStartTicks;
if (BlinkFire) {
if (FlyTicks >100) {
analogWrite(ledFLY,FadeLow);
FlyStartTicks = millis();
BlinkFire=false;
}
} else {
if (FlyTicks >500) {
analogWrite(ledFLY,FadeHigh);
FlyStartTicks = millis();
BlinkFire=true;
}
}
}
////////////////////////////////////////////////////////////////////
} // End of loop;
////////////////////////////////////////////////////////////////////
Прошу прощения, я понял что нужен генератор группового PPM, а не канального декодированного PWM. Для Вашей задачи особой точности не требуется и код вполне работоспособен… но контроль за переполнением CH1PulseStartTicks я бы все-таки сделал… 😃
Все разобрался, всем спасибо за разъяснения.
Теперь с помощью ардуины у меня есть БАНО…
Рано спасибо говорить. Самое интересное только начинается😈. Я так полагаю, что из присутствующих в данной теме, БАНО только ленивый не строил. Итак, мой вариант (рабочий, сделанный в железе):
- два крыльевых огня (красный-зеленый),
- белый проблесковый огонь (двойной проблеск),
- красный проблесковый огонь (одинарный проблеск),
- посадочные фары.
Потребители 1-3 включаются при импульсе >1.3 мс, потребитель 4 - подключается дополнительно при импульсе >1,7 мс. Цацка реализована на attiny13а, объем загружаемого кода - 224 бита (21,9% памяти). Код писался в ассемблере AVR Studio.
Коллеги, озвучьте, плиз, свои камни и размер загружаемого кода.
Рано спасибо говорить. Самое интересное только начинается😈. Я так полагаю, что из присутствующих в данной теме, БАНО только ленивый не строил. Итак, мой вариант (рабочий, сделанный в железе):
- два крыльевых огня (красный-зеленый),
- белый проблесковый огонь (двойной проблеск),
- красный проблесковый огонь (одинарный проблеск),
- посадочные фары.
Потребители 1-3 включаются при импульсе >1.3 мс, потребитель 4 - подключается дополнительно при импульсе >1,7 мс. Цацка реализована на attiny13а, объем загружаемого кода - 224 бита (21,9% памяти). Код писался в ассемблере AVR Studio.
Коллеги, озвучьте, плиз, свои камни и размер загружаемого кода.
Давайте если уж озвучивать, то сразу выкладывать рабочую конфу. Камень такой-то, размер такой-то, весит столько, прошивка вот.
а то не делал только ленивый, а вот в свободном доступе нету.
Мой вариант:
Arduino Pro Mini (ATmega168) = 2,5 грам
Прошивка 3114 байт с загрузчиком из 30720 доступных = 10,14% от возможного.
4 режима, 5 выходов и 1 пропорциональный вход.
Давайте если уж озвучивать, то сразу выкладывать рабочую конфу. Камень такой-то, размер такой-то, весит столько, прошивка вот…
Попробую объяснить свою точку зрения. Рабочие коды коммерческих версий устройств выкладывать никто не будет. Project Ikar звучил это в соседней теме совершенно определенно. Я считаю это справедливым, поскольку затраты времени и здоровья на вылизывание софта могут быть весьма значительными. Именно поэтому я предложил поделиться той частью информации, которая не нанесет разработчикам вреда. Кто сочтет нужным выложить код, тот самостоятельно примет такое решение. Ваша версия БАНО коммерческой ценности не имеет ввиду явной неконкурентоспособности (без обид).
версия БАНО
В ArduCopter Mega (порт на АрдуМега 1280\2560) имеется БАНО, секвенсор. Код открыт.
Попробую объяснить свою точку зрения. Рабочие коды коммерческих версий устройств выкладывать никто не будет. Project Ikar звучил это в соседней теме совершенно определенно. Я считаю это справедливым, поскольку затраты времени и здоровья на вылизывание софта могут быть весьма значительными. Именно поэтому я предложил поделиться той частью информации, которая не нанесет разработчикам вреда. Кто сочтет нужным выложить код, тот самостоятельно примет такое решение. Ваша версия БАНО коммерческой ценности не имеет ввиду явной неконкурентоспособности (без обид).
Что-то я не подумал про комэрцию 😃 есть в этом зерно истины:)
То есть все стараются на этом заработать 😃 окей, нуль-проблем!
Это только буржуи такие не жадные, и не стараются экономить на спичках? На их форумах хоть и с ошибками но код найти можно…
В ArduCopter Mega (порт на АрдуМега 1280\2560) имеется БАНО, секвенсор. Код открыт.
а что такое секвенсор здесь?
в версии Arducopter2.0.34 не нашел бано. Штука конечно очень интресная, но собрать ардукоптер - это не одного дня дело 😃
а что такое секвенсор здесь?
Олег Syberian писал код для последовательного переключения выходов. У него видео есть, где он на коптере включает БАНО, фару, еще что-то.
в версии Arducopter2.0.34 не нашел бано
Вы ищите в профильной ветке - “ArduCopter Mega: порт на обычную Arduino (тестим)”. Там выложены различные версии.
собрать ардукоптер
Не обязательно собирать. Просто посмотреть код. Он там “ардуиновский”.
Что-то я не подумал про комэрцию 😃 есть в этом зерно истины:)
То есть все стараются на этом заработать 😃 окей, нуль-проблем!
Это только буржуи такие не жадные, и не стараются экономить на спичках? На их форумах хоть и с ошибками но код найти можно…
Не все, но некоторые пытаются 😃 . Даже та платформа, на которой Вы реализовали свой проект, производится с чисто коммерческими целями - есть ниша платежеспособных энтузиастов, следовательно она должна быть заполнена. А буржуи жадные по определению, просто настоящий буржуй умеет свою жадность контролировать 😃.