analogWrite() на любом выводе

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

Не раз уже поднималась тема о генерации ШИМа на любом из выводов или на всех выводах сразу. Написал простенькую библиотеку, которая позволяет Ардуино программно генерить 8-ми битный ШИМ на любом из выводов. Библиотека использует TIMER2, тестировалась только на Atmega48/88/168/328, то есть UnoDuemilanoveNano и т.п. 

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

И так. Качаем архив, распаковываем его как обычно в ...\arduino-1.х\libraries\ , запускаем IDE, в примерах должна появиться вкладка PWM и в ней 3 примера. 

Описание функций:

analog.Frequence(SLOW);     // позволяет изменить частоту ШИМа
analog.Frequence(NORMAL);
analog.Frequence(FAST);

analog.Mode(pin, OUTPUT);   // инициализирует ШИМ на данном выводе и настраивает его на выход
analog.Mode(ALL, OUTPUT);  // инициализирует ШИМ на всех 20 выводах и настраивает их на выход
analog.Mode(pin, INPUT);      // отключает ШИМ на данном выводе и настраивает его на вход
analog.Mode(ALL, INPUT);     // отключает ШИМ на всех 20 выводах и настраивает их на вход

analog.Write(pin, val);          // все как и у стандартной функции analogWrite

analog.State(pin);               // возвращает текущее значение ШИМа

Пример:

#include <PWM.h>

int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

void setup()  { 
  // declare pin 13 to be an output:
  analog.Mode(13, OUTPUT);
} 

void loop()  { 
  // set the brightness of pin 13:
  analog.Write(13, brightness);    

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}

Видео

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Понятненько. Интересная библиотечка.

Для леонардо и меги редактируем файл pins.h согласно пин-маппингу.

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

В итоге все пришло к тому, что как таковая библиотека не нужна.

Создайте в своем проекте новую вкладку с именем PWM:

и копируйте туда это содержимое:

#ifdef ALL
#define PIN_0
#define PIN_1
#define PIN_2
#define PIN_3
#define PIN_4
#define PIN_5
#define PIN_6
#define PIN_7
#define PIN_8
#define PIN_9
#define PIN_10
#define PIN_11
#define PIN_12
#define PIN_13
#define PIN_14
#define PIN_15
#define PIN_16
#define PIN_17
#define PIN_18
#define PIN_19
#endif

#define SBI(port, pin) asm volatile ("sbi %0, %1" :: "I" (_SFR_IO_ADDR(port)), "I" (pin))

#define CHECK(pwms, port, pin) \
asm volatile ( \
   "cpc %0, %1      \n\t" \
   "brlo 0f         \n\t" \
   "cbi %2, %3      \n\t" \
   "rjmp 1f         \n\t" \
   "0: sbi %2, %3   \n\t" \
   "1: nop          \n\t" \
   : "+r" (pwm), "+r" (pwms) \
   : "I" (_SFR_IO_ADDR(port)), "I" (pin)\
   )\
   
void Init_PWM()
{
  cli();
  TCCR2A = 0;   
  TCCR2B = 3;   //CLK
  OCR2A = 1;
  TIMSK2 = 2;   //разрешаем прерывание по совпадению
  sei();

#ifdef PIN_0
  SBI(DDRD, 0);
#endif
#ifdef PIN_1
  SBI(DDRD, 1);
#endif
#ifdef PIN_2
  SBI(DDRD, 2);
#endif
#ifdef PIN_3
  SBI(DDRD, 3);
#endif
#ifdef PIN_4
  SBI(DDRD, 4);
#endif
#ifdef PIN_5
  SBI(DDRD, 5);
#endif
#ifdef PIN_6
  SBI(DDRD, 6);
#endif
#ifdef PIN_7
  SBI(DDRD, 7);
#endif
#ifdef PIN_8
  SBI(DDRB, 0);
#endif
#ifdef PIN_9
  SBI(DDRB, 1);
#endif
#ifdef PIN_10
  SBI(DDRB, 2);
#endif
#ifdef PIN_11
  SBI(DDRB, 3);
#endif
#ifdef PIN_12
  SBI(DDRB, 4);
#endif
#ifdef PIN_13
  SBI(DDRB, 5);
#endif
#ifdef PIN_14
  SBI(DDRC, 0);
#endif
#ifdef PIN_15
  SBI(DDRC, 1);
#endif
#ifdef PIN_16
  SBI(DDRC, 2);
#endif
#ifdef PIN_17
  SBI(DDRC, 3);
#endif
#ifdef PIN_18
  SBI(DDRC, 4);
#endif
#ifdef PIN_19
  SBI(DDRC, 5);
#endif
} 

volatile uint8_t pwm;
volatile uint8_t pwms[20];

void analog_Frequence(byte prescaler)
{
  TCCR2B = prescaler;   //CLK
}

void analog_Write(byte pin, byte value)
{
  pwms[pin] = value;
}

byte analog_State(byte pin)
{
  return pwms[pin];
}

ISR(TIMER2_COMPA_vect)
{
asm volatile ("clr %0" : "+r" (TCNT2)); // TCNT2 = 0;

#ifdef PIN_0
  CHECK(pwms[0], PORTD, 0);
#endif
#ifdef PIN_1
  CHECK(pwms[1], PORTD, 1);
#endif
#ifdef PIN_2
  CHECK(pwms[2], PORTD, 2);
#endif
#ifdef PIN_3
  CHECK(pwms[3], PORTD, 3);
#endif
#ifdef PIN_4
  CHECK(pwms[4], PORTD, 4);
#endif
#ifdef PIN_5
  CHECK(pwms[5], PORTD, 5);
#endif
#ifdef PIN_6
  CHECK(pwms[6], PORTD, 6);
#endif
#ifdef PIN_7
  CHECK(pwms[7], PORTD, 7);
#endif
#ifdef PIN_8
  CHECK(pwms[8], PORTB, 0);
#endif
#ifdef PIN_9
  CHECK(pwms[9], PORTB, 1);
#endif
#ifdef PIN_10
  CHECK(pwms[10], PORTB, 2);
#endif
#ifdef PIN_11
  CHECK(pwms[11], PORTB, 3);
#endif
#ifdef PIN_12
  CHECK(pwms[12], PORTB, 4);
#endif
#ifdef PIN_13
  CHECK(pwms[13], PORTB, 5);
#endif
#ifdef PIN_14
  CHECK(pwms[14], PORTC, 0);
#endif
#ifdef PIN_15
  CHECK(pwms[15], PORTC, 1);
#endif
#ifdef PIN_16
  CHECK(pwms[16], PORTC, 2);
#endif
#ifdef PIN_17
  CHECK(pwms[17], PORTC, 3);
#endif
#ifdef PIN_18
  CHECK(pwms[18], PORTC, 4);
#endif
#ifdef PIN_19
  CHECK(pwms[19], PORTC, 5);
#endif

asm volatile ("inc %0" : "+r" (pwm)); //pwm++;
}

пример кода:

#define PIN_12
#define PIN_13

int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

void setup()  
{
  Init_PWM();
  analog_Frequence(2); // предделитель от 1 до 7
}

void loop()  
{ 
  analog_Write(12, 255-brightness);    
  analog_Write(13, brightness);

  brightness = brightness + fadeAmount;

  if (brightness == 0 || brightness == 255) fadeAmount = -fadeAmount ; 
    
  delay(50);                            
}

P.S. #define ALL задействует все 20 выводов дуины.

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

У меги и так шимов много. Для меги имеет смысл применять только на выходы больше 20.

С другой стороны, либа позволяет высвободить таймер1 для себя :)

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

На 8 меге гугаетсо 

C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp: In constructor 'PWM::PWM()':
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:17: error: 'TCCR2A' was not declared in this scope
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:18: error: 'TCCR2B' was not declared in this scope
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:19: error: 'OCR2A' was not declared in this scope
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:20: error: 'TIMSK2' was not declared in this scope
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp: In member function 'void PWM::Frequence(byte)':
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:29: error: 'TCCR2B' was not declared in this scope
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp: At global scope:
C:\MC\arduino-1.0.4\libraries\PWM\PWM.cpp:36: warning: 'TIMER2_COMPA_vect' appears to be a misspelled signal handler

А так хочется ещё пару ножек с ШИМ"мом :(

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

Потому что на меге8 отсутстует таймер2.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Можно немного глупый вопрос, а первый можно задействовать?

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

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

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Тоесть все что имеет в тексте TCCR2A, TCCR2B, OCR2A, TIMSK2, TCCR2B, TIMER2_COMPA_vect изменить на 1 или как?

Вот бы как в дуинки уно... тоесть как в меги 328 были все ноги что поддерживают ШИМ имели поддержку у меги 8-й.

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

Почти, только таймер1 16битный, а следовательно некоторые регистры состоят из младшего и старшего реистров.

Например на OCR1A компилятор ругнтся так как он 16-битный и состоит из OCR1AH и OCR1AL.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Понятно... что ничего непонятно...

Просто сменить 2-ки на 1-ки неполучилось.

Клапауций
Offline
Зарегистрирован: 10.02.2013

HWman пишет:

Понятно... что ничего непонятно...

Просто сменить 2-ки на 1-ки неполучилось.

atmega88 - не?

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Я пользуюсь ATmega8A-PU.

Клапауций
Offline
Зарегистрирован: 10.02.2013

HWman пишет:

Я пользуюсь ATmega8A-PU.

Можно ведь постепенно переползать на более современные камни - по сравнению с мега8-й разницы не заметите, но присутсвуют плюшки аппаратной и программной совместимости с фирменными дуино.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

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

BabaDusya
BabaDusya аватар
Offline
Зарегистрирован: 13.10.2012

Не плохо !  На меге  мне удалось максимум задействовать 14 пинов! А реально их все задействовать под "ШИМ" имея в виду 54 пина? Тут в ...\PWM\PINS изменения сделал, надеясь хотя б 32  зажечь



#define HIGH_0  PORTD|=1<<0
#define HIGH_1  PORTD|=1<<1
#define HIGH_2  PORTD|=1<<2
#define HIGH_3  PORTD|=1<<3
#define HIGH_4  PORTD|=1<<4
#define HIGH_5  PORTD|=1<<5
#define HIGH_6  PORTD|=1<<6
#define HIGH_7  PORTD|=1<<7
#define HIGH_8  PORTB|=1<<0
#define HIGH_9  PORTB|=1<<1
#define HIGH_10 PORTB|=1<<2
#define HIGH_11 PORTB|=1<<3
#define HIGH_12 PORTB|=1<<4
#define HIGH_13 PORTB|=1<<5
#define HIGH_14 PORTB|=1<<6
#define HIGH_15 PORTB|=1<<7 
#define HIGH_16 PORTC|=1<<0
#define HIGH_17 PORTC|=1<<1
#define HIGH_18 PORTC|=1<<2
#define HIGH_19 PORTC|=1<<3
#define HIGH_20 PORTC|=1<<4
#define HIGH_21 PORTC|=1<<5
#define HIGH_22 PORTC|=1<<6
#define HIGH_23 PORTC|=1<<7
#define HIGH_24 PORTH|=1<<0
#define HIGH_25 PORTH|=1<<1
#define HIGH_26 PORTH|=1<<2
#define HIGH_27 PORTH|=1<<3
#define HIGH_28 PORTH|=1<<4
#define HIGH_29 PORTH|=1<<5
#define HIGH_30 PORTH|=1<<6
#define HIGH_31 PORTH|=1<<7



#define LOW_0  PORTD&=~(1<<0)
#define LOW_1  PORTD&=~(1<<1)
#define LOW_2  PORTD&=~(1<<2)
#define LOW_3  PORTD&=~(1<<3)
#define LOW_4  PORTD&=~(1<<4)
#define LOW_5  PORTD&=~(1<<5)
#define LOW_6  PORTD&=~(1<<6)
#define LOW_7  PORTD&=~(1<<7)
#define LOW_8  PORTB&=~(1<<0)
#define LOW_9  PORTB&=~(1<<1)
#define LOW_10 PORTB&=~(1<<2)
#define LOW_11 PORTB&=~(1<<3)
#define LOW_12 PORTB&=~(1<<4)
#define LOW_13 PORTB&=~(1<<5)
#define LOW_14 PORTB&=~(1<<6)
#define LOW_15 PORTB&=~(1<<7)
#define LOW_16 PORTC&=~(1<<0)
#define LOW_17 PORTC&=~(1<<1)
#define LOW_18 PORTC&=~(1<<2)
#define LOW_19 PORTC&=~(1<<3)
#define LOW_20 PORTC&=~(1<<4)
#define LOW_21 PORTC&=~(1<<5)
#define LOW_22 PORTC&=~(1<<6)
#define LOW_23 PORTC&=~(1<<7)
#define LOW_24 PORTH&=~(1<<0)
#define LOW_25 PORTH&=~(1<<1)
#define LOW_26 PORTH&=~(1<<2)
#define LOW_27 PORTH&=~(1<<3)
#define LOW_28 PORTH&=~(1<<4)
#define LOW_29 PORTH&=~(1<<5)
#define LOW_30 PORTH&=~(1<<6)
#define LOW_31 PORTH&=~(1<<7)


для экперимента, без успешно! ((  Или я не там прописал !??  

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

Еще нужно файл PWM.cpp подправить:

#include "PWM.h"

PWM::PWM() 
{
  cli();
  TCCR2A = 0;   //при совпадении уровень OC1A меняется на противоположный
  TCCR2B = 5;   //CLK
  OCR2A = 1;
  TIMSK2 = 2;   //разрешаем прерывание по совпадению
  sei();
  

} 


void PWM::Frequence(byte prescaler)
{
  TCCR2B = prescaler;   //CLK
}


volatile byte pwms[32];

ISR(TIMER2_COMPA_vect)
{
  TCNT2 = 0;
  static byte pwm;
  pwms[0] > pwm ? HIGH_0 : LOW_0;
  pwms[1] > pwm ? HIGH_1 : LOW_1;
  pwms[2] > pwm ? HIGH_2 : LOW_2;
  pwms[3] > pwm ? HIGH_3 : LOW_3;
  pwms[4] > pwm ? HIGH_4 : LOW_4;
  pwms[5] > pwm ? HIGH_5 : LOW_5;
  pwms[6] > pwm ? HIGH_6 : LOW_6;
  pwms[7] > pwm ? HIGH_7 : LOW_7;
  pwms[8] > pwm ? HIGH_8 : LOW_8;
  pwms[9] > pwm ? HIGH_9 : LOW_9;
  pwms[10] > pwm ? HIGH_10 : LOW_10;
  pwms[11] > pwm ? HIGH_11 : LOW_11;
  pwms[12] > pwm ? HIGH_12 : LOW_12;
  pwms[13] > pwm ? HIGH_13 : LOW_13;
  pwms[14] > pwm ? HIGH_14 : LOW_14;
  pwms[15] > pwm ? HIGH_15 : LOW_15;
  pwms[16] > pwm ? HIGH_16 : LOW_16;
  pwms[17] > pwm ? HIGH_17 : LOW_17;
  pwms[18] > pwm ? HIGH_18 : LOW_18;
  pwms[19] > pwm ? HIGH_19 : LOW_19;  
  pwms[20] > pwm ? HIGH_20 : LOW_20;
  pwms[21] > pwm ? HIGH_21 : LOW_21;
  pwms[22] > pwm ? HIGH_22 : LOW_22;
  pwms[23] > pwm ? HIGH_23 : LOW_23;
  pwms[24] > pwm ? HIGH_24 : LOW_24;
  pwms[25] > pwm ? HIGH_25 : LOW_25;
  pwms[26] > pwm ? HIGH_26 : LOW_26;
  pwms[27] > pwm ? HIGH_27 : LOW_27;
  pwms[28] > pwm ? HIGH_28 : LOW_28;
  pwms[29] > pwm ? HIGH_29 : LOW_29; 
  pwms[30] > pwm ? HIGH_30 : LOW_30;
  pwms[31] > pwm ? HIGH_31 : LOW_31;
  pwm++;
  if(pwm == 255) pwm = 0;
}

 
void PWM::Mode(byte pin, bool en)
{
    for(byte i = 0; i < 32; i++)
    {
      pinMode(i, en);
    }
}


void PWM::Write(byte pin, byte value)
{
  pwms[pin] = value;
}


byte PWM::State(byte pin)
{
  return pwms[pin];
}

PWM analog = PWM();

Если процессорного времени хватит, то можно и все 54 задействовать, если же нет то нужно разрядность ШИМа понижать.

BabaDusya
BabaDusya аватар
Offline
Зарегистрирован: 13.10.2012

Большое спасибо за быструю реакцию! Попробывал предварительно : сменил в PWM.cpp  начинку на предложенную, дополнив сразу до 54 пинов! и в ...\PWM\PINS не забыл .  И все тоже самое работают в ШИМе только PB4-PB7(10-13),PD0-PD3(18-21)! (  И ещё, если делаю в скетче доп.ю инициализацию в

void setup()

{pinMode(0, OUTPUT);pinMode(1, OUTPUT);........pinMode(54, OUTPUT);

analog.Mode(0, OUTPUT);analog.Mode(1, OUTPUT);..........analog.Mode(54, OUTPUT);}

то начинает работать и PC0-PC4,PD7(33-38)! ( Вроде правильно вычислил..)   А остальные молчат !((  А хотелось бы научиться,надеюсь это возможно, на всех портах(пинах) МЕГИ...  Может что ещё мы не сделали??

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

Выводы на выход в этом случае можно настраивать целыми портами:

DDRA = 0xFF;
DDRB = 0xFF;
DDRC = 0xFF;
DDRF = 0xFF;
DDRK = 0xFF;

попробуйте снизить частоту:

analog.Frequence(SLOW);

и уменьшить разрядность:

  pwm++;
  if(pwm == 100) pwm = 0;
}

 

BabaDusya
BabaDusya аватар
Offline
Зарегистрирован: 13.10.2012

СПАСИБО Максим!         

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

maksim пишет:

И так. Качаем архив, распаковываем его как обычно в ...\arduino-1.х\libraries\ , запускаем IDE, в примерах должна появиться вкладка PWM и в ней 3 примера. 

Перезалейте пожалуйста архив.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Перезалейте пожалуйста архив, по Вашей сылке битый.

maksim
Offline
Зарегистрирован: 12.02.2012
Сяу Ляу Вей
Offline
Зарегистрирован: 25.10.2013

maksim пишет:
Видеo 

Тоже хочу использовать  составной 2-х монитор, но есть информация  о 4-х или 6-х рамочном  + контроллерном объединителе.

Какая у вас модель?

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Спасибо.

ilyer
Offline
Зарегистрирован: 28.11.2013

а вот частоту следования шим, можно изменить, повысить до 3кгц?

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

Нет.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

А какая частота программного ШИМа? На глаз мерцание не заметно, понятно что больше 24 герц.

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

Да фиг его знает какая, измерьте. А насчет не видно... я например и 3 кГц вижу - когда взгляд отводишь в сторону видны шлейфы.

Может чуть позже выложу данную либу с возможностью задавать выводы до компиляции кода (через директивы препроцессора), а управление выводами через asm-вставки будут организованы, что сэкономит "пару" тактов на обработку кажного вывода. В результате можно будет при небольшом количестве выводов значительно увеличить частоту.

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

Как обещал - новая версия либы. Старую удалить. Как таковая библиотека отсутствует, все находится в файле PWM.ino, который вложен в примеры.

Пример:

#define PIN_12
#define PIN_13

int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

void setup()  
{
  Init_PWM();
  analog_Frequence(2); // предделитель от 1 до 7
}

void loop()  
{ 
  analog_Write(12, 255-brightness);    
  analog_Write(13, brightness);

  brightness = brightness + fadeAmount;

  if (brightness == 0 || brightness == 255) fadeAmount = -fadeAmount ; 
    
  delay(50);                            
}

PWM.ino:

#ifdef ALL
#define PIN_0
#define PIN_1
#define PIN_2
#define PIN_3
#define PIN_4
#define PIN_5
#define PIN_6
#define PIN_7
#define PIN_8
#define PIN_9
#define PIN_10
#define PIN_11
#define PIN_12
#define PIN_13
#define PIN_14
#define PIN_15
#define PIN_16
#define PIN_17
#define PIN_18
#define PIN_19
#endif

#define SBI(port, pin) asm volatile ("sbi %0, %1" :: "I" (_SFR_IO_ADDR(port)), "I" (pin))

#define CHECK(pwms, port, pin) \
asm volatile ( \
   "cpc %0, %1      \n\t" \
   "brlo 0f         \n\t" \
   "cbi %2, %3      \n\t" \
   "rjmp 1f         \n\t" \
   "0: sbi %2, %3   \n\t" \
   "1: nop          \n\t" \
   : "+r" (pwm), "+r" (pwms) \
   : "I" (_SFR_IO_ADDR(port)), "I" (pin)\
   )\
   
void Init_PWM()
{
  cli();
  TCCR2A = 0;   
  TCCR2B = 3;   //CLK
  OCR2A = 1;
  TIMSK2 = 2;   //разрешаем прерывание по совпадению
  sei();

#ifdef PIN_0
  SBI(DDRD, 0);
#endif
#ifdef PIN_1
  SBI(DDRD, 1);
#endif
#ifdef PIN_2
  SBI(DDRD, 2);
#endif
#ifdef PIN_3
  SBI(DDRD, 3);
#endif
#ifdef PIN_4
  SBI(DDRD, 4);
#endif
#ifdef PIN_5
  SBI(DDRD, 5);
#endif
#ifdef PIN_6
  SBI(DDRD, 6);
#endif
#ifdef PIN_7
  SBI(DDRD, 7);
#endif
#ifdef PIN_8
  SBI(DDRB, 0);
#endif
#ifdef PIN_9
  SBI(DDRB, 1);
#endif
#ifdef PIN_10
  SBI(DDRB, 2);
#endif
#ifdef PIN_11
  SBI(DDRB, 3);
#endif
#ifdef PIN_12
  SBI(DDRB, 4);
#endif
#ifdef PIN_13
  SBI(DDRB, 5);
#endif
#ifdef PIN_14
  SBI(DDRC, 0);
#endif
#ifdef PIN_15
  SBI(DDRC, 1);
#endif
#ifdef PIN_16
  SBI(DDRC, 2);
#endif
#ifdef PIN_17
  SBI(DDRC, 3);
#endif
#ifdef PIN_18
  SBI(DDRC, 4);
#endif
#ifdef PIN_19
  SBI(DDRC, 5);
#endif
} 

volatile uint8_t pwm;
volatile uint8_t pwms[20];

void analog_Frequence(byte prescaler)
{
  TCCR2B = prescaler;   //CLK
}

void analog_Write(byte pin, byte value)
{
  pwms[pin] = value;
}

byte analog_State(byte pin)
{
  return pwms[pin];
}

ISR(TIMER2_COMPA_vect)
{
asm volatile ("clr %0" : "+r" (TCNT2)); // TCNT2 = 0;

#ifdef PIN_0
  CHECK(pwms[0], PORTD, 0);
#endif
#ifdef PIN_1
  CHECK(pwms[1], PORTD, 1);
#endif
#ifdef PIN_2
  CHECK(pwms[2], PORTD, 2);
#endif
#ifdef PIN_3
  CHECK(pwms[3], PORTD, 3);
#endif
#ifdef PIN_4
  CHECK(pwms[4], PORTD, 4);
#endif
#ifdef PIN_5
  CHECK(pwms[5], PORTD, 5);
#endif
#ifdef PIN_6
  CHECK(pwms[6], PORTD, 6);
#endif
#ifdef PIN_7
  CHECK(pwms[7], PORTD, 7);
#endif
#ifdef PIN_8
  CHECK(pwms[8], PORTB, 0);
#endif
#ifdef PIN_9
  CHECK(pwms[9], PORTB, 1);
#endif
#ifdef PIN_10
  CHECK(pwms[10], PORTB, 2);
#endif
#ifdef PIN_11
  CHECK(pwms[11], PORTB, 3);
#endif
#ifdef PIN_12
  CHECK(pwms[12], PORTB, 4);
#endif
#ifdef PIN_13
  CHECK(pwms[13], PORTB, 5);
#endif
#ifdef PIN_14
  CHECK(pwms[14], PORTC, 0);
#endif
#ifdef PIN_15
  CHECK(pwms[15], PORTC, 1);
#endif
#ifdef PIN_16
  CHECK(pwms[16], PORTC, 2);
#endif
#ifdef PIN_17
  CHECK(pwms[17], PORTC, 3);
#endif
#ifdef PIN_18
  CHECK(pwms[18], PORTC, 4);
#endif
#ifdef PIN_19
  CHECK(pwms[19], PORTC, 5);
#endif

asm volatile ("inc %0" : "+r" (pwm)); //pwm++;
}

P.S. #define ALL задействует все 20 выводов дуины.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Спасибо :)

ilyer
Offline
Зарегистрирован: 28.11.2013

то есть выше 490гц нельзя? синусоиду с частотой 400гц на ноги вывести невозможно?

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

Почему 490? Как увеличить частоту аппаратного ШИМа читайте тут. Здесвь же программный ШИМ и частота зависит от предделителя и количества задействованых выводов.

ilyer
Offline
Зарегистрирован: 28.11.2013

4 вывода. один с опорнойй синусоидой а 3 - фазные смещенные относ друг друга на 120. как это грамотно описать?

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

У меня данная библиотека конфликтует IRRemote на UNO (обе используют TIMER2)

Можно ктото задействовал TIMER1 ?

Или проще IRremote перенастроить ?

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

Можно сделать как хотите. Как изменить эту любу обсуждалось, а в IRremote есть возможность поменять таймер.

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

maksim пишет:

Можно сделать как хотите. Как изменить эту любу обсуждалось, а в IRremote есть возможность поменять таймер.

Спасибо. Таймер поменял в IRremote. Все заработало с пол-пинка

ilyer
Offline
Зарегистрирован: 28.11.2013

maksim пишет:

Почему 490? Как увеличить частоту аппаратного ШИМа читайте тут. Здесвь же программный ШИМ и частота зависит от предделителя и количества задействованых выводов.

я о том, можно ли в analogwrite записывать чаще чем 490гц?

суть моей проблемы в том что в analogwrite пишутся значения из массива (256 значений описывающих один период синусоиды). генерируется несущая у которой должна быть частота 400гц на выходе. с частотой шима в 490 я никак не смогу записать 400*256=102400значений в секунду. какие есть варианты?

ites
Offline
Зарегистрирован: 26.12.2013

Не получилось скачать архив. Было интересно посмотреть что там.

amvolkov
Offline
Зарегистрирован: 22.12.2013

Использую эту библиотеку на Arduino Nano. Подключены 1.8 inch TFT color display (HY-1.8 SPI), часы DS1302, датчик температуры и влажности DHT11, энкодер, кнопка и блютуз.  На дисплей вывод время/температура, уровень яркости RGB светодиодов. Светодиоды подключены к аналоговым выходам ( analog.Mode(17, OUTPUT); // R и дальше...) 

Все это работает, но при опросе датчика температуры (раз в минуту) светодиоды мигают.





  float h = dht.readHumidity();
  float t = dht.readTemperature();

Я проверял, именно в этом месте светодиоды тухнут. Где-то было написано, что опрос происходит медленно, 250мс. Без подключения библиотеки PWM.h такого не происходит. А мне нехватает ШИМ выходов. Пробовал разные библиотеки DHT11, заработала только одна.

Подскажите, пожалуйста, как с этим бороться? Менять датчик на DHT22?

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

amvolkov пишет:

Я проверял, именно в этом месте светодиоды тухнут. Где-то было написано, что опрос происходит медленно, 250мс. Без подключения библиотеки PWM.h такого не происходит. А мне нехватает ШИМ выходов. Пробовал разные библиотеки DHT11, заработала только одна.

Подскажите, пожалуйста, как с этим бороться? Менять датчик на DHT22?

DHT22 быстрее работать не будет, только точнее. Протокол у него тот же. Можно датчик пореже опрашивать. Но программный PWM все равно будет в это время тормозить. Лучше всего поменять датчик на i2C или аналоговый типа LM335. Тогда опрос будет быстрее. 

При стоимости Arduino Pro Micro 3$ может дешевле отдельный контроллер на PWM поставить?

amvolkov
Offline
Зарегистрирован: 22.12.2013

sav13 пишет:

DHT22 быстрее работать не будет, только точнее. Протокол у него тот же. Можно датчик пореже опрашивать. Но программный PWM все равно будет в это время тормозить. Лучше всего поменять датчик на i2C или аналоговый типа LM335. Тогда опрос будет быстрее. 

При стоимости Arduino Pro Micro 3$ может дешевле отдельный контроллер на PWM поставить?

Да, скорее всего, буду пробовать отдельный контроллер...

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

amvolkov пишет:

Использую эту библиотеку на Arduino Nano. Подключены 1.8 inch TFT color display (HY-1.8 SPI), часы DS1302, датчик температуры и влажности DHT11, энкодер, кнопка и блютуз.  На дисплей вывод время/температура, уровень яркости RGB светодиодов. Светодиоды подключены к аналоговым выходам ( analog.Mode(17, OUTPUT); // R и дальше...) 

Все это работает, но при опросе датчика температуры (раз в минуту) светодиоды мигают.


  float h = dht.readHumidity();
  float t = dht.readTemperature();

Я проверял, именно в этом месте светодиоды тухнут. Где-то было написано, что опрос происходит медленно, 250мс. Без подключения библиотеки PWM.h такого не происходит. А мне нехватает ШИМ выходов. Пробовал разные библиотеки DHT11, заработала только одна.

Подскажите, пожалуйста, как с этим бороться? Менять датчик на DHT22?

Дело в том, что во время опроса библиотека dht в определенные моменты запрещает прерывания, в результате останавливается и ШИМ. Можно попробовать убрать запреты, закомментировав по всей библиотеке все //cli();, но тогда скорее всего датчик не будет опрашиваться...

amvolkov
Offline
Зарегистрирован: 22.12.2013

Спасибо, maksim! Я понял источник проблемы. Главное, что вся связка у меня работает. Теперь до ума доводить буду. 

kentik
Offline
Зарегистрирован: 28.03.2013

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

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

Берите эту #30, той уже нет.

NE_XT
NE_XT аватар
Offline
Зарегистрирован: 22.05.2012

maksim пишет:

Берите эту #30, той уже нет.

Кстати на Leonardo не компилируется.

PWM.ino: In function 'void Init_PWM()':
PWM:43: error: 'TCCR2A' was not declared in this scope
PWM:44: error: 'TCCR2B' was not declared in this scope
PWM:45: error: 'OCR2A' was not declared in this scope
PWM.ino: In function 'void analog_Frequence(byte)':
PWM:116: error: 'TCCR2B' was not declared in this scope
PWM.ino: In function 'void TIMER2_COMPA_vect()':
PWM:131: error: 'TCNT2' was not declared in this scope
maksim
Offline
Зарегистрирован: 12.02.2012

Потому что у ATmega32U4 отсутствует второй таймер, а единственный 8-ми битный таймер это TIMER0. В теории если замените двойки на нули должно завестись. 

vvadim
Offline
Зарегистрирован: 23.05.2012

Есть готовый пульт на NANO. Свободны только пины 0 и 1. Можно ли на них генерить шим для управления драйвером шагового двигателя? С помощью библиотеки maksima вроде можно, но не будут ли какие то подводные камни.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Вот так код компилится под мегу 8-ю:

#ifdef ALL
#define PIN_0
#define PIN_1
#define PIN_2
#define PIN_3
#define PIN_4
#define PIN_5
#define PIN_6
#define PIN_7
#define PIN_8
#define PIN_9
#define PIN_10
#define PIN_11
#define PIN_12
#define PIN_13
#define PIN_14
#define PIN_15
#define PIN_16
#define PIN_17
#define PIN_18
#define PIN_19
#endif

#define SBI(port, pin) asm volatile ("sbi %0, %1 \n\t" :: "I" (_SFR_IO_ADDR(port)), "I" (pin))

#define CHECK(pwms, port, pin) \
asm volatile ( \
   "cpc %0, %1      \n\t" \
   "brlo 0f         \n\t" \
   "cbi %2, %3      \n\t" \
   "rjmp 1f         \n\t" \
   "0: sbi %2, %3   \n\t" \
   "1: nop          \n\t" \
   : "+r" (pwm), "+r" (pwms) \
   : "I" (_SFR_IO_ADDR(port)), "I" (pin)\
   )\
   
void Init_PWM()
{
  cli();
  TCCR1A = 0;   
  TCCR1B = 3;   //CLK
  OCR1A = 1;
  TIMSK = 2;   //разрешаем прерывание по совпадению
  sei();

#ifdef PIN_0
  SBI(DDRD, 0);
#endif
#ifdef PIN_1
  SBI(DDRD, 1);
#endif
#ifdef PIN_2
  SBI(DDRD, 2);
#endif
#ifdef PIN_3
  SBI(DDRD, 3);
#endif
#ifdef PIN_4
  SBI(DDRD, 4);
#endif
#ifdef PIN_5
  SBI(DDRD, 5);
#endif
#ifdef PIN_6
  SBI(DDRD, 6);
#endif
#ifdef PIN_7
  SBI(DDRD, 7);
#endif
#ifdef PIN_8
  SBI(DDRB, 0);
#endif
#ifdef PIN_9
  SBI(DDRB, 1);
#endif
#ifdef PIN_10
  SBI(DDRB, 2);
#endif
#ifdef PIN_11
  SBI(DDRB, 3);
#endif
#ifdef PIN_12
  SBI(DDRB, 4);
#endif
#ifdef PIN_13
  SBI(DDRB, 5);
#endif
#ifdef PIN_14
  SBI(DDRC, 0);
#endif
#ifdef PIN_15
  SBI(DDRC, 1);
#endif
#ifdef PIN_16
  SBI(DDRC, 2);
#endif
#ifdef PIN_17
  SBI(DDRC, 3);
#endif
#ifdef PIN_18
  SBI(DDRC, 4);
#endif
#ifdef PIN_19
  SBI(DDRC, 5);
#endif
} 

volatile uint8_t pwm;
volatile uint8_t pwms[20];

void analog_Frequence(byte prescaler)
{
  TCCR1B = prescaler;   //CLK
}

void analog_Write(byte pin, byte value)
{
  pwms[pin] = value;
}

byte analog_State(byte pin)
{
  return pwms[pin];
}

ISR(TIMER1_COMPA_vect)
{
asm volatile ("clr %0" : "+r" (TCNT2)); // TCNT2 = 0;

#ifdef PIN_0
  CHECK(pwms[0], PORTD, 0);
#endif
#ifdef PIN_1
  CHECK(pwms[1], PORTD, 1);
#endif
#ifdef PIN_2
  CHECK(pwms[2], PORTD, 2);
#endif
#ifdef PIN_3
  CHECK(pwms[3], PORTD, 3);
#endif
#ifdef PIN_4
  CHECK(pwms[4], PORTD, 4);
#endif
#ifdef PIN_5
  CHECK(pwms[5], PORTD, 5);
#endif
#ifdef PIN_6
  CHECK(pwms[6], PORTD, 6);
#endif
#ifdef PIN_7
  CHECK(pwms[7], PORTD, 7);
#endif
#ifdef PIN_8
  CHECK(pwms[8], PORTB, 0);
#endif
#ifdef PIN_9
  CHECK(pwms[9], PORTB, 1);
#endif
#ifdef PIN_10
  CHECK(pwms[10], PORTB, 2);
#endif
#ifdef PIN_11
  CHECK(pwms[11], PORTB, 3);
#endif
#ifdef PIN_12
  CHECK(pwms[12], PORTB, 4);
#endif
#ifdef PIN_13
  CHECK(pwms[13], PORTB, 5);
#endif
#ifdef PIN_14
  CHECK(pwms[14], PORTC, 0);
#endif
#ifdef PIN_15
  CHECK(pwms[15], PORTC, 1);
#endif
#ifdef PIN_16
  CHECK(pwms[16], PORTC, 2);
#endif
#ifdef PIN_17
  CHECK(pwms[17], PORTC, 3);
#endif
#ifdef PIN_18
  CHECK(pwms[18], PORTC, 4);
#endif
#ifdef PIN_19
  CHECK(pwms[19], PORTC, 5);
#endif

asm volatile ("inc %0 \n\t" : "+r" (pwm)); //pwm++;
}

Но ничего не происходит :(