Написание кода передатчика и приемника (для подводного аппарата) за вознаграждение

wenom86
Offline
Зарегистрирован: 04.11.2012

Здравствуйте. У меня в разработке проект подводного телеуправляемого аппарата. Не коммерция, чисто хобби. Посмотреть о чем речь можно в этой теме: http://forum.rcdesign.ru/f130/thread335111.html 

Ищу исполнителя для написания программного кода передатчика и приемника команд управления (вперед, назад, вращение на месте, включение и выключение источников света, управление манипулятором и т.д.)  Передача данных будет происходить по RS485. Аппаратная часть передатчика и приемника изготовлены и работают.

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

Для начала необходимо написать код передатчика, который отправлял - бы в порт Serial в каналы E/F/G/H информацию о нажатии каждой для своего канала тактовой (нефиксируемой) кнопки. Допустим:

a) Включили передатчик - в порт отправляются "0"

б) Нажали и отпустили кнопку - в порт отправляются "1"

в) Нажали и отпустили еще раз - отправляются "0"

Пожелание по коду: (во время нажатия и последующего удержания (пускай даже на полсекунды) кнопки информация, отправляемая в порт не должна меняться. Допустим в порт отправляются нули, при нажатии кнопки в порт или сразу, или после отпускания кнопки должны отправиться единицы, а не 0-1-0-1 и т.д.)

Имеется код, который был написан ранее (если он подходит - отталкиваться необходимо от него)

// Передатчик команд управления v5.1 (23 дек 2014г)
// Органы управления - 4 переменника, 9 кнопок.
// Механизмы оповещения и индикации - 1мотор-вибратор, 1 светодиод

//Цель:
//при нажатии кнопки 1,2,3,4 отправить в сериал-порт информацию о текущем значении.(0 или 1) (канал с фиксацией значения при нажатии)
//при нажатии кнопки 11 отправить в сериал-порт информацию о текущем значении.(0 или 1) (кнопка без фиксации значения)
//при вращении ручки потенциометра 1-4 обработать значения с них и отправить данные в порт для каждого двигателя. (от -100 до 100, нейтральное положение - "0")
//по каналу управления манипулятором передаются значения (от -100 до 0 и от 0 до 100)
//по каналу управления наклоном камеры передаются значения (от 0 до 180)

#define ANALOG_IN0  0 // Порт, к которому подключен переменный резистор 1
#define ANALOG_IN1  1 // Порт, к которому подключен переменный резистор 2
#define ANALOG_IN2  2 // Порт, к которому подключен переменный резистор 3
#define ANALOG_IN3  3 // Порт, к которому подключен переменный резистор 4

int LeftStickX = 0; // переменная Левого стика - ось X (вниз-вверх)
int LeftStickY = 1; // переменная Левого стика - ось Y (пока неиспользуется)
int RightStickX = 2;// переменная Правого стика - ось X (вперед-назад)
int RightStickY = 3;// переменная Правого стика - ось Y (влево-вправо)

int Pin2 = 2;    //пин 2 используется для включения передачи данных по rs485
int Knopka1 = 10; //кнопка1 подключена к 3 цифровому контакту (освещение 1) (фиксируемая) 
int Knopka2 = 7; //кнопка2 подключена к 4 цифровому контакту (освещение 2) (фиксируемая) 
int Knopka3 = 8; //кнопка3 подключена к 5 цифровому контакту (освещение 3) (фиксируемая) 
int Knopka4 = 6; //кнопка4 подключена к 6 цифровому контакту (освещение 4) (фиксируемая) 
int Knopka7 = 11; //кнопка7 подключена к 7 цифровому контакту (манипулятор - сжать) (нефиксируемая)
int Knopka8 = 5; //кнопка8 подключена к 8 цифровому контакту (манипулятор - разжать) (нефиксируемая)
int Knopka9 = 4; //кнопка9 подключена к 9 цифровому контакту (камера - вверх)
int Knopka10 = 3; //кнопка10 подключена к 10 цифровому контакту (камера - вниз)
int Knopka11 = 9; //кнопка11 подключена к 11 цифровому контакту (резервная) (нефиксируемая)
int MotorPin = 12; //моторы в пульте управления подключены через транзистор к 12 цифровому контакту (пока никак не используются)
//int LedPin = 13; // инициализация светодиода, светодиод в пульте управления подключен к 13 цифровому контакту
int KanalMotoraLevogoGor, KanalMotoraPravogoGor, KanalMotoraPerVert, KanalMotoraZadVert; 
int PinUpr1 = 13;
int flag1, flag2, flag3, flag4 = 0;
int KanalKn1, KanalKn2, KanalKn3, KanalKn4 = 0;

void setup() {
  Serial.begin(115200);              // скорость передачи данных в мониторе порта = 115200.
  // Инициализируем цифровые входы/выходы с 3 по 11 в режиме входов.
  pinMode(Knopka1, INPUT);           // назначить выводу порт ввода
  digitalWrite(Knopka1, HIGH);       // активируем подтягивающий резистор 20ком к питанию.
  pinMode(Knopka2, INPUT);           //.......
  digitalWrite(Knopka2, HIGH);
  pinMode(Knopka3, INPUT);        
  digitalWrite(Knopka3, HIGH);
  pinMode(Knopka4, INPUT);        
  digitalWrite(Knopka4, HIGH);
  pinMode(Knopka7, INPUT);        
  digitalWrite(Knopka7, HIGH);
  pinMode(Knopka8, INPUT);        
  digitalWrite(Knopka8, HIGH);
  pinMode(Knopka9, INPUT);        
  digitalWrite(Knopka9, HIGH);
  pinMode(Knopka10, INPUT);        
  digitalWrite(Knopka10, HIGH);
  pinMode(Knopka11, INPUT);        
  digitalWrite(Knopka11, HIGH);
  pinMode(PinUpr1, OUTPUT);
}




void loop() 
{  
// -----------------НАЧАЛО СЧИТЫВАНИЙ ПОКАЗАНИЙ СТИКОВ И ОТПРАВКА ЗНАЧЕНИЙ В ПОРТ-----------------
  LeftStickX = analogRead (ANALOG_IN0);   
  LeftStickY = analogRead (ANALOG_IN1);   
  RightStickX = analogRead (ANALOG_IN2);
  RightStickY = analogRead (ANALOG_IN3);
  Serial.print ("LeftStick-X ");
  Serial.println (LeftStickX);
  Serial.print ("LeftStick-Y ");
  Serial.println (LeftStickY);
  Serial.print ("RightStick-X ");
  Serial.println (RightStickX);
  Serial.print ("RightStick-Y ");
  Serial.println (RightStickY);
  Serial.println ("---------");
// -----------------КОНЕЦ СЧИТЫВАНИЙ ПОКАЗАНИЙ СТИКОВ И ОТПРАВКА ЗНАЧЕНИЙ В ПОРТ-----------------   
  

// -----------------НАЧАЛО ТЕСТА ПРОВЕРКИ РАБОТЫ КНОПОК (при каждом нажатии на кнопку вспыхивает светодиод)( в окончательном коде закомментировать все строчки-----------------
// if (digitalRead(Knopka1) == HIGH && digitalRead(Knopka2) == HIGH && digitalRead(Knopka3) == HIGH && digitalRead(Knopka4) == HIGH &&  digitalRead(Knopka7) == HIGH && digitalRead(Knopka8) == HIGH && digitalRead(Knopka9) == HIGH && digitalRead(Knopka10) == HIGH && digitalRead(Knopka11) == HIGH )
// { digitalWrite (LedPin, LOW);
// }
// else { digitalWrite (LedPin, HIGH);
// }
// -----------------КОНЕЦ ТЕСТА ПРОВЕРКИ РАБОТЫ КНОПОК-----------------
  
  
// -----------------НАЧАЛО ПРЕОБРАЗОВАНИЯ ДАННЫХ С КНОПОК И ПЕРЕМЕННИКОВ В ФОРМАТ ДЛЯ ПЕРЕДАЧИ ПО SERIAL-----------------    
// (-) канал вперед-назад-влево-вправо)
     RightStickX = constrain(RightStickX, 20, 1000);
     RightStickY = constrain(RightStickY, 20, 1000);
     KanalMotoraLevogoGor = map(RightStickX, 20, 1000, 100, -100);
     KanalMotoraPravogoGor = map(RightStickX, 20, 1000, 100, -100);     
     
// (+) начало обработки канала погружения-всплытия)
     LeftStickX = constrain(LeftStickX, 20, 1000);
     KanalMotoraPerVert = map(LeftStickX, 20, 1000, 100, -100);
     KanalMotoraZadVert = map(LeftStickX, 20, 1000, 100, -100);
    
// (+) канал кнопки 1
    if(digitalRead(Knopka1)==LOW&&flag1==0) //если кнопка нажата и переменная flag равна 0 , то ... 
      { digitalWrite(PinUpr1,!digitalRead(PinUpr1));  flag1=1; }                  
    if(digitalRead(Knopka1)==HIGH&&flag1==1) //если кнопка нажата повторно и переменная flag равна 1 ,то ... 
      { flag1=0; }  //обнуляем переменную flag 
    if(digitalRead(PinUpr1)==!HIGH) //если кнопка не нажата и переменная flag равна 1 , то ... 
      { KanalKn1=1;}
    if(digitalRead(PinUpr1)==!LOW) //если кнопка не нажата и переменная flag равна 0 , то ... 
      { KanalKn1=0;}
      


  // -----------------КОНЕЦ ПРЕОБРАЗОВАНИЯ ДАННЫХ С КНОПОК И ПЕРЕМЕННИКОВ В ФОРМАТ ДЛЯ ПЕРЕДАЧИ ПО SERIAL-----------------
   
   
  // -----------------НАЧАЛО ПЕРЕДАЧИ ПРЕОБРАЗОВАННЫХ И ОБРАБОТАННЫХ ДАННЫХ ПО SERIAL-----------------
  digitalWrite (Pin2, HIGH);                // активация передачи данных по rs485
  Serial.print('A');                        //метка начала передачи значения канала "а"
  Serial.println(KanalMotoraLevogoGor);     //.......
  Serial.print('B'); 
  Serial.println(KanalMotoraPravogoGor);      
  Serial.print('C');
  Serial.println(KanalMotoraPerVert);      
  Serial.print('D'); 
  Serial.println(KanalMotoraZadVert);      
  Serial.print('E');
  Serial.println(digitalRead(KanalKn1));
  Serial.print('F'); 
  Serial.println(digitalRead(KanalKn2));  
  Serial.print('G'); 
  Serial.println(!digitalRead(Knopka3));   
  Serial.print('H'); 
  Serial.println(!digitalRead(Knopka4));  
  Serial.print('I'); 
  Serial.println(!digitalRead(Knopka7));              
  Serial.print('J'); 
  Serial.println(!digitalRead(Knopka8));             
  Serial.print('K'); 
  Serial.println(!digitalRead(Knopka9));  
  Serial.print('L'); 
  Serial.println(!digitalRead(Knopka10)); 
  Serial.print('M'); 
  Serial.println(!digitalRead(Knopka11));   
  Serial.println("------------------END------------------");  //конец передачи. 
  // -----------------КОНЕЦ ПЕРЕДАЧИ ПРЕОБРАЗОВАННЫХ И ОБРАБОТАННЫХ ДАННЫХ ПО SERIAL-----------------
  
  delay(10);
  // delay(1000);   // Задержка в 1000 включается только при проверке работоспособности осей стиков в мониторе порта. 
                               // Для включения задержки необходимо раскомментировать строку
                               // Просматривать значения можно в Мониторе порта
                               // В рабочем режиме задержка нужно установить = 10
}

 

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Добрый день!

Не совсем понятно задание. Из описания - все просто (даже элементарно), тем более у вас есть программа. В чем подвох?

wenom86
Offline
Зарегистрирован: 04.11.2012

Дело в том, что катастрофически не хватает времени на изучение программирования. И так хотел запустить аппарат летом 2014, но загвоздка в программе была, хотел сам изучить, но дальше азов не продвинулся. Программа может пока легкая, только будет обрастать доп. Функциями. Подвоха нет, просто нужна помощь человеку-железячнику в программировании.

wenom86
Offline
Зарегистрирован: 04.11.2012

При нажатии на ссылку она не открывается. Чтобы открыть, необходимо стереть в конце ссылки 1 пробел.

 

Artur1985
Offline
Зарегистрирован: 19.02.2013

Добрый вечер.
Искал ответ по синхронизации передачи данных по RS485 и случайно увидел Ваше сообщение. Сам сейчас с другом делаем наброски по аналогичному проекту - проект подводного телеуправляемого аппарата. Приятно видеть, что не только нам лавры Кусто не дают уснуть:).

Тоже делаю на RS485 передачу управления, делаю в свободное время.

По коду

wenom86 пишет:

Имеется код, который был написан ранее (если он подходит - отталкиваться необходимо от него)

Не рекомендовал бы использовать данный код в готовом решении. 

Начнем с UART (Serial), лучше делать отправку и получение на прерываниях + передача байтами + кольцевой буфер, это уменьшит размер кода и сделает его более эффективным, без лишних задержек.

Более рациональное использование ресурсов позволит в будущем иметь запас по расширению, к примеру, для стабилизации при течении (акселерометр, гироскоп) и т.д. Тем более

wenom86 пишет:
Программа может пока легкая, только будет обрастать доп. Функциями.

Примерное описание, данной реализации с неплохим пояснением.

Крайне не желательно использовать delay в loop.

Вы являетесь заказчиком, рекомендовал бы изменить требования к коду для разработчика.

Проект как я понял, почти закончен. Но возможно, будет полезно использование Playstation joystick, вместо кнопок. Более подробно тут.

Будут вопросы, пишите.

 

 
Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Artur1985, а с вашими набросками можно познакомиться?

Artur1985
Offline
Зарегистрирован: 19.02.2013

Отчасти, увы нет времени их публиковать. Сейчас проходят тесты отдельные модули, работы еще много, в том числе и кодинга. 

Я пишу коды и разбераюсь с электроникой, мой друг механикой и корпусом.

Вот пару фото


Габариты 164*156*202мм.

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Меня, как волонтера, именно кодовая часть интересует.

Artur1985
Offline
Зарегистрирован: 19.02.2013

Тут все очень сильно зависит от конкретного Rov. К примеру, для классического Rov, данные идут с береговой станции на Rov, а телеметрия отображается на видео сигнале. К примеру на той же MAX7456. 

Я не стал изобретать велосипед и воспользовался проектом Multiwii, там хорошая схема передачи данных, простой протокол + проверенный IMU. Сейчас подпиливаю под собственные нужды протокол и думаю над синхронизации RS-485. У меня не классический Rov, данные идут в обе стороны. 
 

Gippopotam пишет:

Меня, как волонтера, именно кодовая часть интересует.

Готового решения у меня пока нет, делается в свободное время. 
Мое решение, без доработки использовать не получится. Да можно будет взять саму передачу данных, но протокол придется переписывать. Так как он будет заточен, под особенности моего Rov.

Artur1985
Offline
Зарегистрирован: 19.02.2013

Добрался до рабочего компа, как я говорил, лучше если Вы посмотрите код оригинала.
Вот мой код, по сути код от MultiWii, лишь изменена стилистика.
Так же начал вставлять комментарии.

UART.cpp
 

/**********************************  Библиотеки  **************************************/
#include "Arduino.h"

#include "UART.h"

#include "Def.h"

#include "Config.h"
/**********************************  /Библиотеки  *************************************/

/**************************************************************************************/
/*****************             Класс работы с UART               **********************/
/**************************************************************************************/

// SerialHeadRX - буфер RX для хранения "головы масива"
// SerialTailRX - буфер RX для хранения "хвоста масива"
static volatile uint8_t SerialHeadRX[UARTNumber],SerialTailRX[UARTNumber];

// SerialBufferRX - буфер RX для хранения данных
static uint8_t SerialBufferRX[RXBufferSize][UARTNumber];

// SerialHeadTX - буфер TX для хранения "головы масива"
// SerialTailTX - буфер TX для хранения "хвоста масива"
static volatile uint8_t SerialHeadTX[UARTNumber],SerialTailTX[UARTNumber];

// SerialBufferTX - буфер X для хранения данных
static uint8_t SerialBufferTX[TXBufferSize][UARTNumber];

/// <summary>
// Инициализируем и открываем UART порт 
/// </summary>
/// <param name="port">Номер порта</param>
/// <param name="baud">Скорость работы порта</param>
void UARTOpen(uint8_t port, uint32_t baud) 
{
  // U2X - Удвоение скорости обмена. Если этот разряд установлен в «1», коэффициент деления предделителя контроллера скорости передачи уменьшается с 16 до 8, удваивая тем самым скорость асинхронного обмена по последовательному каналу. В USART разряд U2X используется только при асинхронном режиме работы. В синхронном режиме он должен быть сброшен.
  // UBRRL  и UBRRH - регистры скорости передачи   
  // RXEN - Разрешение приема. При установке этого разряда в «1» разрешается работа приемника USART/UART и переопределяется функционирование вывода RXD.
  // TXEN - Разрешение передачи. При установке этого разряда в «1» разрешается работа передатчика UART и переопределяется функционирование вывода TXD
  // RXCIE - Разрешение прерывания по завершению приема. Если данный разряд установлен в «1», то при установке флага RXC регистра UCSRA генерируется прерывание.
  
  uint8_t h = ((F_CPU  / 4 / baud -1) / 2) >> 8;
  uint8_t l = ((F_CPU  / 4 / baud -1) / 2);
  switch (port) 
  {
    #if defined(ArduinoProMini)
      case 0: UCSR0A  = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
    #endif
    #if defined(ArduinoProMicro)
      case 1: UCSR1A  = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
    #endif
    #if defined(ArduinoMega)
      case 0: UCSR0A  = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
      case 1: UCSR1A  = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
      case 2: UCSR2A  = (1<<U2X2); UBRR2H = h; UBRR2L = l; UCSR2B |= (1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2); break;
      case 3: UCSR3A  = (1<<U2X3); UBRR3H = h; UBRR3L = l; UCSR3B |= (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); break;
    #endif
  }
}

/// <summary>
// Сохраняем полученный байт в буфер RX для хранения данных 
/// </summary>
/// <param name="data">Полученный байт</param>
/// <param name="port">Номер порта</param>
void StoreUartInBuf(uint8_t data, uint8_t portnum) 
{
  // Получаем номер "головы масива" RX
  uint8_t h = SerialHeadRX[portnum];
  // Проверяем, увеличиваем номер "головы масива" RX головы на 1 и если номер "головы масива", станет равным или больше размера буфера, обнуляем переменную h в 0  
  if (++h >= RXBufferSize) 
  {
    h = 0;
  }
  
  // Убрал для отладки
  // Проверяем номер "головы масива" RX и номер "хвоста масива" RX если равен, это ошибка
  if (h == SerialTailRX[portnum]) 
  {
    return; 
  }
  
  // Сохраняем полученный байт в буфер RX для хранения данных
  SerialBufferRX[SerialHeadRX[portnum]][portnum] = data;  
  
  // Сохраняем новый номер "головы масива" RX
  SerialHeadRX[portnum] = h;
}

// Обработчик завершение приема по каналу USART
#if defined(ArduinoProMini)
  ISR(USART_RX_vect)  { StoreUartInBuf(UDR0, 0); }
#endif
#if defined(ArduinoProMicro)
  ISR(USART1_RX_vect)  { StoreUartInBuf(UDR1, 1); }
#endif
#if defined(ArduinoMega)
  ISR(USART0_RX_vect)  { StoreUartInBuf(UDR0, 0); }
  ISR(USART1_RX_vect)  { StoreUartInBuf(UDR1, 1); }
  ISR(USART2_RX_vect)  { StoreUartInBuf(UDR2, 2); }
  ISR(USART3_RX_vect)  { StoreUartInBuf(UDR3, 3); }
#endif

// Обработчик прерывания по опустошению буффера UART
#if defined(ArduinoProMini) || defined(ArduinoMega)
  #if defined(ArduinoProMini)
  ISR(USART_UDRE_vect) 
  {  
  #endif
  #if defined(ArduinoMega)
  ISR(USART0_UDRE_vect) 
  { 
  #endif
    uint8_t t = SerialTailTX[0];
    if (SerialHeadTX[0] != t) 
    {
      if (++t >= TXBufferSize) 
      {
        t = 0;
      }
      UDR0 = SerialBufferTX[t][0];  
      SerialTailTX[0] = t;
    }
    
    if (t == SerialHeadTX[0]) 
    {
      UCSR0B &= ~(1<<UDRIE0);
    } 
  }
#endif
#if defined(ArduinoMega) || defined(ArduinoProMicro)
  ISR(USART1_UDRE_vect) 
  { 
    uint8_t t = SerialTailTX[1];
    if (SerialHeadTX[1] != t) 
    {
      if (++t >= TXBufferSize) 
      {
        t = 0;
      }
      UDR1 = SerialBufferTX[t][1];  
      SerialTailTX[1] = t;
    }
    if (t == SerialHeadTX[1]) 
    {
      UCSR1B &= ~(1<<UDRIE1);
    }
  }
#endif
#if defined(ArduinoMega)
  ISR(USART2_UDRE_vect) 
  {
    uint8_t t = SerialTailTX[2];
    if (SerialHeadTX[2] != t) 
    {
      if (++t >= TXBufferSize) t = 0;
      UDR2 = SerialBufferTX[t][2];
      SerialTailTX[2] = t;
    }
    if (t == SerialHeadTX[2]) 
    {
      UCSR2B &= ~(1<<UDRIE2);
    }
  }
  ISR(USART3_UDRE_vect) 
  { 
    uint8_t t = SerialTailTX[3];
    if (SerialHeadTX[3] != t) 
    {
      if (++t >= TXBufferSize) 
      {
        t = 0;
      }
      UDR3 = SerialBufferTX[t][3];
      SerialTailTX[3] = t;
    }
    if (t == SerialHeadTX[3]) 
    {
      UCSR3B &= ~(1<<UDRIE3);
    }
  }
#endif

/// <summary>
// Сохраняем отправляемый байт в буфер TX для хранения данных
/// </summary>
/// <param name="port">Номер порта</param>
/// <param name="a">Отправляемый байт</param>
void UARTSerialize(uint8_t port, uint8_t a) 
{
  uint8_t t = SerialHeadTX[port];
  if (++t >= TXBufferSize)
  {
    t = 0;
  }
  SerialBufferTX[t][port] = a;
  SerialHeadTX[port] = t;
}

/// <summary>
// Отправляем данные по UART, включаем прерывание по опустошению буффера UART
/// </summary> 
/// <param name="port">Номер порта</param>
void UARTSendData(uint8_t port) 
{
  #if defined(ArduinoProMini)
    UCSR0B |= (1<<UDRIE0);
  #endif
  #if defined(ArduinoProMicro)
    switch (port) 
    {
      case 1: UCSR1B |= (1<<UDRIE1); break;
    }
  #endif
  #if defined(ArduinoMega)
    switch (port) 
    {
      case 0: UCSR0B |= (1<<UDRIE0); break;
      case 1: UCSR1B |= (1<<UDRIE1); break;
      case 2: UCSR2B |= (1<<UDRIE2); break;
      case 3: UCSR3B |= (1<<UDRIE3); break;
    }
  #endif
}

/// <summary>
// Сохраняем отправляемый байт в буфер TX для хранения данных и отправляем данные по UART, включаем прерывание по опустошению буффера UART
/// </summary> 
/// <param name="port">Номер порта</param>
/// <param name="c">Отправляемый байт</param>
void UARTWrite(uint8_t port, uint8_t c)
{
  UARTSerialize(port,c);UARTSendData(port);
}

/// <summary>
// Получает количество байт доступных для чтения из буфера RX
/// </summary> 
/// <param name="port">Номер порта</param>
uint8_t UARTAvailable(uint8_t port) 
{
  return ((uint8_t)(SerialHeadRX[port] - SerialTailRX[port]))%RXBufferSize;
}

/// <summary>
// Читаем данные из буфера RX для хранения данных
/// </summary> 
/// <param name="port">Номер порта</param>
uint8_t UARTRead(uint8_t port) 
{
  // Получаем номер "хвоста масива" RX
  uint8_t t = SerialTailRX[port];
  // Получаем байт по номеру "хвоста масива" RX
  uint8_t c = SerialBufferRX[t][port];
  
  // Проверяем номер "головы масива" RX и номер "хвоста масива" RX если не равен
  if (SerialHeadRX[port] != t) 
  {
     // Проверяем, увеличиваем номер "хвоста масива" RX хвоста на 1 и если номер "хвоста масива", станет равным или больше размера буфера, обнуляем переменную t в 0  
    if (++t >= RXBufferSize) 
    {
      t = 0;
    }
    // Сохраняем новый номер "хвоста масива" RX
    SerialTailRX[port] = t;
  }
  return c;
}

/// <summary>
// Закрываем UART порт
/// </summary> 
/// <param name="port">Номер порта</param>
void UARTClose(uint8_t port) 
{
  switch (port) 
  {
    #if defined(ArduinoProMini)
      case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
    #endif
    #if defined(ArduinoProMicro)
      case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)|(1<<UDRIE1)); break;
    #endif
    #if defined(ArduinoMega)
      case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
      case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)|(1<<UDRIE1)); break;
      case 2: UCSR2B &= ~((1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2)|(1<<UDRIE2)); break;
      case 3: UCSR3B &= ~((1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3)|(1<<UDRIE3)); break;
    #endif
  }
}

 UART.h
 

#ifndef UART_H_
#define UART_H_

/**************************************************************************************/
/*****************             Класс работы с UART               **********************/
/**************************************************************************************/

// Определяем кол-во UART-тов в зависимости от платы
#if defined(ArduinoMega)
  // Если ArduinoMega
  #define UARTNumber 4
#elif defined(ArduinoProMicro)
  // Если ArduinoProMicro
  #define UARTNumber 1
#else
  // Иначе предполагается ArduinoProMini
  #define UARTNumber 1
#endif

// Размер буфера RX
#define RXBufferSize 128

// Размер буфера TX
#define TXBufferSize 128

/// <summary>
// Инициализируем и открываем UART порт 
/// </summary>
/// <param name="port">Номер порта</param>
/// <param name="baud">Скорость работы порта</param>
void UARTOpen(uint8_t port, uint32_t baud);

/// <summary>
// // Сохраняем отправляемый байт в буфер TX для хранения данных
/// </summary>
/// <param name="port">Номер порта</param>
/// <param name="a">Отправляемый байт</param>
void UARTSerialize(uint8_t port, uint8_t a);

/// <summary>
// Отправляем данные по UART, включаем прерывание по опустошению буффера UART
/// </summary> 
/// <param name="port">Номер порта</param>
void UARTSendData(uint8_t port);

/// <summary>
// Сохраняем отправляемый байт в буфер TX для хранения данных и отправляем данные по UART, включаем прерывание по опустошению буффера UART
/// </summary> 
/// <param name="port">Номер порта</param>
/// <param name="c">Отправляемый байт</param>
void UARTWrite(uint8_t port, uint8_t c);

/// <summary>
// Получает количество байт доступных для чтения из буфера RX
/// </summary> 
/// <param name="port">Номер порта</param>
uint8_t UARTAvailable(uint8_t port);

/// <summary>
// Читаем данные из буфера RX для хранения данных
/// </summary> 
/// <param name="port">Номер порта</param>
uint8_t UARTRead(uint8_t port); 

/// <summary>
// Закрываем UART порт
/// </summary> 
/// <param name="port">Номер порта</param>
void UARTClose(uint8_t port);

#endif /* UART_H_ */

Config.h
 

#ifndef CONFIG_H_
#define CONFIG_H_

/**************************************************************************************/
/********************             Класс настроек                ***********************/
/**************************************************************************************/

/********************************  Настройки UART  ************************************/
#define UARTPort              0                    // Порт UART
#define UARTSpeed             115200UL             // Скорость порта UART
/*******************************  /Настройки UART  ************************************/

/*******************************  Настройки Debug  ************************************/
//#define IS_DEBUG_LOOP_SPEED                        // Включение проверки максимального времени прохождения loop
/*******************************  /Настройки Debug  ***********************************/

#endif /* CONFIG_H_ */

Def.h

 

#ifndef DEF_H_
#define DEF_H_

/**************************************************************************************/
/******************             Класс определений                **********************/
/**************************************************************************************/

/*****************************  Определяем тип ардуины  *******************************/
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega2560__)
    
  #define F_CPU 16000000UL                             // Частота процессора

  // Определяем тип ардуины
  #if defined(__AVR_ATmega328P__)
    // Если ArduinoProMini
    #define ArduinoProMini
  #endif
  #if defined(__AVR_ATmega32U4__)
    // Если ArduinoProMicro
    #define ArduinoProMicro
  #endif
  #if defined(__AVR_ATmega2560__)
    // Если ArduinoMega
    #define ArduinoMega
  #endif
#endif
/****************************  /Определяем тип ардуины  *******************************/

#endif /* DEF_H_ */

Protocol.cpp

/**********************************  Библиотеки  **************************************/
#include "Arduino.h"

#include "Config.h"

#include "UART.h"
/**********************************  /Библиотеки  *************************************/

/**************************************************************************************/
/**************          Класс протокола передачи данных           ********************/
/**************************************************************************************/

void Serialize8(uint8_t a) 
{
  UARTSerialize(UARTPort,a);
}

void Serialize16(int16_t a) 
{
  Serialize8((a   ) & 0xFF);
  Serialize8((a>>8) & 0xFF);
}

void Serialize32(uint32_t a) 
{
  Serialize8((a    ) & 0xFF);
  Serialize8((a>> 8) & 0xFF);
  Serialize8((a>>16) & 0xFF);
  Serialize8((a>>24) & 0xFF);
}

Protocol.h

 

#ifndef PROTOCOL_H_
#define PROTOCOL_H_

/**************************************************************************************/
/**************          Класс протокола передачи данных           ********************/
/**************************************************************************************/

void Serialize8(uint8_t a);

void Serialize16(int16_t a);

void Serialize32(uint32_t a);

#endif /* PROTOCOL_H_ */

.ino
 

/**************************************************************************************/
/********************             Основной файл               *************************/
/**************************************************************************************/

/**********************************  Библиотеки  **************************************/
#include "Arduino.h"

#include "Config.h"

#include "Def.h"

#include "UART.h"

#include "Protocol.h"
/**********************************  /Библиотеки  *************************************/

/******************************** Основные функции ************************************/
/// <summary>
/// Настройка при запуске arduino
/// </summary>
void setup()
{
  UARTOpen(UARTPort, UARTSpeed);
}

int i = 0;

/// <summary>
/// Основной цикл
/// </summary>
void loop() 
{  
  if (i == 0)
  {
    // Отправка данных
    Serialize8('H');
    Serialize8('e');
    Serialize8('l');
    Serialize8('l');
    Serialize8('o');
    Serialize8('!');
    Serialize8('\n');
    UARTSendData(UARTPort);
    i = 1;
  }
  
  if (UARTAvailable(UARTPort) > 0)
  {
    uint8_t c = UARTRead(UARTPort);
    
    Serialize8(c);
    UARTSendData(UARTPort);
  }
}
/******************************** /Основные функции ***********************************/

Удачи!

Artur1985
Offline
Зарегистрирован: 19.02.2013

Да чуть не забыл, у меня пока нет рабочего протокола, смотрите MultiWii, там пример протокола. Отправка и получение, вставленны лишь для проверки. 
 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Спасибо!

Artur1985
Offline
Зарегистрирован: 19.02.2013

Не за что, тут все помогают друг другу по мере сил.

wenom86
Offline
Зарегистрирован: 04.11.2012

Здравствуйте Artur1985 и Gippopotam. Телеметрия у меня будет выводиться именно на MAX7456. Первоначальный код действительно не самый удачный, как я посмотрю. О нем, если нужно, можно благополучно забыть. 

Artur1985
Offline
Зарегистрирован: 19.02.2013

День добрый wenom86.

wenom86 пишет:

Телеметрия у меня будет выводиться именно на MAX7456.

Тоже пока остановился на этой микросхеме. Если Вы покупали модуль, не подскажите где?

Ни РФ, ни в Китае не нашел отдельного модуля, есть платы OSD, но они совмещены с контролером, а как к ним подключится еще тот вопрос.

Доставка из США пока для меня не доступна.

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014
Artur1985
Offline
Зарегистрирован: 19.02.2013

Gippopotam пишет:

А что с этими не так?

http://www.ebay.com/itm/170934217208?_trksid=p2059210.m2749.l2649&ssPage...

Не понял Вас, Max485 это модуль RS-485 TTL. Чтобы его купить не надо искать его в США, они есть и у нас. Сам использую такой же, но к OSD он не имеет отношения. 
 
Очень часто, команды передаются на Rov по RS-485, а телеметрия просто налаживается на видео сигнал с помощью MAX7456. Поэтому нет необходимости слать данные наверх, если у Вас нет доп. задач.
 
MAX7456 используется для OSD, есть готовая библиотека для Ардуино и т.д. Если интересно можете почитать в интернете
 
wenom86
Offline
Зарегистрирован: 04.11.2012

MAX7456 заказывал летом с алиэкспреса. за 2 штуки вместе вышло около 11 баксов. Но это только 2 голые микрушки (обвес там, как я посмотрел, копеечный, у нас в радиомагазине все докупил)

wenom86
Offline
Зарегистрирован: 04.11.2012

Artur1985. Можете скинуть мне свою электронку? или напишите мне на wenom86@mail.ru  Думаю нам есть о чем пообщаться.

Artur1985
Offline
Зарегистрирован: 19.02.2013

wenom86 пишет:

MAX7456 заказывал летом с алиэкспреса. за 2 штуки вместе вышло около 11 баксов. Но это только 2 голые микрушки (обвес там, как я посмотрел, копеечный, у нас в радиомагазине все докупил)


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

wenom86 пишет:

Artur1985. Можете скинуть мне свою электронку? или напишите мне на wenom86@mail.ru  Думаю нам есть о чем пообщаться.


Разумеется, письмо отправил.

Probelzaelo
Offline
Зарегистрирован: 15.04.2011

wenom86 пишет:
Ищу исполнителя для написания программного кода передатчика и приемника команд управления (вперед, назад, вращение на месте, включение и выключение источников света, управление манипулятором и т.д.)  Передача данных будет происходить по RS485. Аппаратная часть передатчика и приемника изготовлены и работают.

Андрей, а чем тебя не устроила обычная система управления "штатная" для RC ? с многоканальным же передатчиком/приемником. тебе и нужно всего ничего, исключить ВЧ составляющую и подавать PPM напрямую (с тренерского разьема например) через физический интерфейс типа 485 или что то подобное прямо двумя проводами, на дешифратор-приемника, дальше все "родное". дешифраторов там же обсуждалось в нескольких местах.

Artur1985
Offline
Зарегистрирован: 19.02.2013
День добрый.
Код передачи данных сделал, пока в одну сторону (но обратно Вам не нужно).
 
Для Вашей задачи надо изменить, лишь один метод, у меня пока джойстик от PS2.
 
В дальнейшем планирую отправку в обратную сторону и заменой управления выходами - прямой доступ к регистрам порта, по уму не плохо бы сделать или воспользоваться библиотекой (думаю на этой недели, но загадывать не буду). 
 
Artur1985
Offline
Зарегистрирован: 19.02.2013

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

Мой код передачи данных можно увидеть тут. Будут вопросы, буду стараться отвечать по мере сил.

Сейчас прервался в написании кода, конструирую винты, редуктора, подбираю моторы (пока не рискну делать сам). Да и на работе дел прибавилось.