подскажите как ШИМом сделать 0
- Войдите на сайт для отправки комментариев
Добрый день!
Помогите разобраться с ШИМ.
На многих сайтах пишут, что изменяя содержимое регистра сравнения OCR от 0 до 256 можно регулировать коэффициент заполнения сигнала от 0 до 1. Но у меня получается, что если записать в OCR 0, то диод, подключенный к выходу ШИМ, продолжает чуть-чуть светится. Частота ШИМ 62,5 кГц.
В книжке Хартова "Микроконтроллеры АВР" написано следующее: "Если в регистре сравнения содержится 0, то на выходе будут наблюдаться короткие выбросы". После того как счетный регистр TCNT переполнен он обнуляется и в этот момент времени его значение совпадает с значением нуля в OCR - на выходе формируется коротенький импульс.
Подскажите как этого избежать. Получается, что если даже в OCR будет 0, то контроллер будет ШИМом пытаться открывать ключи в схеме? Работаю с Atmega2560 (arduino atmega). Пишу на С через AVRstudio.
Спасибо.
А так пробовали?
AnalogWrite
На других языках также - режим вывода, в запись цифрового регистра ЛОГ 0
Если пишете на С напрямую, то проще отключать соответствующий таймер для подачи нуля.
Кстати, содержимое восьмибитного регистра не может изменяться от 0 до 256, только от 0 до 255.
Весь таймер, наверное, отключать не стоит вдруг это 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 не равен нулю, то устанавливаем COM0A1 в единицу иначе сбрасываем в ноль.
http://arduino.ru/forum/apparatnye-voprosy/shim-bolee-chem-8-bit#comment-24593
Спасибо большое!
С COM битами все получилось.
Биты OCIE0B (2) и OCIE0A (1) разрешают прерывания при совпадении с A и B, а бит TOIE0 (0) разрешает прерывание по переполнению при установке 1. Если в эти биты записать 0, прерывания от таймера/счетчика будут запрещены.
ах ты некромант проклятый!!! :)
Paul_B - просто обрабатывайте "ноль" как особый случай
ах ты некромант проклятый!!! :)
Просто сам столкнулся с проблемой на ATtiny13. Управляю сервой. С вывода PB0 все управляется нормально, а просто в программе меняю PB0 на PB1 и ни черта не работает. Начал копать, думаю все дело в ШИМ.
Никаких регистров, связанных с таймером T0 не менял, все стоит по умолчанию, а остаточное свечение светодиода на PB0 присутствует, что связано с тем, что таймер по переполнению все-таки по умолчанию работает. Возмодно это таймер на ноге PB1 "устраивает пляски", что сервой управлять невозмодно становится.
под 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 }все оказалось прозаично - у pb1 не хватало мощности прокачать серво - уровень сигнала проваливался до 1В. Поставил через транзистор и все стало ок.
ты PB1 сразу к серве подключал штоли, гений?
ты PB1 сразу к серве подключал штоли, гений?
нормальный электронщик может подключить шо угодно куда угодно...
У сервы есть +5В, Земля и управляющий провод. Так вот PB0 нормально управлял сервой, просадки нет абсолютно. Почему просадка на PB1 я не знаю (смотрю через осциоллограф).