подскажите как ШИМом сделать 0

rich.richmond
Offline
Зарегистрирован: 02.05.2013

 Добрый день!

Помогите разобраться с ШИМ.

На многих сайтах пишут, что изменяя содержимое регистра сравнения OCR от 0 до 256 можно регулировать коэффициент заполнения сигнала от 0 до 1. Но у меня получается, что если записать в OCR 0, то диод, подключенный к выходу ШИМ, продолжает чуть-чуть светится. Частота ШИМ 62,5 кГц.

В книжке Хартова "Микроконтроллеры АВР" написано следующее: "Если в регистре сравнения содержится 0, то на выходе будут наблюдаться короткие выбросы". После того как счетный регистр TCNT переполнен он обнуляется и в этот момент времени его значение совпадает с значением нуля в OCR - на выходе формируется коротенький импульс.

Подскажите как этого избежать. Получается, что если даже в OCR будет 0, то контроллер будет ШИМом пытаться открывать ключи в схеме? Работаю с Atmega2560 (arduino atmega). Пишу на С через AVRstudio.

Спасибо. 

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

А так пробовали?

digitalWrite(PWM,LOW);

AnalogWrite

На других языках также -  режим вывода, в запись цифрового регистра ЛОГ 0

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

Если пишете на С напрямую, то проще отключать соответствующий таймер для подачи нуля.

Кстати, содержимое восьмибитного регистра не может изменяться от 0 до 256, только от 0 до 255.

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

Весь таймер, наверное, отключать не стоит вдруг это TIMER0 или на нем еще что-то крутится. Лучше отключить конкретную ногу МК в регистре TCCRA сбросив биты COMA1/COMB1 и COMA0/COMB0 в нули - Normal port operation, OCA/OCB disconnected.

Пример на TIMER0 для ноги OC0A для режима Fast PWM Mode, в этом режиме COM0A0 всегда равен нулю (Clear OC0A on Compare Match, set OC0A at BOTTOM), поэтому что бы отключить/включить ШИМ достаточно изменить состояние бита COM0A1:

OCR0A ? TCCR0A |= 1<<COM0A1 : TCCR0A &= ~(1<<COM0A1);

если OCR0A не равен нулю, то устанавливаем COM0A1 в единицу иначе сбрасываем в ноль.

http://arduino.ru/forum/apparatnye-voprosy/shim-bolee-chem-8-bit#comment-24593

rich.richmond
Offline
Зарегистрирован: 02.05.2013

Спасибо большое!

С COM битами все получилось. 

Paul_B
Offline
Зарегистрирован: 05.12.2016
Регистр TIMSK0:
7
6
5
4
3
2
1
0
-
-
-
-
-
OCIE0B
OCIE0A
TOIE0
 

Биты OCIE0B (2) и OCIE0A (1) разрешают прерывания при совпадении с A и B, а бит TOIE0 (0) разрешает прерывание по переполнению при установке 1. Если в эти биты записать 0, прерывания от таймера/счетчика будут запрещены.
 
Может попробовать установить
TIMSK0 = 0;

 

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ах ты некромант проклятый!!! :) 

b707
Offline
Зарегистрирован: 26.05.2017

Paul_B - просто обрабатывайте "ноль" как особый случай

Paul_B
Offline
Зарегистрирован: 05.12.2016

DetSimen пишет:

ах ты некромант проклятый!!! :) 

Просто сам столкнулся с проблемой на ATtiny13. Управляю сервой. С вывода PB0 все управляется нормально, а просто в программе меняю PB0 на PB1 и ни черта не работает. Начал копать, думаю все дело в ШИМ.

Никаких регистров, связанных с таймером T0 не менял, все стоит по умолчанию, а остаточное свечение светодиода на PB0 присутствует, что связано с тем, что таймер по переполнению все-таки по умолчанию работает. Возмодно это таймер на ноге PB1 "устраивает пляски", что сервой управлять невозмодно становится.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

под attiny13 не пробовал, но вот код под 85ю, подсветка коридора по датчику движения,

по окончании времени, отключаю ШИМ совсем, все отлично работает

#include <avr/io.h>
#include <util/delay.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// PB0 pin 5 - first led wave
#define PB0_OUT sbi(DDRB,PB0)
#define PB0_IN cbi(DDRB,PB0)
#define PB0_HIGH sbi(PORTB,PB0)
#define PB0_LOW cbi(PORTB,PB0)
// PB1 pin 6 - second led wave
#define PB1_OUT sbi(DDRB,PB1)
#define PB1_IN cbi(DDRB,PB1)
#define PB1_HIGH sbi(PORTB,PB1)
#define PB1_LOW cbi(PORTB,PB1)
// PB2 pin 7 - not use
#define PB2_OUT sbi(DDRB,PB2)
#define PB2_IN cbi(DDRB,PB2)
#define PB2_HIGH sbi(PORTB,PB2)
#define PB2_LOW cbi(PORTB,PB2)
// PB3 pin 2 - PIR device
#define PB3_OUT sbi(DDRB,PB3)
#define PB3_IN cbi(DDRB,PB3)
#define PB3_HIGH sbi(PORTB,PB3)
#define PB3_LOW cbi(PORTB,PB3)
#define PB3_READ bitRead(PINB,PB3)
// PB4 pin 3 - not use
#define PB4_OUT sbi(DDRB,PB4)
#define PB4_IN cbi(DDRB,PB4)
#define PB4_HIGH sbi(PORTB,PB4)
#define PB4_LOW cbi(PORTB,PB4)

#define WORK_LEVEL_LED 1
#define WORK_LEVEL_KEY 1

#if (WORK_LEVEL_LED == 0)
#define LED1ON PB0_LOW
#define LED2ON PB1_LOW
#define LED1OFF PB0_HIGH
#define LED2OFF PB1_HIGH
#define BR1LED OCR0A=255-bright_heart_led
#define BR2LED OCR0B=255-bright_heart_led
#else
#define LED1ON PB0_HIGH
#define LED2ON PB1_HIGH
#define LED1OFF PB0_LOW
#define LED2OFF PB1_LOW
#define BR1LED OCR0A=bright_heart_led
#define BR2LED OCR0B=bright_heart_led
#endif

#if (WORK_LEVEL_KEY == 0)
#define KEYINIT PB3_HIGH
#define KEYTEST PB3_READ==0
#else
#define KEYINIT PB3_LOW
#define KEYTEST PB3_READ==1
#endif

byte deviceMode = 0; // 0-off, 1 minimal light 2 full light
byte bright_heart_led;
boolean flag_people;
unsigned long timer_Led;
unsigned long timer_People;

void setup() {
  // put your setup code here, to run once:
  // init pins
  PB0_OUT; LED1OFF;
  PB1_OUT; LED2OFF;
  PB2_OUT; PB2_LOW; // off unusedpin
  PB3_IN; KEYINIT;
  PB4_OUT; PB4_LOW; // off unusedpin
  // hard pwm
  cbi(TCCR0B, CS02); sbi(TCCR0B, CS01); cbi(TCCR0B, CS00); // N=8
  sbi(TCCR0A, WGM01); sbi(TCCR0A, WGM01); // pwm mode
  // if need 9600 bod = count clock/N/9600-1  = 8000000/8/9600-1 = 103
  // real clock pwm = clock/(n*256) = 8000000/(8*256) = 3906 Hz
}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long current_millis = millis();
  switch (deviceMode) {
    case 1: {
        if ((current_millis - timer_Led) >= 15) { // 4000ms/255 bright level
          timer_Led = current_millis;
          if ((++bright_heart_led) >= 240) {
            if (flag_people) {
              pwm1off();
              LED1ON;
              deviceMode = 3;
              timer_People = current_millis;
              bright_heart_led = 0;
              pwm2on();
              flag_people = false;
            } else {
              deviceMode = 2;
              bright_heart_led = 255;
            }
          } else {
            BR1LED; // pwm level PB0
          }
        }
        break;
      }
    case 2: {
        if ((current_millis - timer_Led) >= 15) { // 4000ms/255 bright level
          timer_Led = current_millis;
          if ((--bright_heart_led) <= 15) {
            pwm1off();
            LED1OFF;
            deviceMode = 0;
          } else {
            BR1LED; // pwm level PB0
          }
        }
        break;
      }
    case 3: {
        if ((current_millis - timer_Led) >= 11) { // 3000ms/255 bright level
          timer_Led = current_millis;
          if ((++bright_heart_led) >= 240) {
            pwm2off();
            LED2ON;
            timer_People = current_millis;
            flag_people = false;
            deviceMode = 4;
          } else {
            BR2LED; // pwm level PB1
          }
        }
        break;
      }
    case 4: {
        if ((current_millis - timer_Led) >= 10000) { // 10 sec max light
          timer_Led = current_millis;
          if (flag_people) {
            timer_People = current_millis;
            flag_people = false;
          } else {
            bright_heart_led = 255;
            pwm1on();
            pwm2on();
            deviceMode = 5;
          }
        }
        break;
      }
    case 5: {
        if ((current_millis - timer_Led) >= 7) { // 2000ms/255 bright level
          timer_Led = current_millis;
          if ((--bright_heart_led) <= 10) {
            pwm1off();
            LED1OFF;
            pwm2off();
            LED2OFF;
            deviceMode = 0;
          } else {
            BR1LED; // pwm level PB0
            BR2LED; // pwm level PB1
          }
        }
        break;
      }
    default: { // mode 0
        if (KEYTEST) {
          deviceMode = 1;
          timer_Led = current_millis;
          timer_People = current_millis;
          bright_heart_led = 0;
          pwm1on();
          flag_people = false;
        }
      }
  }
  if ((current_millis - timer_People) >= 700) { // every 0.7 sec test pir device
    timer_People = current_millis;
    if (KEYTEST) {
      flag_people = true;
    }
  }
}

void pwm1on() {
  sbi(TCCR0A, COM0A1); cbi(TCCR0A, COM0A0); // pwm mode PB0
  //sbi(TCCR0A, WGM01); sbi(TCCR0A, WGM01); // pwm mode PB0
  BR1LED; // pwm level PB0
}

void pwm2on() {
  sbi(TCCR0A, COM0B1); cbi(TCCR0A, COM0B0); // pwm mode PB1
  //sbi(TCCR0A, WGM01); sbi(TCCR0B, WGM01); // pwm mode PB1
  BR2LED; // pwm level PB1
}

void pwm1off() {
  cbi(TCCR0A, COM0A1); cbi(TCCR0A, COM0A0); // no pwm mode PB0
  //sbi(TCCR0A, WGM01); cbi(TCCR0A, WGM01); // no pwm mode PB0
}

void pwm2off() {
  cbi(TCCR0A, COM0B1); cbi(TCCR0A, COM0B0); // no pwm mode PB1
  //sbi(TCCR0A, WGM01); cbi(TCCR0B, WGM01); // no pwm mode PB1
}

 

Paul_B
Offline
Зарегистрирован: 05.12.2016

все оказалось прозаично - у pb1 не хватало мощности прокачать серво - уровень сигнала проваливался до 1В. Поставил через транзистор и все стало ок.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ты PB1 сразу к серве подключал штоли, гений?

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

DetSimen пишет:

ты PB1 сразу к серве подключал штоли, гений?

нормальный электронщик может подключить шо угодно куда угодно...

Paul_B
Offline
Зарегистрирован: 05.12.2016

У сервы есть +5В, Земля и управляющий провод. Так вот PB0 нормально управлял сервой, просадки нет абсолютно. Почему просадка на PB1 я не знаю (смотрю через осциоллограф).