Skip to content

Instantly share code, notes, and snippets.

@neuro-sys
Created November 20, 2011 19:17
Show Gist options
  • Save neuro-sys/1380729 to your computer and use it in GitHub Desktop.
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.
#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