Страница 1 из 2

Помогите решить задачу

Добавлено: 30 авг 2017, 13:44
niksooon
Парни,нуждаюсь в вашей помощи для решения вот такой проблемы-
Задача состоит в следующем- имеется аппаратура управления для rc моделей
радио.jpg
радио.jpg (7.68 КБ) 3612 просмотров
и необходимо её заставить управлять пропорциональным гидрораспределителем
гидрораспределитеоь.png
гидрораспределитеоь.png (18.01 КБ) 3612 просмотров
у которого две катушки двигают золотником....


Далее.....на выходе с аппаратуры имеем вот такой сигнал
servo-signal-pdm.png (3622 просмотра) <a class='original' href='./download/file.php?id=119344&mode=view' target=_blank>Загрузить оригинал (18.6 КБ)</a>
при нейтральном положении джойстика длительность импульса 1500мкс ,а в крайних 500 и 2500мкс

Ну собственно сам нубский вопрос-как на ардуине сделать так чтобы при изменении задающего сигнала от 1500 до 2500мкс активным был один pwm выход ардуины (и србственно pwm на этом выходе менялся от 0 до 100)
А при изменении сигнала от 1500 до 500 мкс в работу вступал другой pwm выход ,ну и разумеется что при среднем положении джойстика (1500мкс) на обоих выходах было по нулям.......
который день ищу примеры скетчей ,но пока ничего похожего нет...........

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 14:03
selenur
Если в Си разбираешься, вот пример скреча ардуиновского, к которому подключен дисплей по I2c, энкодер, и датчик холла.
Энкодером управляется выход PWM, на 11 пине.

Код: Выделить всё

#include <OLED_I2C.h>

/*
Использование выводов
Analog A4 - SDA oled display
Analog A5 - SCL oled display
Digital 11 - PWM out
Digital 5,6 - enconder AB
Digital 2 - (int0) 


*/


OLED  myOLED(SDA, SCL, 8);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];

/* Пины, к которым подключен энкодер */
enum { ENC_PIN1 = 5, ENC_PIN2 = 6 };

// для подсчета пришедших тактов
int countTick = 0;

// для хранения скорости вращения
int rpmold = 0;
int rpm = 0;

int pin = 13;
volatile int state = LOW;

uint8_t i=0;

void setup()
{
  // отключим прерывания
  noInterrupts();           // disable all interrupts
  
  //подключение енкондера
  pinMode(ENC_PIN1, INPUT);
  pinMode(ENC_PIN2, INPUT);  

  // инициализация дисплея
  myOLED.begin();
  myOLED.setFont(SmallFont);
  
  // инициализация генерации ШИМ с применением таймера №2
  // настройка ШИМ - выхода, digital-11, PB3(OC2A)
  pinMode(11, OUTPUT); 
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = TCCR2B & 0b11111000 | 0x02;
  OCR2A = 0;
  OCR2B = 50;
  
  // Добавляем прерывание, по входящему импульсу, KWH interrupt attached to IRQ 1 = pin3
  pinMode(pin, OUTPUT);
  attachInterrupt(0, onPulse, RISING); //RISING
  // подключение прерывания по импульсу на 2-м пине
  
  // настройка 16-ти битного таймера, на переполнение
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;            // preload timer 65536-16MHz/256/2Hz - начальное значение отсчета
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  
  
  // выведем первоначальные данные
    myOLED.setFont(MediumNumbers);
    myOLED.printNumF(i, 2, RIGHT, 0); //строка на желтом фоне
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(rpm, RIGHT, 40); // стока на голубом фоне
    myOLED.update();
  
  // настроим скорость порта
  //Serial.begin(9600);
  
  // включим прерывания
  interrupts();             // enable all interrupts
}

/* Функция декодирования кода Грея, взятая с Википедии.
* Принимает число в коде Грея, возвращает обычное его представление.
*/
unsigned graydecode(unsigned gray)
{
 unsigned bin;

 for (bin = 0; gray; gray >>= 1)
    bin ^= gray;

 return bin;
}

int ppp = 0;

void loop()
{
  // digitalWrite(pin, state);

  
 static uint8_t previous_code = 0; // предыдущий считанный код
 
 /* gray_code - считанное с энкодера значение
  * code - декодированное значение
  */
 uint8_t gray_code = digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1),
         code = graydecode(gray_code);
 
 
 uint8_t needRefresh = 0;
 
 /* Если считался нуль, значит был произведён щелчок ручкой энкодера */
 if (code == 0)
 {
   /* Если переход к нулю был из состояния 3 - ручка вращалась
    * по часовой стрелке, если из 1 - против.
    */
   if (previous_code == 3)
   {
     //Serial.println("->");     
     if (i<245) i+=1;
     OCR2A = i;      
   }
   else if (previous_code == 1)
   {
     //Serial.println("<-");     
     if (i>=10) i-=1;
     OCR2A = i; 
   }    
   
   needRefresh = 1;
   
 }
 
 if (rpmold != rpm)
 {
   needRefresh = 1;
   rpmold = rpm;
 }
 
 if (ppp >100)//needRefresh
 {
    //myOLED.clrScr();
    //myOLED.setFont(MediumNumbers);
    //myOLED.printNumF(i, 2, RIGHT, 0); //строка на желтом фоне
    
    myOLED.clrScr();
    
    myOLED.setFont(MediumNumbers);
    myOLED.printNumI(i, LEFT, 0); //строка на желтом фоне енкондер
    
    myOLED.setFont(MediumNumbers);
    myOLED.printNumI(rpm, RIGHT, 0); //строка на желтом фоне енкондер
    
    int ttt = rpm *60;
    
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(ttt, RIGHT, 40); // стока на голубом фоне
    
    myOLED.update();
   
     needRefresh = 0;
     ppp = 0;
 }

 
 /* Сохраняем код и ждём 1 мс - вполне достаточно опрашивать энкодер
  * не более 1000 раз в секунду.
  */
 previous_code = code;
 delay(1);
 
 ppp++;
}


// прерывание от таймера
ISR(TIMER1_OVF_vect)
{
  countTick = 62500;
  //rpm = 0; // если произошло переполнение, значит нет вращения
  
  //TCNT1 = 0;            // preload timer
  //тут произведем вычисления скорости

//rpm++;

}


// прерывание по пришедшему импульсу
void onPulse()
{
  //state = !state;

  
  countTick = TCNT1; 
  TCNT1 = 0; //переапуск таймера
  
  rpm = 31250 / countTick;
  //rpm = (31250 / countTick) * 60;  
}



Re: Помогите решить задачу

Добавлено: 30 авг 2017, 14:06
Taganrog
Вроде несложно, делай захват импульса таймером он аппаратно посчитает длительность. Формируй ШИМ на другой лапе .
кусок кода с подсчетот:

Код: Выделить всё

  //************       настройка таймера-счётчика 1         ******* подсчитывает длительность между импульсами
  TCCR1A = 0; 
  TCCR1B = 0; 
  TCNT1 = 0; // начальное значение
  TIMSK1 = (1<<ICIE1)|(1<<TOIE1);  //разрешаем прерывание по захвату сигнала на 8 ноге и по переполнению таймера
  TCCR1B = (1<<ICNC1)|(1<<ICES1)|(1<<CS10);  //включаем шумоподавление и  установим делитель на 1 

}







ISR (TIMER1_CAPT_vect) { //прерывание  входящий сигнал на 8 ноге мега328
  tic_rpm = (err_rpm*65536)+ICR1; //сохраняем значения счетчика (количество тиков между импульсами) 
  impuls=1; // флаг прихода нового импульса
  TCNT1=0;  // сбрасываем регистр таймера
  err_rpm=0; // отменяем ошибку. Импульсы присутствуют. 
}   
ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
  err_rpm ++; // количество переполненй 
  if (err_rpm>15){  // если долго нет импульса всеравно тикаем для организации расчетов
    err_rpm=0;
    impuls_off=1;// флаг долгово отсутствия импульса
  }
}

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 17:02
niksooon
Спасибо ,пищу для размышлений подкинули.........
а вот такой еще вопрос как примерно может выглядить скетч ежели на какой либо аналоговый вход подцепить потенциометр (джойстик)? что бы при его среднем положении на обоих выходах pwm было по 0 ,а при перемещении(джойстика) вверх активировался первый pwm (и работал в диапазоне от 0 до 100%) а при движении джойстика вниз активировался второй(и тоже от 0 до 100%) ?
ну и дрейф нуля при этом тоже не мешало бы програмно откорректировать...... ???
ПЫ Сы ,с ардуинкой дел ранее не имел , приедет буквально завтра -послезавтра, пока пытаюсь хоть немного на примерах кода разобраться что к чему...........

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 17:34
SVP
Читаешь АЦП, потом наружу устанавливаешь нужный pwm.
Немного непонятно в чем конкретно проблема.

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 17:58
selenur
При подключении переменного резистора, ардуина при считывании данных с аналогового порта, в переменную записывает значение от нуля до 1024, а дальше вычисление настройки таймеров для генерации pwm сигнала.

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 18:31
sidor094
Можно поставить интегрирующую цепочку на выход джойстика и затем мерить ацп напряжение.

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 18:57
niksooon
Читаешь АЦП, потом наружу устанавливаешь нужный pwm.
Немного непонятно в чем конкретно проблема.
ну нуб я в этом,посему и воспрошаю....... ...
а всё же При подключении переменного резистора, ардуина при считывании данных с аналогового порта, в переменную записывает значение от нуля до 1024 это как бы понятно ,а как должен выглядить код чтобы при изменении значения на каком либо аналоговом входе с 512 до 1024 выход №1 pwm менялся от 0 до 100 % и наоборот при изменении сигнала на аналоговом входе от 512 до 0 на выходе №2 pwm уровень сигнала выростал от 0 до 100 %
Нужно всего то пара другая строк для примера для того чтоб понять как сие надо правильно прописывать............

Re: Помогите решить задачу

Добавлено: 30 авг 2017, 19:42
Taganrog
Попробуй так:

Код: Выделить всё


void setup() {
  pinMode(ledPin, OUTPUT);  //делаем ножку выходом
}

void loop() {
 
  sensorValue = analogRead(0); // читаем аналоговое значение

  sensor=map(sensorValue,0,1023,0,255); // масштабируем из 0-1023 пропорционально до 0-255
  analogWrite(ledPin,sensor); // задаем шим на ножке со скважностью равной sensor
  


}

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 14:21
niksooon
По представленному выше все понятно, и в примерах я такое нашел, но мне надо немного по другому -чтобы при изменении значения на аналоговом входе с 512 до 1024 выход №1 pwm менялся от 0 до 100 % и наоборот при изменении сигнала на этом же аналоговом входе от 512 до 0 на выходе №2 pwm уровень сигнала выростал от 0 до 100 %

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 15:00
selenur
Тут всё очень просто, имеем переменную П1 которая меняется от 0 до 1024, а П2, и П3 собственно значения которые меняются в нужную сторону.
Алгоритм такой:

Код: Выделить всё

Если П1 <= 512 Тогда П2 = 512 - П1
Иначе П2 = 0

Если П1 >= 512 Тогда П3 = П1 - 512
Иначе П3 = 0
В результате чего пока значение П1 меняется от нуля до 512, значение П2 меняется от 512 до нуля, а П3 пока равно нулю.
После того как значение П1 стало увеличиваться от 512 до до 1024, значение П2 продолжает иметь значение 0, а в П3 значение меняется от нуля до 512.

Как значение от нуля до 512 пере-масштабировать в значение от нуля до 100 для П2 и П3 думаю понятно :-)

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 17:48
niksooon
вот что то намудрил со сторонней помощью)

Код: Выделить всё

#define Ppin A0   // сюда подключена средняя нога потенциометра
const int APin = 3;         // пин подключения pwm выхода A
const int BPin = 9;         // пин подключения pwm выхода B
const int Dead = 200;    // ширина мертвой зоны в центре потенциометра
 
int Pot;      //значение с потенциометра
int Aval;   //значение для PWM-выхода A
int Bval;   //значение для PWM-выхода B
int Lo;      //нижняя граница
int Hi;      //верхняя граница
 
 
 
void setup() {
//  Serial.begin(9600);
 
//границы верхней и нижней зоны
Lo = (1024-Dead) / 2;
Hi = Lo+Dead;
 
}
 
 
 
void loop() {
 
//читаем сигнал с потенциометра
Pot = analogRead(Ppin);
 
//нижняя половина: работаем по выходу А
if (Pot <= Lo)
{ Aval = map(Pot,   0,Lo,     255,0);
   Bval = 0;
}
 
else if (Pot >= Hi)   //верхняя половина: работаем по выходу B
{ Aval = 0;
   Bval = map(Pot,   Hi,1023,    0,255);
}
 
else   //мертвая зона в центре: обнуляем оба выхода А и В
{ Aval = 0;
   Bval = 0;
};
 
//записываем полученные значения в PWM-выходы
analogWrite(APin, Aval); 
analogWrite(BPin, Bval); 
 
}
даже работает правильно вроде как.......
Гляньте плиз в самом верху правильно ли пины и прочее бла-бла прописаны?

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 19:04
selenur
В процедуре Setup обычно прописывают инициализацию портов, какой из пинов будет вход/выход, хотя похоже обращения к пинам автоматом добавило эту инициализацию..

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 19:24
niksooon
вот и я пробывал pinMode как положено поназначить ,а компилятор ругаеццо............. если все работает мож так и оставить? и не забивать себе голову?

Re: Помогите решить задачу

Добавлено: 01 сен 2017, 23:37
Taganrog
niksooon писал(а):пробывал pinMode как положено поназначить
На что ругается то?
Ацп стабильнее работает если в сетапе прописать подтягивание ножки к питанию таким образом:
pinMode(A1,INPUT_PULLUP);

Re: Помогите решить задачу

Добавлено: 02 сен 2017, 22:34
niksooon
ну вот к примеру еще код для моих нужд

Код: Выделить всё

//номера пинов, куда подключены потенциометры А и В
#define potApin A0            // потенциометр A
#define potBpin A1            // потенциометр В
 
//номера пинов, куда подключены pwm выходы A и В
const int pwmApin = 3;         // pwm выход A
const int pwmBpin = 9;         // pwm выход B
 
//номер пинов, куда подключены дискретные входы
const int btnPin = 5;            //кнопка СТАРТ
const int snsPin = 6;            //датчик
 
int potA=0;        //значение с потенциометра A
int potB=0;        //значение с потенциометра B
int pwmA=0;     //значение для PWM-выхода A
int pwmB=0;     //значение для PWM-выхода B
boolean btn = false;    //состояние кнопки
boolean sns = false;    //состояние датчика
boolean run = false;    //флаг активности перемещения
 
//---------------------------------------------------------------------------------------------------
void setup() {
//  Serial.begin(9600);
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP); 
//конфигурируем пины, куда подключена дискретные входы
pinMode(btnPin,INPUT)
pinMode(snsPin,INPUT)
 
}
 
//---------------------------------------------------------------------------------------------------
void loop() {
 
//читаем дискретные входы
btn = digitalRead(btnPin);   //кнопка СТАРТ
sns = digitalRead(snsPin);   //датчик
 
//старт движения по нажатию кнопки,  стоп движения по срабатыванию концевика
if ((btn == HIGN)  && (run == LOW)  &&   (sns == HIGH))      run = HIGH;
if ((run == HIGH)  && (sns == LOW))       run = LOW;
 
//формируем сигналы для pwm-выходов
//если выполняется перемещение, то передаем на pwm-выходы сигнал с потенциометра
//если же остановлен, то обнуляем оба выхода А и В
if (run == HIGH)
{ //читаем сигналы с потенциометров
   potA = analogRead(potApin);
   potB = analogRead(potBpin);
 
  //масштабируем сигнал от потенциометра
   pwmA = map(potA,   0,1023,     0,255);
   pwmB = map(potB,   0,1023,     0,255);
}
else   
{ pwmA = 0;
   pwmB = 0;
};
 
//записываем полученные значения в PWM-выходы
analogWrite(pwmApin, pwmA); 
analogWrite(pwmBpin, pwmB); 
 
}
вставил
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP); и нате вам пожалуйста , ругаетссо
упс.png (3318 просмотров) <a class='original' href='./download/file.php?id=119613&mode=view' target=_blank>Загрузить оригинал (55.2 КБ)</a>
че ему надоть, иль что не так мне пока соображалки не хватает........
прошу пардону......причина в другом............

Re: Помогите решить задачу

Добавлено: 02 сен 2017, 22:48
SVP
niksooon писал(а):че ему надоть, иль что не так мне пока соображалки не хватает........
Вы то что красным снизу написано читали ?
Что там написано ?

Re: Помогите решить задачу

Добавлено: 02 сен 2017, 22:53
selenur
После каждой строчки с кодом следует использовать символ ";" вот на его отсутствие и ругается.

Re: Помогите решить задачу

Добавлено: 02 сен 2017, 22:53
niksooon
туплю блин ; запамятовал поставить...........

Re: Помогите решить задачу

Добавлено: 03 сен 2017, 18:57
AVK74
Делать что то критичное по времени из под ардуины довольно таки странно ИМХО.
Такое нужно делать на прерываниях и таймерах.
Четко понимаю что в какое время происходит.
Используйте CodeVision+Proteus хотя бы.
Нисколько не сложнее, но гораздо прозрачнее и никаких непоняток.