Ускорение функции micros()

Buldakov
Offline
Зарегистрирован: 17.01.2016

Micros()

Возвращает количество микросекунд с момента начала выполнения текущей программы на плате Arduino. Значение переполняется и сбрасывается на ноль, приблизительно через 70 минут. На 16MHz платах Ардуино функция micros() имеет разрешение 4 микросекунды (возвращаемое значение всегда кратно 4). На 8MHz платах разрешение функции 8 микросекунд.

Как можно улучшить разрешение функции micros() до 2 или 1 микросекунды?

Клапауций 322
Offline
Зарегистрирован: 31.12.2015

ну, очевидно же - 32MHz!

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Ну следуя логике - частотой процессора - на 32 или 64МГц будет 2 или 1 мкс

Buldakov
Offline
Зарегистрирован: 17.01.2016

Нет 32MHz! не правильный ответ. Железо Arduino nano 16 MHz!

Мне нужен программный способ.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Buldakov пишет:

Micros()

Как можно улучшить разрешение функции micros() до 2 или 1 микросекунды?

Написать свою через прерывание от таймера.

Только, надеюсь, Вы понимаете для чего Вам это нужно и как Вы собираетесь этим пользоваться, т.к. микросекунда - это всего лишь 16 команд процессора. Т.е. Ваша программа неминуемо будет вносить искажения. Если нужно точно, то надо считать количество команд и вносить соответсвующие поправки.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Мне нужно точно измерить частоту в диапазоне от 2000 до 10000 Гц.  Желательно с долями герца. Я беру 100 полных тактов частоты и считаю время нужное для этого. Потом время делю на количество тактов. Получаем частоту.

Код пока такой.

//---------------------------------------------------------------------------------------------------------------------------------//
#include <CyberLib.h>                                                                                                              //
#include <Wire.h>                                                                                                                  //
#include <LiquidCrystal_I2C.h>                                                                                                     //
//---------------------------------------------------------------------------------------------------------------------------------//
LiquidCrystal_I2C lcd(0x27, 16, 2); // Для экрана 16х2 (двухстрочный)                                                              //
//---------------------------------------------------------------------------------------------------------------------------------//
unsigned long per1             =100000;  //                                                                                        //
unsigned long interval_LCD     =  1000;  //Интервал смены показаний на LCD в миллисекундах                                         //
unsigned long lastTime_LCD     =     0;  //Время последнего изменения состояния для LCD в миллисекундах                            //
unsigned long DeltaTime_LCD    =     0;  //Время с момента последнего вывода на LCD в миллисекундах                                //
unsigned long currentTime      =     0;  //Текущее время в милисекундах                                                            //
//---------------------------------------------------------------------------------------------------------------------------------//
boolean sig_new,sig_old,triger_new,triger_old;                                                                                     //
unsigned int t4,p1;                                                                                                                //
unsigned long time_1,time_2;                                                                                                       //
float f;                                                                                                                           //
//---------------------------------------------------------------------------------------------------------------------------------//
void setup() {                                                                                                                     //
pinMode(10, INPUT);                     //Назначим вывод 10 на ввод сигналов                                                       //
digitalWrite(10, HIGH);                 //Включаем подтягивающий резистор                                                          //
D10_In;                                                                                                                            //
lcd.init();                             //Задаем размерность LCD дисплея                                                           //
lcd.backlight();                        //Включаем подсветку экрана                                                                //
lcd.clear();                                          //Очистка экрана                                                             //
}                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//
void loop()                                                                                                                        //
{                                                                                                                                  //
//===================================================================================================================================
p1=0;                                                                                                                              //
label_a :                                                                                                                          //
sig_old=sig_new;                                                                                                                   //
triger_old=triger_new;                                                                                                             //
sig_new=D10_Read;                                                                                                                  //
if (sig_old==0 && sig_new==1                            ) {triger_new=1;t4=p1;p1=p1+1;}                                            //
if (sig_old==0 && sig_new==1 && abs(time_2-time_1)>per1 ) {triger_new=0;p1=0;}                                                     //
if (triger_old==0                                       ) time_1=micros();                                                         //
if (triger_old==1 && triger_new==0                      ) {;} else {time_2=micros();goto label_a;}                                 //
//---Условия для вывода показаний на LCD-------------------------------------------------------------------------------------------//
currentTime=millis();                                                                                                              //
DeltaTime_LCD  =abs(currentTime - lastTime_LCD);      //Время с момента последнего вывода на LCD                                   //
if (DeltaTime_LCD >= interval_LCD )                   //Условия вывода на LCD                                                      //
{                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//
f=1000000.0/(abs(time_2-time_1)/(t4*1.0));                                                                                         //
lcd.setCursor(0, 0);lcd.print(t4);                                                                                                 //
lcd.setCursor(8, 0);lcd.print(abs(time_2-time_1));                                                                                 //
lcd.setCursor(0, 1);lcd.print(f,2);                                                                                                //
//---------------------------------------------------------------------------------------------------------------------------------//
lastTime_LCD = currentTime;                                                                                                        //
}                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//
}                                                                                                                                  //
 

axill
Offline
Зарегистрирован: 05.09.2011

Забудьте тогда про micros()

Берете timer1 16 битный с предделителем 1, настраиваете его на режим ctc и заносите в ocr1a=32000

Настраиваете прерывание по сравнению и там увеличиваете своб переменную счетчика unsigned int

Таким образом получаете 32 разрядный счетчик с тактом счета 1/16000000 секунд, т.е. 

Для большей точности счетчик можно запускать в начале полупериода измеряемой частоты, а в конце полупериода брать значение нашего 32бииного счетчика и пересчитывать его в частоту, потом усреднять на цикле из нескольких измерений

Buldakov
Offline
Зарегистрирован: 17.01.2016

За ответ спасибо. Но проблема в том,  что я еще не изучал как программировать таймеры. Поэтому и сделал таймер на программном коде. Буду теперь разбираться в таймерах.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Buldakov пишет:

Буду теперь разбираться в таймерах.

Правильный источник для этого - http://www.atmel.com/images/doc2505.pdf

Ну и даташит на ATMega328 никто не отменял, конечно.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Попробовал поменять параметры 0 таймера.

Добавил код:

TCCR0B = TCCR0B & 0b11111000 | 0x01;
TCCR2B = TCCR2B & 0b11111000 | 0x01;

Все поменялось. Как сделать время 2 или 1 мкс?

Все научился. надо было добавить для стандартных настроек строку:

TCCR0B = TCCR0B & 0b11111000 | 0x03;

 

И еще глупый вопрос по таймерам.

Я хочу на таймере 2 сделать делитель с переменным коэффициентом деления от 1 до 255. Коэффициент деления должен меняться не в Setup , а в Loop(). таймер должен входную частоту делить и выдавать на выход.  Как мне задать в программе номера входных и выходных пинов?

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

В разделе проекты вроде же был частотомер на базе ардуино. Не подходит или не смотрели?

Buldakov
Offline
Зарегистрирован: 17.01.2016

Единственное, что нашел стояшее

http://www.cqham.ru/forum/showthread.php?20109-%D7%E0%F1%F2%EE%F2%EE%EC%...

У остальных низкая точность на низких частотах.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Может чем поможет http://www.gammon.com.au/timers

Buldakov
Offline
Зарегистрирован: 17.01.2016

Pyotr пишет:

Может чем поможет http://www.gammon.com.au/timers

Спасибо. Здесь хоть на английском, но думаю можно разобраться. Именно то , что хотел

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov пишет:

Мне нужно точно измерить частоту в диапазоне от 2000 до 10000 Гц.  Желательно с долями герца. Я беру 100 полных тактов частоты и считаю время нужное для этого. Потом время делю на количество тактов. Получаем частоту.

То, что вы способны придумать  свой способ измерения -это  конечно хорошо. Но есть общепринятый способ измерения, точнее и удобнее. Один 16-битный таймер тактируется от измеряемого сигнала и считает кол-во своих тактов. Второй таймер отмеряет промежуток времени в 1 секунду. Кол-во пойманных тактов за 1 секунду = частота.  Способ многократно обсуждался здесь, приводились готовые решение, давались ссылки на готовые библиотеки. Зачем изобретать велосипед?

Buldakov
Offline
Зарегистрирован: 17.01.2016

dimax пишет:

То, что вы способны придумать  свой способ измерения -это  конечно хорошо. Но есть общепринятый способ измерения, точнее и удобнее. Один 16-битный таймер тактируется от измеряемого сигнала и считает кол-во своих тактов. Второй таймер отмеряет промежуток времени в 1 секунду. Кол-во пойманных тактов за 1 секунду = частота.  Способ многократно обсуждался здесь, приводились готовые решение, давались ссылки на готовые библиотеки. Зачем изобретать велосипед?

А как этим способом померить частоту с точностью 0.01 Гц?  За интервал времени 1 секунда.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, Измерять 100 секунд. И то не факт, что будет точно. Копеечная ардуина не заменит  профессиональный частотомер.  У неё нет на это ни технических возможностей ни эталонного генератора,  частота кварца на ней гуляет на сотню килогерц, какая тут точность.

Buldakov
Offline
Зарегистрирован: 17.01.2016

dimax пишет:

Buldakov, Измерять 100 секунд. И то не факт, что будет точно. Копеечная ардуина не заменит  профессиональный частотомер.  У неё нет на это ни технических возможностей ни эталонного генератора,  частота кварца на ней гуляет на сотню килогерц, какая тут точность.

Ну по поводу кварца. У него стабильность 10-6 что при 16 мгц составит десятки герц.(реально меньше) Сотни кгц - это стабильность очень плохого мультивибратора если специально постараться.

Теперь задачка, которую надо решить (специально для вас). Нужен металлоискатель. Он собран на RL генераторе с частотой генерации 7000 гц. При подносе металла частота генератора становится 7001 гц. (и это максимальное значение) При этом такое изменение частоты действует меньше 1 секунды. Надо измерить такое динамическое изменение частоты и отфильтровать его. Ваши предложения. Задачка простая.

Есть правда еще вариант сделать аналоговую систему автоподстройки частоты с ФАП с выделением сигнала рассогласования фазы. (у меня было так) Порядка 20 корпусов ОУ (счетверенных)

arduinec
Offline
Зарегистрирован: 01.09.2015

Buldakov пишет:

Теперь задачка, которую надо решить (специально для вас).

Ещё один экзаменатор нашёлся. Кому надо - пусть тот и решает.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov,  В металлоискателях не силён, но очевидно что бы отличить 7000 гц от 7001 не на грани погрешности -потребуется очень серьёзная схемотехника, так что 20 корпусов ОУ -весьма похоже на правду.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Хорошо пусть будет не маталлоискатель. Но суть дела это не меняет.

Дана частота 7000 гц. При максимальном уровне измеряемой величины частота будет 7001 гц. Как измерить этот 1 Гц разницы с высокой точностью? типа 0.001 гц на интервале времени измерения меньше 1 секунды.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Buldakov пишет:
Ну по поводу кварца. У него стабильность 10-6 что при 16 мгц составит десятки герц.(реально меньше) Сотни кгц - это стабильность очень плохого мультивибратора если специально постараться.

Это для нормальных кварцов. У дунек, китайцы лепят нечто, что действительно плавает по частоте, если и не на сотни герц, то сравнимо с мультивибратором.

Измерять "плавающим измерителем" с точностью в третьем порядке .. получится - расскажите обязательно. Очень любопытно.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov пишет:

Дана частота 7000 гц. При максимальном уровне измеряемой величины частота будет 7001 гц. Как измерить этот 1 Гц разницы с высокой точностью? типа 0.001 гц на интервале времени измерения меньше 1 секунды.

По крайней мере для стандартной UNO/NANO никак не измерить . Можно конечно получить после запятой какие-то цифры, но они будут плавать и скакать непредсказуемым образом. Начинать разговор о возможности чего-то вразумительного после запятой можно при наличии прецизионного генератора 16МГц, от которого затактировать МК ардуино.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Buldakov пишет:

Дана частота 7000 гц. При максимальном уровне измеряемой величины частота будет 7001 гц. Как измерить этот 1 Гц разницы с высокой точностью? типа 0.001 гц на интервале времени измерения меньше 1 секунды.

Припустим за 1С происходит 7000 тактов. Счетчик насчитает 7000 +/- 1 такт за 1 секунду. Итого точнее не получится. Нужно использовать аналоговый вход для определения  позиции по фронту на последнем измерении.

Buldakov
Offline
Зарегистрирован: 17.01.2016

По поводу стабильности кварца. На вход arduino подаю сигнал с высокостабильного генератора на 32 мгц с делителем на 555ие19 на выходе получаю частоту 15625 гц. Ее и измеряю. Жду прихода полных 15626 импульсов и определяю время этих импульсов. Время плавает в пределах 1000024 1000032 мкс. Частота плавает в пределе +/- 0.06 гц. Поскольку частотомер чисто программный - то эту погрешность можно отнести к временем между опросами цифрового входа. Опрос происходит с частотой около 450000 раз в секунду. Большей частоты опроса (программным способом) у меня не получилось. Поэтому нестабильность пока ищу сдесь. Другое дело, что долговременная стабильность а arduino плавает. С этим полностью согласен. При включении и прогреве частота уверенно побежала. В данном случае это совсем не важно. Мне не нужно эталонное измеренное значение частоты с высокой стабильностью.

А по поводу того, что частота плавает есть специальные методы для борьбы с этим. например:

https://ru.wikipedia.org/wiki/%D0%90%D0%B4%D0%B0%D0%BF%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%B7%D1%8F%D1%89%D0%B0%D1%8F_%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D1%8F%D1%8F_%D0%9A%D0%B0%D1%83%D1%84%D0%BC%D0%B0%D0%BD%D0%B0

http://konkop.narod.ru/Files/7_74_79.pdf

 

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, я не пойму, к чему вы все эти речи произносите. Есть готовая библа, которая измеряет, усредняет, и прочее. Вы её  пробовали? Пример двух цифр после запятой там прямо на картинке.

Buldakov
Offline
Зарегистрирован: 17.01.2016

dimax пишет:

Buldakov, я не пойму, к чему вы все эти речи произносите. Есть готовая библа, которая измеряет, усредняет, и прочее. Вы её  пробовали? Пример двух цифр после запятой там прямо на картинке.

Я описываю, что у меня получилось. Если вам не интересно - можете не читать.

По поводу данной библиотеки ее я пробовал. При компиляции выдается ошибка и  все на этом. и при том, что она только до 1000 гц. Другая библиотека от 1000 гц и измеряет только целые частоты. Ни одна из них не подходит. Думаете мне охота что то придумывать если можно найти готовое. Так нет же ничего.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, и что, раз у вас не скомпилировалось, значит будем ставить крест? Или всё таки разбираться? У меня не выдаёт ошибок. И по поводу 1000 Герц -это не предел, это рекомендация. Он измеряет и выше в данном режиме. Пробуйте, тестируйте. У меня нет генератора с разрешением менее герца что бы проверить как он измеряет.

Buldakov
Offline
Зарегистрирован: 17.01.2016

А в принципе зачем разбираться в чужом коде. Уже написал свой. Полностью программный. меня устраивает. Если не устроит куплю железку более мощную. Цена вопроса 200 руб. Буду лучше изучать таймеры.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Уважаемый ТС. 

Бросьте попытки использовать всякие библиотеки, там писать не много, а понимания работы будет значительно больше.

Попробуйте выход генератора забросить на вход прерывания: функция attachInterrupt 0 (на digital pin 2) или 1 (на digital pin 3).

После первого начинаем считать их например до 100, на последнем смотрим таймер и делим на 100.

Для более точного определения времени попробуйте использовать таймер с предделителем 001 где какую то N увеличивайте по кругу N++. Вам не надо знать полное время выполнения 100 циклов. Вам достаточно узнать тот хвостик которйы останется после отсчитывания вашего N++, если N типа int то может намотать несколько кругов.

Не используйте в качестве счетчика переменный типа long и функцию micros() - она медленная, а операции с long еще медленнее.

Не парьтесь над стабильностью кварца. Вам достаточно измерить время за секунду до обнаружения металла и при обнаружении. Калибровочное время всегда перерасчитывайте и постоянно поправляйте, тогда не будет проблем на соленых грунтах.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Тут ссылка на то, что вы пытаетесь реализовать. Я такой спаял - прекрасно работает. Идеальная игрушка для ребенка кладоискателя или чернометальщика. 

http://md4u.ru/viewtopic.php?t=3977

Logik
Offline
Зарегистрирован: 05.08.2014

Ну хороше, есть у Вас на входе сигнал из диапазона 7000-7001Гц, и Вы хотите его померить именно в этом диапазоне. Так это просто! Вы опрашиваете нужный пин с частотой 13998Гц. И в результате опроса получаете сигнал с частотой 1-2Гц. А эту уже сильно проще. Далее меряете период и.. а в общем то пересчитывать в частоту для ваших дальнейших целей не нужно. Частота 13998Гц не догма, можна подобрать и такую, чтоб разность сразу на наушники.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Последний вариант кода, того что получился выкладываю ниже.

//
#include <CyberLib.h>                                                                                                              //
#include <Wire.h>                                                                                                                  //
#include <LiquidCrystal_I2C.h>                                                                                                     //
//
LiquidCrystal_I2C lcd(0x27, 16, 2); // Для экрана 16х2 (двухстрочный)                                                              //
//
unsigned long per1             =1000000; // мкс                                                                                    //
unsigned long interval_LCD     =  1000;  //Интервал смены показаний на LCD в миллисекундах                                         //
unsigned long lastTime_LCD     =     0;  //Время последнего изменения состояния для LCD в миллисекундах                            //
unsigned long DeltaTime_LCD    =     0;  //Время с момента последнего вывода на LCD в миллисекундах                                //
unsigned long currentTime      =     0;  //Текущее время в милисекундах                                                            //
//
boolean sig_new,sig_old,triger_new,triger_old;                                                                                     //
unsigned int t4,p1;                                                                                                                //
unsigned long time_1,time_2;                                                                                                       //
float f;                                                                                                                           //
//
void setup() {                                                                                                               //
pinMode(7, INPUT);                      //Назначим вывод 7 на ввод сигналов                                                        //
digitalWrite(7, HIGH);                  //Включаем подтягивающий резистор                                                          //
D7_In;                                                                                                                             //
lcd.init();                             //Задаем размерность LCD дисплея                                                           //
lcd.backlight();                        //Включаем подсветку экрана                                                                //
lcd.clear();                            //Очистка экрана                                                                           //
}                                                                                                                                  //
//
voloop()                                                                                                                        //
{                                                                                                                                  //
//
time_1=micros();                                                                                                                   //
p1=0;                                                                                                                              //
label_a :                                                                                                                          //
sig_old=sig_new;                                                                                                                   //
triger_old=triger_new;                                                                                                             //
sig_new=D7_Read;                                                                                                                   //
if (sig_old==0 && sig_new==1                              ) {triger_new=1;p1=p1+1;}                                                //
if (sig_old==0 && sig_new==1 && abs(micros()-time_1)>per1 ) triger_new=0;                                                          //
if (triger_old==0 && triger_new==1                        ) {time_1=micros();goto label_a;}                                        //
if (triger_old==1 && triger_new==0                        ) {;} else {goto label_a;}                                               //
t4=p1;p1=0;time_2=micros();                                                                                                        //
//---Условия для вывода показаний на LCD-------------------------
currentTime=millis();                                                                                                              //
DeltaTime_LCD  =abs(currentTime - lastTime_LCD);      //Время с момента последнего вывода на LCD                                   //
if (DeltaTime_LCD >= interval_LCD )                   //Условия вывода на LCD                                                      //
{                                                                                                                                  //
//---------------------------------------------------------------
f=1000000.0/(abs(time_2-time_1)/(t4*1.0));                                                                                         //
lcd.setCursor(0, 0);lcd.print(t4);                                                                                                 //
lcd.setCursor(6, 0);lcd.print(abs(time_2-time_1));                                                                                 //
lcd.setCursor(0, 1);lcd.print(f,2);                                                                                                //
//---------------------------------------------------------------
lastTime_LCD = currentTime;                                                                                                        //
}                                                                                                                                  //
//---------------------------------------------------------------
}                                                                                                                                  //
//---------------------------------------------------------------

Просьба помочь это реализовать того, кто разбирается в таймерах. Пока научился только работать с регистрами в setup. и то только в теории по книгам.

Первый этап. Пока не знаю как это реализовать. Но примерный план такой. Настраиваю триггер 2 на предделитель с коэффициентом 1 или 8. как делитель частоты 16 М. Запуск этого триггера осушествляется по условию: triger_old==0 && triger_new==1. остановка триггера 2 по условию: triger_old==1 && triger_new==0. Считаем сколько раз триггер 2 переполнялся и текущее значение в регистре счетном. Потом проделываю тоже самое, что и сейчас, только вместо micros() беру значение из таймера 2. Данным действием мы сможем убрать неточность вызванную функцией micros(). Неточность вызванную длительностью сигнала triger_new=1. пока не трогаем.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Logik пишет:

Частота 13998Гц не догма, можна подобрать и такую, чтоб разность сразу на наушники.

Изменение частоты в 1 Гц - на наушники?

Это бесполезно. На совсем низкой частоте (до субконтроктавы) - да, будет разница в полтона, но здесь и дифференциальная чувствительность уха никакая, и наушники такую частоту, как правило, воспроизвести не могут. Если брать что-то удобное типа 440 Гц, то там 12 Гц - это тоже на самом предел различимости.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Просьба помочь с таймером. В Setup() прописываю такой код.
Хочу запрограэто на выммировать таймер 2 на выдачу частоты в 1024 раза меньше частоты кварца и выдать это на выход 11 Arduino.
Там ничего нет. Просьба подправить, что у меня неправильно.

//Пример программирования 2 таймера 8 бит                                                                                          
pinMode(11, OUTPUT);               //Назначим вывод 11 на вывод сигналов                                                           
TCNT2 =0b00000000;                 //Сбрасываем счетный регистр таймера.
TCCR2A=0b00000000;                 //Сброс настроек таймера                                                                        
OCR2A =0b00000000;                 //Регистр сравнения. Сюда мы записываем то, с чем надо сравнить.                                
TCCR2B=0b00000100;                 
TIMSK2=0b00000000;                 
ASSR  =0b00000000;
 

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov,  На выходе имеем 16000000/1024=15625Hz:

void setup() {
DDRB|=1<<DDB3; //11pin
TCCR2A= (1<<COM2A0)|(1<<WGM21); //CTC mode
TCCR2B=(1<<CS21)|(1<<CS20); // div32
OCR2A=15;
}

void loop() {
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

andriano пишет:

Logik пишет:

Частота 13998Гц не догма, можна подобрать и такую, чтоб разность сразу на наушники.

Изменение частоты в 1 Гц - на наушники?

Это бесполезно. На совсем низкой частоте (до субконтроктавы) - да, будет разница в полтона, но здесь и дифференциальная чувствительность уха никакая, и наушники такую частоту, как правило, воспроизвести не могут. Если брать что-то удобное типа 440 Гц, то там 12 Гц - это тоже на самом предел различимости.

Выделил шрифтом. 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Да спасибо за код. Все работает. теперь посмотрю что я делал неправильно.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Logik пишет:

Выделил шрифтом. 

А толку было выделять, если ПРИ ЛЮБОЙ частоте разница в наушниках будет малоразличима.

Дуругими словами, невозможно подобрать частоту, чтобы добиться в наушниках ощутимого эффекта.

(Выделил на всякий случай)

Buldakov
Offline
Зарегистрирован: 17.01.2016

dimax пишет:

Buldakov,  На выходе имеем 16000000/1024=15625Hz:

void setup() {
DDRB|=1<<DDB3; //11pin
TCCR2A= (1<<COM2A0)|(1<<WGM21); //CTC mode
TCCR2B=(1<<CS21)|(1<<CS20); // div32
OCR2A=15;
}

void loop() {
}

Не понял какие биты перевести в 1

TCCR2A= (1<<COM2A0)|(1<<WGM21); //CTC mode 
TCCR2A=0b00011000     ? или другие?

И частота почему то не 16000000/1024 а 8000000/1024

 

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, это аналог записи TCCR2A=B01000010, советую вам пользоваться буквенными названиями бит, так нагляднее. Второй вопрос не точно понял. Но смысл кажется уловил. После делителя таймер работает с частотой 16000000/делитель, но за один свой такт он может только 1 раз изменить состояние выхода. Соответссно что-бы получить частоту в 1024 раз меньше тактовой нужно разделить на 1024 и ещё раз на 2. В моём скетче это деление происходит 2 раза. Первый раз прескалером на 32, второй раз регистром сравнения на 16 .

Buldakov
Offline
Зарегистрирован: 17.01.2016

По поводу частоты. я беру 16000000 делю на 1024 (предделитель) и у меня должна получиться частота 15625, а получается частота 7822 гц. Как будто еще где то вкрался делитель на 2. (есть подозрение что предделитель переключает выход таймера из 0 в 1  - поэтому частота в 2 раза меньше планируемой)

По поводу TCCR2A=B01000010

в даташите wgm21 вроде 3 бит. А com2A0 вроде 4 бит. поэтому я и писал B00011000 и у меня ничего не работало.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, есть подозрение что предделитель переключает выход таймера из 0 в 1  - поэтому частота в 2 раза меньше планируемой)

Я же вам в предыдущем сообшении написал почему так происходит

в даташите wgm21 вроде 3 бит. А com2A0 вроде 4 бит.

Видимо вы не в тот даташит смотрели.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Может быть не тот даташит.

Теперь другой вопрос.

Как мне прочитать состояние регистра триггера? (типа r1=TCNT2;) Нужно ли на время чтения регистра останавливать счетчик, а потом запускать?

и как посчитать сколько раз триггер сбрасывался до нуля?

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, не понял, что вы хотите конкретно? До скольки должен считать счётный регистр TCNT2?  Например в моём скетче значение TCNT2 никогда не превысит 15. Что-бы считать кол-во переходов через ноль нужно создать прерывание по соответвующему регистру, и в прерывании инкременировать какую-нибудь переменную.

Buldakov
Offline
Зарегистрирован: 17.01.2016

В том то и дело что TCNT2 должен быть не более 15. Но у меня при чтении r1=TCNT2; переменная r1 может принимать значение и 70 и 80?

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Buldakov, в скетче из #36 это невозможно. Либо вы что-то изменили уже у себя.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Сколько не смотрел различные даташиты ничего не понял.  биты wgm21 и com2a1 находятся во всех даташитах на другом месте. И непонятно откуда взялось TCCR2A и TCCR2B. Во всех даташитах только TCCR2. Но в программе забиваю TCCR2 - и выдает ошибку.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Buldakov пишет:

Сколько не смотрел различные даташиты ничего не понял.  биты wgm21 и com2a1 находятся во всех даташитах на другом месте. И непонятно откуда взялось TCCR2A и TCCR2B. Во всех даташитах только TCCR2. Но в программе забиваю TCCR2 - и выдает ошибку.

Какие же это даташиты Вы смотрите?

Открываем даташит на ATMega328P и на стр.143 читаем "The counting sequence is determined by the setting of the WGM21 and WGM20 bits located in the Timer/Counter Control Register (TCCR2A) and the WGM22 located in the Timer/Counter Control Register B (TCCR2B)."

Далее, в п. 18.11 (со стр. 153) оба регистра TCCR2A и TCCR2B подробно описаны.

А Вы какой даташит смотрели?

Buldakov
Offline
Зарегистрирован: 17.01.2016

По вашей ссылке все правильно. Я сммотрю этот даташит. на atmega32 по ссылке ниже. Там на стр. 122 регистр TCCR2.

http://www.gaw.ru/pdf/Atmel/AVR/atmega32.pdf

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

А при чём здесь Atmega32? В Arduino Nano стоит Atmega328P. Это разные микроконтроллеры с разными регистрами. Atmega32 это предыдущее поколение.