Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Синхронизация по фронтам
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Mayak
Здравствуйте. Есть задача. На вход поступает сигнал определенной частоты. На выходе необходимо после вычисления частоты выдать такой же сигнал синхронизированный с входящим по нарастающему и убывающему фронтам.
Делаю так:
- по первому прерыванию int0 включаю счетчик
- по второму прерыванию int0 останавливаю счетчик и вычисляю полупериод
- вычисляю задержки на вход в прерывания и по прерыванию по сравнению таймера меняю выход с 1 на 0 и наоборот.
Прерывание по сравнению происходит раньше смены фронтов входящего сигнала на величину задержки.
По идее должно работать, но на осциллографе частота получается равная, а вот фронты не совпадают.
Подскажите, что не так. Может вообще как-то по другому надо все делать?

Код
;***************************************************************************

;***************************************************************************
.include "m16def.inc"
.def temp=r16;
.def timeL=r17;
.def timeH=r18;
.def counter=r21;

.CSEG          ;начало сегмента
.ORG 0              ;вектор сброса
    rjmp init;
.ORG INT0addr
    rjmp Ext_INT0          ; (INT0) External Interrupt Request 0
.ORG OC1Aaddr            ; Timer/Counter1 Compare Match A
    rjmp Ext_OC1A
.ORG OC1Baddr
    rjmp Ext_OC1B

;==========================
;        Прерывания
;==========================

Ext_INT0:
loop1:
    cpi counter,1;        Захватываем начало периода по 1-му нарастающему фронту
    brne loop2
    ldi r16,0b00000001
    out TCCR1B,r16
    inc counter
    rjmp exit
loop2:
    cpi counter,2;        Захватываем конец периода по 2-му нарастающему фронту
    brne loop3
    ldi r16,0b00000000
    out TCCR1B,r16
    in timeL,TCNT1L;            
    in timeH,TCNT1H
    subi timeL,3;        убираем задержку вычисления периода
    sbci timeH,0
    mov r23,timeH
    mov r22,timeL
    subi r22,51    ;устанавливаем задержку для совпадения фронта
    sbci r23,0    ; и заносим ее в OCR1B
    out OCR1BH,r23        
    out OCR1BL,r22
    lsr timeH    ;Вычисляем длительность импульса
    ror timeL        
    subi timeL,16    ; убираем задержку для смены фронтов
    sbci timeH,0
    out OCR1AH,timeH; длительность импульса в OCR1A
    out OCR1AL,timeL
    ldi r16,0
    out TCNT1H,r16
    out TCNT1L,r16
    inc counter
    rjmp exit
loop3:
    ldi r16,0    ;включаем таймер тс1в
    out GICR,r16
    ldi r16,0b00001000
    out TIMSK,r16
    ldi r16,0b00000001    
    out TCCR1B,r16
    ldi r16,0
    out TCNT1H,r16
    out TCNT1L,r16
exit:
reti

Ext_OC1B:
    ldi r16,0b00010000; запускаем задержку для совпадения фронтов
    out TIMSK,r16
    ldi r16,0
    out TCNT1H,r16
    out TCNT1L,r16
reti

Ext_OC1A:        ; запускаем задержку для смены фронтов
    in r16,PortD
    ldi r17,0b00000001
    eor r16,r17
    out PortD,r16
    ldi r16,0b00000000
    out TCNT1H,r16
    out TCNT1L,r16
reti


;=========================
;        Инициализация
;=========================
Init:
    ldi r31,LOW(RAMEND)
    out spl,r31
    ldi r31,HIGH(RAMEND)
    out sph,r31

    ldi r16,0b11111011; Настройка портов
    out DDRD,r16;
    ldi r16,0b00000100;
    out PortD,r16;
    ldi r16,0b00000011;
    out MCUCR,r16;
    ldi r16,0b01000000;
    out GICR,r16;
    ldi r18,100
    ldi r21,1
    ldi r16,0b00000101;
    sei;
    
reset:  ;RESET
777777
Цитата(Mayak @ Sep 5 2011, 10:49) *
Здравствуйте. Есть задача. На вход поступает сигнал определенной частоты. На выходе необходимо после вычисления частоты выдать такой же сигнал синхронизированный с входящим по нарастающему и убывающему фронтам.

То есть в точности такой же. Тогда зачем его выдавать? Подайте на выход входной сигнал, раз он ничем не отличается от выходного.
Mayak
Спасибо за совет. В итоге нужно будет еще изменять ширину импульса и сдвигать выходной сигнал относительно входящего.
Попробовал просто передавать сигнал - все равно есть задержка, где-то 500 нС.
Код
    sbic PinD,2
    sbi PortD,0
    sbis PinD,2
    cbi PortD,0
zombi
Цитата(Mayak @ Sep 5 2011, 09:49) *
На вход поступает сигнал определенной частоты. На выходе необходимо после вычисления частоты выдать такой же сигнал

Это не возможно.

Цитата(Mayak @ Sep 5 2011, 12:58) *
Спасибо за совет. В итоге нужно будет еще изменять ширину импульса и сдвигать выходной сигнал относительно входящего.
Попробовал просто передавать сигнал - все равно есть задержка, где-то 500 нС.
Код
    sbic PinD,2
    sbi PortD,0
    sbis PinD,2
    cbi PortD,0

И чему вы удивляетесь?
Для выполнения любой команды процессору нужно время равное целому числу тактов входной частоты.
Палыч
Цитата(Mayak @ Sep 5 2011, 13:58) *
... все равно есть задержка, где-то 500 нС.
Очень даже небольшая задержка для МК. А, Вы ошибку какой величины желаете получить?
ILYAUL
QUOTE (Mayak @ Sep 5 2011, 10:49) *
Подскажите, что не так. Может вообще как-то по другому надо все делать?

QUOTE (Mayak @ Sep 5 2011, 10:49) *
- по первому прерыванию int0 включаю счетчик ..... и меняю выход с 1 на 0

QUOTE (Mayak @ Sep 5 2011, 10:49) *
- по второму прерыванию int0 останавливаю счетчик , меняю выход наоборот и выйдя из прерывания вычисляю полупериод

Для этого добавляем
MAIN:
--------------
вычисляю полупериод
rjmp MAIN
А задержку на прерывания считаем один раз - а далее считаем ее константой.
Mayak
Спасибо за советы. Переделал программу. Теперь по прерываниям int0 я вычисляю полупериод, записываю его длительность в TC1 и по прерыванию по сравнению меняю выход с 1 на 0 и наоборот. Вроде работает, но есть небольшое дрожание фаз, как с ним бороться?
Код
;***************************************************************************

;***************************************************************************
;15.08.11
.DEVICE ATmega16
.include "m16def.inc"
.def temp=r16;
.def timeL=r17;
.def timeH=r18;
.def pause=r19;
.def pause1=r20;
.def counter=r21;
.def tempL=r22;
.def tempH=r23

.CSEG          
.ORG 0              
    rjmp init;
.ORG INT0addr
    rjmp Ext_INT0          ; (INT0) External Interrupt Request 0
.ORG OC1Baddr
    rjmp Ext_OC1B

;==========================
;        Прерывания
;==========================

Ext_INT0:
    in timeL,TCNT1L
    in timeH,TCNT1H
    inc counter
    in r16,MCUCR;
    eor r16,r22
    out MCUCR,r16
    ldi r16,0b00000000
    out TCNT1H,r16
    out TCNT1L,r16
    ldi r16,0b00000001
    out TCCR1B,r16
reti


Ext_OC1B:
    in r16,PortD
    eor r16,r22
    out PortD,r16
reti
;=========================
;        Инициализация
;=========================
Init:
    ldi r31,LOW(RAMEND)
    out spl,r31
    ldi r31,HIGH(RAMEND)
    out sph,r31

    ldi r16,0b11111011; Настройка портов
    out DDRD,r16;
    ldi r16,0b00000100;
    out PortD,r16;
    ldi r16,0b00000011;
    out MCUCR,r16;
    ldi r16,0b01000000;
    out GICR,r16;
    ldi counter,1
    ldi r16,0b00001000
    out TIMSK,r16
    ldi r22,0b00000001;
    sei;
    
reset:  ;RESET
    cpi counter,2
    brne reset
    cli
    subi timeL,22             ; делаем задержку
    sbci timeH,0
    out OCR1BH,timeH
    out OCR1BL,timeL
    dec counter;
    sei
rjmp reset
Палыч
Цитата(Mayak @ Sep 8 2011, 12:37) *
есть небольшое дрожание фаз, как с ним бороться?[
"Небольшие" - это сколько? А, сколько хотите получить? Приведенная программа - это только часть будущей большой программы? Наверное, ещё добавится интерфейс управления устройством, добавятся процедуры прерываний?
Судя по тому, что для Вас 500нс - большая величина, то, вероятно, Вы для решения задачи выбрали не верные средства...
Mayak
Наверное все-таки не тем путем я пошел.
Задача такая!
Начальные условия:
На вход поступает сигнал от 5кГц до 80 кГц.
Необходимо:
На выходе получить сигнал такой же частоты, синхронизированный по фронтам. По нажатию кнопки нужно будет сдвигать этот сигнал с определенным шагом на длину импульса. По нажатию другой кнопки нужно будет регулировать длину импульса (ШИМ).
Палыч
Конкретных цифр по желаемой точности Вы так и не привели...

Цитата(Mayak @ Sep 8 2011, 13:55) *
На вход поступает сигнал от 5кГц до 80 кГц.
80 кГц - для программного формирования частоты на AVR - довольно "круто". Посчитайте сами: при тактировании 16МГц - на период следования импульса у Вас есть не более 200 команд МК...

Цитата(Mayak @ Sep 8 2011, 13:55) *
На выходе получить сигнал такой же частоты, синхронизированный по фронтам. По нажатию кнопки нужно будет сдвигать этот сигнал с определенным шагом на длину импульса. По нажатию другой кнопки нужно будет регулировать длину импульса (ШИМ).
Опять же - нет конкретных цифр... Но, при "плавающей" в таком широком диапазоне частоте входных синхроимпульсов невозможно обеспечить задержку между входным и выходным импульсами менее некой величины, если это - нужно. МК не может "предсказывать" приход синхроимпульса, чтобы начать выполнение некой подпрограммы заранее. Да, и ширину импульса на высоких частотах синхроимпульсов вряд ли удастся изменять с шагом менее нескольких процентов...

ILYAUL
QUOTE (Палыч @ Sep 8 2011, 14:45) *
Конкретных цифр по желаемой точности Вы так и не привели...

80 кГц - для программного формирования частоты на AVR - довольно "круто". Посчитайте сами: при тактировании 16МГц - на период следования импульса у Вас есть не более 200 команд МК...

так и ну его нафинг , считать программно, загнать его обратно в счётчик (16 бит) и пусть себе считает по ICP период или длительность, а во второй то что насчитал, а в память сохранять.
Ну, что-то типа того,приблизительно
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.