Щелкунчик
- Войдите на сайт для отправки комментариев
Сб, 15/07/2017 - 06:30
Сделал ультразвуковой отпугиватель крыс на основе программы ЕвгенияП http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-bl...
Для того, чтобы крысы не привыкали к одинаковой частоте, изменяю ее в цикле. В конце некоторых из циклов, (не каждый раз) скорее всего при переходе с OCR1A=330 на OCR1A=290 , раздается звуковой слышимый щелчок.
Почему он возникает и как его можно устранить?
void setup() {
pinMode(9, OUTPUT);
TCCR1A = 0x40; // Переключение пина 9 по сравнению
TCCR1B = 0x09; // Установить СТС режим и делитель частоты 1
OCR1A = 320; // установить TOP
}
uint16_t i;
byte j;
void loop()
{
for(i=290; i<330; i++)
{
noInterrupts();
OCR1A = i;
interrupts();
delay(3);}
}
Мучаюсь, но не могу понять откуда берется щелчок. Пытался комбинировать по всякому - понижать частоту, повышать, зщатем понижать чтобы не было резкого разрыва значения OCR1A, но щелчок все равно возникает. Подскажите в каком направлении искать причину?
void setup() { pinMode(9, OUTPUT); TCCR1A = 0x40; // Переключение пина 9 по сравнению TCCR1B = 0x09; // Установить СТС режим и делитель частоты 1 OCR1A = 320; // установить TOP } void loop() { count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); count_down(); count_up(); } void count_up (void) {uint16_t i; for(i=290; i<=1000; i++)set_OCR1A(i);} void count_down(void) {uint16_t i; for(i=1000; i<=290; i--)set_OCR1A(i);} void set_OCR1A(uint16_t in_reg){ noInterrupts(); OCR1A = in_reg; interrupts(); delay(2);}Желательно посмотреть осциллографом выходной сигнал. В качестве предположения - соединене двух соседних импульсов на границе циклов при смене значения OCR1A или поведение таймера при изменении OCR1A в неподходящий момент. Попробуйте увеличить частоту в 2-4 раза и если причина действительно в объединении имульсов, щелчок может быть исчезнет
9400, У вас таймер не в подходящем режиме для вашей задачи работает. Вы меняете регистр сравнения без учёта текущего состояния счётного регистра, к примеру ситуация-стоп кадр: OCR=300. Таймер уже досчитал до 290. Вы обновляете OCR=280. Что будет? -таймер досчитает до 65535 (возникнет щелчок) потом сброситься и досчитает уже до 280. Для таких задач есть режим: Phase and Frequency Correct
Если я правильно понял (Таблица 2.93. Режимы работы таймеров/счетчиков T1 и T3), то
в режиме 8-bit "Phase and Frequency Correct PWM", TOP=0x00FF:
в режиме 9-bit "Phase and Frequency Correct PWM", TOP=0x01FF:
в режиме 10-bit "Phase and Frequency Correct PWM", TOP=0x03FF:
Но если ОCR1A уже занят под TOP, как манипулировать частотой ? И еще - в этих режимах выходной сигнал брать не с выхода 9, а с 10 или 11 ? (PWM10, PWM11) Какой из режимов 8-9-или-10 bit выбрать и по какой причине?
Заготовка кода
#define MIN_OCR1A 290 #define MAX_OCR1A 770 // при 770 звуковая частота void setup() { pinMode(9, OUTPUT); // или 10 или 11 ?? TCCR1A = 0x40; // Переключение пина 9 по сравнению // как нужно изменить для режима 3 ???????????????? //TCCR1B = 0x09; // Установить СТС режим и делитель частоты 1 TCCR1B=(0<<WGM13) | (0<<WGM12) | (1<<WGM11) | (1<<WGM10); // режим 3, Phase correct PWM 10-bit OCR1A=0x03FF; // TOP для режим 3, Phase correct PWM 10-bit } void loop() {do_down(); do_up();} void do_up (void) {uint16_t i; for(i=MIN_OCR1A; i<=MAX_OCR1A; i++)set_OCR1A(i);} // ?????? void do_down(void) {uint16_t i; for(i=MAX_OCR1A; i>=MIN_OCR1A; i--)set_OCR1A(i);} // ?????? void set_OCR1A(uint16_t in_reg){ noInterrupts(); OCR1A = in_reg; interrupts(); delay(2);} // ??????9400, переведённые справочники лучше сверять ещё и по актуальному даташиту. Страница 132 , нужный режим - №8 Биты PWM* к выходам таймера не имеют никакого отношения. Выходами заведуют биты COM*
С версиями datasheet двойственная ситуация, я смотрел в Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016 на 440 страницах, а Ваше описание от 2015 года на 660 страницах Atmel-8271J-AVR- ATmega-Datasheet_11/2015. Atmega328P и 32Х одно и то же или разные МК ?
Извините за большое количсетво вопросов, но не могу полностью понять смысл описаний стр 132, помогите пожалуйста разобраться в режиме. Еще какой из 8-9-10 бит лучше использовать и почему?
При таком коде от щелкания удалось избавиться и частота пульсирует, но на слух она явно не 25 кГц как мне требуется. В текущей версии включен дополнительный режим 4 ( //---ДР4), но как он связан с пином 9 не понял, где это есть в описании?
#define MIN_OCR1A 290 #define MAX_OCR1A 340 void setup() { pinMode(9, OUTPUT); //TCCR1A = 0x40; // Переключение пина 9 по сравнению // включен дополнительный режим 4 //---ДР1 //page 132, Table 16-3: Normal port operation, OC1A/OC1B disconnected: //TCCR1A=TCCR1A | (0<<COM1A1)| (0<<COM1A0); //---ДР2 /*page 132, Table 16-3: WGM13:0 = 9 or 11: Toggle OC1A on Compare Match, OC1B disconnected (normal port operation). For all other WGM1 settings, normal port operation OC1A/OC1B disconnected.*/ //TCCR1A=TCCR1A | (0<<COM1A1)| (1<<COM1A0); //---ДР3 /*page 132, Table 16-3: Clear OC1A/OC1B on Compare Match when upcounting. Set OC1A/OC1B on Compare Match when downcounting.*/ //TCCR1A=TCCR1A | 1<<COM1A1| (0<<COM1A0); //---ДР4 /*Set OC1A/OC1B on Compare Match when upcounting. Clear OC1A/OC1B on Compare Match when downcounting.*/ TCCR1A=TCCR1A | (1<<COM1A1) | (1<<COM1A0); TCCR1B=(0<<WGM13) | (0<<WGM12) | (1<<WGM11) | (1<<WGM10); // режим 3, Phase correct PWM 10-bit OCR1A=0x03FF; // TOP для режим 3, Phase correct PWM 10-bit } void loop() {do_down(); do_up();} void do_up (void) {uint16_t i; for(i=MIN_OCR1A; i<=MAX_OCR1A; i++)set_OCR1A(i);} void do_down(void) {uint16_t i; for(i=MAX_OCR1A; i>=MIN_OCR1A; i--)set_OCR1A(i);} void set_OCR1A(uint16_t in_reg){ noInterrupts(); OCR1A = in_reg; interrupts(); delay(3);}Что-то я неправильно делаю, иначе
9400, вы читаете то, что я вам пишу или нет?? В #5 я вам конкретно написал нужный Вам режим -№8 Phase and Frequency Correct
Нет он за каким-то x... в третью моду настраивает :(
Нет он за каким-то x... в третью моду настраивает :(
#define MIN_OCR1A 125 #define MAX_OCR1A 20000 void setup() { pinMode(9, OUTPUT); //TCCR1A = 0x40; // Переключение пина 9 по сравнению // включен дополнительный режим ДР4 //---ДР1 //page 132, Table 16-3: Normal port operation, OC1A/OC1B disconnected: //TCCR1A=TCCR1A | (0<<COM1A1)| (0<<COM1A0); //---ДР2 /*page 132, Table 16-3: WGM13:0 = 9 or 11: Toggle OC1A on Compare Match, OC1B disconnected (normal port operation). For all other WGM1 settings, normal port operation OC1A/OC1B disconnected.*/ //TCCR1A=TCCR1A | (0<<COM1A1)| (1<<COM1A0); //---ДР3 /*page 132, Table 16-3: Clear OC1A/OC1B on Compare Match when upcounting. Set OC1A/OC1B on Compare Match when downcounting.*/ //TCCR1A=TCCR1A | 1<<COM1A1| (0<<COM1A0); //---ДР4 /*Set OC1A/OC1B on Compare Match when upcounting. Clear OC1A/OC1B on Compare Match when downcounting.*/ TCCR1A=TCCR1A | (1<<COM1A1) | (1<<COM1A0); //---основной режим №8 //TCCR1B=(0<<WGM13) | (0<<WGM12) | (1<<WGM11) | (1<<WGM10); // режим 3, Phase correct PWM 10-bit //OCR1A=0x03FF; // TOP для режим 3, Phase correct PWM 10-bit //зачем присваивать OCR1A=0x03FF; если в цикле все равно его менять? TCCR1B=(1<<WGM13) | (0<<WGM12) | (0<<WGM11) | (0<<WGM10); // режим 8, PWM, Phase and Frequency Correct //ICR1= ; // TOP для режим 8, Phase and Frequency Correct } void loop() {do_down(); do_up();} void do_up (void) {uint16_t i; for(i=MIN_OCR1A; i<=MAX_OCR1A; i++)set_register(i);} void do_down(void) {uint16_t i; for(i=MAX_OCR1A; i>=MIN_OCR1A; i--)set_register(i);} void set_register(uint16_t in_reg) { noInterrupts(); OCR1A = in_reg; interrupts(); delay(10);} //{ noInterrupts(); ICR1 = in_reg; interrupts(); delay(3);}PS: слышимый звук пропал при любых значениях OCR1A:
Добавил делитель частоты на 8 - нет результата
void setup() { pinMode(9, OUTPUT); //TCCR1A = 0x40; // Переключение пина 9 по сравнению TCCR1B=TCCR1B |(0<<CS12) | (1<<CS11)| (0<<CS10) ; //делитель частоты на 8 #define MIN_OCR1A 80 #define MAX_OCR1A 800 // дополнительный режим ДР4 /*Set OC1A/OC1B on Compare Match when upcounting. Clear OC1A/OC1B on Compare Match when downcounting.*/ TCCR1A=TCCR1A | (1<<COM1A1) | (1<<COM1A0); //---основной режим №8 TCCR1B=TCCR1B | (1<<WGM13) | (0<<WGM12) | (0<<WGM11) | (0<<WGM10); // режим 8, PWM, Phase and Frequency Correct //ICR1= ; // TOP для режим 8, Phase and Frequency Correct } void loop() {do_down(); do_up();} void do_up (void) {uint16_t i; for(i=MIN_OCR1A; i<=MAX_OCR1A; i++)set_register(i);} void do_down(void) {uint16_t i; for(i=MAX_OCR1A; i>=MIN_OCR1A; i--)set_register(i);} void set_register(uint16_t in_reg) { noInterrupts(); OCR1A = in_reg; interrupts(); delay(10);} //{ noInterrupts(); ICR1 = in_reg; interrupts(); delay(3);}Удобнее даже в 9й режим, в 8ом туглинг выхода невозможен. Попробуйте написать самостоятельно. Если не получится, то вот вариант от меня :)
#include <util/delay.h> #define min_freq 20000ul //Hz #define max_freq 25000ul //Hz #define wait 10000ul //wait in between cycles microseconds void setup() { pinMode(9, OUTPUT); TCCR1B=(1<<CS10)|(1<<WGM13) ; //mode 9, divider=1 TCCR1A=(1<<COM1A0)|(1<<WGM10); //mode 9, Toggle OC1A on Compare TIMSK1=1<<OCIE1A; OCR1A=F_CPU/4/min_freq; } void loop(){} ISR (TIMER1_COMPA_vect) { static boolean dir=1; if (dir) {OCR1A < (F_CPU>>2) / min_freq ? OCR1A++ : dir=!dir ; } else {OCR1A > (F_CPU>>2) / max_freq ? OCR1A-- : dir=!dir ; } _delay_us(wait); }