作为一个简单实用的示例,图1中的电路利用一个8位PIC微控制器控制一个4位LED显示器,显示出按下了哪个按钮。当任意按钮被按下时,比较器中断程序会立即作出响应。该程序会在VREF值之间进行循环,直至比较器输出COUT返回高电平,表明该按钮被按下。完整注释的汇编程序源代码总共不到100字。该代码并未作过度优化,从而可方便理解或易于转化到其他控制器上。
汇编程序源代码:
; MULTIBTN.ASM: sensing upto 15 pushbuttons with one I/O (pin6: GP1/CIN-)
; BENABADJI Noureddine - ORAN - Dec. 11...14th, 2013
;
Errorlevel -302 ; avoid warning #302: Register in operand not in bank0.
; Ensure that bank bits are correct.
List P = 12F683
#include "p12f683.inc"
__CONFIG _INTOSCIO&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF&_FCMEN_OFF&_IESO_OFF&_BOD_ON&_CPD_OFF&_CP_OFF
#define LED1 GPIO, 0 ; output bit0 of the 4-bit binary LED display
#define LED2 GPIO, 2 ; output bit1 of the 4-bit binary LED display
#define LED3 GPIO, 4 ; output bit2 of the 4-bit binary LED display
#define LED4 GPIO, 5 ; output bit3 of the 4-bit binary LED display
;----------------------------- define variables ------------------------------
CBLOCK 0x20 ; bank0 = [0x20...0x7F] = 94 bytes
;delay
cnt1, cnt2, cnt3 ; counters
ENDC
;------------------------------------------------------------------------------
BANK0 macro
BCF STATUS, RP0 ; bank0
endm
;------------------------------------------------------------------------------
BANK1 macro
BSF STATUS, RP0 ; bank1
endm
;------------------------------------------------------------------------------
SIregGEval8b macro file, val, jmpOk ; if (file >= val) goto jmpOk ;
MOVLW val
SUBWF file, w ; w = file - val
BTFSC STATUS, C
GOTO jmpOk ; yes
endm
;/////////////////////////////////////////////////////////////////////////////
; MAIN PROGRAM
;/////////////////////////////////////////////////////////////////////////////
ORG 0x00 ; reset vector
GOTO Setup
ORG 0X04 ; interrupt vector
GOTO IntCmp
;/////////////////////////////////////////////////////////////////////////////
;-----------------------------------------------------------------------------
LEDsOFF
CALL Delay256ms
CLRF GPIO ; all LEDs off
RETLW 0
;-----------------------------------------------------------------------------
Delay256ms
CLRF cnt2
CLRF cnt1
NOP ; 1us
DECFSZ cnt1, f ; 1us
GOTO $-2 ; 2us => 4*256 = 1024 us, approx. 1 ms internal delay loop
DECFSZ cnt2, f ; approx. 256 ms external delay loop
GOTO $-4
RETLW 0
;/////////////////////////////////////////////////////////////////////////////
Setup
BANK1
CLRF TRISIO ; config. all I/O as outputs
BCF OPTION_REG, T0CS ; use pin5 as GP2, not TOCKI
CLRF ANSEL ; use all AN as digital I/O
BANK0
CLRF GPIO ; all LEDs off
MOVLW b'00000111'
MOVWF CMCON0 ;comparator off
splash ; (initial test for LEDs)
BSF LED1
CALL LEDsOFF
BSF LED2
CALL LEDsOFF
BSF LED3
CALL LEDsOFF
BSF LED4
CALL LEDsOFF
;;;;;;;;;;
initializeComparator
BANK1
MOVLW b'00001010' ;config. GP1 as input (will be CIN-)
MOVWF TRISIO
;BANK0
MOVLW b'10100001'
;BANK1
MOVWF VRCON ;Vref on, low range, VR<3:0>=0001 => ratio = 1/24
BANK0
MOVLW b'00000100'
MOVWF CMCON0 ;comparator on: CIN- = GP1; CIN+ = Vref; Cout internal
;;;;;;;;;
;enable interrupt
BANK1
BSF INTCON, PEIE ; enable interrupt on Comparator trip
BSF PIE1, CMIE ; enable interrupt on Comparator trip
BANK0
BSF INTCON, GIE ; set general interrupt enable
goto $ ; infinite loop (waiting for an interrupt)
;-----------------------------------------------------------------------------
; Comparator trip interrupt routine
;-----------------------------------------------------------------------------
IntCmp
;don't need to save any context, only interrupting a goto $
BANK0
MOVLW .1
MOVWF cnt3
nextBtn
INCF cnt3, F
SIregGEval8b cnt3, .16, whichBtn ; if (cnt3 >= 16) goto whichBtn ;
MOVLW b'10100000'
ADDWF cnt3, W
BANK1
MOVWF VRCON ;Vref on, low range, VR<3:0>=cnt3<3:0>
BANK0
BTFSS CMCON0, COUT ; Cout == 1 ?
GOTO nextBtn
whichBtn
DECF cnt3, F
BTFSC cnt3, 0
BSF LED1
BTFSC cnt3, 1
BSF LED2
BTFSC cnt3, 2
BSF LED3
BTFSC cnt3, 3
BSF LED4
CALL LEDsOFF
endIntCmp
MOVLW b'10100001'
BANK1
MOVWF VRCON ;Vref on, low range, VR<3:0>=0001 => ratio = 1/24
BANK0
BCF PIR1, CMIF ; clear comparator interrupt flag
RETFIE
;-----------------------------------------------------------------------------
END