Генератор плавающей частоты
- Войдите на сайт для отправки комментариев
Ср, 11/03/2015 - 17:04
Приветствую всех!
Возникла необходимость в генераторе "плавающей" частоты.
Суть такова:
На одном выходе должна быть частота 10кГц-20кГц, изменение частоты должно наростать в течение 1 секунду от 10кГц до 20кГц, одновременно на другом выходе должно происходить обратное от 20кГц до 10кГц. Процесс бесконечный, начинается с включения питания.
Пытался взять за основу сирену
http://arduino.ru/forum/proekty/imitatsiya-sireny-grazhdanskoi-oborony, но что-то на два выхода не получается.
Если кто-то делал подобное, поделитесь скетчем с пенсионером :)
Немного не верно написал.
На одном выходе частота втечение 1 секунды изменяется от 10кГц до 20кГц и снова от 20кГц до 10кГц, а на втором выходе обратная картина, от 20 до 10 и обратно от 10 до 20.
Kollega, это довольно непростая задача. Фактически нужно задействовать 3 таймера, на одном считать время (или использовать millis() ) , а на ещё 2х сделать 2 генератора. На 16-битном таймере не проблема, Он может считать отрезками по 0,0625 us, то есть на диапазон 10kHz-20kHz выпадет на 800...400 отсчётов таймера, вполне плавно. А на оставшимся 8-битном таймере плавной регулировки просто так уже не сделать, тут придётся мудрить что-то..
Вот для одного выхода -довольно просто сделать :)
Да, dimax, вот по этому и не получается у меня... Я думал может у кого-то есть решения, но наверное нет. Вся затея в том, чтобы ограничиться одной ардуинкой, конечно если пристроить генераторы, то проблем нет, но нужно именно одной. :)
.
Kollega, ну как же нет решения? Я вам его написал в общих чертах. Но привёл информацию для мк типа ардуино-уно, т.к. я только с ними работаю. Но возьмите ардуино- леонардо (микро) или ардуино-мега 2560, там по нескольку 16-битных счётчиков, без проблем реализуете свою задумку.
Есть готовая библиотека позволяющая на ATmega168/328 генерировать до 3 независимых частот одновременно с использованием таймеров - т.е. во время генерации может исполняться другой код не задействующий таймеры. А при двух частотах таймер 0 свободен и можно использовать и millis(), micros() и ШИМ.
Сама библиотека от того же автора что и функция tone() в стандартном наборе.
https://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
или есть библиотека
1
MirmPS.h
многозадачность на основе таймера 2
вот инфо, вот библиотека
Спасибо Всем за полезную инфу, приму к сведению!
Вопрос решился немного по другому, на первом выходе действительно нужна была плавающая частота, а на втором достаточно было только постоянную середину между 10кГц и 20, т.е. 15кГц, поэтому работает на втором выходе функция tone с постоянной частотой.
В заблуждение иногда вводит proteus, не всегда корректно в нем работает то, что нормально на железе, и наоборот...
Снова столкнулся с проблемой. Частота у меня сейчас меняется в течение секунды от низкой к высокой и обратно.
01
#define Speaker_pin 10 // пин к которому подключен выход
02
#define Speed_up_down_frequency 1000 // скорость нарастания и убывания частоты
03
04
void
setup
() {
05
pinMode(Speaker_pin, OUTPUT);
// выход сигнала
06
07
}
08
09
void
loop
()
10
{
11
for
(
int
f = 88; f >= 44; f--){
// нарастание частоты
12
Vooooo(f,Speed_up_down_frequency);
13
}
14
15
for
(
int
f = 44; f <= 88; f++){
// убывание частоты
16
Vooooo(f,Speed_up_down_frequency);
17
}
18
19
}
20
21
void
Vooooo(
int
freq,
long
duration){
22
long
time = duration/1/freq;
23
for
(
long
t = 0; t < time; t++)
24
{
25
digitalWrite(Speaker_pin, HIGH);
26
delayMicroseconds(freq);
27
digitalWrite(Speaker_pin, LOW);
28
delayMicroseconds(freq);
29
}
30
}
Но не могу прикрутить к скетчу функцию котроля заряда батареи. По принципу, если батарея разряжена на 50%, то зажигается светодиод. Отдельно такой скетч работает, а как совместить, не разберусь...
01
void
setup
() {
02
// инициализируем пин, подключенный к светодиоду, как выход
03
pinMode(ledPin, OUTPUT);
04
// инициализируем пин, подключенный к делителю, как вход
05
pinMode(buttonPin, INPUT);
06
}
07
08
void
loop
(){
09
10
// считываем значения с делителя
11
buttonState = digitalRead(buttonPin);
12
13
// проверяем напряжение
14
15
if
(buttonState == HIGH) {
16
17
digitalWrite(ledPin, LOW);
18
}
19
else
{
20
21
digitalWrite(ledPin, HIGH);
22
}
23
}
Kollega, а где вы позаимствовали такую форму детектора напряжения? Он конечно будет работать, только идеологически неверно использовать цифровой вход для контроля уровня напряжения, для этого есть ацп или компаратор. И по первому скетчу -генерировать частоту в функции loop это очень плохая затея, меандр будет очень нестабилен, и любое изменение скетча сразу вызовет уход всех ваших настроек, . Вот набросал, посмотрите. На выводе D9 генератор качающейся частоты 10..20кГц, вывод неизменяем. Вывод 13 -светодиод, вывод A1 -вход для измерения напряжения, к нему подключите ваш делитель. Задействовано 2 таймера, таймер 1 генерит сигнал, от 10 до 20кГц с дискретностью 25 Гц., А что бы удобно обслуживать регулировку частоты используется таймер 2, он 400 раз в секунду вызывает прерывание, в котором увеличивается или уменьшается значение регистраOCR1 на единицу, и сответственно меняется частота на 25Гц. Порог срабатывания светодиода задаётся в строке 24.
01
void
setup
(){
02
pinMode (9,OUTPUT);
//выход частоты 10..20кГц
03
pinMode (13,OUTPUT);
//светодиод
04
TCCR2A=(1<<WGM21);
//CTC
05
TCCR2B=(1<<CS21)|(1<<CS22);
//div to 256
06
OCR2A=155;
07
TIMSK2=1<<OCIE2A;
//enable interrapt
08
TCCR1A= (1<<COM1A0)|(1<<COM1B0);
09
TCCR1B= (1<<CS10)|(1<<WGM12);
10
OCR1A=800;
11
}
12
13
ISR (TIMER2_COMPA_vect) {
14
static
int
times=800;
15
static
bool
freq_up=1;
16
if
(freq_up) times --;
17
if
(!freq_up) times ++;
18
OCR1A=times;
19
if
(times <= 400) freq_up=0;
20
if
(times >= 800) freq_up=1;
21
}
22
23
void
loop
() {
24
if
(analogRead(A0) < 512 )digitalWrite(13,HIGH);
25
else
digitalWrite(13,LOW);
26
}
Здравствуйте, dimax! Респект Вам и Уважуха, что отвечете мне и не отправляете, как на многих форумах сначала в гугел, потом в "автошколу" :).
Радиолюбительством я занимался с детства, еще с семидесятых, в восьмидесятых работал на радиозаводе. Но в те времена был "аналог", сейчас времена и технологии совершенно другие. Меня вот на пенсии снова потянуло к паяльнику и запаху канифоли. Я раньше понятия не имел, что такое arduino, случайно в иннете наткнулся на рекламу, когда искал осциллограх.
Тема показалась интересная, теперь пытаюсь постигать азы.
Еще раз Спасибо Вам!
Kollega, а где вы позаимствовали такую форму детектора напряжения? Он конечно будет работать, только идеологически неверно использовать цифровой вход для контроля уровня напряжения, для этого есть ацп или компаратор. И по первому скетчу -генерировать частоту в функции loop это очень плохая затея, меандр будет очень нестабилен, и любое изменение скетча сразу вызовет уход всех ваших настроек, . Вот набросал, посмотрите. На выводе D9 генератор качающейся частоты 10..20кГц, вывод неизменяем. Вывод 13 -светодиод, вывод A1 -вход для измерения напряжения, к нему подключите ваш делитель. Задействовано 2 таймера, таймер 1 генерит сигнал, от 10 до 20кГц с дискретностью 25 Гц., А что бы удобно обслуживать регулировку частоты используется таймер 2, он 400 раз в секунду вызывает прерывание, в котором увеличивается или уменьшается значение регистраOCR1 на единицу, и сответственно меняется частота на 25Гц. Порог срабатывания светодиода задаётся в строке 24.
01
void
setup
(){
02
pinMode (9,OUTPUT);
//выход частоты 10..20кГц
03
pinMode (13,OUTPUT);
//светодиод
04
TCCR2A=(1<<WGM21);
//CTC
05
TCCR2B=(1<<CS21)|(1<<CS22);
//div to 256
06
OCR2A=155;
07
TIMSK2=1<<OCIE2A;
//enable interrapt
08
TCCR1A= (1<<COM1A0)|(1<<COM1B0);
09
TCCR1B= (1<<CS10)|(1<<WGM12);
10
OCR1A=800;
11
}
12
13
ISR (TIMER2_COMPA_vect) {
14
static
int
times=800;
15
static
bool
freq_up=1;
16
if
(freq_up) times --;
17
if
(!freq_up) times ++;
18
OCR1A=times;
19
if
(times <= 400) freq_up=0;
20
if
(times >= 800) freq_up=1;
21
}
22
23
void
loop
() {
24
if
(analogRead(A0) < 512 )digitalWrite(13,HIGH);
25
else
digitalWrite(13,LOW);
26
}
У меня еще такой вопрос. Просимулировал в proteus_е, получается, что время изменения частоы несколько секунд. Мне не обходимо время от низкой к высокой и обратно за одну секунду. Подскажите, каким образом изменить время, и как можно изменить верхнюю и нижнюю частоту, и как можно зафиксировать (на время настройки верхнюю и нижнюю частоту, по тому, что proteus не успевает считывать.)
Kollega, Думаю вы не правильно что-то задали в протеусе. Возможно татовую частоту. (Я не пользуюсь этой прогой, так что не скажу точно) Время считается так - частота процессора (16 000 000 ) / делитель (задано 256), = тактовая частоту таймера, т.е. 62500Гц. Переведём их сразу в секунды для удобства, 1/62500 = 16uS. Далее в 6 строке скетча задаётся количество тактов, которые нужно пропустить перед прерыванием. 16 * 155= 2480 uS. Т.е. каждые 2,48 ms запускается прерывание. Цикл увеличения или уменьшения частоты состоит из 400 прерываний, 2,48 * 400 =992 миллисекунды . Если хотите за секунду и увеличить и уменьшить, то придётся поменять делитель на /1024
TCCR2B=(1<<CS20)|(1<<CS21)
и задержку|(1<<CS20)
;OCR2A=20;
Проверяем: 16 000 000 / 1024 = 15 625 ; 1/15 625 = 64us ; 64*20= 1280us прерывание. Нам нужно сделать их 800 за секунду, 1280*800 = 1,024 s
Зафиксировать частоту -закомментируйте тело прерывания или можно только 16 и 17 строчку.
Изменить частоту - в регистре OCR1A записывать другие значения, рассчитывать можно по аналогии, делитель там 1.
Да. Сейчас понятно. Я протеусом пользуюсь, чтобы хоть как-то сначала получить эмуляцию.
Более лучшей программы для эмуляции не нашел, или плохо искал. У меня стоит еще multisim, но этот эмулятор больше для аналога.
Я в скетч прикрутил еще один светодиод, на эмуляторе заработало.
Т.е. напряжение от 9 до 7 вольт - светится "высокий" заряд батарейки, от 7 до 5 - два светодиода, типа середина, и от 5 вольт и ниже типа "низкий" заряд батарейки.
Вы пользуетесь каким либо эмулятором?
Kollega, Думаю вы не правильно что-то задали в протеусе. Возможно татовую частоту. (Я не пользуюсь этой прогой, так что не скажу точно) Время считается так - частота процессора (16 000 000 ) / делитель (задано 256), = тактовая частоту таймера, т.е. 62500Гц. Переведём их сразу в секунды для удобства, 1/62500 = 16uS. Далее в 6 строке скетча задаётся количество тактов, которые нужно пропустить перед прерыванием. 16 * 155= 2480 uS. Т.е. каждые 2,48 ms запускается прерывание. Цикл увеличения или уменьшения частоты состоит из 400 прерываний, 2,48 * 400 =992 миллисекунды . Если хотите за секунду и увеличить и уменьшить, то придётся поменять делитель на /1024
TCCR2B=(1<<CS20)|(1<<CS21)
и задержку|(1<<CS20)
;OCR2A=20;
Проверяем: 16 000 000 / 1024 = 15 625 ; 1/15 625 = 64us ; 64*20= 1280us прерывание. Нам нужно сделать их 800 за секунду, 1280*800 = 1,024 s
Зафиксировать частоту -закомментируйте тело прерывания или можно только 16 и 17 строчку.
Изменить частоту - в регистре OCR1A записывать другие значения, рассчитывать можно по аналогии, делитель там 1.
Если я правильно понял, частота задана во втором таймере в строке 14. Это верхняя частота? По какой формуле мне нужно сделать расчет для изменения частоты и верхнего и нижнего предела.
Kollega, эмуляторами не пользуюсь, как-то всё не возникало надобности, сам удивляюсь. Но протеус давно скачал и установил, осталось научиться пользоваться)
Частота первый раз задаётся в 10 строке, в обаботчик вносится в регистр таймера в 18 строке. Инициализируется переменная в 14 строке, там задаётся с чего начинать движение частоты туда/сюда.Но на частоту влияет ещё делитель (который впрочем отключен -бит CS10 в 9 строке) Вычислить что писать в регистр для получения частоты можно так:
OCR1A= (16 000 000 /n /2 /div) -1 где n-заданная частота в Гц, div -делитель (стоит на 1)
Проверям для 10kHz (16000000 /10000 /2 /1) -1 = 799. Т.е. я на единицу в скетче ошибся, типа округлил..
Кстати уберите из 8 строки вот это, оно лишнее, не заметил сразу.
|(1<<COM1B0)
Kollega, эмуляторами не пользуюсь, как-то всё не возникало надобности, сам удивляюсь. Но протеус давно скачал и установил, осталось научиться пользоваться)
Частота первый раз задаётся в 10 строке, в обаботчик вносится в регистр таймера в 18 строке. Инициализируется переменная в 14 строке, там задаётся с чего начинать движение частоты туда/сюда.Но на частоту влияет ещё делитель (который впрочем отключен -бит CS10 в 9 строке) Вычислить что писать в регистр для получения частоты можно так:
OCR1A= (16 000 000 /n /2 /div) -1 где n-заданная частота в Гц, div -делитель (стоит на 1)
Проверям для 10kHz (16000000 /10000 /2 /1) -1 = 799. Т.е. я на единицу в скетче ошибся, типа округлил..
Спасибо!
Протеус сам по себе простой, как три копейки СССР :), я тоже его установил несколько дней назад, основные функции освоил за вечер. Только во первых не известно на сколько он врет (еще не сравнивал), но даже визуально видно на примерах, котрые я раньше щупал на идентичных схемах на железе. Во вторых, все "народные" версии протеуса, которые я пробовал, имеют разные глюки, может не сохранить проект, может просто выкинуть из программы...
Kollega, эмуляторами не пользуюсь, как-то всё не возникало надобности, сам удивляюсь. Но протеус давно скачал и установил, осталось научиться пользоваться)
Частота первый раз задаётся в 10 строке, в обаботчик вносится в регистр таймера в 18 строке. Инициализируется переменная в 14 строке, там задаётся с чего начинать движение частоты туда/сюда.Но на частоту влияет ещё делитель (который впрочем отключен -бит CS10 в 9 строке) Вычислить что писать в регистр для получения частоты можно так:
OCR1A= (16 000 000 /n /2 /div) -1 где n-заданная частота в Гц, div -делитель (стоит на 1)
Проверям для 10kHz (16000000 /10000 /2 /1) -1 = 799. Т.е. я на единицу в скетче ошибся, типа округлил..
Спасибо!
А как мы получаем 20 кГц, и что прописано в 19 и 20 строке
1
19
if
(times <= 400) freq_up=0;
2
20
if
(times >= 800) freq_up=1;
dimax, можно вашу электронку?
А как мы получаем 20 кГц, и что прописано в 19 и 20 строке
1
19
if
(times <= 400) freq_up=0;
2
20
if
(times >= 800) freq_up=1;
Что бы разделить повышение частоты от понижения я сделал флаг freq_up, когда счётчик "times" доходит до нужного конца флаг меняется, и в следущий заход частота начинает меняться в другую сторону. 20 кГц при значении OCR1A=400; Я ж вам формулу дал.
Здравствуйте, dimax!
Не могу понять, почему в протеусе нарастание и убывание частоты длится почти полторы минуты. Частота стоит правильно 16мГц, верхняя и нижняя частота совпадает.
Посмотреть можно здесь https://www.youtube.com/watch?v=m6gaJbh1Opc
Kollega, я же писал, что протеусом никогда не пользовался. Тут полно любителей протеуса, может кто подскажет вам. Живьём всё работает на рассчётных частотах, я заливал этот скетч и смотрел осциллографом.
Почитал на разных форумах о протеусе. Толком не нашел ответа, но иногда есть посты о том, что якобы при большом кол-ве прерываний в генераторе, осциллограф глючит, и нужно пользоваться анализатором. Но анализатор у меня почему-то не работает даже в готовых демо библиотеках...
Может позже разберусь.
У меня к Вам еще такой вопрос по светодиоду, я так понимаю, что значение задается от 1023, т.е. в вашем скетче 512 -это половина, начиная от половины заданного светодиод зажигается.
Как задать два условия, например выше 512 не светится, ниже 512 зажигается, а при понижении до 400 гаснет.
Так же хотелось узнать хорошие источники по изучению кода. На официальном сайте ардуино, как-то не совсем удобно написано...
1
void
loop
() {
2
int
aread=analogRead(A0);
3
if
(aread >=400 && aread <= 512 )digitalWrite(13,HIGH);
4
else
digitalWrite(13,LOW);
5
}
Чтива по си и контроллерам -очень много, правда мало что конкретно касается ардуино, но главное принципы -они везде одинаковые.
http://we.easyelectronics.ru/AVR/dokumentaciya-po-avr-mikrokontrolleram-vse-na-russkom.html
PS: думаю вам стоит начать с вот этого http://robocraft.ru/files/books/arduino_notebook_rus_v1-1.pdf
1
void
loop
() {
2
int
aread=analogRead(A0);
3
if
(aread >=400 && aread <= 512 )digitalWrite(13,HIGH);
4
else
digitalWrite(13,LOW);
5
}
Чтива по си и контроллерам -очень много, правда мало что конкретно касается ардуино, но главное принципы -они везде одинаковые.
http://we.easyelectronics.ru/AVR/dokumentaciya-po-avr-mikrokontrolleram-vse-na-russkom.html
PS: думаю вам стоит начать с вот этого http://robocraft.ru/files/books/arduino_notebook_rus_v1-1.pdf
Спасибо!
Правильно ли я мыслю, если мне например нужно изменить частоту. Начальная частота 20кГц
16000000/20000/2/div = 400
Верхняя частота 30кГц
16000000/30000/2/div = 266
(время 1 сек. оставляем без изменения)
Или я накосячил?
01
void
setup(){
02
pinMode (9,OUTPUT);
//выход частоты 20..30кГц
03
pinMode (13,OUTPUT);
//светодиод
04
TCCR2A=(1<<WGM21);
//CTC
05
TCCR2B=(1<<CS21)|(1<<CS22);
//div to 256
06
OCR2A=155;
07
TIMSK2=1<<OCIE2A;
//enable interrapt
08
TCCR1A= (1<<COM1A0)|(1<<COM1B0);
09
TCCR1B= (1<<CS10)|(1<<WGM12);
10
OCR1A=400;
// Заданная частота
11
}
12
13
ISR (TIMER2_COMPA_vect) {
14
static
int
times=400;
// начинаем с заданной
15
static
bool
freq_up=1;
16
if
(freq_up) times --;
17
if
(!freq_up) times ++;
18
OCR1A=times;
19
if
(times <= 266) freq_up=0;
//верхняя частота
20
if
(times >= 400) freq_up=1;
//нижняя частота
21
}
22
23
void
loop() {
24
if
(analogRead(A0) < 512 )digitalWrite(13,HIGH);
25
else
digitalWrite(13,LOW);
26
}
Здравствуйте, dimax! Я тут спрашивал у Вас по поводу частоы, правильно ли я изменил код.
Kollega, вы собираетесь теперь по каждому байту консультироваться? Взять да самостоятельно проверить свои идеи так трудно?