Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "P16F1829.inc"
- __CONFIG _CONFIG1, (_FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF);
- __CONFIG _CONFIG2, (_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF);
- #define INTERRUPT_FLAGS h'0021' ;BANK 0 General Purpose Registers
- #define TMR0_COUNT h'0022'
- errorlevel -302
- org 0x0
- goto START
- org 0x4 ;Interrupt vector, when an interrupt accors this will be executed. It will goto the ISR label.
- goto ISR
- START:
- banksel OSCCON ;Select OSCCON register bank (Memory bank 1, address 099h, Datasheet page: 26)
- movlw b'01011000' ;Set clock speed to 1MHz (Datasheet page: 70)
- movwf OSCCON ;Move the data in WREG to the OSCCON register
- banksel OPTION_REG ;Select OPTION_REG register bank (Memory bank 1, address 095h, Datasheet page: 26)
- bcf OPTION_REG, TMR0CS ;0, use internal instruction cycle clock(Fosc / 4)
- bcf OPTION_REG, PSA ;0, assign prescalar to TMR0
- bsf OPTION_REG, PS0 ;1
- bsf OPTION_REG, PS1 ;1
- bsf OPTION_REG, PS2 ;1 psd<2:0> = 111 = prescalar 1:256
- ;OPTION_REG: Datasheet page: 185
- ;Fosc = 1MHz, Fcy = 1MHz / 4 = 250Khz.
- ;TMR0 will be incremented after 256 cycles because of the prescalar, so 250Khz should be devided by 256:
- ;250Khz / 256 = 976.5625, So the timer will be increment by 976.5625.
- ;TMR0 can't count >255 so every 255 increments an interrupt occurs and TMR0 is set back to 0;
- ;976.5625 / 255 = 3.8296568627, this is how many interrupts happen each second.
- ;1 / 3.8296568627 = 0.2612, this means it takes 261.12 milisecond for each interrupt.
- ;
- ;The LED should blink every second, we can conclude that if there would be 4 interrupts arround 1 second would have passed (1.04448 to be precise).
- ;To get close to 1 second preciser, the prescalar should be decreased, this causes more interrupt which will be more precise.
- ;The disadvantage of using a lower prescalar is that more interrupts will occur, this means your main code will be interuppted more.
- ;LED(DS4) is connected to RC3, by default all the C port pins are set to intput (Datasheet page: 32). RC3 should be set to output.
- banksel TRISC ;Select TRISC register bank (Memory bank: 1, address: 08Eh, Datasheet page: 26)
- bcf TRISC, RC3 ;0, set RC3 to as output (Datasheet page: 136), 0 = output, 1 = input.
- banksel LATC ;Select LATC register bank (Memory bank 2, address 10Eh, Datasheet page: 26)
- bcf LATC, RC3 ;0, clear RC3 in the LATC register (Datasheet page: 136)
- banksel INTERRUPT_FLAGS
- clrf INTERRUPT_FLAGS ;Clear INTERRUPT_FLAGS, this is a shadow register for the Flag bits in the INTCON register.
- clrf TMR0_COUNT ;Clear TMR0_COUNT, this register is increment when an overflow occurs for TMR0.
- bsf INTCON, TMR0IE ;1, Enables the Timer0 overflow interrupt
- bcf INTCON, TMR0IF ;0, Clear Timer0 Overflow Interrupt Flag bit
- bsf INTCON, GIE ;1, Enables all active interrupts
- ;INTCON: Datasheet page: 90
- goto MAIN
- ISR_TMR0_OVERFLOW:
- banksel INTERRUPT_FLAGS
- bsf INTERRUPT_FLAGS, TMR0IF ;1, Set the TMR0IF bit in the shadow register INTERRUPT_FLAGS
- bcf INTCON, TMR0IF ;0, Clear TMR0IF
- return
- ISR:
- btfsc INTCON, TMR0IF ;Check if the TMR0IF overflow flag is set, this bit is set when an overflow happends in Timer0
- call ISR_TMR0_OVERFLOW
- retfie
- LED_TURNON:
- banksel LATC ;Select LATC register bank (Memory bank 2, address 10Eh, Datasheet page: 26)
- bsf LATC, RC3 ;1, Set RC3 bit in the LATC register to 1
- return
- LED_TURNOFF:
- banksel LATC ;Select LATC register bank (Memory bank 2, address 10Eh, Datasheet page: 26)
- bcf LATC, RC3 ;0, Clear RC3 bit in the LATC register to 1
- return
- LED_TOGGLE:
- banksel LATC ;Select LATC register bank (Memory bank 2, address 10Eh, Datasheet page: 26)
- movf LATC, W ;Move the LATC register to WREG
- btfsc WREG, RC3 ;Check if RC3 bit is set in WREG (WREG contains a copy of the LATC register)
- call LED_TURNOFF
- ;The reason why we make a copy of LATC to WREG and use WREG to check the RC3 bit, is because if we would use the
- ;LATC register directly, after the LED is turned off the RC3 bit is set to 0. When the code goes to
- ;the next operation (btfsss WREG, RC3) to check if the RC3 bit is 0, it is 0 because we turned it off in the previous line,
- ;the result is that btfss won't skip the next operation and turns on the LED.
- ;Conclusion: if we don't make a copy of LATC to WREG and use LATC directly the LED would always be on.
- btfss WREG, RC3 ;Check if RC3 bit is clear in WREG (WREG contains a copy of the LATC register)
- call LED_TURNON
- banksel TMR0_COUNT ;LED is now toggled and we can CLEAR the TMR0_COUNT. The code will now wait another 4 Timer0 overflow interrupts
- clrf TMR0_COUNT ;before toggling the LEDs again.
- return
- TMR0_OVERFLOW:
- banksel TMR0_COUNT
- incf TMR0_COUNT ;Increment TMR_COUNT.
- movf TMR0_COUNT, W ;Move TMR0_COUNT in WREG
- xorlw b'00000100' ;Do a XOR operation on WREG and the LITERAL: '00000100'(4), If WREG is equal to the LITERAL then the Z bit in the STATUS register is set to 1.
- btfsc STATUS, Z ;Check if Z = 1.
- call LED_TOGGLE
- banksel INTERRUPT_FLAGS
- bcf INTERRUPT_FLAGS, TMR0IF ;Clear the first bit.
- return
- MAIN:
- btfsc INTERRUPT_FLAGS, TMR0IF ;If the TMR0IF bit is set in the INTERRUPT_FLAGS regiser, TMR0_OVERFLOW will be called. The TMR0IF bit is set when Timer0 overflows and gives an interrupt.
- call TMR0_OVERFLOW
- goto MAIN ;Infinite loop MAIN.
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement