Задача 10.
Устройство
изменяющее состояние нагрузки при
громком звуке длительностью от 5 до 20 мС.
Цель
задачи: разработать устройство и
программу для МК ATmega16 которое будет
анализировать длительность сигнала от
микрофона и если она будет лежать в
пределах 5-20 мС то будет менять
состояние подключенной нагрузки: если
была выключена - то включит и наоборот.
Что
нужно для выполнения этой задачи:
- Компилятор Си для AVR CodeVisionAVR
- Программный эмулятор для AVR
VMLAB = Visual Micro Lab
- DataSheet (ДШ) на МК AVR ATmega16
- знание
других материалов курса
- твердое
знание первой страницы
курса на 5 с плюсом
-
свободное время и желание.
Можно
использовать МК ATmega8
только понадобится ДШ и на него!
Что
делать
с
сигналом от микрофона?
Я предлагаю
использовать встроенный в МК
компаратор - стр. 199 ДШ.

Компаратор
сравнивает напряжения на входах "+"
и "-"
Если
напряжение на "+" выше чем на
"-" то на выходе компаратора ACO
устанавливается высокий уровень - лог.1
а если наоборот то низкий уровень лог.0
Изменение на
выходе компаратора ACO может вызывать
прерывание - мы будем использовать это.
Как же
подать сигнал от микрофона на входы
компаратора?
Я набросал
схему для электретного микрофона.

R1 - питает
микрофон, его номинал зависит от
напряжения питания и типа микрофона -
примерно 3 - 5 КОм.
R2 - 4,7 КОм -
образует с С1 ФНЧ - ослабляет частоты
выше
чем 1/(6.28 * R * C) - отсюда находим С1
R3 - 47 КОм -
образует с С2 ФВЧ - ослабляет частоты
ниже
чем 1/(6.28 * R * C) - отсюда находим С2
Внимание
! В симуляторе VMLAB
есть возможность как бы подключится к
внутренним точкам в МК ! Например
напряжение на выходе компаратора ACO
вы можете вывести в окно SCOPE !
Вы можете
нарисовать эту схему в симуляторе Micro Cap
(всего 6 МБ - куча примеров
схем и масса возможностей! ) и определить номиналы элементов чтобы
получить нужную вам полосу
пропускания входной схемы.
Мы
применили пассивный фильтр - значит он
будет довольно слабо обрезать не
нужные нам частоты - спад около 6 Дб на
октаву (на двукратное изменение
частоты)
А вот в симуляторе
электронных схем Micro Cap
есть примеры активных фильтров
более высоких порядков на ОУ и вы
сможете применить их заранее подобрав
устраивающую вас характеристику.
Еще
более заманчиво - подать сигнал от
микрофона на АЦП МК и применить
цифровую фильтрацию! -
скорости МК хватит, пример цифрового
фильтра есть в AN AVR и на Си с
целочисленной математикой C:\VMLAB\ST6_demo\DSPDEMO.C
Запускаем
компилятор CV
(CodeVisionAVR)
и затем генератор начального кода
программы:

Лучший
друг начинающего микроконтроллерщика!
1)
выбираем ATmega16 и частоту 1 МГц -
высокая точность такта не нужна и можно
использовать внутренний RC генератор МК
в установке фьюзов с завода.
Внешний
кварц не нужен!

2) откроем
ярлык - компаратор:

-
включили компаратор
- включили прерывание по изменению
логического уровня на выходе
компаратора - ACO
3) теперь
включим передатчик USART для отправки
информации из МК через адаптер
rs232 на COM-порт ПК или в терминал VMLAB

-
максимально 4800 бод получается при
тактовой частоте МК 1 МГц
4) Сделаем
ножки PB0 и PB1 выходами

Аналогично
сделайте выходом ножку PC0
Все
установки сделаны.
5) можно
генерировать начальный текст
программы и
сохранять файлы

Сохраните файлы вот так:

Теперь
у вас должен быть открыт текст
программы в окне компилятора CodeVisionAVR.
Надо
наполнить программу смыслом!
Используя
мастер начального кода компилятора вы
поняли, что при любом изменении
логического уровня на выходе
компаратора ACO будет возникать
прерывание и мы будем попадать в
функцию обработчик прерывания:
|
|
|
|
// Analog Comparator interrupt service routine
interrupt [ANA_COMP] void
ana_comp_isr(void)
{
// Place your code here
при
изменении ACO
мы попадаем сюда ...
}
|
|
|
|
|
А
изменение уровня на выходе компаратора
вызывается сигналом микрофона
преодолевшим фильтрацию.
Попали в
прерывание и что с ним делать?
Ну можно
наверно запомнить что это случилось! т.е.
посчитать его - обычно для этого
используют некоторую переменную
например:
|
|
|
|
#include <stdio.h>
uunsigned char int_ctr = 0;
/* мы объявили переменную которая
называется int_ctr и может хранить
число от 0 до 255
сейчас в ней число 0
Эта переменная глобальная - значит
доступна в любом месте программы
это еще и пример обрамления
многострочного комментария
к программе*/
|
|
|
|
|
Добавляемый
в программу код я буду писать
синим!
Комментарии
к программе - зеленым.
Теперь
нужно добавить в функцию обработчик
прерывания
- строчку
кода увеличивающую на 1 переменную
int_ctr
- значит
посчитать возникшее прерывание.
-
запретить пока прерывание от
компаратора! Иначе, как только мы
выйдем из функции обработки прерывания
оно будет мгновенно возникать снова
пока есть звук и логический уровень ACO
"трепыхается"!
|
|
|
|
При
возникновении любого разрешенного
индивидуально прерывания
происходит запрещение глобально
всех прерываний в МК "очисткой"
(значит обнулением) бита_i в регистре
SREG
эквивалентно выполнению строки: #asm("cli")
Выполнение кода функции
обработчика прерывания до конца и
автоматический выход из нее
разрешает глобально все
разрешенные индивидуально
прерывания! "установкой" (set -
значит сделать "1") бита_i в
регистре SREG
эквивалентно выполнению строки: #asm("sei")
Важно!
Если
вы покинете функцию обработчик
прерывания не выполнив ее код до
конца (например через старый добрый
оператор goto) бита_i в регистре SREG
останется "0" и ни каие
прерывания не произойдут пока вы не
разрешите их програмно!
например такой строчкой: #asm("sei")
|
|
|
|
|
-но
прежде я бы хотел добавить
диагностическую (методы
отладки программы МК здесь) строчку
кода
изменяющую состояние ножки
PC0 на противоположное
существующему.
делаем:
|
|
|
|
// Analog Comparator interrupt service routine
interrupt [ANA_COMP] void
ana_comp_isr(void)
{
// при изменении уровня на выходе компаратора
// мы попадаем сюда!
// Place your code here
PORTC.0^=1;
/*инвертировать
бит0 регистра
если был "0" станет "1" и
наоборот
при
возникновении прерывания мы сможем
увидеть момент попадания сюда в
виртуальном осциллографе SCOPE
симулятора VMLAB или на реальном подключенном
к ножке PC0 */
int_ctr = int_ctr
+ 1;
/*
мы посчитали
прерывание, увеличив на 1 счетчик
прерываний переменную int_ctr
конечно
программисты написали бы
int_ctr++;
красивей,
элегантней, но смысл тот же! */
ACSR
&=~(1<<3);
/*
Сделали "0" бит_3 в регистре ACSR
- стр 200 в ДШ мега16.
Это
запрещает прерывание от изменения
выхода компаратора!
Register – ACSR
• Bit 3 – ACIE: Analog Comparator Interrupt Enable
When the ACIE bit is written logic one and the I-bit in the Status Register is set, the Analog
Comparator Interrupt is activated.
When written logic zero, the interrupt is disabled.
*/
} |
|
|
|
|
дословно
на Си
PORTC.0^=1;
означает:
взять значение бит_0 регистра PORTC
сделать XOR (исключающее или) этого
значения с числом 1 (а проще =
инвертировать бит) и результат
записать опять в бит_0 регистра PORTC
Логическое
"исключающее или" - XOR - значит, что
напротив 1 значение меняется!
байт А |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
байт В |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
A^B |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
Старайтесь
думать над значением каждой строки
программы и четко проговаривать
выполняемые операции !
Давайте
разберем как мы обнулили бит_3
написав:
ACSR &=~(1<<3);
&=
означает
сделать логическое "и" того
переменной слева с результатом вычисления
того, что справа и результат поместить
в переменную слева.
Логическое
"и" значит что только 1 и 1 дают 1
Логическое
И |
A |
B |
A
& B |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
Пожалуйста
изучите логические операции -
их не много.
Это нужно вам !
Вычислим что у нас
справа:
1<<3
означает
сдвинуть число 1 на 3 разряда влево - это
равносильно умножению на 2 в 3-й степени,
или на 8. Делается так:
0000
0001 - это число 1
0000
0010 - это число 2 что равно числу 1
сдвинутому на 1 разряд в лево или умноженному
на 2 в первой степени.
0000
0100 - это число 4 что равно числу 1
сдвинутому на 2 разряда в лево или умноженному
на 2 в квадрате.
0000
1000 - это число 8 или результат (1<<3)
~
означает инверсию - т.е. 1 сделать 0 и
наоборот.
~(1<<3)
эквивалентно ~0000
1000 и дает число: 1111 0111
Итак мы
нашли что: ACSR
&=~(1<<3);
эквивалентно:
ACSR
= (ACSR & 1111
0111);
Вы
наверно поняли операцию "и" и
видите, что напротив 0 в регистре
ACSR
получится 0 не
зависимо что там было раньше, а другие
биты регистра не изменятся!
Обязательно
и подробно комментируйте свою
программу! не откладывайте на потом...
Потом не сделаете !
... знаю, знаю. Сам такой !
Дальнейший
алгоритм простой - в начале программы
нужно подождать тишину более 0.2 сек.
Затем ждем звука. Обнаружив прерывание
мы сделаем паузу 5 мС и вновь разрешим
прерывания от компаратора. Если
прерывание случится - значит сигнал
длится не менее 5 мС и мы будем жадать
еще 15 мС и вновь разрешим прерывание -
если оно не случится в течении 0.2 С то
можно считать что звук длился от 5 до 20
мС - переключаем состояние ножек PB0 PB1
напротивоположное - а к ним подключено
исполнительное устройство.
Если что-то
не так как описано выше то мы
возвращаемся в начало программы.
Продолжение
следует.
Хотите
- посмотрите задачу 9
|