Created
November 20, 2011 19:17
-
-
Save neuro-sys/1380729 to your computer and use it in GitHub Desktop.
PIC16F690 star wars imperial march PWM with interrupts. Connect the output pin to a floppy drive, or a printer, or a scanner, you name it for fun.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#INCLUDE p16f690.inc | |
PROCESSOR P16F690 | |
__CONFIG _INTRC_OSC_NOCLKOUT&_FCMEN_ON&_IESO_ON&_BOR_ON&_CPD_OFF&_CP_OFF&_MCLRE_OFF&_PWRTE_OFF&_WDT_OFF | |
ERRORLEVEL -302 ; SUPRESS BANK WARNING. | |
RADIX DEC | |
CBLOCK 0x20 ; RAM AREA | |
PULSE_TEMP ; PULSE FREQUENCY ALTERNATING FLAG | |
ISR_W_TEMP ; ISR STATE SAVING REGISTERS | |
ISR_STATUS_TEMP | |
ISR_PCLATH_TEMP | |
IS_PLAYING | |
SILENT_NOTE | |
DURATION | |
NOTE | |
COUNTER | |
TEMP | |
ENDC | |
ORG 0x0 | |
GOTO RESET | |
ORG 0x4 ; INTERRUPT VECTOR | |
MOVWF ISR_W_TEMP ; SAVE PREVIOUS STATE. | |
SWAPF STATUS,W | |
MOVWF ISR_STATUS_TEMP | |
BANKSEL PCLATH | |
MOVF PCLATH,W | |
MOVWF ISR_PCLATH_TEMP | |
BANKSEL PIR1 | |
BTFSC PIR1,TMR1IF ; IS TIMER1 THE SOURCE OF INTERRUPT? | |
GOTO TIMER1_ISR ; JUMP TO ITS ISR | |
TIMER0_ISR: | |
BTFSS IS_PLAYING,0 ; IS PLAYING? | |
GOTO TIMER0_EXIT ; THEN DON'T ALTERNATE THE PULSE | |
MOVLW 0xFF | |
XORWF NOTE,W ; DOES NOTE EQUAL TO 0xFF? | |
BTFSC STATUS,Z | |
GOTO PULSE_OFF ; YES, IT'S A MUTE NOTE, DON'T ALTERNATE. | |
BANKSEL PORTC | |
BTFSC PULSE_TEMP,0 ; CHECK THE LAST STATE OF PULSE, IS IT ZERO? | |
GOTO PULSE_ON | |
PULSE_OFF: | |
BCF PORTC,4 | |
BSF PULSE_TEMP,0 | |
GOTO TIMER0_EXIT | |
PULSE_ON: | |
BSF PORTC,4 | |
BCF PULSE_TEMP,0 | |
TIMER0_EXIT: | |
BANKSEL TMR0 | |
MOVF NOTE,W ; SET THE NOTE'S FREQUENCY DELAY EACH TIME | |
MOVWF TMR0 ; IN CASE IT WAS CHANGED BY TIMER1. | |
BANKSEL INTCON | |
BCF INTCON,T0IF ; ENABLE TIMER0 AGAIN. | |
ISR_EXIT: | |
SWAPF ISR_STATUS_TEMP,W ; RESTORE PREVIOUS STATE. | |
MOVWF STATUS | |
SWAPF ISR_W_TEMP,F | |
SWAPF ISR_W_TEMP,W | |
BANKSEL PCLATH | |
MOVF ISR_PCLATH_TEMP,W | |
MOVWF PCLATH | |
RETFIE | |
TIMER1_ISR: | |
BTFSS IS_PLAYING,0 ; IS THE MUSIC PLAYING? | |
GOTO TIMER1_EXIT ; NO, GET OUT. | |
BANKSEL PCLATH | |
MOVLW HIGH NOTE_DELAY_FACTORS | |
MOVWF PCLATH | |
MOVF COUNTER,W | |
CALL MUSIC ; GET THE NOTE FROM MUSIC SHEET | |
MOVWF TEMP ; SAVE IT TO TEMP. | |
MOVLW 0x80 | |
XORWF TEMP,W ; IS IT ENDED? (0x80) | |
BTFSC STATUS,Z | |
GOTO RESET_COUNTER ; YES, REWIND THE SONG. | |
MOVLW 0xFF ; IS IT MUTE NOTE? (0xFF) | |
XORWF TEMP,W | |
BTFSS STATUS,Z | |
GOTO NOT_MUTE ; NO, CONTINUE AS USUAL. | |
MOVLW 0xFF ; YES WE HAVE A MUTE NOTE. | |
MOVWF NOTE ; SKIP DELAY FACTOR TABLE. | |
GOTO MUTE_END | |
NOT_MUTE: | |
MOVF TEMP,W ; RESTORE THE NOTE FROM TEMP. | |
CALL NOTE_DELAY_FACTORS ; GET THE FREQUENCY DELAY FOR THE NOTE | |
MUTE_END: | |
MOVWF NOTE ; STORE IT FOR TIMER0 TO PROCESS | |
; SET DURATION OF NOTE | |
INCF COUNTER,F ; THE SECOND VALUE IN MUSIC SHEET TABLE | |
BANKSEL T1CON ; IS THE DURATION DIVIDER. | |
BCF T1CON,TMR1ON ; TURN OFF TIMER1 TO MAKE CHANGES TO IT | |
MOVF COUNTER,W | |
CALL MUSIC ; GET THE SECOND VALUE/DURATION DIVIDER. | |
BANKSEL TMR1H | |
MOVWF TMR1H ; STORE IT IN THE HIGH BYTE OF TIMER1 | |
BANKSEL T1CON ; COUNTER | |
BSF T1CON,TMR1ON ; TURN ON TIMER1 TO ACTIVE IT. | |
INCF COUNTER,F ; THE NEXT NOTE IN MUSIC SHEET TABLE. | |
TIMER1_EXIT: | |
BANKSEL PIR1 | |
BCF PIR1,TMR1IF | |
GOTO ISR_EXIT | |
RESET_COUNTER: | |
CLRF COUNTER ; REWIND THE MUSIC SHEET COUNTER | |
MOVLW 0xFF | |
MOVWF NOTE ; MUTE IT FOR THE REWIND DELAY | |
GOTO TIMER1_EXIT | |
ORG 0x100 | |
RESET: | |
MOVLW HIGH NOTE_DELAY_FACTORS | |
MOVWF PCLATH | |
BANKSEL TRISC | |
CLRF TRISC ; MAKE ALL PORTC OUTPUT. | |
BANKSEL PORTC | |
CLRWDT ; CLEAR WATCH-DOG TIMER SO THAT PRESCALER | |
; BELONGS TO TIMER0 | |
BANKSEL OPTION_REG | |
MOVLW B'11010011' ; TIMER0 HAS 1:16 PRESCALER | |
ANDWF OPTION_REG,F | |
BANKSEL T1CON ; TIMER 1 HAS 1:8 PRESCALER | |
BCF T1CON,TMR1ON | |
BSF T1CON,T1CKPS1 | |
BSF T1CON,T1CKPS0 | |
BCF T1CON,T1OSCEN | |
BCF T1CON,TMR1CS | |
CLRF TMR1L | |
CLRF TMR1H | |
BSF T1CON,TMR1ON | |
BANKSEL INTCON | |
BSF INTCON,T0IE ; ENABLE INTERRUPTS. | |
BSF INTCON,GIE | |
CALL CLEAR_RAM | |
BSF IS_PLAYING,0 | |
START: | |
GOTO START | |
; FIRST BYTE IS THE NOTE OFFSET FROM NOTE_DELAY_FACTORS TABLE. | |
; SECOND BYTE IS THE DURATION DIVIDER. 0 IS A ROUGHLY LONG. 0x80 IS THE HALF OF | |
; THAT. ETC... | |
; 0x80 IN THE FIRST BYTE MARKS THE ENDING OF THE SONG. | |
; 0xFF IN THE FIRST BYTE MEANS A MUTE NOTE. | |
MUSIC: | |
ADDWF PCL,F | |
DT 10,0x80 | |
DT 0xFF,0x80 | |
DT 10,0x80 | |
DT 0xFF,0x80 | |
DT 10,0x80 | |
DT 0xFF,0x80 | |
DT 6,0x80 | |
DT 0xFF,0xC0 | |
DT 13,0xC0 | |
DT 10,0x80 | |
DT 0xFF,0x80 | |
DT 6,0x80 | |
DT 0xFF,0xC0 | |
DT 13,0xC0 | |
DT 10,0x0 | |
DT 0xFF,0 | |
DT 17,0x80 | |
DT 0xFF,0x80 | |
DT 17,0x80 | |
DT 0xFF,0x80 | |
DT 17,0x80 | |
DT 0xFF,0x80 | |
DT 18,0x80 | |
DT 0xFF,0xC0 | |
DT 13,0xC0 | |
DT 9,0x80 | |
DT 0xFF,0x80 | |
DT 6,0x80 | |
DT 0xFF,0xC0 | |
DT 13,0xC0 | |
DT 10,0x0 | |
DT 0xFF,0 | |
DT 18,0xC0 | |
DT 15,0xC0 | |
DT 12,0xC0 | |
DT 9,0xC0 | |
DT 15,0xC0 | |
DT 12,0xC0 | |
DT 9,0xC0 | |
DT 6,0xC0 | |
DT 12,0xC0 | |
DT 9,0xC0 | |
DT 6,0xC0 | |
DT 3,0xC0 | |
DT 9,0xC0 | |
DT 6,0xC0 | |
DT 3,0xC0 | |
DT 0,0xC0 | |
DT 10,0x0 | |
DT 0x80 | |
NOTE_DELAY_FACTORS: | |
ADDWF PCL,F | |
RETLW 82 | |
RETLW 92 | |
RETLW 101 | |
RETLW 110 | |
RETLW 118 | |
RETLW 125 | |
RETLW 133 | |
RETLW 140 | |
RETLW 146 | |
RETLW 152 | |
RETLW 158 | |
RETLW 164 | |
RETLW 169 | |
RETLW 174 | |
RETLW 178 | |
RETLW 183 | |
RETLW 187 | |
RETLW 190 | |
RETLW 194 | |
RETLW 198 | |
RETLW 201 | |
RETLW 204 | |
RETLW 207 | |
RETLW 210 | |
RETLW 0 | |
CLEAR_RAM: | |
MOVLW 0x20 | |
MOVWF FSR | |
CLEAR_NEXT: | |
CLRF INDF | |
INCF FSR,F | |
BTFSS FSR,4 | |
GOTO CLEAR_NEXT | |
RETURN | |
END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment