[an error occurred while processing this directive]
Начал было сагу писать, но надоело...
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

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

Отправлено AK 05 октября 2002 г. 17:15
В ответ на: Мне бы пока невытесняющую, для PIC, а дальше сам разберусь :-) (-) отправлено Анатоль 05 октября 2002 г. 16:29

Я лучше куски своей старой round-robin для PIC покидаю. На ассемблере написана. На С будет по сути то ж самое, но придется ассемблерные вствки делать, это неизбежно. У PIC архитектура кривая, так что довольно некузяво получилось. Пардон за дурной аглицкий.


;1. General
;----------
; Program is organised as a multitask system. The following
;relatively indepentent tasks run sumalteneously:
; - Display task (#1)
; - Keypad task (#2)
; - Backlight task (#3)
; - Buzzer task (#4)
; - none (#5)
; - Language interpreter (#6)
; - none (#7)
; - none (#8)
; Tasks get control exclusivly, ie. other tasks cannot
;intercept control "by force".
; If a task has to wait something it must execute DELAY
;macro sending required delay in W register. This macro stores
;return address in a RAM table and passes control to the core.
;The core calculates return time and stores it in the RAM table.
;Then the core decides which task should get control, fetches
;the task return address from the table and bypasses control to
;the task.
;
;2. Delay
;--------
; Delay value is in ticks. Each task has its own tick
;selected from the following range: 10ms (default), 100ms
;and 1s. Ticks are selected by a tick control variable.
; There are two special delay values, 00 and FFh.
; If task sets DELAY=00 it means that the task can continue
;immediately, without delay. Task executes DELAY=00 as "a good
;will" allowing other tasks to take control. It happens when the
;task can continue, but its duties are not time critical.
; If task sets DELAY=FFh it means that the task has finished
;and would like to sleep. Next invokation of the task should be
;made by another task which requires this task service. Typical
;sample is the buzzer task: it is started by request from either
;keypad ("beep on keypress") or interpreter, when sound is finished
;buzzer task goes to sleep.
;
;3. Syncronisation
;-----------------
; Tasks required to be relatively short. In the worst case
;all tasks must be executed inside 10ms tick, therefore each task
;should not execute more than 150 instructions at once. If more
;than 100 instructions need to be processed the "splitters"
;DELAY=00 must be installed.
; If tasks are too long then accuracy of delays are
;compromised.
;
;4. Core
;-------
; The core is a simple OS kernel. It looks after time flags
;and switches control between tasks.
; Also the core is in charge of task context saving/restore.
;The following registers are stored when task releases control to
;the core:
; W (time delay)
; PCLATH (return address hi)
; PCL (return address low)
; Context must be stored inside the task before control
;is passed to the core. The core returns control with RAM bank 0.
; At power-up return addresses are set to the tasks entry
;points, time delays are set to 0 (immediate access).
;
;5. Timing
;---------
; When timer interrupt occurs it sets 10ms, 100ms and
;1s flags.
; The core checks the 10ms flag. If the flag is present it
;does the following:
; -- checks tick setting for each task
; -- if tick setting is 10ms and task time delay is in the
;range 0; Then the core does the same if 100ms or 1s flags
;are set.
; When timing duties are completed the core checks time
;delay for a task. If its value is 0 it passes control to the task.
;When task return control the core checks next task, etc.
; ------------------------------------------------------------------

; *****************
; *** RTOS core ***
; *****************
L_MAIN clrf STATUS ; set bank 0
set_PCLATH ; set page
btfss PORTB,BIT_PC ; PC present?
call L_PC ; yes
btfsc FLAGS,BIT_PC_PRESENT ; PC has been detected?
goto L_BEGIN ; yes, reset
btfsc FLAGS,BIT_POWER_FAIL ; power failure?
goto L_POWER_FAIL ; yes

; ****************************
; *** Switch between tasks ***
; ****************************
L_NEXT_TASK
clrwdt ; service WDT
btfsc TFLAGS,BIT_T10MS ; 10ms flag?
goto L_CORE_TIME ; yes
incf TASK ; select next task
bcf TASK,3 ; 8=0
prepare_table 10 ;
rlf TASK,W ; get safe value
andlw b'00001110' ; range 2..E
addwf PCL ; jump (safe even if interrupt occurs)

goto L_NEXT_TASK ; speed up
goto L_NEXT_TASK ;
; goto L_SET_TASK8 ;
; goto L_SET_TASK8 ;

goto L_SET_TASK1 ; display
goto L_SET_TASK1 ;
goto L_SET_TASK2 ; keyboard
goto L_SET_TASK2 ;
goto L_SET_TASK3 ; backlight
goto L_SET_TASK3 ;
goto L_SET_TASK4 ; buzzer
goto L_SET_TASK4 ;
goto L_SET_TASK5 ; zero pressure
goto L_SET_TASK5 ;
goto L_SET_TASK6 ; interpreter
goto L_SET_TASK6 ;

goto L_NEXT_TASK ; speed up
goto L_NEXT_TASK ;
; goto L_SET_TASK7 ;
; goto L_SET_TASK7 ;

; *** set task 1
L_SET_TASK1
movf TDELAY1 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH1,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL1,W ; restore low addr
movwf PCL ; jump to task

; *** set task 2
L_SET_TASK2
movf TDELAY2 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH2,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL2,W ; restore low addr
movwf PCL ; jump to task

; *** set task 3
L_SET_TASK3
movf TDELAY3 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH3,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL3,W ; restore low addr
movwf PCL ; jump to task

; *** set task 4
L_SET_TASK4
movf TDELAY4 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH4,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL4,W ; restore low addr
movwf PCL ; jump to task

; *** set task 5
L_SET_TASK5
movf TDELAY5 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH5,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL5,W ; restore low addr
movwf PCL ; jump to task

; *** set task 6
L_SET_TASK6
movf TDELAY6 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH6,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL6,W ; restore low addr
movwf PCL ; jump to task

; *** set task 7
L_SET_TASK7
movf TDELAY7 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH7,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL7,W ; restore low addr
movwf PCL ; jump to task

; *** set task 8
L_SET_TASK8
movf TDELAY8 ; =0 ?
btfss STATUS,Z ;
goto L_NEXT_TASK ; no
movf PCLATH8,W ; yes, restore hi addr
movwf PCLATH ;
movf PCL8,W ; restore low addr
movwf PCL ; jump to task

; ************************
; *** Task time duties ***
; ************************
; *** select tasks with 0 < TDELAYx < FF
L_CORE_TIME
movf TDELAY1 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK2 ; yes
incfsz TDELAY1,W ; =FF?
goto L_COUNT_TASK1 ; no
L_TIM_TASK2
movf TDELAY2 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK3 ; yes
incfsz TDELAY2,W ; =FF?
goto L_COUNT_TASK2 ; no
L_TIM_TASK3
movf TDELAY3 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK4 ; yes
incfsz TDELAY3,W ; =FF?
goto L_COUNT_TASK3 ; no
L_TIM_TASK4
movf TDELAY4 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK5 ; yes
incfsz TDELAY4,W ; =FF?
goto L_COUNT_TASK4 ; no
L_TIM_TASK5
movf TDELAY5 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK6 ; yes
incfsz TDELAY5,W ; =FF?
goto L_COUNT_TASK5 ; no
L_TIM_TASK6
movf TDELAY6 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK7 ; yes
incfsz TDELAY6,W ; =FF?
goto L_COUNT_TASK6 ; no
L_TIM_TASK7
movf TDELAY7 ; =0?
btfsc STATUS,Z ;
goto L_TIM_TASK8 ; yes
incfsz TDELAY7,W ; =FF?
goto L_COUNT_TASK7 ; no
L_TIM_TASK8
movf TDELAY8 ; =0?
btfsc STATUS,Z ;
goto L_END_TIMTASK ; yes
incfsz TDELAY8,W ; =FF?
goto L_COUNT_TASK8 ; no
L_END_TIMTASK
; *** clear flags and return
bcf TFLAGS,BIT_T1MS ;
bcf TFLAGS,BIT_T10MS ;
bcf TFLAGS,BIT_T100MS ;
bcf TFLAGS,BIT_T1SEC ;
goto L_NEXT_TASK ; end

; ******************
; *** Count time ***
; ******************
L_COUNT_TASK1
movf TICKS14,W ; tasks 1-4
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
; WRK,0 flag is set/cleared in L_TASK_TICK
decf TDELAY1 ; yes
goto L_TIM_TASK2 ; next
L_COUNT_TASK2
rrf TICKS14,W ; tasks 1-4
movwf WRK ; temp store
rrf WRK,W ;
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY2 ; yes
goto L_TIM_TASK3 ; next
L_COUNT_TASK3
swapf TICKS14,W ; tasks 1-4
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY3 ; yes
goto L_TIM_TASK4 ; next
L_COUNT_TASK4
rlf TICKS14,W ; tasks 1-4
movwf WRK ; temp store
rlf WRK ; rotate through carry
rlf WRK,0 ;
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,W ; should be decremented?
decf TDELAY4 ; yes
goto L_TIM_TASK5 ; next

; *** special case - always 1sec
; for zero pressure cancelling
L_COUNT_TASK5
movf TICKS58,W ; tasks 5-8
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY5 ; yes

goto L_TIM_TASK6 ; next
L_COUNT_TASK6
rrf TICKS58,W ; tasks 5-8
movwf WRK ; temp store
rrf WRK,W ;
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY6 ; yes
goto L_TIM_TASK7 ; next
L_COUNT_TASK7
swapf TICKS58,W ; tasks 5-8
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY7 ; yes
goto L_TIM_TASK8 ; next
L_COUNT_TASK8
rlf TICKS58,W ; tasks 5-8
movwf WRK ; temp store
rlf WRK ; rotate through carry
rlf WRK,W ;
andlw b'00000011' ; select task
call L_TASK_TICK ; find tick
btfsc WRK,0 ; should be decremented?
decf TDELAY8 ; yes
goto L_END_TIMTASK ;

; ****************************
; *** Task tick subroutine ***
; ****************************
; gets tick selector in W: 00=1ms, 01=10ms, 10=100ms, 11=1s
; returns WRK,0=1 if TDELAYx needs to be decremented
L_TASK_TICK
movwf WRK ; temp store
prepare_table 8 ;
rlf WRK,W ; safe value
andlw b'00000110' ;
bsf WRK,0 ; set flag in advance
addwf PCL ;
goto L_CHECK10MS ; 10ms minimum
goto L_CHECK10MS ;
goto L_CHECK10MS ;
goto L_CHECK10MS ;
goto L_CHECK100MS ;
goto L_CHECK100MS ;
goto L_CHECK1S ;
goto L_CHECK1S ;


L_CHECK10MS
btfss TFLAGS,BIT_T10MS ; 10ms?
bcf WRK,0 ; no, clear flag
return ;

L_CHECK100MS
btfss TFLAGS,BIT_T100MS ; 100ms?
bcf WRK,0 ; no, clear flag
return ; no

L_CHECK1S
btfss TFLAGS,BIT_T1SEC ; 1s?
bcf WRK,0 ; no, clear flag
return ; no


Возврат из задач в ядро RTOS - при помощи макросов. Для каждой задачи - свой макрос:
; mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
; mmmmmmm This MACRO returns control from task 1 to kernel mmmmmmmmm
; mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
delay1 MACRO
bcf STATUS,RP0 ; set bank 0
movwf TDELAY1 ; store delay value in table
IF (low $)>0F8h ; if next instructions hit page border
goto ((high $)+1)*100h ; then jump to the beginning of the new page
org ((high $)+1)*100h ; and start new page
ENDIF
movlw high $ ; store page addr
movwf PCLATH1 ;
movlw (low $)+4 ; store return addr
movwf PCL1 ;
clrf PCLATH ; set page 0
goto L_MAIN ; go to kernel
; *** kernel returns control here
nop ; to ensure correct jump if interrupt occurs
ENDM

Флаг тиков вырабатывается в прерывании. В приведенном куске много
лишнего (т.е. специфического для моей конкретной задачи), другие
прерывания я отрезал. Кому надо, поймет :-)))

; *******************************
; Main interrupt routine
; *******************************
; ************
; Save context
; ************
org 4 ; interrupt vector
movwf CTXW ; save W in either bank
swapf STATUS,W ; save status
bcf STATUS,RP0 ; in bank 0
movwf CTXSTAT ; store STATUS
movf FSR,W ; save FSR
movwf CTXFSR ;
movf PCLATH,W ; save PCLATH
movwf CTXPCLA ;
clrf PCLATH ; page 0

; ****************
; Which interrupt?
; ****************
L_INT_CHECK
btfsc INTCON,INTF ; PFAIL*?
goto L_PFAIL ; yes
btfsc PIR1,ADIE ; A/D ?
goto L_ADC ; yes
btfsc PIR1,TMR2IF ; timer 2?
goto L_TICK1MS ; yes


; ***************
; Restore context
; ***************
movf CTXPCLA,W ; restore PCLATH
movwf PCLATH ;
movf CTXFSR,W ; restore FSR
movwf FSR ;
swapf CTXSTAT,W ; restore STATUS
movwf STATUS ;
swapf CTXW ; restore W
swapf CTXW,W ; use SWAP to keep STATUS inaffected
retfie ; end interrupt

; *******************************
; TIMER 2 interrupt
; *******************************
; timer 2 is reloaded each 100us, interrupt
; occurs each 1ms,
; TICL,TICKH is decimal counter, start value 9999h

L_TICK1MS
bsf TFLAGS,BIT_T1MS ; set tick flag
bcf PIR1,TMR2IF ; clear flag

; *** regulate backlight
movf BKLT_SM,W ; backlight OFF?
andlw b'01100000' ;
btfsc STATUS,Z ; x00xxxxx?
goto L_INT_BKLT_OFF ; yes, set driver OFF

; *** backlight is ON
btfsc BKLT_SM,7 ; full brightness? ie is key pressed?
goto L_INT_BKLT_ON ; yes, set ON unconditionally

; *** toggle backlight
btfsc PORTD,BIT_BKLT ; backlight ON?
goto L_INT_BKLT_ON ; no, set it ON

; *** set driver OFF
L_INT_BKLT_OFF
movlw PORTD_ ; prepare backlight=off auxilary=off
btfsc PORTD,BIT_AUX ; auxilary ON?
movlw PORTD_AUX_ ; yes, keep it ON
movwf PORTD ; switch backlight driver off, keep AUX, SDA and SCL
goto L_INT_VLV_CHK ; exit

; *** set driver ON
L_INT_BKLT_ON
movlw PORTD_BKLT_ ; prepare backlight=on, auxilary=off
btfsc PORTD,BIT_AUX ; auxilary ON?
movlw PORTD_BKLT_AUX_ ; yes, keep it ON
movwf PORTD ; switch backlight driver on, keep AUX, SDA and SCL
goto L_INT_VLV_CHK ; exit


Одна из задач, для примера:

; Keyboard task description
; -------------------------
; Keyboard task is invoked with intervals defined by KPDDBNC variable.
; Each time when invoked it fills 4 LSB of KEY1-KEY4 shift registers by new
; samples of keys. Then it checks short and long key press/release.
; Short key press/release is defined by bit #4 of the related
; KEYx shift register. Long key press/release is defined by bit #7 of
; KEYx shift register. All "0" - key pressed, all "1" - key released.
; KEYS stores a combination of all keys: 4 LSB store short press/release,
; 4 MSB store long press/release. The KEYS stores value in the inverted form:
; 1 - key is pressed, 0 - key is released
; KEYS_PRESSED is used as a handshake variable. Its low nibble reflects
; KEYS either long or short press value. The hi nibble is a counter to swithch
; speed. When KEY_PRESSED=0 it means that all keys are released. When a key is
; pressed then hi nibble <>0. Initially is set to 0001 by a long keypress.
; External tasks should read low nibble and then clear it. The keyboard task
; updates the low nibble if a keypress is detected and increases the hi nibble.
; If the hi nibble is less than 0100 then update is made by long keypress else
; it is made by short keypress. Request for buzzer beep is made accordingtly,
; but only in case when the low nibble of KEYS_PRESSED is cleared


; *****************
; *** Init task ***
; *****************
L_TASK2_START
L_TASK2 movlw 0FFh ; clear keys
movwf KEY1 ;
movwf KEY2 ;
movwf KEY3 ;
movwf KEY4 ;
clrf KEYS ;
clrf KEYS_PRESSED ;
movlw 2 ; default 20ms
movwf KPDDBNS ;

; ******************
; *** Input keys ***
; ******************
L_TASK2_RUN
set_bank 0 ; ensure
movf TICKS14,W ; set tick to 10ms
andlw b'11110011' ;
iorlw b'00000100' ;
movwf TICKS14 ;
clrf CNT ; clear flags

; *** input keys
call L_TASK2_INKEYS ;
; *** check keys
call L_TASK2_CHKKEYS ; result is in KEYS

; *** exit if all keys are released
movf KEYS,W ;
andlw 0Fh ; check short release
btfss STATUS,Z ; all 0?
goto L_TASK2_PR ; no, a key is pressed
clrf KEYS_PRESSED ; yes, all keys are released
goto L_TASK2_LIM ; exit

; *** a key is pressed
L_TASK2_PR
bsf BKLT_SM,7 ; set full brightness
movf KEYS_PRESSED,W ; low nibble cleared? (ie handshake?)
andlw 0Fh ;
btfss STATUS,Z ;
goto L_TASK2_LIM ; no, exit
nop ; debug

; *** handshake OK
movf KEYS_PRESSED,W ; hi nibble x110 xxxx ?
andlw 70h ; select
xorlw 70h ; compare
btfss STATUS,Z ; equal?
goto L_TASK2_LPR ; no, use longpress

; *** use shortpress
btfss CNT,0 ; shortpress flag?
goto L_TASK2_LIM ; no, exit
movf KEYS,W ; yes, update
andlw 0Fh ; select shortpress
iorlw 70h ; simulate hi nibble counter
movwf KEYS_PRESSED ; store
bsf BUZZ_REQUEST,BIT_KBD_BEEP ; set request to buzzer
goto L_TASK2_LIM ; exit

; *** use longpress
L_TASK2_LPR
movf KEYS_PRESSED,W ; first keypress?
btfsc STATUS,Z ;
goto L_TASK2_LPR1 ; yes

; *** not a first
btfss CNT,7 ; longpress flag?
goto L_TASK2_LIM ; no, exit
L_TASK2_LPRX
movf KEYS,W ; yes, update
andlw 0Fh ; select
iorwf KEYS_PRESSED ; combine (note: low nibble was 0)
movlw 10h ; count longpresses
addwf KEYS_PRESSED ;
bsf BUZZ_REQUEST,BIT_KBD_BEEP ; set request to buzzer
goto L_TASK2_LIM ; exit

; *** first keypress
L_TASK2_LPR1
btfss CNT,0 ; shortpress flag?
goto L_TASK2_LIM ; no, exit
goto L_TASK2_LPRX ;

; *************
; *** Sleep ***
; *************
; *** limit
L_TASK2_LIM
movf KPDDBNS,W ; range 10..150 ms per sample
andlw 0Fh ; (5 shifts => 50..750ms)
movwf KPDDBNS ;
movlw 1 ; 00->1
movf KPDDBNS ;
btfsc STATUS,Z ; =0?
movwf KPDDBNS ; yes, replace by 1

movf KPDDBNS,W ;
delay2 ;
goto L_TASK2_RUN ; loop

; --------------------------------------------------------------------------
; *********************
; **** SUBROUTINES ****
; *********************

; ******************
; *** Input keys ***
; ******************
; shift a sample into KEYx - use only 5 lsb bits, keep 3 msb unchanged
L_TASK2_INKEYS
; *** input key 1
bsf STATUS,C ;
btfss PORTD,BIT_KFLAT ; key pressed?
bcf STATUS,C ; yes
rlf KEY1,W ; shift new sample
andlw 0Fh ; select 5 lsb only
movwf WRK ; temp store
movf KEY1,W ; get old value
andlw 0F0h ; select 4 msb
iorwf WRK,W ; combine with bit shift
movwf KEY1 ; store

; *** input key 2
bsf STATUS,C ;
btfss PORTD,BIT_KPLUS ; key pressed?
bcf STATUS,C ; yes
rlf KEY2,W ; shift new sample
andlw 0Fh ; select 5 lsb only
movwf WRK ; temp store
movf KEY2,W ; get old value
andlw 0F0h ; select 4 msb
iorwf WRK,W ; combine with bit shift
movwf KEY2 ; store

; *** input key 3
bsf STATUS,C ;
btfss PORTD,BIT_KMINUS ; key pressed?
bcf STATUS,C ; yes
rlf KEY3,W ; shift new sample
andlw 0Fh ; select 5 lsb only
movwf WRK ; temp store
movf KEY3,W ; ket old value
andlw 0F0h ; select 4 msb
iorwf WRK,W ; combine with bit shift
movwf KEY3 ; store

; *** input key 4
bsf STATUS,C ;
btfss PORTD,BIT_KUNIT ; key pressed?
bcf STATUS,C ; yes
rlf KEY4,W ; shift new sample
andlw 0Fh ; select 5 lsb only
movwf WRK ; temp store
movf KEY4,W ; ket old value
andlw 0F0h ; select 4 msb
iorwf WRK,W ; combine with bit shift
movwf KEY4 ; store
return ;


; ******************
; *** Check keys ***
; ******************
; update KEYS value
L_TASK2_CHKKEYS
clrf KEYS ; it will be refreshed
; *** check key 4
movf KEY4,W ; get value
call L_TASK2_KEYX ; check
movwf KEY4 ; store
; *** check key 3
movf KEY3,W ; get value
call L_TASK2_KEYX ; check
movwf KEY3 ; store
; *** check key 2
movf KEY2,W ; get value
call L_TASK2_KEYX ; check
movwf KEY2 ; store
; *** check key 1
movf KEY1,W ; get value
call L_TASK2_KEYX ; check
movwf KEY1 ; store
btfss CNT,0 ; shortpress flag?
goto L_TASK2_ULP ; no
bsf KEY1,0 ; yes, syncronise
bsf KEY2,0 ; all keys
bsf KEY3,0 ;
bsf KEY4,0 ;

; *** update longpress
L_TASK2_ULP
btfss CNT,7 ; longpress?
return ; no
movf KEY1,W ;
iorlw 0C0h ;
movwf KEY1 ;
movf KEY2,W ;
iorlw 0C0h ;
movwf KEY2 ;
movf KEY3,W ;
iorlw 0C0h ;
movwf KEY3 ;
movf KEY4,W ;
iorlw 0C0h ;
movwf KEY4 ;
return ; exit

; ***********************
; *** Check key value ***
; ***********************
; Input value is in W, output value is in W, WRK is used
; If 7 lsb are the same then assign the value (0 or 1) to bit #7 else leave it unchanged
; If 6 lsb are the same then assign the value (0 or 1) to bit #6 else leave it unchanged
; If 5 lsb are the same then:
; 1) assign the value (0 or 1) to bit #5
; 2) reverse value to bit #0
; else leave bit #5 unchanged

L_TASK2_KEYX
movwf WRK ; temp store

; *** check press
andlw 7Fh ; 7 lsb =0?
btfss STATUS,Z ;
goto L_TASK2_KEYX6 ; no
bcf WRK,7 ; yes, clear bit #7
bsf CNT,7 ; indicate new long key press

L_TASK2_KEYX6
andlw 3Fh ; 6 lsb =0?
btfsc STATUS,Z ;
bcf WRK,6 ; yes, clear bit #6
andlw 1Fh ; 5 lsb =0?
btfsc STATUS,Z ;
bcf WRK,5 ; yes, clear bit #6
andlw 0Fh ; 4 lsb =0?
btfss STATUS,Z ;
goto L_TASK2_KEYXX ; no
bcf WRK,4 ; yes, clear bit #4
bsf CNT,0 ; indicate new short key press

; *** check release
L_TASK2_KEYXX
comf WRK,W ; invert key value
andlw 7Fh ; 7 lsb =1?
btfsc STATUS,Z ;
bsf WRK,7 ; yes, set bit #7
andlw 3Fh ; 6 lsb =1?
btfsc STATUS,Z ;
bsf WRK,6 ; yes, set bit #6
andlw 1Fh ; 5 lsb =1?
btfsc STATUS,Z ;
bsf WRK,5 ; yes, set bit #5
andlw 0Fh ; 4 lsb =1?
btfsc STATUS,Z ;
bsf WRK,4 ; yes, set bit #4

; *** exit
L_TASK2_KEYXE
bsf STATUS,C ; shift result into KEYS
btfsc WRK,4 ; is bit #4 set?
bcf STATUS,C ; yes (inverted value)
btfss WRK,7 ; is bit #7 clear (long key press)?
bsf KEYS,3 ; yes (inverted value)
rlf KEYS ; shift C and bit #3 into right position
movf WRK,W ; get result
return ; and finish subroutine


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

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru