Help programming a pic12f683 in assembly

Discussion in 'Embedded Systems and Microcontrollers' started by Daemon, Jun 2, 2011.

  1. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Hi guys

    I am attempting to learn assembly and program a switched timer for a fishing torpedo.

    I am using MPLAB IDE v8.56 to write the assembly code and debug it

    I have read the datasheet, although it hasn't all sunk in and gone through several of the tutorials available on the net but I need some examples or someone to steer me in the right direction please.

    This is not homework, it is a hobby project I am building at home.

    My circuit works like this
    I have a 12v battery attached to GP4 via a 7805 and a resistor divider to reduce the voltage below 5v for the pic to read the voltage
    I have one reed switch on GP2 as the circuit will be activated by a magnet from outside the body of the torpedo as it is fully contained and waterproofed.
    I have 1 led and resistor. on GP0
    I also have a mosfet grounded on GP1 and switched by GP5

    The timer will work like this

    psuedo code
    is switch open on powering unit
    if yes light led steady for 1 second then flash to indicate low voltage cutoff setting
    if low voltage setting done save to EEPROM
    is switch not open on powering unit
    if not then blink led up to 6 times to indicate setting of motor timer. ie 5 blinks equals 5x5 minutes or25 minutes
    then light led steady to indicate ready to run
    when switch next opened start 1 minute timer to allow time to get the torpedo in the water then start saved motor timer and activate mosfet to switch on motor
    when set motor timer elapses or low voltage cutoff setting reached stop motor
    if switch held open for longer than 10 seconds after timer indication then power off circuit

    I intend to write all the code and debug it to the best of my ability but will need some help(other than saying look in the data sheet) in order to correct anything I haven't quite worked out

    The order I will write the program I think would be in this order
    1. Implement the interrupt on change features of the chip so the chip can be put into low power sleep mode and also power on when the switch is activated
    2. Write the code for the adc feature so I can read the lvc(low voltage cutoff) setting and store it in EEPROM
    3. Write the subroutine for the 5 minute delay and how to store that in EEPROM
    4. Write the code with all the timers etc to blink, light and flash the led and activate the motor.

    Does anyone have any suggestions for me on a better way to do things or a better order to write it?

    Thanks for reading this
    Steve
     
  2. beenthere

    Retired Moderator

    Apr 20, 2004
    15,815
    282
    Don't try to write the whole program code all at once. Assembly code can be done in modules, so you can get started by flashing LED's and using a pot to supply voltages to the ADC for conversion. Programming is weird, but sometimes it clicks and you can do anything.
     
  3. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Sounds like a good plan. Start with the template code so that you already have the context saving for the interrupts.
    ADC and EEPROM code is in the datasheet, but the sample code does not restore the bank back to bank 0. Also the sample code expects certain variables to be in the memory that is shared between banks (addresses 0x70-0x7f).

    Have a go, get to know the IDE and simulator and if you get stuck, we are here to help.
     
  4. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Thanks guys.
    Will write something up and post it and see how I go.
    Will be doing exactly as suggested too and doing it in modules.

    Sorry for the late reply, I clicked instant notification but it never happened.
    Will need to be more watchful.
    Cheers
     
  5. beenthere

    Retired Moderator

    Apr 20, 2004
    15,815
    282
    Keep accurate track of your variable names - saves all sorts of grief as the code gets larger.
     
  6. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    From the tutorials etc I have read so far I have pieced together the following code
    I was going to only add the interrupt on change code but have also added a 5 minute delay subroutine and some definitions

    Please tell me what you think.
    My next step would be writing the code for the low voltage cutoff setting and EEPROM

    Code ( (Unknown Language)):
    1.  
    2. ;Timer with low voltage cutoff
    3. ;Program to monitor a 12v battery
    4. ;Uses a FET to drive a load
    5. ;Switches the load off when volts reach minimum (10v)
    6. ;Reed switch 2 triggers advance in timer incremented by 5 minutes
    7. ;This causes led to flash number of 5 minute intervals up to 30 minutes
    8. ;Reed switch 1 held on power up causes led to flash quickly 5 times indicating lvc programming mode has been entered
    9. ;once lvc programming mode has been entered voltage is tested through a LM7805 and value is stored in EEPROM for lvc function
    10. ;Written for PIC12F683 (8 pin)
    11. ;On startup if reed switch 2 is not activated within 1 second the led flashes the number of times it is programmed for then waits for reed switch 1 to activate
    12. ;Pushing Reed switch 1 again at this time activates the timer
    13. ;If during led flashing reed switch 2 is activated again new timer period will be set
    14. ;Pin 2(GP5) switches mosfet, Pin 6(GP1) switches mosfet, Pin 3(GP4) reads voltage, Pin 7(GP0) LED output, Pin 5(GP2) Switch input, Pin 1(VDD), Pin 8(VSS)
    15.  
    16. ;//PREPROCESSOR ===============================================|---|
    17.  
    18.     LIST    p=12F683
    19.     include "P12F683.INC"
    20.  
    21.     __CONFIG    _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
    22.     errorlevel -302
    23.     errorlevel -312
    24.    
    25.  
    26. nBUTTON      EQU    D'02'            ; Reed switch 1 on GP2
    27. nBUTTON2    EQU D'03'            ; Reed switch 2 on GP3
    28. nB_LED        EQU    D'00'            ; switch activated led on GP0
    29. clockrate      EQU     .4000000        ; 4MHz
    30.  
    31.  
    32.         CBLOCK    0x20
    33.         Delay:2            ;Define two registers for the delay and delay + 1
    34.         mode            ;Mode
    35.         count1            ; for 5 minute delay    
    36.         cs_W            ; ISR save context
    37.         cs_STATUS        ; "
    38.         SW1                ; Switch #1
    39.         SW2                ; Switch #2
    40.         TMR                ; timer value in minutes
    41.         d1                ;Delay variables for 5 minute timer
    42.         d2                ;
    43.         d3                ;
    44.         d4                ;
    45.  
    46.     ENDC
    47.  
    48.  
    49.  
    50.     org 0x0000
    51.     goto    init
    52.  
    53. ; interrupt service routine :
    54. ;----------------------------
    55. ISR    org    0x004    
    56.         movwf    cs_W                ; save W
    57.         movf    STATUS,w            ; save status
    58.         movwf    cs_STATUS            ;
    59.  
    60. isr_end                            ;restore context then return
    61.         movf    cs_STATUS,w            ;restore STATUS
    62.         movwf    STATUS
    63.         swapf    cs_W,f                ;restore w
    64.         swapf    cs_W,w
    65.         retfie
    66.  
    67. ; 5 minute delay subroutine
    68. DelayW      movwf   count1         ;call DelayW with 1 in w it will set 5 minutes
    69.                                 ;call DelayW with 2 in w it will set 10 minutes etc
    70. Delay5
    71.          ;299999995 cycles
    72.        movlw   0x54
    73.        movwf   d1
    74.        movlw   0xA1
    75.        movwf   d2
    76.        movlw   0xFD
    77.        movwf   d3
    78.        movlw   0x02
    79.        movwf   d4
    80. Delay_0
    81.        decfsz   d1, f
    82.        goto   $+2
    83.        decfsz   d2, f
    84.        goto   $+2
    85.        decfsz   d3, f
    86.        goto   $+2
    87.        decfsz   d4, f
    88.        goto   Delay_0
    89.  
    90.          ;5 cycles
    91.        goto   $+1
    92.        goto   $+1
    93.        nop
    94.  
    95.       decfsz   count1   ,f
    96.       goto   Delay5
    97.       retlw   0x00
    98.  
    99.  
    100. ; initialize port and registers :
    101. ;--------------------------------
    102. init
    103.       banksel    GPIO
    104.       movf    GPIO,w                ;Clear mismatch condition
    105.       bcf        INTCON,GPIF            ;clear interrupt flag
    106.                                 ;configure ports
    107.    
    108.        
    109.     END
    110.  
    Thanks
    Steve
     
  7. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Looks OK so far. To deal with the interrupt happening when the main code is in bank 1, cs_W and cs_STATUS should be defined in a second section starting cblock 0x70 (available from both banks) and there should be a banksel after saving W and STATUS in the ISR.
     
  8. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Like this?
    I have pasted just the cblock and isr section
    Code ( (Unknown Language)):
    1.  
    2.         CBLOCK    0x20
    3.         Delay:2            ;Define two registers for the delay and delay + 1
    4.         mode            ;Mode
    5.         count1            ; for 5 minute delay    
    6.        
    7.         SW1                ; Switch #1
    8.         SW2                ; Switch #2
    9.         TMR                ; timer value in minutes
    10.         d1                ;Delay variables for 5 minute timer
    11.         d2                ;
    12.         d3                ;
    13.         d4                ;
    14.  
    15.     ENDC
    16.  
    17.         CBLOCK    0x70
    18.         cs_W            ; ISR save context
    19.         cs_STATUS        ; "
    20.  
    21.     ENDC
    22.  
    23.     org 0x0000
    24.     goto    init
    25.  
    26. ; interrupt service routine :
    27. ;----------------------------
    28. ISR    org    0x004    
    29.     movwf    cs_W                ; save W
    30.     movf    STATUS,w            ; save status
    31.     movwf    cs_STATUS            ;
    32.     banksel    GPIO
    33.  
     
  9. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    That's it.
     
  10. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    I have read a tutorial by Nigel Goodwin and hopefully ported it to the pic12f683 correctly and GP4 of my pic.

    I am not sure of my facts as far as the result of the adc. I want to set a 10v low voltage cutoff, do I need to connect a variable power supply to the circuit to do this or can I work out the value by using the ratio instead and simply program it from MPLab.

    For instance I have 2 resistors going through an lm7805(which has the 12v from the 2 7ah batteries connected to it)
    The resistors are 33k and 10k so I think it would work like so
    for a 10 bit number (0-1023) then I have a ratio of 4.3
    If I want the cutoff to be 10v then that should make the number to set as 479 being 479 *.005v=2.395v at pic times ratio of 4.3 makes it 2.395*4.3=10.2985v

    I worked out the ratios etc using this spreadsheet
    http://www.flyelectric.ukgateway.net/PIC ADC resistors and current.xls

    Do I then need to put that value in w and then call the adc routines?
    I decided to leave the eeprom routine until later for now.

    Code ( (Unknown Language)):
    1.  
    2.   ;//PREPROCESSOR ===============================================|---|
    3.  
    4.     LIST    p=12F683
    5.     include "P12F683.INC"
    6.  
    7.  
    8.     __CONFIG    _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
    9.     errorlevel -302
    10.     errorlevel -312
    11.     CBLOCK    0x21
    12. NumH
    13. NumL
    14.     ENDC
    15.            
    16.             org        0x0000
    17. Init_ADC    org        0x004
    18. ; Set ADCON0
    19.             movlw   b'10000001'
    20.             movwf   ADCON0
    21. ; Set ADSEL
    22.             BANKSEL ANSEL
    23.             movlw   b'10000101'
    24.             movwf   ANSEL
    25.             BANKSEL ADCON0
    26.         return
    27.  
    28. Read_ADC
    29.             bsf    ADCON0, GO        ;initiate conversion
    30.             btfsc   ADCON0, GO
    31.             goto    $-1            ;wait for ADC to finish
    32.  
    33.             movf    ADRESH,W
    34.             andlw   0x03
    35.             movwf   NumH
    36.             BANKSEL ADRESL
    37.             movf    ADRESL,W
    38.             BANKSEL    ADRESH
    39.         movwf    NumL            ;return result in NumL and NumH
    40.         return    
    41.         END
    42.  
     
  11. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Didn't mean to write that but couldn't edit my post. I was writing while thinking about the EEPROM code I will write next and wrote this accidentaly. I can see how it works and think I have a handle on the adc.

    I think the code is better like this too
    Code ( (Unknown Language)):
    1.  
    2.   ;//PREPROCESSOR ===============================================|---|
    3.  
    4.     LIST    p=12F683
    5.     include "P12F683.INC"
    6.  
    7.  
    8.     __CONFIG    _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
    9.     errorlevel -302
    10.     errorlevel -312
    11.     CBLOCK    0x21
    12. NumH
    13. NumL
    14.     ENDC
    15.            
    16.             org        0x0000
    17. Init_ADC    org        0x004
    18. ; Set ADCON0
    19.             movlw   b'10000001'
    20.             movwf   ADCON0
    21.             CALL SampleTime ;Acquisiton delay
    22. ; Set ADSEL
    23.             BANKSEL TRISIO ;
    24.             BSF TRISIO,4 ;Set GP4 to input
    25.             BANKSEL ANSEL
    26.             MOVLW b'01110010' ;ADC Frc clock,4MHz
    27.             IORWF ANSEL ; and GP4 as analog
    28.             BANKSEL ADCON0
    29.         return
    30.  
    31. Read_ADC
    32.             bsf    ADCON0, GO        ;initiate conversion
    33.             btfsc   ADCON0, GO
    34.             goto    $-1            ;wait for ADC to finish
    35.  
    36.             movf    ADRESH,W
    37.             andlw   0x03
    38.             movwf   NumH
    39.             BANKSEL ADRESL
    40.             movf    ADRESL,W
    41.             BANKSEL    ADRESH
    42.         movwf    NumL            ;return result in NumL and NumH
    43.         return    
    44. SampleTime    nop
    45.             nop
    46.             nop
    47.             nop
    48.             nop
    49.             nop
    50.             nop
    51.             nop
    52.             nop
    53.             nop
    54.             nop
    55.             nop
    56.             return        
    57.  
    58.         END
    59.  
    60.  
     
    Last edited: Jun 11, 2011
  12. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    You should be able to edit your posts now.
    I've given it a quick run through the simulator and it is complaining about TAD time being less than 1.6us so you should look at the value for ADCON0.
    Presumably there is some code missing because otherwise there are a couple of RETURNs that shouldn't be there.
    Also the default values for some of the FSRs isn't 0 so:
    bsf TRISIO, 4 does nothing because the default is b'00111111'

    doesn't change ANSEL to b'01110010' because the default is b'00001111'
    Use movwf ANSEL instead.

    I'm not sure it's necessary for analog input but I turn the comparator off if I'm not using it:
     
  13. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Yes, the data sheet referred to calling sampletime for the acquisition time but didn't specify how to set it up. So I guessed.
    Here is the code in the data sheet.
    Code ( (Unknown Language)):
    1.  
    2. ;This code block configures the ADC
    3. ;for polling, Vdd reference, Frc clock
    4. ;and GP0 input.
    5. ;
    6. ;Conversion start & polling for completion
    7. ; are included.
    8. ;
    9. BANKSEL TRISIO ;
    10. BSF TRISIO,0 ;Set GP0 to input
    11. BANKSEL ANSEL ;
    12. MOVLW B’01110001’ ;ADC Frc clock,
    13. IORWF ANSEL ; and GP0 as analog
    14. BANKSEL ADCON0 ;
    15. MOVLW B’10000001’ ;Right justify,
    16. MOVWF ADCON0 ;Vdd Vref, AN0, On
    17. [COLOR=RoyalBlue]CALL SampleTime ;Acquisiton delay[/COLOR]
    18. BSF ADCON0,GO ;Start conversion
    19. BTFSC ADCON0,GO ;Is conversion done?
    20. GOTO $-1 ;No, test again
    21. BANKSEL ADRESH ;
    22. MOVF ADRESH,W ;Read upper 2 bits
    23. MOVWF RESULTHI ;Store in GPR space
    24. BANKSEL ADRESL ;
    25. MOVF ADRESL,W ;Read lower 8 bits
    26. MOVWF RESULTLO ;Store in GPR space
    27.  
    I was trying to edit it to an3 and I wasn't sure how to set the correct conversion and acquisition time. In fact the setup for the adc configuration has lost me completely.
    I have changed the code to add the comparator off and paste here the edited part of adcon0 but still not sure how to setup ansel.
    Code ( (Unknown Language)):
    1.  
    2. ;turn off comparator
    3.             movlw 0x07
    4.             movwf CMCON0
    5.  
    6. Init_ADC    org        0x004
    7. ; Set ADCON0
    8.             [COLOR=RoyalBlue]movlw   b'11001111';right justify,vref,an3,go/done,adc enable?[/COLOR]
    9.             movwf   ADCON0
    10.             CALL SampleTime ;Acquisiton delay
    11. ; Set ADSEL
    12.             BANKSEL ANSEL
    13.             MOVLW b'11001111'
    14.             MOVWF ANSEL
    15.             BANKSEL ADCON0
    16.         return
    17.  
    Yes this is just one module so I am guessing as these are set up as subroutines I would call the read or write from the correct place in the full code, hence the returns.

    Thanks for your guidance Mark. I really appreciate it. I am starting to 'get it' slowly.
     
  14. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    For ADCON0 I would go for:
    10001101
    If you use a voltage regulator for the PIC it usually makes sense to use Vdd as the reference (although your setup may be different).
    The go/done bit should not be set in the same instruction that turns on the A/D.

    for ANSEL I would go for:
    00011000
    fosc/8 and an3

    I think that should work.
     
  15. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    I have pasted the eeprom example code from the data sheet altered slightly only so they can be called.

    Code ( (Unknown Language)):
    1.  
    2.     #include "P12F683.INC"
    3.     errorlevel -302
    4.  
    5.     GLOBAL    EEPROM_W
    6.     GLOBAL    EEPROM_R
    7.  
    8.     org 0x2100
    9.    
    10. ;Read EEPROM data
    11. EEPROM_R    
    12.     BANKSEL EEADR ;
    13.     MOVLW [COLOR=RoyalBlue]CONFIG_ADDR[/COLOR] ;
    14.     MOVWF EEADR ;Address to read
    15.     BSF EECON1,RD ;EE Read
    16.     MOVF EEDAT,W ;Move data to W
    17.     return
    18. ;Write EEPROM data
    19. EEPROM_W
    20.     BANKSEL EECON1 ;
    21.     BSF EECON1,WREN ;Enable write
    22.     BCF INTCON,GIE ;Disable INTs
    23.     BTFSC INTCON,GIE ;See AN576
    24.     GOTO $-2 ;
    25.     MOVLW 55h ;Unlock write
    26.     MOVWF EECON2 ;
    27.     MOVLW 0AAh ;
    28.     MOVWF EECON2 ;
    29.     BSF EECON1,WR ;Start the write
    30.     BSF INTCON,GIE ;Enable INTS
    31.     return
    32.    
    33.     END
    34.  
    In my case from doing my adc conversion I copied the adc result into numH and numL. As it is right justified can I just ignore the numH and am I correct that the contents of numL are what I want to write to and then later read from EEPROM memory? I cannot work out from the data sheet how to copy that data with the code provided.

    It halts at 1st error at the bit highlighted in blue for config_addr. It also gave an error for the location Aah so I changed it to 0Aah
    Is that the right way to do it?
     
  16. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    I would think you probably want to save all of ADRES.
    Here's how I do it for loading and saving in the first 2 locations, but on a slightly different PIC. The only differences seem to be that EEDATA seems to be called EEDAT which probably needs changing, and the 2 lines in your sample starting ;see AN576. May as well add those lines.
    Reading and writing EEPROM is one of the trickier things to do on a PIC.

    Also, if you aren't using interrupts then you can comment out the line which enables them (although if the individual interrupts aren't enabled {default settings} then it makes no difference).

    Code ( (Unknown Language)):
    1. ORG 0x2100
    2. de 0xFF
    3. de 0x00
    Code ( (Unknown Language)):
    1. writeEE
    2.     bsf STATUS,RP0 ;Bank 1
    3.     bsf EECON1,WREN ;Enable write
    4.     bcf INTCON,GIE ;Disable INTs
    5.     movlw 0x55 ;Unlock write
    6.     movwf EECON2 ;
    7.     movlw 0xAA ;
    8.     movwf EECON2 ;
    9.     bsf EECON1,WR ;Start the write
    10.     bsf INTCON,GIE ;Enable INTS
    11.     bcf STATUS, RP0 ;bank 0
    12.     return
    13.  
    14. readEE
    15.     BSF STATUS, RP0 ; Bank 1
    16.     MOVWF EEADR ; Address to read
    17.     BSF EECON1, RD ; EE Read
    18.     MOVF EEDATA, W ; W = EEDATA
    19.     BCF STATUS, RP0 ; Bank 0
    20.     return
    Code ( (Unknown Language)):
    1. clrw
    2. call readEE
    3. movwf redduty
    4. movlw 0x01
    5. call readEE
    6. movwf blueduty
    Code ( (Unknown Language)):
    1.     movf redduty, W
    2.     bsf STATUS, RP0                    ;page 1
    3.     clrf EEADR
    4.     movwf EEDATA
    5.     call writeEE
    6.     bsf STATUS, RP0                    ;page 1
    7. waitEE
    8.     btfsc EECON1, WR
    9.     goto waitEE
    10.     bcf STATUS, RP0                    ;page 0    
    11.     movf blueduty, W
    12.     bsf STATUS, RP0                    ;page 1  
    13.     incf EEADR, F
    14.     movwf EEDATA
    15.     call writeEE    
     
  17. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Okay so the EEPROM subroutines are unchanged and you move your adres in your case redduty to w then to the EEDATA and then call the writeEE.

    Why do you do this
    Code ( (Unknown Language)):
    1.  
    2. movlw  0x01
    3.  
    In between reading the data from EEPROM?

    Is a waitEE required for each write because I can't see where it is being called from.

    Also being right justified and the most significant bit in my case being in NumH and the rest being in NumL how do I reassemble them before copying the result to w then to EEDATA

    Sorry if this seems dense but I couldn't follow how and where to inject my own data in to the correct location.

    Thanks
    Steve
     
  18. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    The "movlw 0x01" is because readEE expects the eeprom address to save into to be in W. For the first read W was 0 (clrw).
    There is a goto waitEE a couple of lines later. Those few lines are checking that the write has completed (it takes a little while).
    Only one wait is required because I assume there is no need to write again soon after the second write.

    Really you can just swap redduty and blueduty for NumH and NumL. It's a good idea to step through in the simulator and watch the flow and check everything works.
    The de'0xff' part saves 2 values in the eeprom, which would be your default value. You can read the PIC with your programmer to check that the values are actually changing.
    Presumably later you want to compare the value in NumH and NumL with savedNumH and savedNumL (or similar names).
    That's easy enough. You subtract NumH from SavedNumH, if the answer isn't zero then you can tell which number is bigger.
    If the answer is zero then subtract NumL from SavedNumL and then you know which number was bigger.
     
    Daemon likes this.
  19. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Got it finally.
    Thanks Mark
     
  20. Daemon

    Thread Starter Active Member

    Jun 20, 2009
    33
    0
    Hi Mark

    Someone else assisted me with the following code. Its not finished yet as I need to implement the routines we have made.

    I get an error 'Error - section '.org_0' type is non-overlay and absolute but occurs in more than one input file'
    Can you tell me what that means?
    I have searched the routines for a duplication of org 0x000 but cannot find one.

    Here is the code
    Code ( (Unknown Language)):
    1.  
    2. ;//PREPROCESSOR ===============================================|---|
    3.  
    4.     LIST    p=12F683
    5.     include "P12F683.INC"
    6.  
    7.     __CONFIG    _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
    8.     errorlevel -302
    9.     errorlevel -312
    10.  
    11.         EXTERN    adc
    12.         EXTERN    EEPROMRW
    13.         EXTERN    Interrupt_on_change
    14.  
    15. delA        equ 20h    ;
    16. delB        equ 21h    ;
    17. temp1        equ 22h    ;
    18. temp2        equ    23h    ;
    19. pushes        equ    24h    
    20. flashes        equ    25h
    21. Stat_sav    equ 26h
    22. W_sav       equ 27h
    23.  
    24. ;****************************************************************
    25. ;Equates
    26. ;****************************************************************
    27. status        equ    0x03
    28. rp1            equ    0x06
    29. rp0            equ    0x05
    30. option_reg    equ 81h
    31.  
    32.    
    33.         ;bits
    34.  
    35. rp0        equ    5            ;bit 5 of the status register
    36.  
    37.  
    38.  
    39. ;****************************************************************
    40. ;Beginning of program
    41. ;****************************************************************
    42.         org        0x00
    43.     cblock 0x20
    44.            d1
    45.            d2
    46.           d3
    47.            d4
    48.            count1            ; for 5 minute delay    
    49.         SW1                ; Switch #1
    50.         SW2                ; Switch #2
    51.         TMR                ; timer value in minutes
    52.       endc
    53.         GOTO    SetUp
    54.         nop
    55.         ORG    4                ;interrupts always vector to here
    56.         GOTO    isr
    57.         nop
    58. SetUp   bsf        status, rp0     ;Bank 1            
    59.         movlw    b'10111000'        ;Set TRIS  GP0,1,2 out   GP3,4,5 input
    60.         movwf    TRISIO               ;    
    61.         bcf     option_reg,7    ;pull-ups enabled        
    62.         MOVLW    b'00000100'        ;prescaler (1:32)
    63.         movwf    option_reg     ;TMR0 interrupts = 6 mS apart
    64.         BCF        STATUS, RP0        ;bank 0
    65.         movlw   07h             ;turn off Comparator ports
    66.         movwf   CMCON0           ;must be placed in bank 0  
    67.         Clrf    TMR0            ;clear Timer0 register    
    68.         clrf    flashes    
    69.         incf    flashes
    70.         movlw    0xA0            ;set GIE <7> and T0IE <5>
    71.         movwf    INTCON            ;enable Interrupts
    72.         goto     Main    
    73.  
    74.  
    75. isr        MOVWF    W_sav            ;first save critical registers
    76.         SWAPF    STATUS,W
    77.         BCF        STATUS,RP0        ;change to bank 0
    78.         MOVWF     Stat_sav    
    79.  
    80.         btfss    GPIO,4        ;test switchA
    81.         call    switchPressed
    82.  
    83.         BCF        INTCON,T0IF
    84.         BCF        INTCON,INTF
    85.         SWAPF    Stat_sav,W
    86.         MOVWF    STATUS        ; restore status
    87.         SWAPF    W_sav,F    
    88.         SWAPF     W_sav,W        ; restore w without changing status
    89.         RETFIE    
    90.  
    91. ;********************
    92. ;* Delays             *
    93. ;********************
    94.  
    95.  
    96. _10mS    movlw    0Ah
    97.         movwf    delB
    98.         nop
    99.         decfsz     delA,f
    100.         goto     $-2
    101.         decfsz     delB,f
    102.         goto     $-4    
    103.         retlw     00    
    104.  
    105.  
    106. _250mS    nop
    107.         decfsz     delA,f
    108.         goto     $-2
    109.         decfsz     delB,f
    110.         goto     $-4    
    111.         retlw     00    
    112.  
    113.  ; Delay = 60 seconds
    114. ; Clock frequency = 4 MHz
    115.  
    116. ; Actual delay = 60 seconds = 60000000 cycles
    117. ; Error = 0 %
    118.  
    119. Delay60            ;59999994 cycles
    120.     movlw    0x23
    121.     movwf    d1
    122.     movlw    0xCB
    123.     movwf    d2
    124.     movlw    0x83
    125.     movwf    d3
    126. Delay_1
    127.     decfsz    d1, f
    128.     goto    $+2
    129.     decfsz    d2, f
    130.     goto    $+2
    131.     decfsz    d3, f
    132.     goto    Delay_1
    133.  
    134.             ;6 cycles
    135.     goto    $+1
    136.     goto    $+1
    137.     goto    $+1      
    138.  
    139. ; Delay = 300 seconds
    140. ; Clock frequency = 4 MHz
    141.  
    142. ; Actual delay = 300 seconds = 300000000 cycles
    143. ; Error = 0 %
    144.  
    145.  
    146.  
    147. DelayW      movwf   count1
    148.  
    149. Delay5
    150.          ;299999995 cycles
    151.    movlw   0x54
    152.    movwf   d1
    153.    movlw   0xA1
    154.    movwf   d2
    155.    movlw   0xFD
    156.    movwf   d3
    157.    movlw   0x02
    158.    movwf   d4
    159. Delay_0
    160.    decfsz   d1, f
    161.    goto   $+2
    162.    decfsz   d2, f
    163.    goto   $+2
    164.    decfsz   d3, f
    165.    goto   $+2
    166.    decfsz   d4, f
    167.    goto   Delay_0
    168.  
    169.  
    170.       decfsz   count1   ,f
    171.       goto   Delay5
    172.       retlw   0x00
    173.  
    174.  
    175. ;****************************
    176. ;* Sub Routines             *
    177. ;****************************
    178.  
    179. switchPressed
    180.  
    181.         movf    flashes,W    
    182.         movwf    temp1
    183.         movlw   06
    184.         xorwf   temp1     ;if flashes=6
    185.         btfss   status,Z  ;z=1 if flashes=6
    186.         goto    $+4
    187.         movlw   1
    188.         movwf   flashes
    189.         goto    $-8        
    190.  
    191.         bsf     GPIO,0   ;turn on LED    
    192.         call    _250mS
    193.         bcf     GPIO,0   ;turn off LED    
    194.         call    _250mS
    195.         decfsz  temp1,f
    196.         goto    $-5
    197.         incf    flashes,f
    198.         btfss   GPIO,5        ;loop until SwA is released
    199.         goto    $-1
    200.         retlw    00
    201.  
    202.  
    203. ;************************
    204. ;* Main                 *
    205. ;************************
    206.  
    207. Main    
    208.             btfss   GPIO,5        ;test switchA
    209.         call    SwA_Pressed
    210.         btfss   GPIO,4        ;test switchB
    211.         call    SwB_Pressed
    212.         goto    $-4  
    213.  
    214. SwA_Pressed
    215.         call    switchPressed
    216.         goto Main
    217.  
    218. SwB_Pressed
    219.  
    220.         call Delay60
    221.         goto Main
    222.  
    223. ;************************
    224. ;*EEPROM                 *
    225. ;************************
    226.  
    227.         org        2100h            
    228.  
    229.  
    230.         END
    231.  
     
Loading...