Страница 1 из 2
Помогите решить задачу
Добавлено: 30 авг 2017, 13:44
niksooon
Парни,нуждаюсь в вашей помощи для решения вот такой проблемы-
Задача состоит в следующем- имеется аппаратура управления для rc моделей

- радио.jpg (7.68 КБ) 3612 просмотров
и необходимо её заставить управлять пропорциональным гидрораспределителем

- гидрораспределитеоь.png (18.01 КБ) 3612 просмотров
у которого две катушки двигают золотником....
Далее.....на выходе с аппаратуры имеем вот такой сигнал
при нейтральном положении джойстика длительность импульса 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); и нате вам пожалуйста , ругаетссо
че ему надоть, иль что не так мне пока соображалки не хватает........
прошу пардону......причина в другом............
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 хотя бы.
Нисколько не сложнее, но гораздо прозрачнее и никаких непоняток.