1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Pic debounce routine

Discussion in 'Microcontrollers' started by ssaguiar, Jun 7, 2010.

  1. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Hi to all.
    This is my first post in this forum and I'm glad to be here.

    I am working in a project of a controller for a electronic driven oven and have a question about keys debounce / autorepeat I wish to ask.
    In this project, there are several keys:
    - Set temperature;
    - Set time;
    - Set toaster on/off;
    - Light on;
    - On/off;
    - Up;
    - Down.

    In this project, when you push the Up or Down keys, it ill increment / decrement the display value, making a beep each time.
    If you keep the key (Up or Down) pressed for more than 2 seconds, the display value will increment faster (2 values per second) and, if you keep the key pressed formore than 4 seconds after that, these values will increment even faster (4 values per second, more or less).
    The processo used is thepic16f677, but I can use for develop, the 16f877a, because I have an easyPic4 development board and it's circuit is diferent from the pcb board of the project..

    Has anybody any idea on how to make this work, in pic assembler (mpasm)?

    Thanks to all for any help.
    Sergio
     
  2. Wp100

    Wp100 Active Member

    Joined:
    Feb 3, 2009
    Messages:
    960
    Likes:
    43
    Location:
    England
    Hi,

    There are several ways you can achieve keyboard control.
    Here are some simple examples.
     

    Attached Files:

  3. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    Here is a simple program that fast increments up and down after 2 seconds:

    HTML:
    ;****************************************************************
    ;*     Started 18/6/2009   
    ;2 Digit UP / Down Counter with FastCount after 2secs
    ;Port B drives 7 segment display
    ;Up sw on RA2   Down on RA3
    ;Units drive on RA0   Tens drive on RA1             *
    ;*                              *
    ;****************************************************************

        list P = 16F628 ;microcontroller
        include     ;registers for F628


        __Config    _cp_off & _lvp_off & _pwrte_on
            & _wdt_off & _intRC_osc_noclkout & _mclre_off
       
    ;code protection - off
    ;low-voltage programming - off
    ;power-up timer -  on
    ;watchdog timer - off
    ;use internal RC for 4MHz - all pins for in-out


    ;****************************************************************
    ; variables - names and files
    ;****************************************************************


            ;files for F628 start at 20h
           
    temp1       equ 20h ;for delay
    temp2       equ 21h ;for delay
    SwUp        equ 22h ;
    SwDwn       equ 23h ;
    units       equ 24h ;
    tens        equ 25h ;
    Sw_Flag     equ 26h ;
    FastCount   equ 27h ;

    ;****************************************************************
    ;Equates
    ;****************************************************************
    status      equ 0x03
    cmcon       equ 0x1F
    rp1     equ 0x06
    rp0     equ 0x05
    portA       equ 0x05
    portB       equ 0x06

    ;****************************************************************
    ;Beginning of program
    ;****************************************************************
    reset   org 00  ;reset vector address  
        goto    SetUp   ;goto SetUp
               

    table   addwf   PCL,F           ;02h,1  add W to program counter
            retlw   b'00111111'     ; "0"   -|F|E|D|C|B|A
            retlw   b'00000110'     ; "1"   -|-|-|-|C|B|-
            retlw   b'01011011'     ; "2"   G|-|E|D|-|B|A
            retlw   b'01001111'     ; "3"   G|-|-|D|C|B|A
            retlw   b'01100110'     ; "4"   G|F|-|-|C|B|-
            retlw   b'01101101'     ; "5"   G|F|-|D|C|-|A
            retlw   b'01111101'     ; "6"   G|F|E|D|C|-|A
            retlw   b'00000111'     ; "7"   -|-|-|-|C|B|A
            retlw   b'01111111'     ; "8"   G|F|E|D|C|B|A
            retlw   b'01101111'     ; "9"   G|F|-|D|C|B|A


    ;****************************************************************
    ;* port A and B initialisation                  *
    ;****************************************************************

    SetUp   bsf status,rp0 
        movlw   b'00001100' ;Make RA0,1 out   RA2,3 in
        movwf   05h     ;trisA 
        clrf    06h     ;trisB Make all RB output
        bcf status,rp0  ;select programming area - bank0
        movlw   b'10000000' ;Turn off T0CKI, prescale for TMR0=1
        movwf   option_reg     
        clrf    portB       ;Clear Port B of junk
        clrf    units       ;zero the units file       
        clrf    tens        ;zero the tens file    
        clrf    Sw_Flag
        movlw   07h     ;turn comparators off and enable
        movwf   cmcon       ;    pins for I/O functions
        goto    Main                       
                       

    ;****************************************************************
    ;* Delay 10mS       10 x 1,000uS            *
    ;****************************************************************

    D_10mS  movlw   0Ah
        movwf   temp2
    D_a nop
        decfsz  temp1,f
        goto    D_a
        decfsz  temp2,f
        goto    D_a
        retlw   00
           
           
    FastUp  btfss   Sw_Flag,2   ;First time through loop?
        goto    FU_2        ;yes
        btfsc   Sw_Flag,7   ;Has 5Hz bit been set?
        goto    FU_3
    FU_1    incfsz  FastCount,f ;Increment FastCount
        movlw   d'100'
        xorwf   FastCount,w
        btfss   status,2    ;reached 100 loops?
        retlw   00
        clrf    FastCount
        bsf Sw_Flag,7   ;set bit for 5Hz incrementing  
                   
    FU_2    bsf Sw_Flag,2  ;Up button has been pressed 
        incf    units,f
        movlw   0Ah    ;put 10 into w
        xorwf   units,w   ;compare units file with 10
        btfss   status3,2 ;zero flag in status file. Set if units is 10
        retlw   00
        clrf    units
        incf    tens,f
        movlw   0Ah ;put 10 into w
        xorwf   tens,w  ;compare units file with 10
        btfsc   status,2 ;zero flag in status file. Set if tens is 10
        clrf    tens               
        retlw   00  ;display passes 99 but not below 0
           
           
    FU_3    incfsz  FastCount,f ;Increment FastCount
        movlw   d'5'
        xorwf   FastCount,w
        btfss   status,2    ;reached 5 loops?
        retlw   00
        clrf    FastCount      
        goto    FU_2           
           
    Dwn btfsc   Sw_Flag,3
        retlw   00
        bsf Sw_Flag,3
        decf    units,f
        movlw   0FFh    ;put FFh into w
        xorwf   units,w ;compare units file with FFh
        btfss   status,2 ;zero flag in status file. Set if units is 10
        retlw   00
        movlw   09
        movwf   units   ;put 9 into units file
        decf    tens,f
        movlw   0FFh    ;put 0FFh into w
        xorwf   tens,w  ;compare tens file with 0FFh
        btfsc   status,2 ;zero flag in status file. Set if tens is 0FFh
        goto    $+2 ;tens file is 0FFh
        retlw   00                     
        clrf    tens
        clrf    units
        retlw   00  ;display  not below 0  
           
    ;****************************************************************
    ;* Main                             *
    ;****************************************************************

    Main    btfss   portA,2     ;test switch-press for UP
        call    FastUp      ;UP switch pressed
        btfss   portA,3     ;test switch-press for Down
        call    Dwn     ;Down switch pressed
        movlw   b'00000001' ;Make RA0 HIGH for units drive  
        movwf   portA  
        movf    units,w     ;copy unit value into w
        call    table       ;unit display value will return in w
        movwf   portB       ;output units value
        call    D_10mS      ;call delay
        clrf    portB       ;clear display
        movlw   b'00000010' ;Make RA1 HIGH for tens drive  
        movwf   portA          
        movf    tens,w      ;copy tens value into w    
        call    table       ;tens display value will return in w
        movwf   portB       ;output tens value
        call    D_10mS      ;call delay
        clrf    portB       ;clear display     
        btfsc   portA,3     ;bit will be zero when sw is pressed
        bcf Sw_Flag,3   ;button not pressed. Clear down flag
        btfss   portA,2     ;bit will be zero when sw is pressed
        goto    Main
        bcf Sw_Flag,2   ;button not pressed. Clear Up flag
        bcf Sw_Flag,7   ;Clear Up repeat flag
        clrf    FastCount
        goto    Main       
           
        END    
     
     
    Last edited: Jun 8, 2010
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil

    Thanks, my friends, for your answers.
    I will try to implement the keys routine and will post here as soon as I have it working.
     
  6. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Hi to all.

    I have implemented the keys code in my code but I am still having seveal problems.
    I just can't make the display work as expected, nor even the leds.
    The keyboard routine, once the turbo is active, it stays on untill we reset the processor.

    I wish to know if somebody could help me to understand how to make this work.
    In ths aplication, the display is multiplexed with the keys and the leds.
    Atached to this message, I have uploaded the source code and the project for Proteus.

    I thank you for any help.
     

    Attached Files:

  7. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    Firstly you have to convert all the wording to English.
    Secondly you have to remove all the unnecessary instructions such as CALL TIMERSET
    Thirdly you have to simplify a lot of the routines, such as removing the macros as they are only used once and remove clrw and put it in MAINCONTINUE
    Then you have to supply a circuit diagram so we can see how you are multiplexing the displays and what you are really doing.

    You have totally gone against everything I have ever taught.
    The first thing you do is produce a routine to activate the displays. Then introduce one key and one LED.
    During the time when the last display is illuminated you have time to do all sorts of "housekeeping."
    This involves looking at the input port and dealing with the data, processing it and storing it.
    This is a much simpler way of tackling your requirement and the program will be half the size. And you will be able to understand it.
    What you are doing is very simple.
     
    Last edited: Jun 16, 2010
  8. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Thank you colin55 for your answer.
    The circuit diagram is included in the Proteus project.
    I have tried everything but have no luck.
    Sometimes, the keyboard works with the display.
    The leds don't work at all.
    First, I have implemented this code without having to use interrupts to be simpler, but I used an osciloscope to see how was the original tming of the displays and leds circuit and I have found that the displays and leds are active this way:
    1 - activate display 1 during 2 ms then turn it off;
    2 - activate leds during 2 ms then turn it off;
    3 - activate display 2 during 2 ms then turn it off;
    4 - activate display 3 during 2ms then turn it off and restart.

    By this way, the total time is 8ms dvided by the displays and leds (the keying of the transistors).

    I though that, to have such behavior, it was best to use interrupts and a state machine's implementation (in the scope, the timing was allways the same even when pressing a key or).

    I will try to make the code simpler and will translate the rest of the code to english (I allways do this, but this time, I started to make the comments in portuguese.

    Much of the code is more complicated because the original project don't use all the stuff in on port (for example PORTB), they use the keys, display's cathodes and leds cathodes on some pins of the ports B and A, thus why the code sometimes is much more complicated (If the hardware was made more inteligent, I could put all stuff in one port using, for example, mowf PORTB, but I can't, as I have to output pin by pin).

    Sergio
     
  9. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    This is the code, all translated to english.
    All tabs set to 4.

    Sergio
     

    Attached Files:

    Last edited: Jun 16, 2010
  10. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    Export the schematic to .pdf or .gif
     
  11. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Here it is, in pdf format.

    The leds in RA0 and RA1 just represent the reles wich activate the heaters (main heater and toaster).

    Sergio
     

    Attached Files:

    • oven.PDF
      File size:
      57.9 KB
      Views:
      198
  12. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    You have used the wrong micro. Why don't you use a PIC16F628. It has a full port and this will make it easier to drive the displays. You need dropper resistors in the lines to the 7 segment displays.
    You need to do a "run-of-four" in the scan routine with three displays and then 8 LEDs. The other three outputs will have to be added to each of the displays as the 8th item. After the "run-of-four" you do a very quick look at the 7 switches.
    Draw this up as a matrix and create the scan routine.

    What you have to remember is this: You have to spend all your time scanning and displaying the LEDs and 7-segment displays. This will take a full port (PortB) plus 4 lines from PortA. You will need a dedicated line from PortA to drive the buzzer.
    This leaves one input-only line unused and two output lines.
    Each display will get approx 25% "on-time."

    You start by allocating 4 files for the data for the displays and LEDs. These are cleared and the routine looks up a table for the 7 lowest bits and either includes the 8th (or not) for the LED that is also included in the "run." This will put "000" on the dislay. You can include "leading zero blanking." The fourth item in the run simply outputs the data for the LEDs.

    Include the debounce in this routine and also the fast increment feature. Allocate a file for the data from the switches and a file for the flags (from the fast forward requirement). You will also need to include the data for the buzzer.

    Now you have everything set up.

    You simply have one scan routine that does all the work.
     
    Last edited: Jun 17, 2010
  13. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Dear colin55:

    Thank you, my fiend, for your answer.

    The problem is exactly this: I can't change this circuit because it is already implemented in a commercial product.
    They had one person that made the firmware for them and as they don't have access to the source code and the person is no more available, they ask to make the firmware again, based on the original circuit.

    Sergio
     
    Last edited: Jun 19, 2010
  14. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    Who drew the circuit diagram? How can Q7, 8 and 9 work? How are the displays connected?
    D5A will be a 5v6 zener. D6A and D6B are around the wrong way.

    If you have to follow a previous layout, draw up the scanning diagram - the scanning circuit. I have absolutely no idea how the displays are connected.
     
    Last edited: Jun 17, 2010
  15. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    I had this exact feeling when I started, but, after take a time to see how the circuit works, I got this:

    The Q7, Q8 and Q9 works because the V_IN2 voltage is negative (this voltage came from anodes of diodes D1 and D4, in the main supply).

    The main supply has no transformer (I just don't agree with this, but those guys want to keep the cost at minimum - again: I don't think this is a good thing to do).

    The resistor R3, capacitor C1, resistor R1 and the resistor R2, provides the reference for the main voltage sensor (It's used to see if the main voltage dropped below some level).
    The V_IN1, at the cathode of diodes D2 and D3, in power supply, gives the 12 volts voltage thru the C4 capacitor and D7A diode, and, then, the circuit D5A, R4 and Q1 generates the 5 Volts (VCC) wichis used by pic, leds, displays etc..
    The reles have supply from the -12 volts, wich is generated by the anodes of D1 and D4 regulated by C3, D6A and D6B. This is why the emiters of the transistors Q7, Q8 and Q9 are tied to ground.

    As I said, this is not a circuit of mine and I really don't agree with the lack of a transformer.

    Sergio
     
  16. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    The first thing you do is produce a table with 2 bytes for each digit. The first byte accesses RA 2 4 5 and the second byte access RB4567.
    The scan routine will access these two bytes and send them to the displays.
    Do this first: Get 000 on the displays.
     
  17. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    Ok, I'm going to do this.
    First, I have two questions:

    - Do you think it's best to have the scan code driven by interrupts (as I did) or in the main loop?

    - I think I will make 2 routines that will return a byte each from a table as in DECOD_DISPLAY, but one for PORTA and another FOR PORTB. What do you think? Is it best this way, so I just have to see what is the value, call table for PORTA, put the returned value in PORTA (MOVLW PORTA), then make it again, for PORTB?

    Thanks again.

    Sergio
     
  18. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    This is what I talk about:

    Code (text):

    DECOD_DISPLAY_A:
        MOVWF   TEMP            ; Put number in displacement variable
        MOVLW   LOW TABLE_A     ; cop to W the 8 LSB bits of the TABLE address
        ADDWF   TEMP,F          ; add the value to the displacement variable
        MOVLW   HIGH TABLE_A    ; copy to W the upper 5 bits of the TABLE ddress
        BTFSC   STATUS,C        ; Test to see if the sum activates the carry bit
        ADDLW   0x01            ; if carry, sum 1 to W
        MOVWF   PCLATH          ; sets PCLATH using the TABLE address
        MOVF    TEMP,W          ; copy the displacement value to W
        MOVWF   PCL             ; copy W to PCL

    TABLE_A:
    ;       A
    ;    _______
    ;   |       |
    ; F |       | B
    ;   |   G   |
    ;    -------
    ;   |       |
    ; E |       | C
    ;   |_______|
    ;       D
                    ;   |7|6|5|4|3|2|1|0| - Bits PORTA
                    ;   |-|-|B|E|-|A|-|-|
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 0
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 1
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 2
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 3
        RETLW   B'00010100' ;   |-|-|B|X|-|X|-|-| - 4
        RETLW   B'00011000' ;   |-|-|X|X|-|A|-|-| - 5
        RETLW   B'00100000' ;   |-|-|X|E|-|A|-|-| - 6
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 7
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 8
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 9

    DECOD_DISPLAY_B:
        MOVWF   TEMP            ; Put number in displacement variable
        MOVLW   LOW TABLE_B     ; cop to W the 8 LSB bits of the TABLE address
        ADDWF   TEMP,F          ; add the value to the displacement variable
        MOVLW   HIGH TABLE_B    ; copy to W the upper 5 bits of the TABLE ddress
        BTFSC   STATUS,C        ; Test to see if the sum activates the carry bit
        ADDLW   0x01            ; if carry, sum 1 to W
        MOVWF   PCLATH          ; sets PCLATH using the TABLE address
        MOVF    TEMP,W          ; copy the displacement value to W
        MOVWF   PCL             ; copy W to PCL

    TABLE_B:
                        ;|7|6|5|4|3|2|1|0| -    Bits PORTB
                        ;|C|F|D|G|-|-|-|-| -
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 0
        RETLW   B'11110000' ;   |X|X|X|X|-|-|-|-| - 1
        RETLW   B'11000000' ;   |X|X|D|G|-|-|-|-| - 2
        RETLW   B'01000000' ;   |C|X|D|G|-|-|-|-| - 3
        RETLW   B'10100000' ;   |X|F|X|G|-|-|-|-| - 4
        RETLW   B'10100000' ;   |X|F|X|G|-|-|-|-| - 5
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 6
        RETLW   B'01110000' ;   |C|X|X|X|-|-|-|-| - 7
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 8
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 9
     
    Wit this, I just have to call DECOD_DISPLAY_A and DECOD_DISPLAY_B and will have the number converted to bcd and ready to be put in PORTA and in PORTB (the diplay's cathodes).

    What do you think about this solution? Isn't bette than call all the former conversion stuff I had?

    Thanks
     
  19. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    With the code below, the displays, the leds and the led onoff interrupt to make it blink, are working fine.
    I started testing the displays with '0's as you sugeted, and, then added the leds stuff, tested it and, after that, the interrupt stuff and tested it.
    I am using the interrup because the led is suposed to be blinking when the oven is waiting for commands or is in pause mode.

    Do you think it's ok?

    Thanks

    Code (text):

        ;**********************************************************************
        ;                                                                     *
        ;**********************************************************************
        ;    Filename:      oven.asm                                          *
        ;    Date:                                                            *
        ;    File Version:                                                    *
        ;                                                                     *
        ;    Author:                                                          *
        ;    Company:                                                         *
        ;                                                                     *
        ;**********************************************************************
        ;    Files Required: P16F677.INC                                      *
        ;                                                                     *
        ;**********************************************************************
        ;    PIC 16F677 pinout:                                               *
        ;                          |--\/--|                                   *
        ;                     Vdd -|1   20|- Vss                              *
        ;    RA5/T1CKI/OSC1/CLKIN -|2   19|- RA0/AN0/C1IN+/ICSPDAT/ULPWU      *
        ; RA4/AN3/T1G/OSC2/CLKOUT -|3   18|- RA1/AN1/C12IN0-/VREF/ICSPCLK     *
        ;            RA3/MCLR/VPP -|4   17|- RA2/AN2/T0CKI/INT/C1OUT          *
        ;                     RC5 -|5   16|- RC0/AN4/C2IN+                    *
        ;               RC4/C2OUT -|6   15|- RC1/AN5/C12IN1-                  *
        ;           RC3/AN7C12IN3 -|7   14|- RC2/AN6/C12IN2-                  *
        ;              RC6/AN8/SS -|8   13|- RB4/AN10/SDI/SDA                 *
        ;             RC7/AN9/SDO -|9   12|- RB5/AN11                         *
        ;                     RB7 -|10  11|- RB6/SCK/SCL                      *
        ;                          --------                                   *
        ;                                                                     *
        ;**********************************************************************

    ;/****************************************************************************
    ;* DESCRIPTION: System definitions.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

        ERRORLEVEL -302 ;remove message about using proper bank

        LIST  P=16F677
        INCLUDE <P16F677.INC>
        __CONFIG _BOR_OFF & _FCMEN_OFF & _IESO_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO

    ;/****************************************************************************
    ;* DESCRIPTION: Program variables and constant definitions.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    TEMPER      EQU 0x20                        ; Store temperature
    TEMP        EQU 0x21                        ; General use variable
    W_TEMP      EQU 0x22                        ; Temporary W register
    STATUS_TEMP EQU 0x23                        ; Temporary STATUS register
    UNITS       EQU 0x24                        ; UNITS
    TENS        EQU 0x25                        ; TENS
    HUNDREDS    EQU 0x26                        ; HUNDREDS
    AUX         EQU 0x27                        ; GENERAL AUX. REGISTER
    TEMPO0      EQU 0x28
    TEMPO1      EQU 0x29
    T1_CONTA    EQU 0x2A                        ; Aux. Timer1 counter
    TMR_1MS     EQU 0x2B                        ; Counter for 1 ms period
    TMR_100MS   EQU 0x2C                        ; Counter for 100 ms period

    ; Leds
    #DEFINE     LED_CMN             PORTC,2     ; Leds Anodes

    #DEFINE     LED_UP              PORTA,4     ; Led UP
    #DEFINE     LED_TIMER           PORTB,6     ; Led TIMER
    #DEFINE     LED_TEMP            PORTB,5     ; Led TEMP
    #DEFINE     LED_DWN             PORTA,2     ; Led DWN
    #DEFINE     LED_LIGHT           PORTB,4     ; Led LIGHT
    #DEFINE     LED_TOASTER         PORTA,5     ; Led TOASTER
    #DEFINE     LED_ONOFF           PORTC,6     ; Led ONOFF

    ; Displays
    #DEFINE     DISP1               PORTC,3     ; Anode display DIS0
    #DEFINE     DISP2               PORTC,4     ; Anode display DIS1
    #DEFINE     DISP3               PORTC,5     ; Anode display DIS2

    ;/****************************************************************************
    ;* DESCRIPTION: Got Start of program.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************
        ORG     0x0000

        GOTO    START

    ;*****************************************************************************
        ORG 0x0004

        MOVWF   W_TEMP          ; save W content to W_TEMP
        SWAPF   STATUS,W        ; put STATUS in W...
        MOVWF   STATUS_TEMP     ; ... Then save it in STATUS_TEMP

        BCF     PIR1,TMR1IF     ; Clear Timer1 Interrupt flag

        MOVLW   0x18            ;
        MOVWF   TMR1L           ;
        MOVLW   0xFC            ;
        MOVWF   TMR1H           ; Init TIMER1 with decimal 64536 (interrupt every 1ms)


        INCF    TMR_1MS,F       ; Increment TR_1MS (1 ms counter)
        MOVLW   D'100'
        XORWF   TMR_1MS,W       ; Is TMR_1MS = 100?
        BTFSC   STATUS,Z        ; No, skip if TMR_1MS < 100
        GOTO    INC100MS        ; Yes, zero TMR_1MS and inc TMR_100MS
        GOTO    END_INT         ; No, exit interrupt

    INC100MS
        MOVLW   D'0'            ;
        MOVWF   TMR_1MS         ; Zero TMR_1MS
        INCF    TMR_100MS,F     ; Increment TMR_100MS (100 ms counter)
        MOVLW   D'5'            ; 500 ms?
        XORWF   TMR_100MS,W     ; Is TMR_100MS = 5 (500ms)?
        BTFSC   STATUS,Z        ; No, skip if TMR_100MS < 5
        GOTO    INCCONTA        ; Yes, zero TMR_100MS and inc 0,5 seconds counter
        GOTO    END_INT         ; No, Exit interrupt

    INCCONTA:
        MOVLW   D'0'            ;
        MOVWF   TMR_100MS       ; Zero 100 ms counter (reached 500ms)  
        BSF     STATUS,RP0      ; Bank 1
        BCF     STATUS,RP1      ;
        BCF     LED_ONOFF       ; LED_ONOFF output

        BCF     STATUS,RP0      ; Bank 0
        BCF     STATUS,RP1      ;

        MOVLW   D'1'            ; Verify if ...
        XORWF   T1_CONTA,W      ; passed 1/2 second ...
        BTFSC   STATUS,Z        ;
        GOTO    LEDON           ; Led ONOFF is ON? Goto LEDON
    LEDOFF:
        BCF     LED_ONOFF       ; Turn OFF LEDON_OFF
        GOTO    LEDOUT          ; ok, done...
    LEDON:
        BSF     LED_ONOFF       ; Turn ON LED_ONOFF
    LEDOUT:
        DECFSZ  T1_CONTA,F      ; Decrement the Counter rRegister
        GOTO    END_INT         ; If diferent of zero, exit interrupt
        MOVLW   2               ;
        MOVWF   T1_CONTA        ; Restart Counter Register with 2  


    END_INT:
        SWAPF   STATUS_TEMP,W   ; Restaure STATUS content...
        MOVWF   STATUS          ; ... from STATUS_TEMP
        SWAPF   W_TEMP,F        ; Restaure W content...
        SWAPF   W_TEMP,W        ; ... from W_TEMP.

        RETFIE                  ; Return from interrupt

    ;/****************************************************************************
    ;* DESCRIPTION: Decodes value in W register to display segments for PORTA.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    DECOD_DISPLAY_A:
        MOVWF   TEMP            ; Put number in displacement variable
        MOVLW   LOW TABLE_A     ; cop to W the 8 LSB bits of the TABLE address
        ADDWF   TEMP,F          ; add the value to the displacement variable
        MOVLW   HIGH TABLE_A    ; copy to W the upper 5 bits of the TABLE ddress
        BTFSC   STATUS,C        ; Test to see if the sum activates the carry bit
        ADDLW   0x01            ; if carry, sum 1 to W
        MOVWF   PCLATH          ; sets PCLATH using the TABLE address
        MOVF    TEMP,W          ; copy the displacement value to W
        MOVWF   PCL             ; copy W to PCL

    TABLE_A:
    ;       A
    ;    _______
    ;   |       |
    ; F |       | B
    ;   |   G   |
    ;    -------
    ;   |       |
    ; E |       | C
    ;   |_______|
    ;       D
                            ;   |7|6|5|4|3|2|1|0| - Bits PORTA
                            ;   |-|-|B|E|-|A|-|-|
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 0
        RETLW   B'00010100' ;   |-|-|B|X|-|X|-|-| - 1
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 2
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 3
        RETLW   B'00010100' ;   |-|-|B|X|-|X|-|-| - 4
        RETLW   B'00110000' ;   |-|-|X|X|-|A|-|-| - 5
        RETLW   B'00100000' ;   |-|-|X|E|-|A|-|-| - 6
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 7
        RETLW   B'00000000' ;   |-|-|B|E|-|A|-|-| - 8
        RETLW   B'00010000' ;   |-|-|B|X|-|A|-|-| - 9


    ;/****************************************************************************
    ;* DESCRIPTION: Decodes value in W register to display segments, for PORTB.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    DECOD_DISPLAY_B:
        MOVWF   TEMP            ; Put number in displacement variable
        MOVLW   LOW TABLE_B     ; cop to W the 8 LSB bits of the TABLE address
        ADDWF   TEMP,F          ; add the value to the displacement variable
        MOVLW   HIGH TABLE_B    ; copy to W the upper 5 bits of the TABLE ddress
        BTFSC   STATUS,C        ; Test to see if the sum activates the carry bit
        ADDLW   0x01            ; if carry, sum 1 to W
        MOVWF   PCLATH          ; sets PCLATH using the TABLE address
        MOVF    TEMP,W          ; copy the displacement value to W
        MOVWF   PCL             ; copy W to PCL

    TABLE_B:
                            ;   |7|6|5|4|3|2|1|0| - Bits PORTB
                            ;   |C|F|D|G|-|-|-|-| -
        RETLW   B'00010000' ;   |C|F|D|X|-|-|-|-| - 0
        RETLW   B'01110000' ;   |C|X|X|X|-|-|-|-| - 1
        RETLW   B'11000000' ;   |X|X|D|G|-|-|-|-| - 2
        RETLW   B'01000000' ;   |C|X|D|G|-|-|-|-| - 3
        RETLW   B'00100000' ;   |C|F|X|G|-|-|-|-| - 4
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 5
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 6
        RETLW   B'01110000' ;   |C|X|X|X|-|-|-|-| - 7
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 8
        RETLW   B'00000000' ;   |C|F|D|G|-|-|-|-| - 9

    ;/****************************************************************************
    ;* DESCRIPTION: Little Delay to let display show digit.
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    DELAY_MS:                   ; Delay routine - W is the number of ms of delay.
        MOVWF   TEMPO1          ; put w in temp variable
        MOVLW   D'250'
        MOVWF   TEMPO0
        DECFSZ  TEMPO0,F
        GOTO    $-1
        DECFSZ  TEMPO1,F
        GOTO    $-5
        RETURN

    ;/****************************************************************************
    ;* DESCRIPTION: binary_to_bcd - 8-bits
    ;* INPUT:       TEMPER  - 8-bit binary number
    ;* RETURN:      CENTENA - the hundreds digit of the BCD conversion
    ;*              DEZENA  - the tens digits of the BCD conversion
    ;*              UNIDADE - the ones digits of the BCD conversion
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/
    BINARY_TO_BCD:

        MOVWF   AUX             ; sve the value to convert in AUX
        CLRF    UNITS           ;
        CLRF    TENS            ;
        CLRF    HUNDREDS        ; RESET variables
        MOVF    AUX,F           ;
        BTFSC   STATUS,Z        ; Is the value to convert = 0?
        RETURN                  ; Yes - Return
                                ; No
        INCF    UNITS,F         ; Increment unit
        MOVF    UNITS,W         ;
        XORLW   0X0A            ;
        BTFSS   STATUS,Z        ; unit = 10d ?
        GOTO    $+3             ; No
                                ; yes
        CLRF    UNITS           ; Reset unit
        INCF    TENS,F          ; Increment tens
        MOVF    TENS,W          ;
        XORLW   0X0A            ;
        BTFSS   STATUS,Z        ; Tens = 10d ?
        GOTO    $+3             ; No
                                ; Yes
        CLRF    TENS            ; Reset tens
        INCF    HUNDREDS,F      ; Increment hundreds
        DECFSZ  AUX,F           ; End of conertion ?
        GOTO    $-.14           ; No - go back to continue the convertion
        RETURN                  ; Yes

    ;/****************************************************************************
    ;* DESCRIPTION: Program Initialization
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    START:
        BCF     STATUS,RP0      ; Bank 2
        BSF     STATUS,RP1      ;
        CLRF    ANSEL           ; digital I/O
        CLRF    ANSELH          ;   "   "   "
        BCF     STATUS,RP0      ; Bank 2
        BSF     STATUS,RP1      ;
        MOVLW   B'00000000'
        MOVWF   CM1CON0         ; disable comparator
        MOVLW   B'00000000'     ; Not necessary?
        MOVWF   CM2CON0         ; disable 2nd comparator
        MOVLW   B'00000000'     ; Not necessary?
        MOVWF   CM2CON1         ; disable 3rd comparator
        BSF     STATUS,RP0      ; Bank 1
        BCF     STATUS,RP1      ;
        MOVLW   B'00001000'     ;
        MOVWF   TRISA           ;
        MOVLW   B'00000000'     ;
        MOVWF   TRISB           ;
        MOVLW   B'10000010'     ;
        MOVWF   TRISC           ;
        BCF     STATUS,RP0      ; Bank 0
        BCF     STATUS,RP1      ;
        BCF     SSPCON,SSPEN    ; Disable Synchronous Serial Port

        ; Turn off all reles, displays and leds
        BSF     LED_CMN         ; Leds off
        BSF     DISP1           ; Display1 off
        BSF     DISP2           ; Display2 off
        BSF     DISP3           ; Display3 off

        MOVLW   D'180'          ; Init temperature with 180 degrees Celsius
        MOVWF   TEMPER
        MOVLW   2               ;
        MOVWF   T1_CONTA        ;

        ; Init Timer1
        MOVLW   B'00000000'     ; Configure TIMER1 for internal clock and prescaler 1:1
        MOVWF   T1CON           ; Init Timer1
        MOVLW   0x18            ;
        MOVWF   TMR1L           ;
        MOVLW   0xFC            ;
        MOVWF   TMR1H           ; Init TIMER1 with decimal 64536 (interrupt every 1ms)

        BSF     STATUS,RP0      ; Bank 1
        BCF     STATUS,RP1      ;
        MOVLW   B'00000001'     ; Enable TIMER1 Overflow Interrupt
        MOVWF   PIE1
        BCF     STATUS,RP0      ; Bank 0
        BCF     STATUS,RP1      ;
        CLRF    PIR1            ; Clear Peripheral Interrupt Flags
        BSF     INTCON, PEIE    ; Enable Peripheral Interrupts
        BSF     T1CON, TMR1ON   ; Start TMR1
        BSF     INTCON, GIE     ; Enable Global Interrupts


    ;/****************************************************************************
    ;* DESCRIPTION: Main Program
    ;* RETURN:      none
    ;* ALGORITHM:   none
    ;* NOTES:       none
    ;*****************************************************************************/

    MAIN_LOOP:
        MOVF    TEMPER,W        ; Put temperature in W
        CALL    BINARY_TO_BCD   ; Decode Temperature to bcd

        BSF     LED_CMN         ; Leds off

        MOVF    UNITS,W         ; copy units to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_A ; convert
        MOVWF   PORTA           ; put it in PORTA
        MOVF    UNITS,W         ; copy units to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_B ; convert
        MOVWF   PORTB           ; put it in PORTA
        BCF     DISP1           ; display 1 on
        MOVLW   D'2'            ;
        CALL    DELAY_MS        ; delay 2 ms
        BSF     DISP1           ; display 1 off

        MOVF    TENS,W          ; copy tens to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_A ; convert
        MOVWF   PORTA           ; put it in PORTA
        MOVF    TENS,W          ; copy tens to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_B ; convert
        MOVWF   PORTB           ; put it in PORTA
        BCF     DISP2           ; display 1 on
        MOVLW   D'2'            ;
        CALL    DELAY_MS        ; delay 2 ms
        BSF     DISP2           ; display 1 off

        MOVF    HUNDREDS,W      ; copy hundeds to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_A ; convert
        MOVWF   PORTA           ; put it in PORTA
        MOVF    HUNDREDS,W      ; copy hundeds to W
        ;MOVLW  D'0'
        CALL    DECOD_DISPLAY_B ; convert
        MOVWF   PORTB           ; put it in PORTA
        BCF     DISP3           ; display 1 on
        MOVLW   D'2'            ;
        CALL    DELAY_MS        ; delay 2 ms
        BSF     DISP3           ; display 1 off

        BCF     LED_UP          ; led UP ON
        BCF     LED_DWN         ; led DWN ON
        BCF     LED_TEMP        ; led TEMP ON
        BSF     LED_TIMER       ; led TIMER OFF
        BSF     LED_LIGHT       ; led LIGHT OFF
        BSF     LED_TOASTER     ; led TOASTER OFF
        BCF     LED_CMN         ; Leds on
        MOVLW   D'2'            ;
        CALL    DELAY_MS        ; delay 2 ms
        BSF     LED_CMN         ; Leds off


        GOTO    MAIN_LOOP       ; Back to main loop

        END
     
     
  20. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    1 - Use lower case for nmemonics
    2. Have you cleared: units, tens, and hundreds before starting?
    3. You don't need interrupts. It just makes things more complex.
    4. Put the tables in the first page Page0 and go to them. This will simplify the code to:

    movf units,w
    goto tableA






    Here is a very short delay routine

    del_2mS

    movlw 02
    movwf temp1
    nop
    decfsz temp2
    goto $-2
    retlw 00

    each unit put into temp1 will produce 1mS delay. temp2 will be 00 at start of second and further calls to this delay.
     
    Last edited: Jun 17, 2010
  21. ssaguiar

    ssaguiar New Member

    Joined:
    Jun 7, 2010
    Messages:
    83
    Likes:
    0
    Location:
    Florianopolis, Brazil
    About the lower case, you mean the asm mneumonics (BTFSC btfsc, ADD add...)?
    I use upper case because it's easier for me to read them ( I have some atention deficit).

    Thanks to point me the need to clear the units, tens ad hundreds. Just done.

    How to make the led blink without interrupt and without loosing time in delays? The delays can break the displays timing, don't? Remember I still have to make the buzzer plays when one key is pressed the first time, make the a/d channel for the temperature sensor read it and monitor the low volatge sensor.

    I didn't understand how to use he tables in page 0.
    Do I have to put "banksel 0" in the start of the table's codes?

    About the deay routine, Thanks for it, but the routine I have in my code isn't good? It can be used for any valu between 1 and 255 ms:
    Code (text):

    DELAY_MS:                   ; Delay routine - W is the number of ms of delay.
        MOVWF   TEMPO1          ; put w in temp variable
        MOVLW   D'250'
        MOVWF   TEMPO0
        DECFSZ  TEMPO0,F
        GOTO    $-1
        DECFSZ  TEMPO1,F
        GOTO    $-5
        RETURN
     
    Thanks again for be so kind with me and have all the patience you have.
     
    Last edited: Jun 17, 2010

Share This Page