Объявление

Свернуть
Пока нет объявлений.

Программное дeкодирование DTMF по принципу АОН на базе микроконтроллера PIC16F628

Свернуть
X
Свернуть
  •  

  • Программное д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 PCLdtmf_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 и переделать её на своё усмотрение: Исходная таблица для расчёта эталонных значений.

    Теперь рассмотрим как это всё работает т.е., сейчас я прокоментирую самые на мой взгляд - интересные части:



    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 бод), в целях контроля работоспособности алгоритма, само собой зациклив сканирование и подключив на вход компаратора "бипер" + источник шума, по следующей схеме:
    Нажмите на изображение для увеличения.

Название:	dtmf.gif
Просмотров:	900
Размер:	5.5 Кб
ID:	3382 />
    Вариант схемы в формате PCAD 4.5
    Для работы этой схемы необходимо выполнить следующую инициализацию:

    ;-------------------------------; инициализация модуля компараторов
    movlw B'00000101'
    movwf CMCON ; подключен только 2 компаратор (входы 1 компаратора можно использовать
    bsf STATUS,RP0 ; как цифровые для полноценного ввода-вывода)
    movlw B'11100110'
    movwf VRCON ; на вывод RA2 подключаем внутренний источник +Vout=1,25 (при питании +5в)
    bcf STATUS,RP0;-------------------------------; инициализация USART
    bsf STATUS,RP0
    movlw .25 ; задаём скорость 9600
    movwf SPBRG
    bsf TXSTA,BRGH
    bcf TXSTA,SYNC
    bsf TXSTA,TXEN
    bcf STATUS,RP0
    bsf RCSTA,SPEN Далее включаем в проект следующую тестовую подпрограмму:

    out_DTMF
    call out_busy
    movwf TXREG
    returnout_busy
    clrwdt
    btfss PIR1,TXIF
    goto out_busy
    return Которая выдаёт значение рабочего регистра в асинхронном режиме в порт компьютера, само собой в рабочий регистр надо будет грузить по очереди все 8 регистров F697_1 ... F1633_1 и дополнять пробелами для наглядности(что-б значения корреляции для одной и той-же частоты в терминалке выводились в столбик), например вот так:

    movf F697_1,w
    call out_DTMF
    movf F770_1,w
    call out_DTMF
    ..............
    movf F1633_1,w
    call out_DTMF
    movlw 0x20
    call out_DTMF
    .............. Теперь когда мы своими глазами убедились в том что корреляционный алгоритм действительно устойчиво работает (и если такая работа(вероятность,надёжность...) Вас устраивает) можно провести перевод значений максимумов в реальное значение 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_500pd_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-х байт и результат заносится в счётчик совпадений достаточно проста для понимания даже начинающим.

      Возможность размещать комментарии к сообщениям отключена.

    Метки статей

    Свернуть

    Меток пока нет.

    Новые статьи

    Свернуть

    Обработка...
    X