ШИМ более чем 8 бит

ogogon
ogogon аватар
Offline
Зарегистрирован: 04.04.2011

Добрый день, коллеги!

Подскажите, pls, можно ли штатными средствами программирования Ардуины переключить ея ШИМ в режиме более чем 8-и разрядов? (Нужно хотя бы 16...)

Ogogon.

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

Можно попытаться программно сделать 16-ти битный ШИМ, а аппаратно только 10 бит и то только на 16-ти битном таймере.

ogogon
ogogon аватар
Offline
Зарегистрирован: 04.04.2011

Гм... А почему только десять?

Из умной книжки Евстифеева следует Божий План Спасения:

Разрешаются соотв. прерывания, в регистр сравнения записывается значение, задается пре-делитель для таймера T1 и он исправно дергает сигналом в момент совпадения значения с заданным числом.

Кто отгрызает биты от шестнадцати?

Ogogon.

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

Вы не верно понимаете о чем идет речь в этой книге. Никто ничего не отгрызает. Разрядность таймера и разрядность ШИМа - это совершенно разные вещи. Еще раз вам повторяю на дуине аппаратно на 16-ти битном таймере можно запустить максимум 10-ти битный ШИМ ,больше только программно.

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

Вот пример 16-ти битного ШИМа на 13 выводе, естественно со своими "недостатками"...

volatile uint16_t pwm = 30;
char fadeAmount = 1;

void setup()
{
  cli();
  DDRB |= 1<<5;         
  PORTB &= ~(1<<5);
  TCCR1A = 0;  
  TCCR1B = 1;  
  TIMSK1 = 3; 
  sei(); 
}

void loop() 
{
  pwm += fadeAmount;
  if (pwm == 0 || pwm == 6000) fadeAmount = -fadeAmount; 
  OCR1AH = highByte(pwm);  
  OCR1AL = lowByte(pwm); 
  delay(1);
}

ISR(TIMER1_COMPA_vect) 
{
  PORTB &= ~(1<<5);
}

ISR(TIMER1_OVF_vect)
{
  if(pwm > 30) PORTB |= 1<<5; 
}

 

ogogon
ogogon аватар
Offline
Зарегистрирован: 04.04.2011

Извините пожалуйста, Максим, но я не совсем понимаю, что я не верно понимаю...

Милейший г-н Евстифеев рисует нам следующую картину мира:

Имеет быть 16-битный счетчик TCNT1. Рядом с ним стоят два 16-битных регистра сравнения ORC1A и ORC1B и без передышки сравнивают.

Значения TCNT1 непрерывно бегут вверх и когда они совпадают со значением регистра сравнения, Ардуина (точнее говоря Atmel ATMega) рефлекторно дергает ногой. На каждый регистр сравнения своей. Потом счетчик переполняется, генерирует прерывание, обнуляется и бежит с самого начала. (А. В. Евстифеев "Микроконтроллеры AVR семейств Tiny и Mega фирмы ATMEL" 5-е издание, Москва, Издательский дом «Додэка XXI», 2008. Стр. 279-300)

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

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

Не затруднит ли Вас объяснить, где я заблуждаюсь?

Ogogon.

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

Вы не верно понимаете значения слов аппаратный и программный.
То о чем вы пишите - это и есть программный способ.
Подредактировал пример выше под ваше описание.

Но и я походу ошибался (а может и нет), вроде как можно сгенерить аппаратно 16-битный ШИМ, но только на одной ноге - OC1A (дуина 9).

step962
Offline
Зарегистрирован: 23.05.2011

Даташит, раздел 15.9.3 "Fast PWM Mode" (в 15.9.4 "Phase Correct PWM Mode" - то же самое):

"The PWM resolution for fast PWM can be fixed to 8-, 9-, or 10-bit, or defined by either ICR1 or
OCR1A. The minimum resolution allowed is 2-bit (ICR1 or OCR1A set to 0x0003), and the maximum
resolution is 16-bit (ICR1 or OCR1A set to MAX).
"

В 15.9.5 "Phase and Frequency Correct PWM Mode" написаны пости те же самые буквы, правда уже без фиксированных разрешений 8, 9, 10 бит.

НО...

Здесь есть одно большое "но":

Максимальная частота даже в режиме быстрого ШИМ'а - 16000000/N/(1+TOP) = 244 Гц.

Ниже - пожалуйста, выше - ни-ни...

 

ogogon
ogogon аватар
Offline
Зарегистрирован: 04.04.2011

step962 пишет:

НО...

Здесь есть одно большое "но":

Максимальная частота даже в режиме быстрого ШИМ'а - 16000000/N/(1+TOP) = 244 Гц.

Ниже - пожалуйста, выше - ни-ни...

Прошу прощения, Вы не расшифруете членов выражения?

Почему 16000000? Что есть N и ТОР?

 

Ogogon.

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

В общем, "добил" этот вопрос, я был не прав и вас ввел в заблуждение - можно организовать и аппаратный 16-битный ШИМ на обоих выводах таймера OC1A(D9) и OC1В(D10), единственный недостаток описанный выше это частота 244 Гц. Пример:

void setup()
{
  cli();
  DDRB |= 1<<1 | 1<<2;         
  PORTB &= ~(1<<1 | 1<<2);
  TCCR1A = 0b00000010; 
  //TCCR1A = 0b10100010;  
  TCCR1B = 0b00011001;  
  ICR1H = 255;
  ICR1L = 255;
  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);
    }
  }
}

В сериал-монитор вводите A100, A65000 или B150, B12300 и т.д. и на соответствующих выводах (9 или 10) генерится 16-битный ШИМ с заданной скважностью.

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

ogogon пишет:

Прошу прощения, Вы не расшифруете членов выражения?

Почему 16000000? Что есть N и ТОР?

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

16бит - TOP = 65535,
без пределителя -  
N = 1,
получаем:

16000000/1/(1+65535) = 244

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

И вот еще пример, в котором и разрядность ШИМа можно менять

void setup()
{
  cli();
  DDRB |= 1<<1 | 1<<2;         
  PORTB &= ~(1<<1 | 1<<2);
  TCCR1A = 0b00000010; 
  //TCCR1A = 0b10100010;  
  TCCR1B = 0b00011001;  
  ICR1H = 255;
  ICR1L = 255;
  sei(); 
  Serial.begin(9600);
  Serial.println("PWM resolution: 16-bit");
  Serial.println("PWM frequency: 244 Hz");
  Serial.println("PWM duty OC1A(D9): 0");
  Serial.println("PWM duty OC1B(D10): 0");
  Serial.println();
}

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);
      Serial.print("PWM duty OC1A(D9): ");
      Serial.println(pwm);
    }
    if(c == 'B')
    { 
      pwm ? TCCR1A|=1<<5 : TCCR1A&=~(1<<5);
      OCR1BH = highByte(pwm);  
      OCR1BL = lowByte(pwm);
      Serial.print("PWM duty OC1B(D10): ");
      Serial.println(pwm);
    }
    if(c == 'R')
    {
      Serial.println();
      Serial.print("PWM resolution: ");
      Serial.print(pwm);
      Serial.println("-bit");
      pwm = pow(2, pwm);
      ICR1H = highByte(pwm);  
      ICR1L = lowByte(pwm);
      Serial.print("PWM frequency: ");
      Serial.print(16000000/(pwm+1UL));
      Serial.println(" Hz");
      Serial.println();
    }
  }
}

Разрядность задается вводом в сериал символа R и количества бит: R2, R3,  R4, .... R14, R15, R16

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

Maksim, а что делают строчки 28 и 36 в скетче? Непонятны символы знак вопроса и двоеточие.

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

Это проверка на 0 ,если ее убрать, то ШИМ нельзя будет отключить полностью.
Можно написать так:

 if(pwm > 0) TCCR1A |= 1<<5; else TCCR1A &= ~(1<<5);

или так

 if(pwm == 0) TCCR1A &= ~(1<<5); else TCCR1A |= 1<<5;

 

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

Спасибо, буду знать.

Lonrag
Offline
Зарегистрирован: 25.02.2015

Будет ли работать для ардуино мега 2560, как управлять - как вводить в сериал "А100", и почему от 100 до 65000 и от 150 до 12300. заранее спасибо.

Lonrag
Offline
Зарегистрирован: 25.02.2015

как собрать тоже самое на 120Гц?

Lonrag
Offline
Зарегистрирован: 25.02.2015

разобрался....

odemma
Offline
Зарегистрирован: 21.11.2015

Подскажите пожалуйста, таким образом можно только на 2х выходах разрядность повысить?

Мне бы еще на 3,5,6,11 ногах того же хотелось.

axill
Offline
Зарегистрирован: 05.09.2011

odemma пишет:

Подскажите пожалуйста, таким образом можно только на 2х выходах разрядность повысить?

Мне бы еще на 3,5,6,11 ногах того же хотелось.

в атмега328 один 16ти разрядный таймер с двумя каналами ШИМ, т.е. Можно иметь аппаратно только два 16бит канала ШИМ. Остальное только программно или используя другой МК

На меге 12 аппаратных каналов 16 бит

odemma
Offline
Зарегистрирован: 21.11.2015

программно это c помощью  map() имеется ввиду?

axill
Offline
Зарегистрирован: 05.09.2011

odemma пишет:

программно это c помощью  map() имеется ввиду?

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

В аппаратном варианте установки low и high делаются автоматически без участия кода программы

Logik
Offline
Зарегистрирован: 05.08.2014

odemma пишет:

Подскажите пожалуйста, таким образом можно только на 2х выходах разрядность повысить?

Я дико извиняюсь, но Вы твердо уверены что оно Вам надо? Я конечно понимаю, перфекционизм и максимализм, но  такие задачи не каждый день наблюдаются, и очень вероятно, что Вы не тем путем идете.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Может уже говорили, но на Леонардо счётчик 4 10-битный, те два выхода шим 10-бит

odemma
Offline
Зарегистрирован: 21.11.2015

Спасибо Вам axill, теперь понятно чего и как.

HUSTON
Offline
Зарегистрирован: 04.04.2016

Привет maksim.  Я проверил твою програмку на осциллографе(INSTRUSTAR ISDS205A) и для вывода ардуино d10 получил такой же график как и для D9 при диапазоне на 16битах от 150 до 65535. Причём для d9 и d10 в диапазоне от 1600 до 65535  регулировка ШИМ сигнала идёт корректно. В диапазоне 0-1600 сигнал ШИМ неравномерно распределяется по периоду повторения. Почему у вас написано что регулировка происходит в диапазоне A100, A65000 или B150, B12300??? можем списаться по почте?(oleg_komarov_1996@mail.ru)