Какой контроллер выбрать для решения задачи

Vactorman
Vactorman аватар
Offline
Зарегистрирован: 30.05.2013

Здравствуйте, уважаемые форумчане!

Объясню суть задачи:

Необходимо получить по интерфейсу UART 4 числа (int16) в интервале [1000;2000]. На основе этих чисел на 4 ногах выдать ШИМ с периодом 20000 микросекунд и длительностью, равной этим числам (для каждой ноги свое число). Потом снова получить 4 числа, изменить параметры ШИМ-сигнала и так далее... Период получения чисел по UART равен периоду ШИМ.

 

Реально ли это в принципе (на Arduino), реально ли это сделать на 1 контроллере, и если все-таки да, то на каком лучше это реализовать?

 

Спасибо за помощь! :)

 

tsostik
Offline
Зарегистрирован: 28.02.2013

По идее, с этой задачей справится любой контроллер, имеющий аппаратный UART со скоростью достаточной для приема 8 байт за 20мс (то есть 400bps и выше) и достаточное

число ног для вывода сигнала. То есть, в частности, любая атмега. Для этого хватит абсолютно любой ардуины.

maksim
Offline
Зарегистрирован: 12.02.2012

tsostik пишет:

Для этого хватит абсолютно любой ардуины.

Не любой.

maksim
Offline
Зарегистрирован: 12.02.2012

Тоесть вам нужны 4 канала 16-титных ШИМов частотой 50Гц управляемых по УАРТу.

Вот пример 2-канального 16-битного ШИМа на таймере1 с задачей скважности кодами АСКИ:

void setup()
{
  cli();                   // запречаем все прерывания
  DDRB |= 1<<1 | 1<<2;     // настраиваем выводы 9 и 10 на выход      
  TCCR1A = 0b00000010;     
  TCCR1B = 0b00011001;     // установим предделител, младшие 3 бита
  ICR1H = 0xFF;            // установим разрядность
  ICR1L = 0xFF;
  sei();                   // разрешаем все прерывания
  Serial.begin(9600);
}

void loop() 
{
  if(Serial.available()) 
  {
    char c = Serial.read();
    uint16_t pwm = Serial.parseInt();
    if(c == 'A')
    { 
      pwm ? TCCR1A|=1<<7 : TCCR1A&=~(1<<7);
      OCR1AH = highByte(pwm);  
      OCR1AL = lowByte(pwm);
    }
    if(c == 'B')
    { 
      pwm ? TCCR1A|=1<<5 : TCCR1A&=~(1<<5);
      OCR1BH = highByte(pwm);  
      OCR1BL = lowByte(pwm);
    }
  }
}

А вот с частотой небольшая проблема: 

      Fpwm = F_CPU/N/(1+TOP)

F_CPU - тактовая частота МК
TOP - разрядность
N - предделитель

возможные предделители:

0 0 1 clkI/O/1 (No prescaling)
0 1 0 clkI/O/8 (From prescaler)
0 1 1 clkI/O/64 (From prescaler)
1 0 0 clkI/O/256 (From prescaler)
1 0 1 clkI/O/1024 (From prescaler)

при N=1 получаем ~244 Гц, а при N=8  ~30 Гц. Что бы добиться именно 50 Гц нужно менять кварцевый резонатор. 50 * 65535 = 3276750 Гц. Более или мене близкое это 3.276MHz HC49/U. Но опять есть НО , при такой низкой тактовой частоте будут проблемы со скорость UART и нефакт что скорость передачи вас устроит.

Ну а теперь почему не любой контроллер. Потому что у Atmega168/328 один 16-битный таймер , а нужно два. Поэтому подойдут LeonardoMicroMega2560Due в расчет не беру.

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

maksim, вам бы ваши примеры отдельными темами  для новичков сделать... типа работа с таймером, шим  и т.п.

а то опять придется тоже самое повторять через денек другой :)

tsostik
Offline
Зарегистрирован: 28.02.2013

maksim пишет:

Не любой.

А зачем для одиночного ШИМ-импульса вообще использовать аппаратный ШИМ?

Считали четыре значения из UARTа, сохранили пять пар в виде "время + нужное состояние портов по истечении этого времени". Если несколько чисел совпадают - значений будет не пять, а меньше.

Настроили в OCR первое событие, в прерывании по совпадению счетчика установили ноги и слежующее время срабатывания. Как только дошли до пары "20000;b0000", забрали следующую порцию комманд, которая зачиталась и подготовилась в основном цикле за послеждние 20мс.

Частота 8МГц и предделитель 8 как раз дадут один тик таймера в 1 мкс.

Vactorman
Vactorman аватар
Offline
Зарегистрирован: 30.05.2013

tsostik пишет:

maksim пишет:

Не любой.

А зачем для одиночного ШИМ-импульса вообще использовать аппаратный ШИМ?

Считали четыре значения из UARTа, сохранили пять пар в виде "время + нужное состояние портов по истечении этого времени". Если несколько чисел совпадают - значений будет не пять, а меньше.

Настроили в OCR первое событие, в прерывании по совпадению счетчика установили ноги и слежующее время срабатывания. Как только дошли до пары "20000;b0000", забрали следующую порцию комманд, которая зачиталась и подготовилась в основном цикле за послеждние 20мс.

Частота 8МГц и предделитель 8 как раз дадут один тик таймера в 1 мкс.

 

Общую идею понял, а можно несколько поподробней? Или ткните носом в материал, где пожно про это прочесть. Просто информации море, а времени как всегда в обрез.

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

про управление таймером авров куча статей, а программу пишем ручками, пробуем... про то как писать саму прорамму нигде не написано

maksim
Offline
Зарегистрирован: 12.02.2012

Сразу не понял вот этого "[1000;2000]" - и на автомате проигнорировал. Тогда задача еще проще. http://www.atmel.com/Images/doc8161.pdf

Vactorman
Vactorman аватар
Offline
Зарегистрирован: 30.05.2013

maksim пишет:

Сразу не понял вот этого "[1000;2000]" - и на автомате проигнорировал. Тогда задача еще проще. http://www.atmel.com/Images/doc8161.pdf

Ушел читать :) Спасибо!

maksim
Offline
Зарегистрирован: 12.02.2012

tsostik пишет:

Частота 8МГц и предделитель 8 как раз дадут один тик таймера в 1 мкс.

Кстати тогда можно и на 16 МГц сделать, предделитель 8 + "программный предделитель" в самом обработчике прерывания и получится 50 Гц.

maksim
Offline
Зарегистрирован: 12.02.2012

Так все-таки. Нужен одиночный импульс или постоянный ШИМ сигнал до получения новых значений? То есть нет данных - нет следующего импульса..

Vactorman
Vactorman аватар
Offline
Зарегистрирован: 30.05.2013

maksim пишет:

Так все-таки. Нужен одиночный импульс или постоянный ШИМ сигнал до получения новых значений? То есть нет данных - нет следующего импульса..

Чип получает значения по UART  и генерирует ШИМ на их основе. Пришли новые данные - изменяем параметры сигнала и продолжаем генерировать. Если до конца текущего периода данные не обновились, используем старые значения. 

Как бы я сделал на C (не на ардуино). 

Один поток работает с UART, читает из него данные и пишет их в 4 глобальные переменные. Далее 1 или 4 потока берут из них информацию о длительности импульса (так как период фиксирован) и генерируют ШИМ. Вроде так. Подойдет ли такой алгоритм для Ардуино?

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

какие потоки... у вас один МК. Перед тем как что то ваять, нужно хоть немного с вопросом ознакомиться. Хоть бы глянули на каких МК платы ардуиновские делаются, что эти МК на борту имеют, типовые примеры посмотрели. А то у вас что теплое, что мягкое.

tsostik
Offline
Зарегистрирован: 28.02.2013

Здесь будет примерно тоже самое -

в главном цикле читаем данные из юарта и готовим их для функции дергающей порты.

В прерывании по совпадению первого таймера включаем/выключаем соответствующий пин и записываем сетчик для следующего совпадения.

Это все, если нужна четкая частота ШИМ 50 Гц.

Если частота нужна примерная - просто ШИМ отдаем на откуп двум таймерам, по два канала на таймер. В главном цикле пишем управляющую информацию,

а весь шим делается сам. Но для этого, как уже писал maksim подойдет не любой контроллер, а имеющий на борту два 16-битных счетчика.

Еще можно урезать требование к разрешению ШИМа до 8 бит, тогда опять подойдет любо контроллер и вся логика превратится в четыре Serial.read()  и  analogWrite().

 

maksim
Offline
Зарегистрирован: 12.02.2012

Vactorman пишет:

Как бы я сделал на C (не на ардуино). 

А чем по вашему С отличается от "ардуино" ? 

Vactorman пишет:

Один поток работает с UART, читает из него данные и пишет их в 4 глобальные переменные. Далее 1 или 4 потока берут из них информацию о длительности импульса (так как период фиксирован) и генерируют ШИМ. Вроде так. Подойдет ли такой алгоритм для Ардуино?

Почти пойдет. Здесь роль "потоков" будет играть основной цикл и прерывания.