Ayudadme con un "Indicador de marchas para moto según pulsos velocidad y r.pm."

Ver el tema anterior Ver el tema siguiente Ir abajo

Ayudadme con un "Indicador de marchas para moto según pulsos velocidad y r.pm."

Mensaje por merenat el Sáb 14 Mayo 2011 - 16:32

Pues eso el circuito lo hizo Pat Fruth en el 2007 pero para una honda y en mi yamaha FZ6 no funciona bien, bailan las marchas.

Basicamente lo que hace es cuando se genera una interrupcion por rpm empieza a contar los pulsos de la rueda. La estrella de encendido da 8 pulsos por vuelta y la rueda 30 (mas despacio )si no recuerdo mal. Lo que hace es la media de 8 capturas y luego guarda el dato como referencia para indicar la marcha que esta engranada la transmision.
Creo que si en vez de mirar la media se le diera un valor max y min para la primera , vaya un margen de valores variables para cada marcha no habria problema. Al leer el resultado que guarda en la eprom oscila pero siempre entre los mismos valores. El circuito lo he construido con kicad y con toner/plancha para hacerlo en una sola cara, que el autor lo hizo en dos.
Me podriais echar una mano? ... ya se que mi unica contribución al foro es que se abriera el apartado de presentaciones pero es que no sé mucho más.
Cuando pueda contar bien las marchas le quitaria la posibilidad de invertir los numeros que no tiene sentido y le pondria un indicador de "candado puesto en la rueda" a traves de un interruptor en su soporte y quizás un scottoiler (engrasador automatico) casero.
La verdad es que hay unos cuantos hechos con pic pero no liberan el codigo y este que es GNU me gustaria mejorarlo y publicarlo.



Código:

;---------------------------------------------------------------------------------------------
;Description: Program for displaying the gear position of a Honda motorcycle
;            on a seven segment LED display
;  Copyright (C) 2007  Pat Fruth
;
;  This program is free software: you can redistribute it and/or modify
;  it under the terms of the GNU General Public License as published by
;  the Free Software Foundation.
;
;  This program is distributed in the hope that it will be useful,
;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;  GNU General Public License for more details.
;
;  You should have received a copy of the GNU General Public License
;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
;Version: 1.3
;Date: 12.22.2007
;MCU: PIC16F88
;Author: Pat Fruth email:pat@patfruth.com
;Change History:
; V1.3         12.22.2007
;  Added ambient light sensor to automatically adjust display intensity.
;  Incorporated a standard Cadmium Sulfide (CdS) photo-cell to sense ambient light conditions,
;  by setting up a simple voltage divider.
;  Using PORTA pin AN2 as an analog input, an A/D conversion is done to sense night time
;  riding conditions.  If it's dark out, then reduce the display intensity by turning off the
;  transistor that normally drives the common anode leg of the seven segment display.
;  Cleaned up numerous comment typos.  Can you say "spell checker" ;-)
;  Cleaned up formatting for easier reading.
; V1.2         12.01.2007
;  Initial stable version
;---------------------------------------------------------------------------------------------
; DISCLAIMER:
; IN NO EVENT, UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SHALL I, OR ANY
; PERSON BE LIABLE FOR ANY LOSS, EXPENSE OR DAMAGE, OF ANY TYPE OR NATURE ARISING OUT OF THE
; USE OF, OR INABILITY TO USE THIS SOFTWARE OR PROGRAM, INCLUDING, BUT NOT LIMITED TO, CLAIMS,
; SUITS OR CAUSES OF ACTION INVOLVING ALLEGED INFRINGEMENT OF COPYRIGHTS, PATENTS, TRADEMARKS,
; TRADE SECRETS, OR UNFAIR COMPETITION.
;---------------------------------------------------------------------------------------------
;Overview:
; Most Honda motorcycles have no direct indication of which gear the transmission is in at
; any given moment in time.  It is left to the rider to sense, and remember, which gear he/she
; is in.  Most modern Hondas do, however, have an electronic fuel injection & ignition system.
; As such, there are several electrical signals that can be measured/leveraged in order to facilitate
; the derivation of the information necessary to determine which gear the transmission is in at
; any given moment in time.  This information can then be directly provided to the rider via
; a visual display mechanism.
; The following four signals are monitored in order to derive the information necessary to
; determine which gear the transmission is in;
; - The counter shaft on a Honda incorporates a variable reluctance type pulse generator
; that produces a digital square wave signal.  This pulse generator is often referred to as the
; "Vehicle Speed Sensor" (VSS) in the Honda service manuals.  The signal's frequency varies in
; direct proportion to rear wheel speed.
; - The flywheel on a Honda engine incorporates a variable reluctance type pulse generator that
; produces a semi-square wave A/C signal.  This pulse generator is often referred to as the
; "Ignition Pulse Generator" in the Honda service manuals.  This signal's frequency varies in
; direct proportion to engine speed.
; - There is a mechanical SPST neutral switch, providing continuity to chassis ground when
; the transmission is in neutral.
; - There is a mechanical SPST clutch switch, providing continuity to chassis ground when the
; clutch is disengaged (in other words, when the rider has the clutch pulled in).
;
; Running this program, the microcontroller continuously monitors the four afore mentioned
; signals, and visually displays the following information on a seven segment LED display.
;  Char      Description
;  ----      -----------
;  "0"      Neutral
;  "1"      1st gear
;  "2"      2nd gear
;  "3"      3rd gear
;  "4"      4th gear
;  "5"      5th gear
;  "6"      6th gear (for those that have six gears)
;  "-"      a dash, indicating the clutch is disengaged
;  "L"      indicates the unit is in "Learning" mode
;
; Learning mode -
; Upon initial installation and powerup, the microcontroller must first be "taught" how may
; gears the motorcycle has, and then, for each of those gears, how many ignition cycles
; occur for a defined set of counter shaft revolution cycles.  These values are captured,
; and then stored in the microcontroller's on-board EEPROM memory so that it may then
; be retrieved/used in the future.  This program incorporates a special "Learn" mode algorithm
; to do just that.  Upon power up, the software checks to see if there is valid data stored
; in EEPROM memory.  If not, "Learn" mode is entered.  If so, normal execution proceeds.
; There is also logic to accommodate a momentary pushbutton, which can be used to force "Learn" mode
; to be entered.  If the pushbutton is being depressed during power-on-reset, and is held
; down for approximately one second immediately there-after, "Learn" mode will be entered.
; When "Learn" mode is entered in this way, an "L" will be displayed on the LED display, at
; which point the pushbutton should then be released. Upon entering "Learn" mode, the
; display will begin to continuously flash 5 and then 6.  When the number, corresponding
; to the number of gears the motorcycle has, is showing (either 5 or 6), pressing the pushbutton
; will cause that number to be stored, and then used as the number of gears in the future.
; The display will begin to quickly flash that number, as confirmation that the selection has
; been made for that number of gears.  When the pushbutton is then released, the display will
; proceed to slowly flash gear number 1.  With the motorcycle running, and on a center/rear
; stand, the rider should put the motorcycle in first gear, and release the clutch.
; Once the rear wheel is spinning, the rider should depress & hold the pushbutton, signaling
; the microcontroller to proceed to learn the number of ignition cycles that occur for a given
; number of counter shaft cycles.  This measurement is repeated eight times.  The average of those
; eight measurements is then calculated, and stored into EEPROM memory.  At this point the
; display will begin to quickly flash the gear number that was just learned.  The rider can
; then release the pushbutton, signaling the microcontroller to proceed with learning the next
; gear.  This process is repeated until all gears have been learned.
;
; Ambient light sensor -
; The single-digit seven segment display's brightness/intensity is automatically adjusted,
; based on the intensity of the surrounding ambient light conditions. During normal mid-day
; riding conditions, the display's brightness will be high so that it can be seen in
; moderate-to-intense ambient light.  During night-time riding conditions, the display's
; intensity will be low so that it won't be a blinding distraction.
; This is accomplished by configuring a simple voltage divider, comprised of a fixed value
; resistor and a cadmium sulfide photo-cell.  The resulting voltage drop created by the
; cadmium sulfide photo-cell is measured by coupling the voltage divider to the PORTA RA2/AN2
; pin, which is configured as an analog A/D converter input channel.
; In order to minimize "false trigger" occurrences, and to provide a certain level of hysteresis,
; these ambient light measurements are captured in a 16 byte array.  As new measurements are
; captured, the oldest measurements are overwritten.  Each time a new measurement is captured,
; a new rolling average of the last 16 measurements is calculated.
; Because there is considerable variability in photo-cell performance characteristics (not to
; mention rider preferences), this program includes a feature which allows the rider to "set"
; the desired ambient light threshold at which the display's intensity should switch from
; high to low.  Depressing the "Learn" pushbutton for 1 second after the motorcycle is turned
; on (running or not), and in neutral, will cause the current average ambient light level
; measurement to be captured and stored in EEPROM data memory.  When the capture is complete,
; the display will begin to flash, at which point the pushbutton can be released.
; This measurement will then be used as the threshold going forward.  Ambient light conditions
; lower than this threshold will result in the display's intensity being lowered.
;
; Display intensity -
; The actual adjustment of the display's intensity is accomplished by switching a transistor
; on or off.  The transistor is used to bypass the current limiter in the seven segment display's
; common anode leg connection to Vdd.  This provides a more direct path to Vdd, thus increasing
; current draw of the display.  The base of the transistor is connected to the PORTA RA3 pin.
; Setting RA3 to logic low turns the transistor on, thereby increasing the display's intensity.
; Setting RA3 to logic high turns the transistor off, thereby decreasing the display's intensity.
;
; PORT pin assignments -
; PORTB
;  RB0 = input.
;  Receives the signal from the motorcycle's Vehicle Speed Sensor (VSS).
;  Configured to exploit the microcontroller's external interrupt feature.
;  RB1:RB7 = output
;  Used to drive the individual segments of the seven segment LED display.
; PORTA
;  RA0 = input.
;    Receives input from the motorcycle's neutral switch circuit.
;    Logic 0 (low) indicates the transmission is in neutral.
;    Logic 1 (high) indicates the transmission is not in neutral.
;  RA1 = input.
;    Receives input from the motorcycle's clutch switch circuit.
;    Logic 0 (low) indicates the clutch is engaged.
;    Logic 1 (high) indicates the clutch is not engaged.
;  RA2 = analog input.
;    Receives input from a simple voltage divider network, incorporating a standard
;    Cadmium Sulfide (CdS) photo-cell.  The higher the A/D result, the darker the ambient
;    light conditions.  0xFF = full dark,  0x00 = intense light.
;  RA3 = output.
;    Drives a PNP transistor that connects the common anode leg of the seven segment display
;    to Vdd.  Logic low turns the transistor on, thus allowing maximum current to flow thru
;    the seven segment display LEDs.  When the transistor is turned off current is forced to
;    flow thru a 1K ohm current limiting resistor, thus reducing the display's intensity.
;  RA4/T0CKI = input.
;    Receives the signal from the motorcycle's Ignition Pulse Generator (IPG).
;    Configured as the external clock source for the microcontroller's built-in Timer0 module.
;      Timer0 is configured to run in asynchronous counter mode.
;  RA5 = input.
;    Unused.  Tied low via connection to ground.
;  RA6 = input.
;    Receives input from the "Learn" mode momentary pushbutton switch.
;    Logic 0 (low) indicates the button is being depressed.
;    Logic 1 (high) indicates the button is not being depressed.
;  RA7 = input.
;    Receives input from the "Digit Orientation" two-pin header/jumper.
;    Logic 0 (low) indicates the jumper is shorted.
;    Logic 1 (high) indicates the jumper is open.
;      If shorted, this indicates that the user has mounted the LED display upside down, and
;      thus the output information should be presented accordingly.
;
; Data EEPROM storage map -
;  Addr   Description
;  ----   -----------
;  0x00   Number of gears
;  0x01   Number of IGP cycles per VSS cycle for 1st gear
;  0x02   Number of IGP cycles per VSS cycle for 2nd gear
;  0x03   Number of IGP cycles per VSS cycle for 3rd gear
;  0x04   Number of IGP cycles per VSS cycle for 4th gear
;  0x05   Number of IGP cycles per VSS cycle for 5th gear
;  0x06   Number of IGP cycles per VSS cycle for 6th gear
;  0x07   Valid data signature. 0xCC indicates valid data.  Anything else indicates invalid data
;  0x08   The ambient light sensor threshold
;---------------------------------------------------------------------------------------------

    ERRORLEVEL -302 ;remove message about using proper bank

;***** Declarations and microcontroller configuration *****
    PROCESSOR 16f88
    #include "p16f88.inc"
    __CONFIG _CONFIG1, _CP_OFF&_DEBUG_OFF&_WRT_PROTECT_OFF&_CPD_OFF&_LVP_OFF&_BODEN_ON&_MCLR_OFF&_PWRTE_ON&_WDT_OFF&_INTRC_IO
    __CONFIG _CONFIG2, _IESO_OFF&_FCMEN_OFF

;***** Declaration of variables *****
    cblock 0x20    ; Beginning of RAM in bank 0
    AMBIENT0        ; The AMBIENT0-F array MUST be aligned on a 16 byte boundary
    AMBIENT1        ; AMBIENT0-F hold the A/D results for the last 16 A/D conversions
    AMBIENT2        ;    of the ambient light sensor
    AMBIENT3
    AMBIENT4
    AMBIENT5
    AMBIENT6
    AMBIENT7
    AMBIENT8
    AMBIENT9
    AMBIENTA
    AMBIENTB
    AMBIENTC
    AMBIENTD
    AMBIENTE
    AMBIENTF
    AMBIENTIX      ; Index to the current AMBIENT address, used for indirect addressing
    AMBIENTSUML    ; Low order byte of the sum of the above 16 ambient samples
    AMBIENTSUMH    ; High order byte of the sum of the above 16 ambient samples
    AMBIENTAVG      ; Average of the 16 array entries above
    AMBIENTTHRESH  ; The level at which the display intensity should be lowered
    TEMP            ; Various temporary use
    VSSINTS        ; Counts the interrupts that result from the VSS square wave
    VSSINT          ; An internal (software) interrupt prescaler, boolean 0x00=no int, 0xff=int
    TMR0_1          ; Holds the first copy of the Timer0 counter
    TMR0_2          ; Holds the second copy of the Timer0 counter
    NUMGEARS        ; The number of gears for this motorcycle
    GEAR            ; Holds the gear number to be displayed on the seven segment LED display
    GEAR2          ; Holds the gear number, used as a count down loop counter
    THRESH1        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 1st gear
    THRESH2        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 2nd gear
    THRESH3        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 3rd gear
    THRESH4        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 4th gear
    THRESH5        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 5th gear
    THRESH6        ; Retrieved from EEPROM, holds the "learned" number of IPG cycles for 6th gear
    PAUSEH          ; Used by the Pausems routine, holds the high order byte of the number ms
    PAUSEL          ; Used by the Pausems routine, holds the low order byte of the number ms
    LOOPCOUNT      ; Used by various routines, as a loop counter
    IPGSUML        ; Low order bye of the sum of IPG pulses
    IPGSUMH        ; High order bye of the sum of IPG pulses
    endc

    cblock 0x70    ; Beginning of RAM memory common to all banks
    W_TEMP          ; Temporary storage of the W register, used by the interrupt service routine
    STATUS_TEMP    ; Temporary storage of the STATUS register, used by the interrupt service routine
    endc

;***** Declaration of symbol equates *****
LEARNBTN        equ 6          ; PORTA, pin RA6, has the "Learn" mode pushbutton
NEUTRALSW      equ 0          ; PORTA, pin RA0, has the Neutral switch input
CLUTCHSW        equ 1          ; PORTA, pin RA1, has the Clutch switch input
INTENSITY      equ 3          ; PORTA, pin RA3, controls display intensity
   
;***** Beginning of program memory structure *****
    ORG        0x00            ; Reset Vector
    goto        Init            ; After power-on-reset, jump to this location

    ORG        0x04            ; Interrupt vector
    goto        IntSvc          ; Interrupt Service routine

;***** Beginning of interrupt service routine *****
; This code is executed any time an "Interrupt", of any kind, occurs.
; Here we place logic that queries the various interrupt flags in order to determine the reason
; for the interrupt.
; In this particular case, the only interrupt that should be happening is the INTF interrupt.
; Each time a low-to-high transition occurs on the RB0/INT pin, as a result of the pulses arriving
; from the VSS, we will briefly interrupt execution of the main processing loop, execute
; this little bit of code, and then return control back to the main loop.
IntSvc
                                ; Save W & STATUS
    movwf      W_TEMP          ; Copy W to TEMP register
    swapf      STATUS,W        ; Swap status to be saved into W
                                ; Swaps are used because they do not affect the status bits
    movwf      STATUS_TEMP    ; Save status to STATUS_TEMP register

    btfss      INTCON,INTF    ; Are we handling an INT on RB0?
    goto        IntSvcExit      ; No
    btfss      INTCON,INTE    ; Are we supposed to be handling INT interrupts at this time?
    goto        IntSvcExit      ; No

; This routine tallies up counter shaft rotation cycles emitted by the VSS.
; Each time this ISR is driven, the counter shaft will have rotated a fraction of a full revolution.
;  Note: On the Honda RC51, there are 27 pulses per counter shaft revolution.
; Here we effectively divide the VSS frequency by 128.
; We use a RAM variable (VSSINT) as a boolean indicator of these rotations.
; Every 64 cycles from the VSS will result in the VSSINT variable switching from 0x00 to 0xFF
; or vise versa.  The state of the VSSINT variable is monitored in the main loop routine below.
    incf        VSSINTS,F      ; Increment the VSSINTS ram variable
    btfss      VSSINTS,6      ; Have we tallied up 64 (0x40, B'01000000') of em yet?
    goto        IntSvcExit      ; No
    clrf        VSSINTS        ; Yes, so restart the counter
    comf        VSSINT,F        ; And toggle the VSSINT flag

IntSvcExit
    bcf        INTCON,INTF    ; Clear the Interrupt flag
                                ; Restore W & STATUS
    swapf      STATUS_TEMP,W  ; Swap STATUS_TEMP register into W
                                ; (sets bank to original state)
    movwf      STATUS          ; Move W into STATUS register
    swapf      W_TEMP,F        ; Swap W_TEMP
    swapf      W_TEMP,W        ; Swap W_TEMP into W
    retfie                      ; Return from interrupt
;***** Beginning of main execution logic.  Execution begins here upon power on *****
Init
; Initialize the system clock oscillator frequency
    banksel    OSCCON
    bsf        OSCCON,IRCF1   ; Configure the internal system clock to run at 4MHz
    bsf        OSCCON,IRCF2   ; IRCF2:IRFC1:IRFC0 = B'110'
   
; Initialize the Watch Dog Timer (WDT) period select for approx 1 second timeout.
; But leave the WDT disabled, we'll enable it later.
; In the case where the motorcycle stops moving, there will be no more interrupts
; arriving from the VSS.  Thus, it is possible that we get stuck in an infinite loop
; in the DoIPGCount routine, waiting for the VSSINTS varible to switch states.
; The WDT is used here to break this infinite loop, and reset the processor.
; The WDT runs on it's own dedicated oscillator (31.25 kHz).  So we configure the
; period select configuration bits to scale this down to give us an approx 1 sec
; timeout.  31,250 Hz / 32768 = .953 Hz = 1.04 sec.
    banksel    WDTCON
    movlw      B'00010100'    ; period select = 1:32768, SWDTEN = 0 (off)
    movwf      WDTCON
    banksel    OPTION_REG
    bcf        OPTION_REG,PS2   ; PS2:PS0 = 000 means prescaler 1:1
    bcf        OPTION_REG,PS1
    bcf        OPTION_REG,PS0

; Initialize A/D converter channels
    banksel    ANSEL
    movlw      B'00000100'    ; Make all channels digital except RA2/AN2
    movwf      ANSEL

; Initialize PORTB
    banksel    TRISB
    movlw      B'00000001'    ; Make PORTB all output, except RB0
    movwf      TRISB
    banksel    PORTB
    movlw      0xFF            ; Turn off all seven segment display segments
    movwf      PORTB
   
; Initialize PORTA
    banksel    TRISA
    movlw      B'11110111'    ; Make PORTA all input, except RA3
    movwf      TRISA
    bcf        PORTA,INTENSITY ; Bring RA3 low (make the display bright)

; Initialize the A/D converter so we can sense ambient light conditions.
; We effectively make it an 8-bit conversion by configuring the A/D result as left-justified.
    banksel    ADCON1
    bcf        ADCON1,VCFG0    ; Configure the A/D converter to use Vdd & Vss as +/- Vrefs
    bcf        ADCON1,VCFG1
    bcf        ADCON1,ADFM    ; Configure A/D result to be left-justified
    banksel    ADCON0
    bcf        ADCON0,CHS0    ; Select A/D Channel 2 CHS=b'010'
    bsf        ADCON0,CHS1
    bcf        ADCON0,CHS2
    bsf        ADCON0,ADCS0    ; Use internal RC oscillator for A/D conversions
    bsf        ADCON0,ADCS1
    bcf        ADCON0,ADON    ; Turn off the A/D converter, we'll turn it on when we need it.
    banksel    PIE1
    bcf        PIE1,ADIE      ; Disable A/D Interrupts.  We're going to poll instead

; Initialize Timer0 module as an async counter so it can count IPG cycles
    banksel    OPTION_REG
    bsf        OPTION_REG,T0CS   ; Timer0 clock source is RA4/T0CKI
    bcf        OPTION_REG,T0SE ; Increment Timer0 on rising edge
   
; Initialize RAM variables
    banksel    0
    clrf        VSSINTS        ; Start VSS interrupts off at zero
    clrf        VSSINT          ; Turn off our quasi VSS interrupt flag
    bsf        INTCON,INTE    ; Enable RB0/INT to generate interrupts from the Vehicle Speed Sensor (VSS)
    bcf        INTCON,GIE      ; But disable Global Interrupts for now

    btfss      STATUS,NOT_TO  ; Check to see if a Watch Dog Timer reset occurred
    goto        LoadEE          ; If so, then just reload data from EEPROM and go

                                ; Use indirect addressing to clear the 16 byte array that holds
                                ;  the ambient light sensor samples.
                                ; Only do this during normal reset.  Leave this data in place
                                ;  in the case of a WDT reset.
    movlw      low AMBIENT0    ; Get the memory address of the beginning of the array
    movwf      AMBIENTIX      ; Save it.  It'll be used as an array index later on.
    movwf      FSR            ; And put it in the File Select Register (FSR)
    clrf        INDF            ; The INDF Special Function Register will act on the address contained in the FSR
    incf        FSR,F          ; Point to the next array entry
    btfss      FSR,4          ; Have we done all 16 yet?
    goto        $-3            ; No, so do the next one

; Test to see if we should go into "Learn" mode.
; The PORTA RA6 pin has a pushbutton.  Holding the button down will cause the pin to go low
    btfsc      PORTA,LEARNBTN  ; Check if the push button is being held down
    goto        LoadEE          ; If not, then proceed
    movlw      high .1000      ; If so, then setup to debounce for 1 sec (1000 ms)
    movwf      PAUSEH
    movlw      low .1000
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; And check if the button is still being held down
    goto        LoadEE          ; If not, then proceed

; Here we begin the "Learn" mode.
; If we got here, then the user either powered up with the "Learn" mode button depressed,
; or the main routine determined that the EEPROM contents was invalid, and has to be (re)populated.
; First we must display the letter "L" on the LED display.
; Then we forcibly invalidate the contents of EEPROM.
; Valid EEPROM contents is indicated by the presence of a special value (0xCC) in EEPROM
; storage location 0x07.  Writing 0xFF to this location therefore indicates invalid data.
StartLearn
    movlw      high Hexto7seg
    movwf      PCLATH
    movlw      0x07            ; code for "L" (for "Learn")
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the segments in the display
    movlw      0x07            ; Get ready to write data to EEPROM location 0x07
    movwf      GEAR
    movlw      0xFF            ; Write 0xFF to EEPROM
    call        WriteEE        ; Go write the data to EEPROM
    btfss      PORTA,LEARNBTN  ; Wait for the button to be released
    goto        $-1            ; Loop until button released
    movlw      0x05            ; Start with 5 gears
    movwf      GEAR
; First we must determine the number of gears this motorcycle has.
; So, we begin by slowly flashing 5, and then 6.  When the number corresponding to the number
; of gears for this motorcycle is showing, depressing the pushbutton will cause that number
; to be stored in EEPROM location 0x00.  This is then used to control operations going forward.
LearnNumGears
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR            ; Get the gear number to be displayed
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins
    movlw      high .1000      ; Pause for 1 sec
    movwf      PAUSEH
    movlw      low .1000
    movwf      PAUSEL
    call        Pausems
    btfss      PORTA,LEARNBTN  ; Check if button pressed?
    goto        StoreNumGears  ; Yes, so go store the number of gears
    movlw      0xFF            ; Turn off the PORTB pins
    movwf      PORTB
    movlw      high .500      ; Pause for 500 ms
    movwf      PAUSEH
    movlw      low .500
    movwf      PAUSEL
    call        Pausems
    incf        GEAR,F          ; Increment to the next gear
    movfw      GEAR            ; Get the gear number
    xorlw      0x07            ; Have we gone past 6th?
    btfss      STATUS,Z
    goto        LearnNumGears  ; No
    movlw      0x05            ; Yes, so wrap back to 5
    movwf      GEAR
    goto        LearnNumGears
; Now that the pushbutton has been pressed, indicating that the number of gears has been
; selected... begin quickly flashing that number as confirmation.  When the button is
; released, then proceed to learn the individual gears
StoreNumGears
    movfw      GEAR            ; Get the GEAR number into W
    movwf      NUMGEARS        ; Save NUMGEARS for use in loop control going forward
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; Check if button still pressed
    goto        LearnGears      ; No, so go start learning each gear
    movlw      0xFF            ; Turn off all segments
    movwf      PORTB
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    goto        StoreNumGears  ; Then continue flashing the display quickly

LearnGears
    movfw      NUMGEARS        ; Store the number of gears for this motorcycle
    clrf        GEAR            ; Set GEAR to zero (used as the EEPROM storage addr)
    call        WriteEE        ; Write the data
                                ; Get ready to iterate thru the "Learn" mode
    incf        GEAR,F          ; Start at gear number 1
    movfw      NUMGEARS        ; And set up a count-down loop counter
    movwf      GEAR2
; Begin Learn mode, by flashing the gear number on/off slowly (once every second).
; We'll do this until the user depresses the pushbutton.
BlinkSlow
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR            ; Get the GEAR number to be displayed on the LED
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins
    movlw      high .500      ; Pause for 500 ms
    movwf      PAUSEH
    movlw      low .500
    movwf      PAUSEL
    call        Pausems
    btfss      PORTA,LEARNBTN  ; Check if button pressed
    goto        Learn          ; If so, proceed to learn it
    movlw      0xFF            ; Otherwise, turn off all segments
    movwf      PORTB
    movlw      high .500      ; Pause for 500 ms
    movwf      PAUSEH
    movlw      low .500
    movwf      PAUSEL
    call        Pausems
    goto        BlinkSlow      ; Continue to flash the display
; Learn the actual number of IPG cycles per VSSINT transision
Learn
    movlw      high .100      ; Debounce the pushbutton. Pause for 100 ms
    movwf      PAUSEH
    movlw      low .100
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; Check if button is still depressed
    goto        BlinkSlow      ; If not, then resume flashing
    call        AvgIPGCount    ; Now go get the average of 8 sample timings
    addlw      0x03            ; Add some padding
    call        WriteEE        ; Store the timing for this gear into EEPROM
; Indicate that "Learning" has completed, by flashing the gear number on/off quickly (once every 400 ms).
; We'll do this until the user releases the pushbutton.
BlinkFast
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR            ; Get the GEAR number to be displayed on the LED
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; Check if button pressed
    goto        LearnNext      ; If not, proceed to set up for learning the next gear
    movlw      0xFF            ; Turn off all segments
    movwf      PORTB
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    goto        BlinkFast      ; Then continue flashing the display quickly
; Now that we've "Learned" a gear, and the user has released the pushbutton, set up for learning
; the next gear.
LearnNext
    movlw      high .100      ; Debounce the pushbutton. Pause for 100 ms
    movwf      PAUSEH
    movlw      low .100
    movwf      PAUSEL
    call        Pausems
    btfss      PORTA,LEARNBTN  ; Check if button is still released
    goto        BlinkFast      ; If not, then resume flashing

    incf        GEAR,F          ; Increment the gear number to be learned
    decfsz      GEAR2,F        ; Decrement the learning loop counter, and exit if zero
    goto        BlinkSlow      ; Got start blinking the new gear number we need to learn
                                ; Whewww, we're done
    movlw      0x07
    movwf      GEAR
    movlw      0xCC            ; Now write the special signature (0xCC), indicating EEPROM data is valid
    call        WriteEE        ; Write the data

; Here we retrieve all previously "Learned" data from EEPROM.
; If we got here, then the user either powered up without the "Learn" mode button depressed,
; or the "Learn" code above has just completed.
; First we check to see if the special signature (0xCC) is present at EEPROM location 0x07.
; If not, then we proceed to "Learn" mode.  If so, we re-hydrate all the RAM variables that hold
; the previously learned values.
LoadEE
    movlw      0x07            ; Start with the location that is supposed to hold our special signature
    movwf      GEAR            ;  0x07 in this case
    call        ReadEE          ; Go retrieve a byte of EEPROM data from that location
    xorlw      0xCC            ; Did the special signature come back?
    btfss      STATUS,Z        ; If so, the Z (zero) bit in the STATUS register will be set
    goto        StartLearn      ; No, so go to "Learn" mode code

    decf        GEAR,F          ; Re-hydrate all the RAM variables used to hold the thresholds
    call        ReadEE          ; Working from gear 6 thru 1
    movwf      THRESH6        ; .
    decf        GEAR,F          ; ..
    call        ReadEE          ; ...
    movwf      THRESH5        ; ....
    decf        GEAR,F
    call        ReadEE
    movwf      THRESH4
    decf        GEAR,F
    call        ReadEE
    movwf      THRESH3
    decf        GEAR,F
    call        ReadEE
    movwf      THRESH2
    decf        GEAR,F
    call        ReadEE
    movwf      THRESH1
    decf        GEAR,F          ; Location zero will contain the number of gears for this motorcycle
    call        ReadEE
    movwf      NUMGEARS

    movlw      0x08            ; EEPROM location 0x08 holds any previously learned ambient light
    movwf      GEAR            ;  light sensor threshold
    call        ReadEE
    movwf      AMBIENTTHRESH

    banksel    WDTCON
    bsf        WDTCON,SWDTEN  ; Turn on the Watch Dog Timer now.
    banksel    0

;---------------------------------------------------------------------------------------------
; This is the beginning of "THE" main loop.
; Once all the initialization, learning, and EEPROM data retrieval has completed, we execute
; this infinite loop.
; Each iteration of the loop does the following:
; - Checks the state of the neutral, and clutch switches.
;  - If neither is active, do a timing to get the current number of IPG cycles per VSS cycles.
; - Display the results on the LED display.
; - Get an A/D conversion for the voltage level of the ambient light sensor.
; - Compute a rolling average of the 16 most recent ambient light sensor samples.
; - Adjust the intensity of the display, based on the average ambient light level.
; - Pause for 100ms.
Loop
    btfss      PORTA,NEUTRALSW ; Are we in neutral?
    goto        DebounceNeutral ; Yes
    btfss      PORTA,CLUTCHSW  ; Is the clutch pulled in?
    goto        DebounceClutch  ; Yes

    call        DoIPGCount      ; Otherwise go get a current view of IPG cycles to VSS cycles
    movwf      TEMP            ; Save the results of the count

                                ; The following series of tests essentially zeros in on which
                                ; gear we are currently in.  It does this by comparing the
                                ; newly stored timing to the previously learned values for each
                                ; gear until it finds the right threshold.  When we exit the
                                ; this series of tests, the GEAR variable will have the GEAR
                                ; number to be displayed.
    movlw      0x06
    movwf      GEAR            ; Move 6 to the gear indicator
    movfw      NUMGEARS
    xorlw      0x06            ; Does this motorcycle have 6 gears?
    btfss      STATUS,Z
    goto        $+5            ; No, so skip around the test for 6th
    movfw      TEMP
    subwf      THRESH6,W      ; If W > THRESH, then C will be clear
    btfsc      STATUS,C        ; If C is clear, then we're in a lower gear
    goto        Display

    decf        GEAR,F          ; Decrement to 5th gear
    movfw      TEMP
    subwf      THRESH5,W      ; If W > THRESH, then C will be clear
    btfsc      STATUS,C        ; If C is clear, then we're in a lower gear
    goto        Display

    decf        GEAR,F          ; Decrement to 4th gear
    movfw      TEMP
    subwf      THRESH4,W      ; If W > THRESH, then C will be clear
    btfsc      STATUS,C        ; If C is clear, then we're in a lower gear
    goto        Display

    decf        GEAR,F          ; Decrement to 3rd gear
    movfw      TEMP
    subwf      THRESH3,W      ; If W > THRESH, then C will be clear
    btfsc      STATUS,C        ; If C is clear, then we're in a lower gear
    goto        Display

    decf        GEAR,F          ; Decrement to 2nd gear
    movfw      TEMP
    subwf      THRESH2,W      ; If W > THRESH, then C will be clear
    btfsc      STATUS,C        ; If C is clear, then we're in a lower gear
    goto        Display

    decf        GEAR,F          ; so we must be in 1st gear
    goto        Display

DebounceNeutral
    movlw      .20            ; Debounce constant
    movwf      LOOPCOUNT      ; Initialize debounce loop counter
    movfw      PORTA          ; Make a copy of the contents of PORTA
    andlw      B'00000001'    ; Mask off all but RA0
    movwf      TEMP            ; Save it
DebounceNeutral1
    movfw      PORTA          ; Check PORTA again
    andlw      B'00000001'    ; Mask off all but RA0
    xorwf      TEMP,W          ; Seen it before?
    btfss      STATUS,Z
    goto        DebounceNeutral ; No
    decfsz      LOOPCOUNT,F    ; Yes, so decrement the loop counter and exit if zero
    goto        DebounceNeutral1 ; If loop counter still > zero, check the switch again
    btfsc      PORTA,NEUTRALSW ; Still indicating neutral?
    goto        Loop            ; No
    movlw      0x0            ; Display "0" on the LED display
    movwf      GEAR
; But first.......
; If the user is pressing the "learn" button at this point, then he wants to set the
; ambient light threshold to the current averaged ambient light conditions.
; So here, we check the state of the button.  If it is being held down for a second, then
; we stash the current ambient sensor rolling average into EEPROM location 0x08, blink the
; display, and wait for the button to be released.
    btfsc      PORTA,LEARNBTN  ; Is the learn button is being pressed?
    goto        Display        ; No, so go display gear

    banksel    WDTCON          ; We must turn off the Watch Dog Timer so we don't incur
    bcf        WDTCON,SWDTEN  ;  a device reset
    banksel    0
    movlw      high .1000      ; Debounce by pausing for 1 sec
    movwf      PAUSEH
    movlw      low .1000
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; Is the learn button still being pressed?
    goto        AmbientLearnExit ; No, so get out
    movlw      0x08            ; Yes, so set the EEPROM location to hold the ambient threshold
    movwf      GEAR
    movfw      AMBIENTAVG      ; Get the most current averaged ambient light sensor level
    movwf      AMBIENTTHRESH  ; Save it as the new threshold
    xorlw      0x00            ; Are we at minimum already?
    btfss      STATUS,Z
    decf        AMBIENTTHRESH,F ; No, so bump it by 1
    movfw      AMBIENTTHRESH  ; get it back into W
    call        WriteEE        ; Now write it to EEPROM
AmbientLearnBlink
    movlw      0x00            ; Blink code for neutral
    movwf      GEAR
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    btfsc      PORTA,LEARNBTN  ; Check if button still pressed
    goto        AmbientLearnExit ; No
    movlw      0xFF            ; Turn off all segments
    movwf      PORTB
    movlw      high .200      ; Pause for 200 ms
    movwf      PAUSEH
    movlw      low .200
    movwf      PAUSEL
    call        Pausems
    goto        AmbientLearnBlink ; Then continue flashing the display quickly
AmbientLearnExit
    clrwdt
    banksel    WDTCON
    bsf        WDTCON,SWDTEN  ; Turn the Watch Dog Timer back on
    banksel    0
    goto        Display

DebounceClutch
    movlw      .20            ; Debounce constant
    movwf      LOOPCOUNT      ; Initialize debounce loop counter
    movfw      PORTA          ; Make a copy of the contents of PORTA
    andlw      B'00000010'    ; Mask off all but RA1
    movwf      TEMP            ; Save it
DebounceClutch1
    movfw      PORTA          ; Check PORTA again
    andlw      B'00000010'    ; Mask off all but RA1
    xorwf      TEMP,W          ; Seen it before?
    btfss      STATUS,Z
    goto        DebounceClutch  ; No
    decfsz      LOOPCOUNT,F    ; Yes, so dec loop counter and continue if zero
    goto        DebounceClutch1 ; If loop counter still > zero, check the switch again
    btfsc      PORTA,CLUTCHSW  ; Still indicating clutch pulled in?
    goto        Loop            ; No
    movlw      0x08            ; Dummy gear number to indicate a "-" (dash)
    movwf      GEAR

Display
    movlw      high Hexto7seg
    movwf      PCLATH
    movfw      GEAR            ; Get the gear number into the W register
    call        Hexto7seg      ; Convert it to a 7 segment display decode
    movwf      PORTB          ; Turn on the PORTB pins

    call        DoAmbient      ; Go get a fresh sample from the ambient light sensor
    call        AvgAmbient      ; Go compute a rolling average of the ambient samples

                                ; Is the ambient average at, or above, the threshold?
    subwf      AMBIENTTHRESH,W ; The higher the number, the less intense the ambient light
    btfss      STATUS,C        ; If not, carry will be set
    goto        $+3            ; No, so jump around
    bcf        PORTA,INTENSITY ; Bring RA3 low (makes the display bright)
    goto        $+2            ; Jump around
    bsf        PORTA,INTENSITY ; Bring RA3 high (makes the display dim)

    movlw      high .100      ; Pause for 100 ms
    movwf      PAUSEH
    movlw      low .100
    movwf      PAUSEL
    call        Pausems

    clrwdt
    goto        Loop            ; Jump to the beginning of the main loop, and do it all again.

; End main loop
;---------------------------------------------------------------------------------------------
; Begin subroutines

; Subroutine: Pausems
;  Used to burn some CPU cycles doing nothing meaningful.
;  This routine assumes a system clock frequency of 4 MHz.
; Inputs:
;  PAUSEL - Low order byte of the number of milliseconds
;  PAUSEH - High order byte of the number of milliseconds
; Temporary:
;  LOOPCOUNT - Loop counter
; Output:
;  None
Pausems
Loop1
    movf        PAUSEL,F        ; Decrease PAUSEH and PAUSEL the necessary
    btfsc      STATUS,Z        ; number of times and call subprogram Delay1ms
    goto        Dechi
    call        Delay1ms
    decf        PAUSEL,F
    goto        Loop1
Dechi
    movf        PAUSEH,F
    btfsc      STATUS,Z
    goto        Done
    call        Delay1ms
    decf        PAUSEH,F
    decf        PAUSEL,F
    goto        Loop1
Delay1ms                        ; Delay1ms produces a one millisecond delay
    movlw      .100            ; 100*10us=1ms
    movwf      LOOPCOUNT      ; LOOPCOUNT<-100
Loop2
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    decfsz      LOOPCOUNT,F    ; Time period necessary to execute loop Loop2
    goto        Loop2          ; equals 10us
Done
    return                      ; Return to caller

; Subroutine: WriteEE
;  Write a byte of data to EEPROM storage
; Inputs:
;  GEAR - should be set to the GEAR number, which will be used as the EEPROM address
;  W register - should contain the data to be stored
; Temporary:
;  None
; Output:
;  None
WriteEE
    banksel    EEDATA          ; Select the bank of EEDATA
    movwf      EEDATA          ; Data value to write
    banksel    GEAR
    movf        GEAR,W          ; Use the GEAR number as the EEPROM address
    banksel    EEADR          ; Select bank of EEADR
    movwf      EEADR          ; Data memory address to write
    banksel    EECON1          ; Select bank of EECON1
    bcf        EECON1,EEPGD    ; Point to DATA EEPROM mem (as opposed to PGM mem)
    bsf        EECON1,WREN    ; Enable writes
    banksel    INTCON          ; Select bank of INTCON
    bcf        INTCON,GIE      ; Disable Global Interrupts
    btfsc      INTCON,GIE      ; Global Interrupts really disabled?
    goto        $-2            ; NO, try again
    banksel    EECON2          ; Select bank of EECON2
    movlw      0x55
    movwf      EECON2          ; Write 55h
    movlw      0xAA
    movwf      EECON2          ; Write AAh
    bsf        EECON1,WR      ; Set WR bit to begin write
    btfsc      EECON1,WR      ; Wait for write to finish
    goto        $-1            ;    looping until it is
    bsf        INTCON,GIE      ; Enable Global Interrupts
    bcf        EECON1,WREN    ; Disable writes
    banksel    0              ; Select bank 0 now that we're all done
    return                      ; Return to caller
   
; Subroutine: ReadEE
;  Read a byte of data to EEPROM storage
; Inputs:
;  GEAR - should be set to the GEAR number, which will be used as the EEPROM address
; Temporary:
;  None
; Output:
;  W register - contains the EEPROM data byte that has been read
ReadEE
    banksel    0
    movf        GEAR,W          ; Get GEAR number into the W register
    banksel    EEADR          ; Select bank of EEADR
    movwf      EEADR          ; Data memory address to read
    banksel    EECON1          ; Select bank of EECON1
    bcf        EECON1,EEPGD    ; Point to data memory
    bsf        EECON1,RD      ; EE Read
    banksel    EEDATA          ; Select bank of EEDATA
    movf        EEDATA,W        ; Get EEDATA into W register
    banksel    0              ; Select bank 0 now that we're all done
    return                      ; return to caller
; Subroutine: DoIPGCount
;  Determine the number of IPG cycles that occur in the time it takes for a set number
;  of VSS cycles to occur.  This is essentially accomplished by:
;  - Taking a snapshot of Timer0 counter
;  - Resetting the VSS interrupt flag (i.e. setting VSSINT to 0x00)
;  - Waiting for the VSS interrupt flag to be set (i.e. VSSINT will change to 0xFF)
;  - Taking a second snapshot of Timer0 counter
;  - Calculating the difference between the two Timer0 snapshots
; Inputs:
;  None
; Temporary:
;  TMR0_1 - 1st snapshot of Timer0 counter
;  TMR0_2 - 2nd snapshot of Timer0 counter
; Output:
;  W register - contains the number of IPG cycles that had occurred
DoIPGCount
    clrf        VSSINTS
    clrf        VSSINT
    bcf        INTCON,INTF    ; Clear the 'INT' interrupt flag
    bsf        INTCON,GIE      ; Enable global interrupts

    movfw      TMR0
    movwf      TMR0_1          ; Save the current contents of Timer0
    btfss      VSSINT,0        ; Now wait for the VSS interrupt flag to go high
    goto        $-1

    movfw      TMR0            ; The whole time that was happening, Timer0 was counting IPG cycles
    movwf      TMR0_2          ; So, save the current contents of Timer0 again
    movfw      TMR0_1
    subwf      TMR0_2,W        ; Subtract the two Timer0 snapshots
   
    bcf        INTCON,GIE      ; Disable global interrupts
    btfsc      INTCON,GIE      ; Make sure.... are global interrupts really disabled now?
    goto        $-2            ; No, try again

    return                      ; Return to caller with the count in the W register

; Subroutine: AvgIPGCount
;  Call DoIPGCount 8 times, and calculate the average of the 8 results
;  This routine assumes the Timings will never exceed an 8 bit result
; Inputs:
;  None
; Temporary:
;  IPGSUML - low order 8 bits of the 16 bit sum of IPG cycles
;  IPGSUMH - high order 8 bits of the 16 bit sum of IPG cycles
; Output:
;  W register - contains the averaged timings
AvgIPGCount
    clrf        IPGSUML        ; Clear the variables that will be used
    clrf        IPGSUMH        ; to hold the sum of the eight timings

    call        DoIPGCount      ; Now go get a timing #1
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #2
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #3
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #4
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #5
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #6
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #7
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits
    call        DoIPGCount      ; Now go get a timing #8
    addwf      IPGSUML,F      ; Add it to the rest
    btfsc      STATUS,C        ; Did we have a carry
    incf        IPGSUMH,F      ; Yes, so bump the high order 8 bits

    rrf        IPGSUMH,F      ; Now we divide the sum by 8
    rrf        IPGSUML,F      ;  by shifting right 3 times
    rrf        IPGSUMH,F
    rrf        IPGSUML,F
    rrf        IPGSUMH,F
    rrf        IPGSUML,F
    movfw      IPGSUML        ; Get the result into the W register
    return                      ; Return to caller

; Subroutine: DoAmbient
;  The ambient light sensor is a standard cadmium sulfide photo-cell, configured in a simple
;  voltage divider network.  The resulting voltage drop created by the photo-cell is connected
;  to the PORTA RA2/AN2 pin, which has been configured as an analog input.  Here we do an A/D
;  conversion on that voltage.
;  This routine is used to update an array of the 16 most recent A/D conversions.
;  As the array fills, we wrap around to the beginning again.  The values in the array will
;  then be used in calculating a rolling average.
; Inputs:
;  AMBIENTIX - The array index, pointing at the storage location of the next available location
;  PORTA AN2 - The input voltage to do the A/D conversion on
; Temporary:
;  None
; Output:
;  AMBIENT0<->AMBIENTF - one of the 16 slots in the AMBIENT array, pointed to by AMBIENTIX
DoAmbient
    movfw      AMBIENTIX      ; Get the current array index
    movwf      FSR            ; Put it in the File Select Register
   
    bsf        ADCON0,ADON    ; Turn on the A/D converter
    call        Delay1ms        ; Wait for the A/D converter to settle
    bcf        PIR1,ADIF      ; Clear the A/D interrupt flag
    bsf        ADCON0,GO      ; Start an A/D conversion
    btfsc      ADCON0,GO_DONE  ; Test the GO_DONE bit and wait until it is clear,
    goto        $-1            ;    indicating the A/D conversion is done
    bcf        ADCON0,ADON    ; Turn off the A/D converter

    movfw      ADRESH          ; Get the A/D result into W
    movwf      INDF            ; Save the result of the A/D conversion into the location pointed to by FSR
    incf        AMBIENTIX,F    ; Bump the array index
    btfsc      AMBIENTIX,4    ; Have we reached the end of the 16 byte array yet?
    bcf        AMBIENTIX,4    ; Yes, so wrap back to the beginning
    return                      ; Return to caller

; Subroutine: AvgAmbient
;  Compute a rolling average of the 16 ambient sensor array samples
; Inputs:
;  AMBIENT0<->AMBIENTF - The 16 byte AMBIENT array
; Temporary:
;  AMBIENTSUML - Low order byte of the sum of the 16 array elements
;  AMBIENTSUMH - High order byte
; Output:
;  AMBIENTAVG - Holds the computed average
;  W register - Holds the computed average
AvgAmbient
    movlw      low AMBIENT0    ; Get the memory address of the beginning of the array
    movwf      FSR            ; Save it in the File Select Register (FSR)
    clrf        AMBIENTSUML    ; Clear the high order byte of the sum
    clrf        AMBIENTSUMH    ; Clear the low order byte of the sum
    movfw      INDF            ; Get the data from the array entry pointed to by the FSR
    addwf      AMBIENTSUML,F  ; Add it to the sum
    btfsc      STATUS,C        ; Did the addition result in a carry
    incf        AMBIENTSUMH,F  ; Yes, so bump the high order byte
    incf        FSR,F          ; Point at the next array entry
    btfss      FSR,4          ; Have we done all 16 array entries yet?
    goto        $-6            ; No, do another
    rrf        AMBIENTSUMH,F  ; Now we divide the sum by 16
    rrf        AMBIENTSUML,F  ;  by shifting right 4 times
    rrf        AMBIENTSUMH,F
    rrf        AMBIENTSUML,F
    rrf        AMBIENTSUMH,F
    rrf        AMBIENTSUML,F
    rrf        AMBIENTSUMH,F
    rrf        AMBIENTSUML,F  ; Leaving the result in the low order byte of sum
    movfw      AMBIENTSUML    ; Get the final result into W
    movwf      AMBIENTAVG      ; Save the average
    return                      ; Return to caller

; End subroutines
;---------------------------------------------------------------------------------------------
; Begin translate tables
              
    ORG       0x300          ; Make sure to align translate table on a new page boundary
; Subroutine: Hexto7seg
;  Take the binary value in W, which is what we want to have displayed on our LED display,
;  and convert it to a bit pattern needed to turn on the right PORT pins to light the LED
;  segments.
;  The logic level of the PORTA RA7 pin is used to control which lookup table is used.  If
;  the user has installed his LED display in an upside-down position, then he will have
;  installed the jump onto the 2 pin jumper header.  This will drive the RA7 pin low.
;  If the user has installed the LED display in the upright position, then he will have
;  uninstalled the jumper.  And RA7 will be high.
; Inputs:
;  W register - the binary value representing the data to be displayed
;  PORTA,RA7 - the two pin digit orientation jumper
; Temporary:
;  None
; Output:
;  W register - contains the bit pattern needed to turn on the segments of the LED, when
;                the contents of W is later written to PORTB
Hexto7seg
    btfss      PORTA,7        ; Use the upside-down decodes if RA7 is low
    goto        UpsideDown
; PORTB output pins mapped to 7 segment LED display (upright)
;      a
;    -------
; f |      | b
;  |      |
;    -------
; e |  g  | c
;  |      |
;    -------
;      d
;
; RB0 = n/a - s/b low at all times
; RB1 = g
; RB2 = f
; RB3 = e
; RB4 = d
; RB5 = c
; RB6 = b
; RB7 = a
    addwf      PCL,f
    retlw      B'00000010'    ; decode 0
    retlw      B'10011110'    ; decode 1
    retlw      B'00100100'    ; decode 2
    retlw      B'00001100'    ; decode 3
    retlw      B'10011000'    ; decode 4
    retlw      B'01001000'    ; decode 5
    retlw      B'01000000'    ; decode 6
    retlw      B'11100010'    ; decode L
    retlw      B'11111100'    ; decode "-" (indicates the clutch is pulled in)

UpsideDown
; PORTB output pins mapped to 7 segment LED display (upside-down)
;      d
;    -------
; c |      | e
;  |      |
;    -------
; b |  g  | f
;  |      |
;    -------
;      a
;
; RB0 = n/a - s/b low at all times
; RB1 = g
; RB2 = f
; RB3 = e
; RB4 = d
; RB5 = c
; RB6 = b
; RB7 = a
    addwf      PCL,f
    retlw      B'00000010'    ; decode 0
    retlw      B'11110010'    ; decode 1
    retlw      B'00100100'    ; decode 2
    retlw      B'01100000'    ; decode 3
    retlw      B'11010000'    ; decode 4
    retlw      B'01001000'    ; decode 5
    retlw      B'00001000'    ; decode 6
    retlw      B'00011110'    ; decode L
    retlw      B'11111100'    ; decode "-" (indicates the clutch is pulled in)
    end
Gracias si has llegado hasta aqui que vaya ladrillo.
avatar
merenat
Nuevo Usuario
Nuevo Usuario

Mensajes : 9
Fecha de inscripción : 18/02/2009

Volver arriba Ir abajo

Re: Ayudadme con un "Indicador de marchas para moto según pulsos velocidad y r.pm."

Mensaje por merenat el Miér 12 Oct 2011 - 21:52

voy haciendo pruebas, de momento he modificado para que guarde capturas en la epprom para saber que va haciendo. Pero las tengo que sacar de picklab a mano y cambiar de hex a decimal para meterlo en una hoja de calculo de libreoficce. Hay alguna forma de copiar los datos mas rapido y luego pasarlo a dec con la propia hoja de calculo? Edito: Con la función =HEXADEC(valor) y si abro con gedit el hex obtengo esto:
:104200000600AA00AA00AA00AA00AA00AA00CC00E0
:10421000FF00780053004700370031003000FF00F6
:10422000FF007B00510043003A0038003300FF00DC
:10423000FF007700540042003A0035002D00FF00D7
:10424000FF007400520043003C0035003200FF00C4
:10425000FF00770053004100380035002E00FF00BA
:10426000FF007D0059004300370036002F00FF009B
:10427000FF00770057004100390034002E00FF0096
:10428000FF0074005B004B00380033003200FF0079
:10429000FF0074004E003F003C0031002F00FF0083
:1042A000FF00760053003E003C0033003000FF006A
:1042B000FF00790051003E00370031002F00FF0061
:1042C000FF007800560043003B0034002D00FF0043
:1042D000FF007A0058004100390036003000FF002E
:1042E000FF0075004E0040003C0036002E00FF002D
:1042F000FF00730054004100380034003000FF001C
:10430000FF00750052004000390033003100FF000B
:10431000FF00750051003D00380038002E00FF00FE
:10432000FF00720057004200370032003000FF00EB
:10433000FF0072005000440035003D002D00FF00DA
:10434000FF0072005A0042003D0033003000FF00C1
:10435000FF00FF00FF00FF00FF00FF00FF00FF0065
:10436000FF00FF00FF00FF00FF00FF00FF00FF0055
:10437000FF00FF00FF00FF00FF00FF00FF00FF0045
:10438000FF00FF00FF00FF00FF00FF00FF00FF0035
:10439000FF00FF00FF00FF00FF00FF00FF00FF0025
:1043A000FF00FF00FF00FF00FF00FF00FF00FF0015
:1043B000FF00FF00FF00FF00FF00FF00FF00FF0005
:1043C000FF00FF00FF00FF00FF00FF00FF00FF00F5
:1043D000FF00FF00FF00FF00FF00FF00FF00FF00E5
:1043E000FF00FF00FF00FF00FF00FF00FF00FF00D5
:1043F000FF00FF00FF00FF00FF00FF00FF00FF00C5

estan los numeros intercalados con 00 pero ya me pierdo de como sacarlos.

avatar
merenat
Nuevo Usuario
Nuevo Usuario

Mensajes : 9
Fecha de inscripción : 18/02/2009

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba

- Temas similares

 
Permisos de este foro:
No puedes responder a temas en este foro.