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

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

Естественно, TIMER1 16-ти битный, в то время как код написан под 8-битный таймер. Будет время сделаю под 16-ти битный. Но можете и сами посмотреть даташит и настоить по аналогии с 8-ми битным.

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

http://hwmans.blogspot.com/2014/03/attiny13a.html может кому будет полезно.

damber
Offline
Зарегистрирован: 05.10.2014

Выложите библиотеку пожалуйста.

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_Frequency(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_Frequency(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 выводов дуины.

damber
Offline
Зарегистрирован: 05.10.2014

Для ардуино леонардо (китайского образца как про мини выглядит) Нужно менять что ни будь ?

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

Автор, пожалуйста, сделайте по анадлогии программный ШИМ для ATmega8.

redvik
Offline
Зарегистрирован: 10.11.2015

Подскажите на портах где програмный ШИМ только у меня digitalWrite  не работает?

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

Интересная тема. Глубоко "тонет" и всеравно "всплывает" и подход к проблеме очень перспективный. 

Я у себя использую совсем небольшую либку для таймера 1.  Делает она дето следующее:

1. генерирует временные интервалы от 4мксек до 0,5сек для каждого обслуживаемого "устройства". Величины интервалов задает само устройство на каждом такте.

2. Поддерживает такие "устройства": ШИМ 8 бит на любом пине, сервопривод 8бит на любом пине, ШИМ 8 бит на выводе сдвигового регистра расширения, сервопривод 8бит на выводе сдвигового регистра расширенияпроизвольное устройство конечный автомат с временными интервалами.

3. Одновременно работающих устройств - 255 (реально пробовал штук 10 - работает). Т.е. часть из них ШИМ, часть сервами ворочает, а какое-то морзянкой мигает.

4. Работа с пинами напрямую, использовать digitalWrite можно, но не желательно.

Работает на Нано и Мини. На других не тестил, должна работать на любом 328.

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

_mikka
Offline
Зарегистрирован: 01.11.2015

Logik пишет:

Интересная тема. Глубоко "тонет" и всеравно "всплывает" и подход к проблеме очень перспективный. 

Я у себя использую совсем небольшую либку для таймера 1.  Делает она дето следующее:

1. генерирует временные интервалы от 4мксек до 0,5сек для каждого обслуживаемого "устройства". Величины интервалов задает само устройство на каждом такте.

2. Поддерживает такие "устройства": ШИМ 8 бит на любом пине, сервопривод 8бит на любом пине, ШИМ 8 бит на выводе сдвигового регистра расширения, сервопривод 8бит на выводе сдвигового регистра расширенияпроизвольное устройство конечный автомат с временными интервалами.

3. Одновременно работающих устройств - 255 (реально пробовал штук 10 - работает). Т.е. часть из них ШИМ, часть сервами ворочает, а какое-то морзянкой мигает.

4. Работа с пинами напрямую, использовать digitalWrite можно, но не желательно.

Работает на Нано и Мини. На других не тестил, должна работать на любом 328.

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

А моглибы вы хотябы просто исходниками поделиться ?

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

_mikka пишет:

А моглибы вы хотябы просто исходниками поделиться ?

Пробуйте. 

https://cloud.mail.ru/public/5ZoS/8W79KQrZJhttps://cloud.mail.ru/public/5ZoS/8W79KQrZJ

Слегка обрезаная. Без сдвигового регистра как стандартного устройства. Его сейчас потестить не на чем.

Простенький пример.



#include "Timer1.h"

#define LED_PIN 13
#define SHIM_PIN 12
#define SERVO_PIN A1



byte StatusSOS;
word SOS(void* c)
{
  byte status=*(byte*)c;
  word pause=20000;
  switch (status)
  {
   case 0: return pause;
   case 1:
   case 3:
   case 5:
   case 13:
   case 15:
   case 17:
Set1:
         SetPin(LED_PIN, HIGH);
         goto NextStatus;
   case 7:
   case 9:
   case 11:
         pause*=3;
         goto Set1;
   case 25: 
         status=0;  
   default:
         SetPin(LED_PIN, LOW);
NextStatus:
         *(byte*)c=status+1;
         return pause; 
 }
}


TIMER1_ADD_PWM(Shim1, SHIM_PIN)

TIMER1_ADD_SERVO(Servo1,SERVO_PIN)



TIMER1_INTERRUPT_LIST_BEGIN
TIMER1_INTERRUPT_LIST_ADD(SOS, &StatusSOS)
TIMER1_INTERRUPT_LIST_SERVO_ADD(Servo1)
TIMER1_INTERRUPT_LIST_PWM_ADD(Shim1)
TIMER1_INTERRUPT_LIST_END

TIMER1 Timer1SystemObject;


void setup() 
{
  pinMode(SHIM_PIN, OUTPUT);
  pinMode(SERVO_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(115200);
  

  Servo1.Status=1;
  Shim1.Status=1;
  StatusSOS=1;
}

void loop()
{ 
  delay(100);
  Servo1.Phase+=1;
  Shim1.Phase+=10;
}

Шевелит сервой, шимует светодиод а вторым светодиодом SOS сигналит.

_mikka
Offline
Зарегистрирован: 01.11.2015

Logik пишет:

_mikka пишет:

А моглибы вы хотябы просто исходниками поделиться ?

Пробуйте. 

https://cloud.mail.ru/public/5ZoS/8W79KQrZJhttps://cloud.mail.ru/public/5ZoS/8W79KQrZJ

Слегка обрезаная. Без сдвигового регистра как стандартного устройства. Его сейчас потестить не на чем.

Ссылка не работатет, не могу скачать

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

Наверно потому что задвоилась при вставке https://cloud.mail.ru/public/5ZoS/8W79KQrZJ

Megawollt
Offline
Зарегистрирован: 06.12.2015

У меня на уно вообще никак не работает, хотя компилируется без ошибок

splans
splans аватар
Offline
Зарегистрирован: 06.07.2015

Подскажите, что не так.

Делаю DMX диммер на програмном шиме, нет определяется уровень, где копать, вот так работаек как свитч


#include <DMXSerial.h>
#define PIN_13

void setup()  
{
  DMXSerial.init(DMXReceiver);
  
 
}

void loop()  
{  
  
unsigned long lastPacket = DMXSerial.noDataSince();

analogWrite(13, DMXSerial.read(1));
 
}

ав от так ваще ничего


#include <DMXSerial.h>
#define PIN_13

void setup()  
{
  DMXSerial.init(DMXReceiver);
  Init_PWM();
  analog_Frequence(2);
 
}

void loop()  
{  
  
unsigned long lastPacket = DMXSerial.noDataSince();

analog_Write(13, DMXSerial.read(1));
 
}

 

tolikaka
Offline
Зарегистрирован: 23.05.2013

Здравствуйте, Максим!

Интересует, все-таки, вариант в виде библиотеки (да и ссылки все битые уже). Не могли бы Вы ее выложить сюда. Путем вставки кода в скетчи все получается, но нужен именно библиотечный вариант для вставки в другой мой проект по управлению семисегментным ЖКИ (1/4 multiplex , 1/3 bias)

Сам попытался (после 2 дней разбора семантики Вашего кода), не получается как то создать библиотеку самостоятельно. Знаний и пониманий еще маловато. Подозреваю что можно сделать в таком виде как тут http://robotosha.ru/arduino/multi-tasking-arduino.html 

но видать от переизбытка новой информации за единицу времени, мозги переклинивает.А тут еще и работать надо )

Заранее, премного благодарствую!!

ArhAngeL
Offline
Зарегистрирован: 06.02.2018

Подскажите, кто пользуется этой чудом, почему код программного ШИМ почему-то блокирует обмен по serial. Если в скетче закоментировать строку Init_PWM(); - общение по serial команда/ответ проходят без проблем, как только подключаю код PWM - все, глухо. При попытке вывести значение любой переменной по serial - программа зависает вовсе. Пытался понять, что мешает: предположил, что код PWM задействует ШИМ и на RX TX, так как рассчитан на все пины ардуино. Пробовал оставить только строки с пинами, которые использую - эффект тот же. Видимо там что-то "зарыто" в коде ассемблера...

Моя программа:

#define PIN_4                  
#define PIN_7                  

int brightnessDDR = 0;         // яркость модулей ОЗУ
int fadeAmountDDR = 1;         // прирощение яркости ОЗУ
int modDDR = 3;                // режим подсветки ОЗУ
int incomingByte;              // переменная сериал

void setup()  
{
  Init_PWM();
  analog_Frequence(3); // предделитель от 1 до 7 частоты ШИМ
  pinMode(4, OUTPUT);
  pinMode(7, OUTPUT);
  Serial.begin(9600); // скорость порта 9600
}

void loop()  
{ 
    if (Serial.available() > 0) {
      incomingByte = Serial.read() ;
      if(incomingByte == '0'){
          modDDR = 0 ;
          Serial.println("Подсветка DDR отключена") ;
      }
      else if (incomingByte == '1'){
          modDDR = 1 ;
          Serial.println("Подсветка DDR постоянное свечение") ;
      }
      else if (incomingByte == '2'){
          modDDR = 2 ;
          Serial.println("Подсветка DDR синхронное дыхание") ;
      }
      else if (incomingByte == '3'){
          modDDR = 3 ;
          Serial.println("Подсветка DDR асинхронное дыхание") ;
      }  
    }
      
  if (modDDR == 0) {
      brightnessDDR = 0 ;
      analog_Write(4, brightnessDDR) ;    
      analog_Write(7, brightnessDDR) ;
  }
  if (modDDR == 1) {
      brightnessDDR = 50 ;
      analog_Write(4, brightnessDDR) ;    
      analog_Write(7, brightnessDDR) ;  
  }
  if (modDDR == 2) {
      analog_Write(4, brightnessDDR) ;    
      analog_Write(7, brightnessDDR) ;
      brightnessDDR = brightnessDDR + fadeAmountDDR ;
      if (brightnessDDR == 0 || brightnessDDR == 50) {
          fadeAmountDDR = -fadeAmountDDR ; 
      }
  }
  if (modDDR == 3) {
      analog_Write(4, 50-brightnessDDR) ;    
      analog_Write(7, brightnessDDR) ;
      brightnessDDR = brightnessDDR + fadeAmountDDR ;
      if (brightnessDDR == 0 || brightnessDDR == 50) {
          fadeAmountDDR = -fadeAmountDDR ; 
      }
  }
  delay(40);
}
#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 ( \
   "cp %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)
{
TCNT2 = 0; // asm volatile ("clr %0" : "+r" (TCNT2));

#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++;
}

 

ildaronii
Offline
Зарегистрирован: 30.09.2018

Так где можно найти библиотеку от Maksima?