Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
Карта сайта | Пишите нам | В избранное | eng     

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


Вариант схемы в формате 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    
    return
out_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_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 набрал за один день) или просто "ляпы", или будут вопросы и пожелания - то отпишите мне: Сергею Смирнову, или заходите на мой форум просто пообщатся на тему о различных доработках и разработках в области связи.

Сайт: http://www.zk.ru/smsn/dtmf/

 Разместите Ваш проект у нас на сайте и его смогут увидеть сотни посетителей в день. Ваши проекты присылайте вебмастеру.
Правила оформления проектов
  1. Необходимо наличие схемы, описания устройства и т.д. (для отдельных проектов - драйвера, программное обеспечение и их описание)
  2. Схемы и другие картинки должны быть в форматах .jpg или.gif. К ним обязательно должны идти подписи, поясняющие, что на данной схеме (картинке) изображено.
  3. Описание устройства - в форматах .doc, .txt или .html.
  4. Проект не должен нарушать чьих-либо авторских прав.
Ваши проекты присылайте вебмастеру
Приглашаем специалистов
В России кризис и увольнения персонала, а в Телесистемах, как обычно, не так как у всех: мы расширяем деятельность, набираем новых сотрудников и ищем новых партнеров.
Изделия для разработчиков
Программатор «PICPROG» «PICPROG» - универсальный промышленный программатор.
Копировщик PIC16x8x Копировщик PIC16x8x - тиражирование в автономном режиме.
Наши телефоны: (495) 638-88-00, (499) 940-95-75, факс (499) 735-04-91, мобильные: (903) 530-10-01 и (909) 638-88-00 (БиЛайн).
E-mail:

Copyright © ООО "Телесистемы", 1997 — 2024    Копируйте на здоровье! За ссылку на www.telesys.ru мы вам будем очень признательны.

Rambler's Top100