Внимание! У нас изменились номера телефонов. Звоните: (495) 638-88-00, (499) 940-95-75, факс (499) 735-04-91; +7(909) 638-88-00 и +7(903) 530-10-01 (Билайн).
Микроэлектронные проекты. Сергей Смирнов. Программное дeкодирование DTMFпо принципу АОН на базе микроконтроллера PIC16F628
На данной страничке сделана попытка рассказать о том, как самому написать программу декодера
DTMF для PIC (например в целях уменьшения вашей схемы на целую микросхему апаратного декодера DTMF типа 1008ВЖ18),
на основе распостранённого алгоритма - массово используемого в АОНах, подробное описание которого имеется вот тут:
Теория корреляционного алгоритма для АОН .
Если желания или времени разбиратся (в чём я был прав, а что лутчше переделать по своему) в моёй программе нет, то можете
не тратя время - скачать архив с исходным текстом на asm, для включения в свой проект.
Для остальных (тем кому это интересно) попробую объяснить как это всё работает, те "разобрать свою программу
по косточкам" на самом простом и понятном даже для новичка уровне:
В качестве эталонного сигнала в программе используется таблица значений SIN и COS для каждой из
8 частот DTMF. Таблица составлена таким образом, чтоб при выборке из неё очередных 2х байт
(16 бит) иметь в регистрах Byte1 и Byte2 значения эталонных 8 частот для данного момента
времени(выборке) как по синусам так и по косинусам одновременно (в этой части я ничего не изобретал а взял классическое решение от АОНа,
вот здесь: Пример выборки для АОНа ).
Вот собственно и сам текст хитро перемещаемой подпрограммы выборки из таблицы более 256 байт
( делал не я, автор Peet_on_B3 ) которая загружает в регистры Byte1 и Byte2 очередные значения:
tab_dtmf
call tab_00
movwf Byte1
call tab_00
movwf Byte2
clrf PCLATH ; 00 - адрес PCLATH откуда был вызов ПП
return
tab_00
movf dtmf_page,w
movwf PCLATH ; выход из таблицы с сохранением значения в W регистре
incf dtmf_adrs,f
btfsc STATUS,Z
incf dtmf_page,f
decf dtmf_adrs,w
movwf PCL
dtmf_file
include dtmf.tab ; это файл значений таблицы эталонных частот DTMF
Выборка новых пар значений и сравнение их с входным
сигналом из таблицы происходит с периодом в 70 мкс (так само собой получилось, при частоте задающего генератора 4 Мгц), итого за ~17,9 мс происходит 256 выборок,
что достаточно для накопления статистики о наибольшем присутствии какой то одной из 4 частот
в каждой из верхней и нижней группе, но это моё субъективное мнение, тк я считаю что увеличение выборок до 512 "съест" половину программной памяти(свёртывать в 2 раза таблицу по чётным и
нечётным строкам(как используют в АОН в целях экономии) нельзя, тк при разворачивании произойдёт нарушение временного "статус-кво" и придётся цикл выборки привязывать к таймеру, что есть потери времени и
ненужное задействование апаратных ресурсов - что мне никак не хочется), а уменьшение до 128 (любимое число АОНов тк укладывается в 10 мс)"сгладит" максимумы на уровне шумов и DTMF декодерирование,
например в условиях радиканала будет не уверенным. В АОНах "окно" увеличивать принципиально нельзя из-за того что там принимается "безинтервальник" с фиксированой длительностью цифр,
а в DTMF окно можно без проблем "растянуть" минимум на 40 мс.
Хотя может я и не прав, но во всяком случае переменная цикла равная 256
и не требующая перезагрузки это красиво, код в цикле выполняется строго 70 мкс не зависимо не от чего и не требует синхронзации от таймера, доп.внешнего кварца итд
- то это тоже красиво, оставшегося времени хватает на обработку и
программа "вписывается красиво по времени" в 1/2 минимального времени обнаружения DTMF и 1/3 минимального времени генерации DTMF
и при этом не требует "эксклюзивного" кварца 3,58 а работает от классического 4 МГц (в тестовом варианте работает весьма сносно даже от встроенного IRC).
Если требуется по каким-то соображениям, увеличить или уменьшить размеры таблицы (в моём варианте это 512 байт т.е. 1/4 программной памяти)) а так-же
изменить время выборки - вобщем если у Вас есть желание и время "поиграть" с этими параметрами, то можете скачать архив
с исходной таблицей в Excel и переделать её на своё усмотрение: Исходная таблица для расчёта эталонных значений.
Теперь рассмотрим как это всё работает т.е., сейчас я прокоментирую самые на мой взгляд - интересные части:
В этом блоке происходит выборка "окна" в 17,9 мс, я тут ничего не изобретал а использовал принцип предложенный Елисеевым Александром
pd_200
call tab_dtmf ; выборка очередных 2х байт из таблицы
btfsc CMCON,7 ; смотрим на состояние выхода встроенного компаратора
comf Byte1,f ; инвертируем сразу все 16 отчётов если на выходе "1"
btfsc CMCON,7 ; или оставляем всё как есть если на выходе компаратора "0"
comf Byte2,f
btfss Byte1,0 ; подсчитываем все "1" для 16 накопительных ячеек за 256 циклов
incf F697_1,f ; это ещё не коэфициенты кореляции а просто счётчики совпадений
btfss Byte1,1 ; эталонов синусоид и косинусоид с реальным сигналом
incf F697_2,f
btfss Byte1,2
incf F770_1,f
btfss Byte1,3
incf F770_2,f
btfss Byte1,4
incf F852_1,f
btfss Byte1,5
incf F852_2,f
btfss Byte1,6
incf F941_1,f
btfss Byte1,7
incf F941_2,f
btfss Byte2,0
incf F1209_1,f
btfss Byte2,1
incf F1209_2,f
btfss Byte2,2
incf F1336_1,f
btfss Byte2,3
incf F1336_2,f
btfss Byte2,4
incf F1477_1,f
btfss Byte2,5
incf F1477_2,f
btfss Byte2,6
incf F1633_1,f
btfss Byte2,7
incf F1633_2,f
decfsz CScan,1
goto pd_200 ; крутимся 256 раз (17920 мкс) - накапливая статистику (1 оборот строго 70 мкс)
В следующем блоке происходит обработка того что приняли в окне по принципу вычитания "половинки+поправка"
(поправка нужна так-так в таблицу укладывается не всегда кратное число периодов и соответственно сумма "1" будет не 128 !!!)
и последующего сложения SIN и COS составляющих, те имитация вычисления "сложения SIN и COS по модулю два"
из накопительных ячеек F697_1...F1633_2 в целях получения значений "ноль" если сигнал отсутствует или "около нуля"
если сигнал имеет слабую корреляцию с искомой частотой при её фазе 0, 90, 180 или 270 градусов
movlw .136 ; вычитаем 128 + плюс поправочный коэфициент
subwf F697_1,f ; и сохраняем SIN+COS в Fxxx_1
btfss STATUS,C ; если произошёл заем те число меньше то значит приняли
comf F697_1,f ; инверсию (сдвиг фазы на 180), что нас тоже интересует
movlw .131 ; теперь переворчиваем фазу и имеем в итоге инфо о корреляции
subwf F697_2,f ; при фазе 0 и 180 градусов как для синуса так и для косинуса.
btfss STATUS,C
comf F697_2,f
movf F697_2,w
addwf F697_1,f
; обработка частоты 697 Гц закончена, продолжаем то-же
movlw .128 ; проделывать и для остальных частот, сохраняя результат
subwf F770_1,f ; корреляции в регистрах Fxxx_1(в целях экономии ОЗУ)
btfss STATUS,C
comf F770_1,f
movlw .127
subwf F770_2,f
btfss STATUS,C
comf F770_2,f
movf F770_2,w
addwf F770_1,f
movlw .130
subwf F852_1,f
btfss STATUS,C
comf F852_1,f
movlw .130
subwf F852_2,f
btfss STATUS,C
comf F852_2,f
movf F852_2,w
addwf F852_1,f
movlw .128
subwf F941_1,f
btfss STATUS,C
comf F941_1,f
movlw .128
subwf F941_2,f
btfss STATUS,C
comf F941_2,f
movf F941_2,w
addwf F941_1,f
movlw .130
subwf F1209_1,f
btfss STATUS,C
comf F1209_1,f
movlw .128
subwf F1209_2,f
btfss STATUS,C
comf F1209_2,f
movf F1209_2,w
addwf F1209_1,f
movlw .129
subwf F1336_1,f
btfss STATUS,C
comf F1336_1,f
movlw .129
subwf F1336_2,f
btfss STATUS,C
comf F1336_2,f
movf F1336_2,w
addwf F1336_1,f
movlw .135
subwf F1477_1,f
btfss STATUS,C
comf F1477_1,f
movlw .128
subwf F1477_2,f
btfss STATUS,C
comf F1477_2,f
movf F1477_2,w
addwf F1477_1,f
movlw .131
subwf F1633_1,f
btfss STATUS,C
comf F1633_1,f
movlw .125
subwf F1633_2,f
btfss STATUS,C
comf F1633_2,f
movf F1633_2,w
addwf F1633_1,f ; первичная обработка 8x10=80 мкс (всего ~1/240 часть от общего времени выбоки и обработки "окна")
Теперь можно протестировать работу программы наглядно, те выдать в цикле значения ячеек
F697_1 ... F1633_1 в программу-терминалку на Ваш персональный компьютер через апаратный USART 16F628 (8 бит, 1 стоповый, 9600 бод),
в целях контроля работоспособности алгоритма, само собой зациклив сканирование и подключив на вход компаратора "бипер" + источник шума,
по следующей схеме:
Которая выдаёт значение рабочего регистра в асинхронном режиме
в порт компьютера, само собой в рабочий регистр надо будет грузить по очереди все 8 регистров F697_1 ... F1633_1
и дополнять пробелами для наглядности(что-б значения корреляции для одной и той-же частоты в терминалке выводились в столбик), например вот так:
Теперь когда мы своими глазами убедились в том что корреляционный алгоритм
действительно устойчиво работает (и если такая работа(вероятность,надёжность...) Вас устраивает)
можно провести перевод значений максимумов в реальное значение DTMF и сохранить его в регистре "RxDtmf"
используя следующий код:
clrf RTemp ; очистка битового указателя на начальные максимумы
movlw F697_1 ; загружаем указатель на F697_1
movwf FSR
movf INDF,w
subwf F770_1,w
btfss STATUS,C
goto pd_300
incf FSR,1
incf FSR,1
bsf RTemp,0
pd_300
movf INDF,w
subwf F852_1,w
btfss STATUS,C
goto pd_320
movlw F852_1
movwf FSR
bsf RTemp,1
pd_320
movf INDF,w
subwf F941_1,w
btfsc STATUS,C
bsf RTemp,2
movlw F1209_1
movwf FSR
movf INDF,w
subwf F1336_1,w
btfss STATUS,C
goto pd_340
incf FSR,1
incf FSR,1
bsf RTemp,3
pd_340
movf INDF,w
subwf F1477_1,w
btfss STATUS,C
goto pd_360
movlw F1477_1
movwf FSR
bsf RTemp,4
pd_360
movf INDF,w
subwf F1633_1,w
btfsc STATUS,C
bsf RTemp,5
btfss RTemp,2 ; разбираемся какое принято базовое число 1,4,7,10
goto pd_400 ; в зависимости от состояния 3 флагов в регистре указателе
movlw .10 ; на максимум в верхней группе частот
movwf RxDtmf
goto pd_500
pd_400
btfss RTemp,1
goto pd_420
movlw .7
movwf RxDtmf
goto pd_500
pd_420
btfss RTemp,0
goto pd_440
movlw .4
movwf RxDtmf
goto pd_500
pd_440
movlw .1
movwf RxDtmf
; блок коррекции по номеру столбца базового числа
pd_500 ; те прибавляем к 1,4,7,10 числа 1,2,3 в зависимости
btfss RTemp,5 ; от состояния 3 флагов в регистре указателе
goto pd_520 ; на максимум в нижней группе частот
movlw .3
addwf RxDtmf,1
goto pd_600
pd_520
btfss RTemp,4
goto pd_540
incf RxDtmf,1
incf RxDtmf,1
goto pd_600
pd_540
btfsc RTemp,3
incf RxDtmf,1 ; в RxDtmf конечный результат ( только коду "0" соотв.зачение 11 !!!)
В итоге получили искомый код DTMF за время менее 20 мс,
если-б это был АОНовский "безинтервальник" - можно было-б сказать что "дело сделано", но тк у DTMF
есть такая неприятность как неизвестная длительность (от 60 мс и больше) и паузы между посылками,
то приходится ещё делать несколько повторных проверок (хватает 2х но лутчше 3),
при этом попутно ловится пауза запись значения в регистр "00" если DTMF отсутствует,
что так-же можно использовать в Вашей программе. Эту часть программы я тут не привожу тк считаю что
та часть моей программы где делается сравнение 2-х байт и результат заносится в счётчик совпадений
достаточно проста для понимания даже начинающим.
На этом пока всё - берите готовый проект для MPLab и дополняйте своим кодом,
если найдёте на страничке неточности (подчти всё в НТМL набрал за один день) или просто "ляпы",
или будут вопросы и пожелания - то отпишите мне: Сергею Смирнову,
или заходите на мой форум
просто пообщатся на тему о различных доработках и разработках в области связи.
Необходимо наличие схемы, описания устройства и т.д. (для отдельных проектов - драйвера, программное обеспечение и их описание)
Схемы и другие картинки должны быть в форматах .jpg или.gif. К ним обязательно должны идти подписи, поясняющие, что на данной схеме (картинке) изображено.
Описание устройства - в форматах .doc, .txt или .html.
Проект не должен нарушать чьих-либо авторских прав.