[an error occurred while processing this directive]
Вот для PEC16 для AVR:
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено Леонид Иванович 19 июня 2006 г. 13:35
В ответ на: О вопрос в студийю, об обработке датчика угла и вращения , бифазного. + отправлено Kenat 19 июня 2006 г. 12:28

Обработка энкодера по прерываниям неудобна, так как требуется давить дребезг. Более того, чтобы корректно реализовать квадратурный декодер 1х (или 2х, 4х), прерывания должны происходить не по фронту или спаду одного из сигналов, а по любому изменению состояния энкодера. Я обрабатываю энкодер и его кнопку в основном цикле программы. Если программа чем-то занята, то она всё равно не сможет отреагировать на вращение энкодера, а буферизовать проделанный поворот и откладывать его обрботку - это уже слишком. Практика показала, что для комфорного использования энкодера задержки на подавление дребезга не должны превышать 500 мкс, иначе становится заметным пропуск шагов при резком повороте ручки. Я использую 300 мкс. Столь малые времена, к сожалению, не могут быть сформированы системным таймером как большинство других временных интервалов в программе. Поэтому приходится применять "тупую" задержку в виде цикла. Для таких малых интервалов это вполне допустимо, потери производительности процессора будут минимальными. Тем более, что обработка энкодера - это общение с пользователем, который всегда является самым медленным звеном системы :) Более того, если какая-то задача в основном цикле захочет временно забрать все ресурсы процессора (за вычетом потерь на прерывания), она сможет это сделать. В это время энкодер обслуживаться не будет. Для кнопки время подавления дребезга должно быть существенно большим, я использую 50 мс. Уж очень разные механические характеристики контактных групп кнопки и энкодера.

Программа построена следующим образом: в начале программы один раз вызывается инициализация энкодера iEnc. В основном цикле, который "крутится" с той частотой, которую позволяет процессор и его загрузка на данный момент, вызывается основная задача энкодера mEnc. Она в глобальной переменной Msg оставляет код события энкодера. Этот код передается всем задачам основного цикла, любая из них может его обработать. Функция mEnc вызывает функцию сканирования энкодера EScan, осуществляет подавление дребезга, реализует 1х квадратурный декодер и формирует код события. Квадратурный декодер большей кратности применить тоже можно, но для PEC-16 именно для декодера 1х на каждый щелчок приходится один инкремент/декремент.

Вот текст модуля поддержки энкодера:


;Encoder support module

;----------------------------------------------------------------------------

;Constantes:

.equ ENDEB = 300 ;encoder debounce delay, uS
.equ SWDEB = 50000 ;switch button debounce delay, uS

;----------------------------------------------------------------------------

;Derivated constantes:

.equ ENDEBV = ENDEB/100

.if ENDEBV > MAXBYTE
.error "out of range constant"
.endif

.equ SWDEBV = SWDEB/100

.if ENDEBV > MAXBYTE
.error "out of range constant"
.endif

;----------------------------------------------------------------------------

;Messages:

.equ msgNop = 0x00 ;no operation
.equ msgInc = 0x01 ;increment
.equ msgDec = 0x02 ;decrement
.equ msgKdn = 0x03 ;key down
.equ msgKup = 0x04 ;key up

;----------------------------------------------------------------------------

.DSEG ;Data segment

;----------------------------------------------------------------------------

.CSEG ;Code segment

;----------------------------------------------------------------------------

;Encoder subsystem init:

iEnc: ldi Msg,msgNop ;no operation
rcall EScan ;scan encoder
mov EncSt,temp ;save encoder state
ret

;----------------------------------------------------------------------------

;Encoder read:

mEnc: rcall EScan ;scan encoder
mov Cnt,temp ;save encoder state
eor temp,EncSt ;check for changes
breq no_ch ;return, no changes

ldi temp,ENDEBV ;debounce delay for encoder
bbrc temp,2,no_sw
ldi temp,SWDEBV ;debounce delay for switch button
no_sw: rcall Delay

rcall EScan ;scan encoder
cp temp,Cnt ;check encoder state
brne no_ch ;return, bounce

mov temp,EncSt ;previous encoder state
mov EncSt,Cnt ;save new encoder state

;Switch button check:

bbrc temp,2,s_0
bbrs Cnt,2,q1x ;no changes
ldi Msg,msgKdn ;key down message
rjmp e_ret
s_0: bbrc Cnt,2,q1x ;no changes
ldi Msg,msgKup ;key up message
rjmp e_ret

;1x quadrature decoder:

q1x: bbrc temp,0,a_0
a_1: bbrc Cnt,0,a_10
rjmp no_ch
a_0: bbrs Cnt,0,a_01
rjmp no_ch
a_01: bbrc Cnt,1,pls
rjmp no_ch
a_10: bbrc Cnt,1,min
rjmp no_ch

pls: ldi Msg,msgInc ;send increment message
rjmp e_ret

min: ldi Msg,msgDec ;send decrement message
rjmp e_ret

no_ch: ldi Msg,msgNop ;send no operation message
e_ret: ret

;----------------------------------------------------------------------------

;Scan encoder:
;Out: temp - encoder state

EScan: clr temp
Skip_if_Port_EF1_0
stbr temp,0
Skip_if_Port_EF2_0
stbr temp,1
Skip_if_Port_ESB_0
stbr temp,2
ret

;----------------------------------------------------------------------------

;Delay:
;Input: temp = delay [x100 uS]

Delay: push Cnt
de2: ldi Cnt,FCLK/100000
de1: dec Cnt ;1 +
nop ;1 +
nop ;1 +
nop ;1 +
nop ;1 +
nop ;1 +
nop ;1 +
nop ;1 +
brne de1 ;2 = 10
dec temp
brne de2
pop Cnt
ret

;----------------------------------------------------------------------------

Вот текст основного модуля программы:


;* Title : Encoder PEC-16 test
;* Version : 1.00
;* Target : ATmega8
;* Author : wubblick@yahoo.com

;----------------------------------------------------------------------------

.include "m8def.inc"
.include "macros.mac"
.include "Header.asm"

;------------------------- Interrupt Vectors: -------------------------------

.CSEG ;code segment
.org 0
rjmp Init ;reset vector
.org OC1Aaddr
rjmp Timer ;Timer1 OC vector
.org SPMaddr+1 ;skip vector table

;-------------------- Program Execution Starts Here: ------------------------

Init: ldy RAMEND
out SPL,YL ;locate stack
out SPH,YH
rcall iWdog ;start internal watchdog
rcall iPorts ;ports init
rcall iVar ;variables init
rcall iTimer ;system timer init
rcall iEnc ;encoder subsystem init
;...
sei ;interrupts enable

;Main loop:

Main: rcall mEnc ;read encoder
;process encoder messages
;...
rcall mWdog ;watchdog restart
rjmp Main ;loop

;------------------------- Subroutines area: --------------------------------

;Internal watchdog init:

iWdog: wdr
ldi temp,(1< out WDTCR,temp
ldi temp,(1< out WDTCR,temp ;watchdog enable, period 260 mS

;Internal watchdog restart:

mWdog: bbrc FLAGS,WUpd,nu
clbr FLAGS,WUpd
wdr ;internal watchdog restart
nu: ret

;----------------------------------------------------------------------------

;Ports init:

iPorts: ldi temp,PUPB
out PORTB,temp ;init PORTB and on/off pullup
ldi temp,DIRB
out DDRB,temp ;set PORTB direction

ldi temp,PUPC
out PORTC,temp ;init PORTC and on/off pullup
ldi temp,DIRC
out DDRC,temp ;set PORTC direction

ldi temp,PUPD
out PORTD,temp ;init PORTD and on/off pullup
ldi temp,DIRD
out DDRD,temp ;set PORTD direction
ret

;----------------------------------------------------------------------------

;Variables init:

iVar: clr FLAGS ;clear flags
ret

;----------------------------------------------------------------------------

;System timer init:

iTimer: ldi temp,0
out TCCR1A,temp ;OC disable, PWM disable
ldi temp,(1< out TCCR1B,temp ;CTC, CK/1

ldi temp,byte2(T1Div-1)
out OCR1AH,temp ;compare register load
ldi temp,byte1(T1Div-1)
out OCR1AL,temp

in temp,TIMSK
ori temp,(1< out TIFR,temp ;clear pending interrupts
out TIMSK,temp ;output compare interrupt enable
ret

;System timer interrupt:

Timer: push temp
in temp,SREG ;save status register
push temp
stbr Flags,WUpd ;set watchdog update flag
;...

pop temp
out SREG,temp ;restore status register
pop temp
reti

;----------------------------------------------------------------------------

.include "Encoder.asm" ;link encoder control module

;----------------------------------------------------------------------------

Вот заголовочный файл проекта:


;Project header file

;----------------------------------------------------------------------------

;Constantes:

.equ FCLK = 10000000 ;Fclk, Hz
.equ TSYS = 1000 ;time base, uS

;----------------------------------------------------------------------------

;Derivated constantes:

.equ MAXBYTE = 0xFF
.equ MAXWORD = 0xFFFF

.equ T1Div = ((((Fclk/1000)*Tsys)/100)+5)/10 ;CK/1

.if T1Div > MAXWORD
.error "out of range constant"
.endif

;----------------------------------------------------------------------------

;Port Definitions:

.equ DIRB = 0b11111111 ;Port B direction
.equ PUPB = 0b00000000 ;Port B pull-ups

.equ DIRC = 0b11001111 ;Port C direction
.equ PUPC = 0b00110000 ;Port C pull-ups
.equ EF2 = PC4 ; Encoder F2
.equ EF1 = PC5 ; Encoder F1

.macro Skip_if_Port_EF1_0 ;skip if EF1 = 0
sbic PINC,EF1
.endm

.macro Skip_if_Port_EF2_0 ;skip if EF2 = 0
sbic PINC,EF2
.endm

.equ DIRD = 0b11111110 ;Port D direction
.equ PUPD = 0b00000001 ;Port D pull-ups
.equ ESB = PD0 ; Encoder SB

.macro Skip_if_Port_ESB_0 ;skip if ESB = 0
sbic PIND,ESB
.endm

;----------------------------------------------------------------------------

;Global Register Variables:

;r0, r1 used with mul instruction

.def EncSt = r2 ;store encoder state

.def temp = r16 ;temporary register temp
.def Cnt = r17 ;temporary register Cnt
.def Msg = r18 ;message code

.def FLAGS = r25 ;flags
.equ WUpd = 0 ;watchdog update flag

;r26,r27 used as X-register
;r28,r29 used as Y-register
;r30,r31 used as Z-register

;----------------------------------------------------------------------------

Вот файл макросов, которые могут встречаться в данном проекте:


;***** Macros

.macro clbr ;clear bit in register
cbr @0,exp2(@1)
.endm

.macro stbr ;set bit in register
sbr @0,exp2(@1)
.endm

.macro bbrc ;branch if bit in register clear
sbrs @0,@1
rjmp @2
.endm

.macro bbrs ;branch if bit in register set
sbrc @0,@1
rjmp @2
.endm

.macro bbic ;branch if bit in I/O clear
sbis @0,@1
rjmp @2
.endm

.macro bbis ;branch if bit in I/O set
sbic @0,@1
rjmp @2
.endm

.macro addi ;add immediate
subi @0,-@1
.endm

.macro ldx ;load XL, XH with word
ldi XL,byte1(@0)
ldi XH,byte2(@0)
.endm

.macro ldy ;load YL, YH with word
ldi YL,byte1(@0)
ldi YH,byte2(@0)
.endm

.macro ldz ;load ZL, ZH with word
ldi ZL,byte1(@0)
ldi ZH,byte2(@0)
.endm

.macro table ;load Z pointer
ldi ZL,low (@0*2)
ldi ZH,high(@0*2)
.endm

.macro stdi ;store immediate indirect with displacement
ldi temp,@1
std @0,temp
.endm

.macro ldsx ;load XL, XH from memory
lds XL,@0+0
lds XH,@0+1
.endm

.macro ldsy ;load YL, YH from memory
lds YL,@0+0
lds YH,@0+1
.endm

.macro ldsz ;load ZL, ZH from memory
lds ZL,@0+0
lds ZH,@0+1
.endm

.macro stsx ;store XL, XH in memory
sts @0+0,XL
sts @0+1,XH
.endm

.macro stsy ;store YL, YH in memory
sts @0+0,YL
sts @0+1,YH
.endm

.macro stsz ;store ZL, ZH in memory
sts @0+0,ZL
sts @0+1,ZH
.endm


Составить ответ  |||  Конференция  |||  Архив

Ответы


Отправка ответа

Имя (обязательно): 
Пароль: 
E-mail: 
NoIX ключ Запомнить

Тема (обязательно):
Сообщение:

Ссылка на URL: 
Название ссылки: 

URL изображения: 


Rambler's Top100 Рейтинг@Mail.ru
Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание

E-mail: info@telesys.ru