Слабое мерцание светодиодной ленты при нулевой скважности программного ШИМ

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

Добрый день. Столкнулся с такой проблемой: используя программный ШИМ при выставлении скважности на выходе 0 остается слабое свечение с мерцанием светодиодной ленты.

Вкладка программы

#define PIN_4                  // подсветка FANfront №1
#define PIN_7                  // подсветка FANtop

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

void setup()  
{
  Init_PWM();
  analog_Frequence(1); // предделитель от 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("Подсветка ОЗУ выключены") ;
      }
      else if (incomingByte == '1'){
          modDDR = 1 ;
          Serial.println("Подсветка ОЗУ постоянный режим") ;
      }
      else if (incomingByte == '2'){
          modDDR = 2 ;
          brightnessDDR = 0 ;
          Serial.println("Подсветка ОЗУ синхронная пульсация") ;
      }
      else if (incomingByte == '3'){
          modDDR = 3 ;
          brightnessDDR = 0 ;
          Serial.println("Подсветка ОЗУ асинхронная пульсация") ;
      }      
    }
      
  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);
}  

Вкладка 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++;
}

Схема управления нагрузкой собрана на мосфетах IRF520, токоограничительные резисторы затвора 100 Ом, подтягивающие резисторы 10 кОм, лента 12 В пробовал на разных светодиодах, эффект один и тот же.

Без ардуино лента не горит вообще, утечки через мосфет нет, напряжение на выходе ардуино при скважности 0 тестером не померить, несколько милливольт, осцилографа к сожалению нет. Свечение появляется только после запуска программы контроллера и перехода в режим "отключено".

Информации по этому поводу не нашел в интернете. Само мерцание меня не напрягает и в режиме, когда лента горит или "дышит" - незаметно для глаза. Но почему при скважности 0 на затворе мосфета остается потенциал, который заставляет ленту подсвечиваться мне не понятно.

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

Заранее благодарю за ответ! Не судите строго, если просмотрел эту тему на форуме, но инфу нашел только о сглаживании пульсаций ШИМ.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ArhAngeL, неоднократно обсуждали.  У ШИМа таймером нет нулевого дьюти. Загляните в родную дуиновскую функцию analogWrite, и всё поймёте.

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

dimax пишет:

ArhAngeL, неоднократно обсуждали.  У ШИМа таймером нет нулевого дьюти. Загляните в родную дуиновскую функцию analogWrite, и всё поймёте.

Спасибо. Буду разбираться. Я так понимаю это никак не вылечить.

sadman41
Offline
Зарегистрирован: 19.10.2016

digitalWrite(pin, LOW) ?

ELITE
ELITE аватар
Offline
Зарегистрирован: 11.01.2018

конденсатор припаять к ленте - уберет мерцание

номинал подберете сами исходя из мощности ленты

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ArhAngeL пишет:

Спасибо. Буду разбираться. Я так понимаю это никак не вылечить.

Очень пессимистично дорогой товарищ! Есть как минимум 2 способа, один из них в дуиновской функции.

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

sadman41 пишет:

digitalWrite(pin, LOW) ?

Попробовал на скорую руку - эффект тот же. Завтра плотно позанимаюсь.

ELITE пишет:

конденсатор припаять к ленте - уберет мерцание

номинал подберете сами исходя из мощности ленты

Спасибо, но проблема не в наличии мерцания, о нем и метоах борьбы с ним я в курсе.

dimax пишет:

Очень пессимистично дорогой товарищ! Есть как минимум 2 способа, один из них в дуиновской функции.

2 часа рыл интернет, стандартные функции управления уровнем на пинах не дают ничего.

sadman41
Offline
Зарегистрирован: 19.10.2016

Я считал, что это гарантированно отключает PWM на пине:

void digitalWrite(uint8_t pin, uint8_t val) {
...
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
...
}

 

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

sadman41 пишет:

Я считал, что это гарантированно отключает PWM на пине:

void digitalWrite(uint8_t pin, uint8_t val) {
...
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
...
}

 

Спасибо, попробую завтра. Не силён в синтаксисе, значения менять в строке void digitalWrite(uint8_t pin, uint8_t val) pin = номер пина, а val в данном случае 0?

sadman41
Offline
Зарегистрирован: 19.10.2016

Не совсем понимаю зачем вам менять там что-то. Это исходный код digitalWrite() - внутри себя он выключает PWM на пине перед тем, как установить HIGH или LOW. Так что, на мой взгляд, использование этой функции должно было купировать проблему с мерцанием, если оно действительно вызывано работой PWM.