Щелкунчик

9400
Offline
Зарегистрирован: 15.07.2017

Сделал ультразвуковой отпугиватель крыс на основе программы  ЕвгенияП  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);}
}

 

 

9400
Offline
Зарегистрирован: 15.07.2017

Мучаюсь, но не могу понять откуда берется щелчок. Пытался комбинировать по всякому - понижать частоту, повышать, зщатем понижать чтобы не было резкого разрыва  значения 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);}

 

 

Monday
Offline
Зарегистрирован: 01.07.2017

9400 пишет:
не могу понять откуда берется щелчок. Пытался комбинировать по всякому - понижать частоту, повышать, зщатем понижать чтобы не было резкого разрыва  значения OCR1A, но щелчок все равно возникает. Подскажите в каком направлении искать причину?

Желательно посмотреть осциллографом выходной сигнал. В качестве предположения - соединене двух соседних импульсов на границе циклов при смене значения OCR1A или поведение таймера при изменении OCR1A в неподходящий момент. Попробуйте увеличить частоту в 2-4 раза и если причина действительно в объединении имульсов, щелчок может быть исчезнет

 

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

9400, У вас таймер не в подходящем режиме для вашей задачи работает. Вы меняете регистр сравнения без учёта текущего состояния счётного регистра,  к примеру ситуация-стоп кадр: OCR=300. Таймер уже досчитал до 290. Вы обновляете OCR=280. Что будет? -таймер досчитает до 65535 (возникнет щелчок) потом сброситься и досчитает уже до 280.  Для таких задач есть режим: Phase and Frequency Correct

9400
Offline
Зарегистрирован: 15.07.2017

dimax пишет:
Для таких задач есть режим: Phase and Frequency Correct
в даташите "20.12.4. Phase Correct PWM Mode". По двум описаниям - английскому для 328P (не полностью понимаю смысл) и Евстифееву на русском языке (Atmel ATmega328/P [DATASHEET] page 171; Евстифеев 13.6.3. Режимы работы,  стр. 288)

Если я правильно понял (Таблица 2.93. Режимы работы таймеров/счетчиков T1 и T3), то

в режиме 8-bit "Phase and Frequency Correct PWM",  TOP=0x00FF:  

TCCR1B=(0<<WGM13) | (0<<WGM12) | (0<<WGM11) | (1<<WGM10); // режим 1, Таблица 2.93
OCR1A=TOP=0x000FF;  // TOP

в режиме 9-bit "Phase and Frequency Correct PWM",  TOP=0x01FF:

TCCR1B=(0<<WGM13) | (0<<WGM12) | (1<<WGM11) | (0<<WGM10); // режим 2, Таблица 2.93
OCR1A=0x01FF; // TOP

в режиме 10-bit "Phase and Frequency Correct PWM",  TOP=0x03FF:

TCCR1B=(0<<WGM13) | (0<<WGM12) | (1<<WGM11) | (1<<WGM10); // режим 3, Таблица 2.93
OCR1A=0x03FF; // TOP

Но если О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);} // ??????
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

9400, переведённые справочники лучше сверять ещё и по актуальному даташиту.  Страница 132 , нужный  режим - №8   Биты PWM* к выходам таймера не имеют никакого отношения. Выходами заведуют биты COM*

 

9400
Offline
Зарегистрирован: 15.07.2017

dimax пишет:
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);} 

 

Что-то я неправильно делаю, иначе

// режим 3, Phase correct PWM 10-bit
//зачем присваивать OCR1A=0x03FF; если в цикле все равно его менять?

 

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

9400, вы читаете то, что я вам пишу или нет??   В #5 я вам конкретно написал нужный Вам режим -№8  Phase and Frequency Correct

Нет он за каким-то x... в третью моду настраивает :(

9400
Offline
Зарегистрирован: 15.07.2017

dimax пишет:
9400, вы читаете то, что я вам пишу или нет??   В #5 я вам конкретно написал нужный Вам режим -№8  Phase and Frequency Correct

Нет он за каким-то x... в третью моду настраивает :(

  Ошибся я. Исправил, но что нужно  записать в   ICR1 ?

 

#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:

#define MIN_OCR1A 125
#define MAX_OCR1A 20000

 

9400
Offline
Зарегистрирован: 15.07.2017

Добавил делитель частоты на 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);} 

 

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

Удобнее даже в 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); 
}