pic18f assembly example 6 – discrete filter implementation

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; When the interrupt service routine is called an ADC on channel 0 is performed and this value  is used as an
;    input to the discrete system given by the difference equation y[n] = x[n]-0.3x[n-1]+0.3y[n-1]-0.75y[n-1]
;    The output of the discrete system is then sent to a  DAC (MCP4921) via the SPI protocol.
;
; Test cicruit used is same as at http://eleceng.dit.ie/daq_lite/build.html
;
; This code is just an educational example and no attempt has been made to optimise it in any way. Use it whatever way you want but I don't accept any responsibility for any problems this code might cause you.
;
; NOTE 1: Only the most significant 8 bits of the 10-bit ADC are used. Therefore the
;    the ADC values used are in the range of 0-255.
; NOTE 2: When implementing the discrete system the ADC values are interpreted as a signed signal which varies between 0.9922 (=127/128) and -1.
;    An ADC value of 255 is interpreted as a signal value of 0.9922; an ADC value of 0 is interpreted as a signal value of -1 ;
;    an ADC value of 128 is interpreted as a signal value of 0; An ADC value of 127 is interpreted as a signal value of -0.0078 (1/128)
; NOTE 3: The pic18f does not have a floating point unit and signed decimal values are represented in and 8-bit, fixed point, 2's complement format.
;    A signal value of 0.9922 is stored as a binary value of '01111111' in memory 
;    A signal value of -1 is stored as a binary value of '10000000'  in memory
;    A signal value of 0.5 is stored as binary value of '01000000' in memory 
;    A signal value of -0.5 is stored as binary value of '11000000' in memory 
;    A signal value of 0.75 is stored as binary value of '01100000' in memory 
;    A signal value of -0.75 is stored as binary value of '10100000' in memory 
;    A signal value of 0.0078 is stored as binary value of '00000001' in memory
;    A signal value of -0.0078 is stored as binary value of '11111111' in memory 
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------
 

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset

 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority.
    org 0x0008
    goto hi_isr ;once a high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once a low priority interrupt is triggered jump to low_isr

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 ; the following code is placed at address 0x0100 in program memory (Flash memory)
Main
    ; store the filter variables in a contiguous block in RAM starting at address 0x000
    cblock 0x000
    ; y_1 = y[n-1]; y_2 = y[n-2]; x_1 = x[n-1]; x_2 = x[n-2]
    x, y,a1,a2,b0,b1,b2, var1,var2, x_1, y_1, x_2, y_2
    endc

    ; set up b and a coefficients of the discrete system (y[n] = x[n]-0.3x[n-1]+0.3y[n-1]-0.75y[n-1])
    movlw .127
 	movwf b0 ; approx = 1 (exact value is 0.9922)
    movlw B'11011010'
 	movwf b1 ; approx = -0.3 (exact value is -0.3047) 
    movlw B'00000000'
 	movwf b2 ; = 0
    movlw B'00100110'
 	movwf a1 ; = approx 0.3 (exact value is 0.3047)
    movlw B'10100000'
 	movwf a2 ; = -0.75

    ; intialise the 'past value' variables to zero
    clrf y_1
    clrf y_2
    clrf x_1
    clrf x_2

    call micro_config ; configure pins,timers, ADC etc.

main_loop
    nop ; Just wait for a timer interrupt to be triggered
    goto main_loop

    
    ;----------------------------------------------------------------------------------------------------------
    ;-------multiply accumulate - multiply var1 by var2 and accumulate result in y   --------------------------
    ;------   this routine is used a lot to filter the signal -------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
mac
    ; pic18f only has 8X8 unsigned multiply - the following code analyses the result of an 8X8 unsigned multiply to produce a signed result
    movf var1, W
    mulwf var2 ; var1 * var2 -> PRODH:PRODL (var1 and var interpreted as     btfsc var2, 7 ; Test Sign Bit (NOTE: if var2 is negative (2's complement representation) then its unsigned interpretation is 256-var2 and then the result stored in PROD is var1*(256-var2) = var1*256-var1*var2
    btfsc var2, 7 ; Test Sign Bit
    subwf PRODH, F ; PRODH = PRODH - var1 (equivalent to PROD = PROD - var1*256)
    movf var2, W
    btfsc var1, 7 ;Test Sign Bit
    subwf PRODH, F ; PRODH = PRODH - var2

    ; The two most significant bits of PROD are sign bits so shift PRODH to the left and grab the most significant bit of PRODL to get the 8 most significant useful bits.
    rlncf PRODH,0 ; W contains PRODH shifted to the left by one
    movwf var2 ; using var2 as it is available (not for any other reason)
    bsf var2, 0
    BTFSS PRODL,7 ; set the most significant bit of PRODL as the least signifcant in W
    bcf var2, 0
    movf var2,W

    addwf y,f ; accumulate the result of multiplication in y. Note not handling overflow. Would also be better to accumulate those 7 bits discarded after the multiplication and round afterwards for a more accurate result

    return

    
    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
     ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H

	bsf ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready
	btfsc ADCON0, GO
    goto adc_not_ready

    clrf y

    movf y,W

    movf ADRESH,W
    addlw -128 ; account for dc offset. The input values from ADRESH will be in range 0-255. These values represent a signal that varies betwen 1 and -1: the ADC value of 255 is mapped to 1 and ADC value of 0 is mapped to -1; ADC value of 128 is mapped to 0.

    movwf x
    movwf var1
    movff b0,var2
    call mac ; multiply var1 by var2 and accumulate the result in y (mac - multiply accumulate)

    movff x_1, var1
    movff b1, var2
    call mac;

    movff x_2, var1
    movff b2, var2
    call mac;

    movff y_1, var1
    movff a1, var2
    call mac;

    movff y_2, var1
    movff a2, var2
    call mac

    ; update past values of the inputs and outputs to use on next iteration of the discrete system
    movff y_1, y_2
    movff y, y_1
    movff x_1, x_2
    movff x, x_1

    movf y,W
    addlw .128 ; account for dc offset
    movwf y
    goto spi_write ;write contents of y to SPI device
end_int
    retfie ;return and reset interrupts

    
    
    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
micro_config
     ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD
    clrf LATD ; turn off all LATD output pins

    ; SPI configuration ------------------------------------------------------------
    clrf TRISC
    ;bcf TRISC,3 ; pin 3 on PORTC used as SPI clock and should be configured as an output to operate in master mode
    ;bcf TRISC,5 ; pin 5 on PORTC used for SPI serial data out (SDO) and should be configured as an output
    movlw B'10110000' ; set up SPI control register see pg 163 for details
    movwf SSPCON1;
    bsf SSPSTAT,CKE; data transmitted on rising edge
    ; END SPI config ----------------------------------------------------------


    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON

    ; all channels set up for ADC - no particular reason why
    movlw B'00000001'
 	movwf ADCON1

    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2

    clrf ADCON0; select analog channel 0;
    bsf ADCON0,ADON; //enable ADC

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0
    bsf INTCON, TMR0IE; Enable TIMER0 interupt

    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2

    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler

    ; setup so that timer0 overflow is triggered quickly initially
    ; after the first trigger then set it up so that it is triggered at the rate you want in the high_isr routine
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts
    bsf T0CON, TMR0ON; turn on timer 0
    return

    ;----------------------------------------------------------------------------------------------------------
    ;-----WRITE contents in y to DAC (MCP4921) using SPI ------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
spi_write
    ;two bytes of data sent to spi daq (a 12-bit dac). First nibble of first byte is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value. The second byte contains the 8 least signifcant bits of the 12-bit value

	bcf LATD, LATD1; // Select SPI DAC chip

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with spi dac config data to be sent to SPI device
    ; First nibble of first byte sent to dac is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value
    swapf y, f
    movlw 0x0f
    andwf y, W ; W no holds 4 most signicant bits in lower nibble

    iorlw 0x70 ; these are configuration bits for spi dac
    movwf SSPBUF

spi_wait1
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait1 ;No

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with y data to be sent to SPI device

    movlw 0xf0
    andwf y, W ;
    movwf SSPBUF

spi_wait2
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait2 ;No

	bsf LATD, LATD1; // Select SPI DAC chip
    goto end_int


    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0300
low_isr
    nop ; put whatever you would like to do on low priority interrupt here
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 5 – Sample ADC and pass through to DAC

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; When the interrupt service routine is called an ADC on channel 0 is performed and this value is sent a DAC (MCP4921) via a SPI protocol.
;
; Test cicruit used is same as at http://eleceng.dit.ie/daq_lite/build.html
;
; In the main part of the code the value associated with analog channel 0 is monitored in a continuous loop. If the value
;   is high then LATD2 is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------
 
;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset

 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority.
    org 0x0008
    goto hi_isr ;once a high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once a low priority interrupt is triggered jump to low_isr

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 ; the following code is placed at address 0x0100 in program memory (Flash memory)
Main

y  equ  0x20 ; y refers to a register at address 0x20
    call micro_config ; configure pins,timers, ADC etc.

main_loop
    nop ; Just wait for a timer interrupt to be triggered
    goto main_loop

    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
     ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H

	bsf ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready
	btfsc ADCON0, GO
    goto adc_not_ready

    movff ADRESH, y
    goto spi_write ;write contents of y to SPI device
end_int
    retfie ;return and reset interrupts

    
    
    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
micro_config
     ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD
    clrf LATD ; turn off all LATD output pins

    ; SPI configuration ------------------------------------------------------------
    clrf TRISC
    ;bcf TRISC,3 ; pin 3 on PORTC used as SPI clock and should be configured as an output to operate in master mode
    ;bcf TRISC,5 ; pin 5 on PORTC used for SPI serial data out (SDO) and should be configured as an output
    movlw B'10110000' ; set up SPI control register see pg 163 for details
    movwf SSPCON1;
    bsf SSPSTAT,CKE; data transmitted on rising edge
    ; END SPI config ----------------------------------------------------------


    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON

    ; all channels set up for ADC - no particular reason why
    movlw B'00000001'
 	movwf ADCON1

    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2

    clrf ADCON0; select analog channel 0;
    bsf ADCON0,ADON; //enable ADC

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0
    bsf INTCON, TMR0IE; Enable TIMER0 interupt

    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2

    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler

    ; setup so that timer0 overflow is triggered quickly initially
    ; after the first trigger then set it up so that it is triggered at the rate you want in the high_isr routine
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts
    bsf T0CON, TMR0ON; turn on timer 0
    return

    ;----------------------------------------------------------------------------------------------------------
    ;-----WRITE contents in y to DAC (MCP4921) using SPI ------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
spi_write
    ;two bytes of data sent to spi daq (a 12-bit dac). First nibble of first byte is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value. The second byte contains the 8 least signifcant bits of the 12-bit value

	bcf LATD, LATD1; // Select SPI DAC chip

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with spi dac config data to be sent to SPI device
    ; First nibble of first byte sent to dac is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value
    swapf y, f
    movlw 0x0f
    andwf y, W ; W no holds 4 most signicant bits in lower nibble

    iorlw 0x70 ; these are configuration bits for spi dac
    movwf SSPBUF

spi_wait1
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait1 ;No

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with y data to be sent to SPI device

    movlw 0xf0
    andwf y, W ;
    movwf SSPBUF

spi_wait2
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait2 ;No

	bsf LATD, LATD1; // Select SPI DAC chip
    goto end_int


    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0300
low_isr
    nop ; put whatever you would like to do on low priority interrupt here
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 4 – sample Analog Channel on timer interrupt

May 20, 2014 Leave a comment
;------------------------------------------------------------------------------------------------------------------------------; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; This assembly code uses a timer interrupt to read an analog channel every 1ms.
; When the interrupt service routine is called an ADC on channel 0 is performed.
; In the main part of the code the value associated with analog channel 0 is monitored in a continuous loop. If the value
;   is high then LATD2 is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;------------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Change the sampling rate from 1kHz to 1Hz

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. The micro jumps to 0x0000 on a reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. 
    org 0x0008
    goto hi_isr ;once an high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once an low priority interrupt is triggered jump to low_isr
    

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 
Main
    goto pin_config ; configure the timers, ADC, IO pins, interrupts etc. 
    
main_loop   ; This loop runs forever waiting for interrupts to be triggered
    ; if the analog input is greater than Vss/2 then turn on LATD2 else turn it off
    BTFSC ADRESH, 7 ; ADRESH stores the 8 most significant bits after a 10 bit ADC conversion. Just check the most significant bit to see if the value is 'large' or 'small'
    goto set_LATD2
    goto reset_LATD2
set_LATD2
    BSF LATD, 2
    goto main_loop
reset_LATD2
    BCF LATD, 2
    goto main_loop   

    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
pin_config
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs

    movlw 0xf0
    movwf TRISD
    
    clrf LATD ; turn off all LATD output pins
    BSF LATD,1 ; turn on LATD1
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 
    
    ; all channels set up for ADC - no particular reason why 
    movlw B'00000001'
 	movwf ADCON1
    
    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2
    
    clrf ADCON0; select analog channel 0; 	
    BSF ADCON0,ADON; //enable ADC 
    
    BCF INTCON, GIE ;Disable global interrupts
    BCF T0CON, TMR0ON; turn off timer 0       
    BSF INTCON, TMR0IE; Enable TIMER0 interupt
     
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    BCF T0CON,0
    BCF T0CON,1
    bCF T0CON,2
    
    BCF T0CON, T0CS; use internal instruction cycle clock
    BCF T0CON, T08BIT; use 16 bit mode
    BCF T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H
    
    BSF INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    BSF INTCON, GIE ;Enable global interrupts  
    BSF T0CON, TMR0ON; turn on timer 0        
    
    goto main_loop
    
    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200 
hi_isr
    BTFSS INTCON, TMR0IF
    goto end_int
    BCF INTCON, TMR0IF; reset interrupt
  
    ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H
    
	BSF ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready    
	BTFSC ADCON0, GO 
    goto adc_not_ready
	
end_int
    retfie ;return and reset interrupts
 

    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine  -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------   
    org 0x0300 
low_isr
    nop
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 3 – an interrupt example

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code uses a timer interrupt to set LATD2 high for 50ms then low for 50ms, repeatedly.
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;---------------------------------------------------------------------


; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Use the counter register set up in the code to change the on-off rate from 10Hz to 1Hz

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)

    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. 
    org 0x0008
    goto hi_isr
    org 0x0018
    goto low_isr
 
;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 
Main
counter  equ  0x10 ; counter refers to a register at address 0x10
    clrf counter ; clear the counter
    
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    banksel TRISD
    movlw 0xf0
    movwf TRISD
    
    clrf LATD ; turn off all LATD output pins
    bsf LATD,3 ; turn on LATD3
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0       
    bsf INTCON, TMR0IE; Enable TIMER0 interupt
     
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2
    
    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H
    
    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts  
    bsf T0CON, TMR0ON; turn on timer 0    
    
loop   
    nop; ;loop waiting for interrupts to be trigged
    goto loop   

    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    org 0x0200 
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
    ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like timer overflow flag triggered every 500ms so will set timer to 0xffff - 1000 = 0x£CAF
    movlw 0xAF
    movwf TMR0L
    movlw 0x3C
    movwf TMR0H
    
    incf counter, f ; increment the counter
    
    ;invert LATD2
    movlw 0x4
    xorwf LATD,F

end_int
    retfie ;return and reset interrupts
 

    ;-----Low Priority Interrupt Service Routine  -------------------------------------------------------------   
    org 0x0300 
low_isr
    nop
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 2 – digital output high-low

May 20, 2014 Leave a comment
 
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code uses a timer to set LATD2 high for 50ms then low for 50ms, repeatedly
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;------------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Change the on-off rate from 10Hz to 100 Hz
;    2. Change the on-off rate from 10Hz to 1.25Hz by changing the timer prescaler  

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------

    org 0x0100 
Main
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD 
    clrf LATD
    bsf LATD,2 ; turn on LATD2
    bsf LATD,3 ; turn on LATD3
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 
    
    ;------- Set up timer0 to increment every 1us
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2
    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bcf INTCON, TMR0IF; reset timer overflow flag
    BSF T0CON, TMR0ON; turn on timer 0    
        
loop  
    ; check if the timer0 overflow flag has been set
    BTFSS INTCON, TMR0IF
    goto loop
    bcf INTCON, TMR0IF; reset timer overflow flag
    ;Could set up an interrupt to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;The timer is incremented every 1us.
    ;Would like timer overflow flag triggered every 50ms so will set timer to 0xffff - 50000 = 0x3CAF
    movlw 0xAF
    movwf TMR0L
    movlw 0x3C
    movwf TMR0H
    
    ;invert LATD2
    movlw 0x4
    XORWF LATD,F

    goto loop   
    END
Categories: pic18f, Uncategorized

pic18f assembly example 1 – digital output controlled by digital input

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code monitors RD4 (pin 27)  on the pic18f4620. If RD4 is high LATD2 (pin 21) is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. change the digital input monitored to RD3
;    2. Set LATD2 high if both RD3 and RD4 are high


;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. For this reason you 
 ;don't want to place any 'code' at these locations and this is why the you just jump to somewhere else in memory after a reset. 
 ;If interrupts aren't used then there's no problem just moving the Main code to address 0x0000
 

;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------
    org 0x0020 ;The main code section will be programmed starting from address 20H.
Main
    ; configure D0-D3 as outputs and D4-D7 as inputs by modifying the TRISD register
    movlw 0xf0
    movwf TRISD 
    CLRF LATD ; turn off all the outputs
    
main_loop
    BTFSS PORTD,4 ; if RD4 is set skip the next line
    goto turn_LATD2_off
        
    bsf LATD,2 ; turn on LATD2 - we wont reach this line in loop if RD4 is low
    goto main_loop
    
turn_LATD2_off   
    bcf LATD,2 ; turn on LATD2        
    goto main_loop   

    END

Categories: pic18f, Uncategorized

cross correlation demo

April 25, 2014 2 comments
% A demonstration of cross correlation in action.
% Hit the space bar during the demo to execute
% 
% https://dadorran.wordpress.com/2014/04/25/cross-correlation-demo/
clc;close all
a = [0.1 0.2  -0.1 4.1 -2 1.5 0 ];
b = [0.1 4 -2.2 1.6 0.1 0.1 0.2];

len = length(a);
if(len ~= length(b))
    error('vectors supplied must be the same length');
end
figure
set(gcf, 'position', [ 285   347   642   367]);

max_amp = max([max(a) max(b)]);
min_amp = min([min(a) min(b)]);


plot_h = 0.25;
text_h = 0.1;
ax1 = subplot(2,1,1);
pl1_line = plot(a);
labels1 = text([1:len], a , num2str(a'), 'VerticalAlignment','bottom', ...
                             'HorizontalAlignment','right','fontsize',8);
hold on; pl1_dot = plot(a,'r.');
xlim([1 len])
ylim([min_amp max_amp])

set(ax1,'position', [(1/3) 0.95-plot_h (1/3) plot_h])
set(ax1,'visible','off')

ax2 = subplot(2,1,2);
pl2_line = plot(b);
labels2 = text([1:len], b , num2str(b'), 'VerticalAlignment','bottom', ...
                             'HorizontalAlignment','right','fontsize',8);
hold on; pl2_dot = plot(b,'r.');
xlim([1 len])
ylim([min_amp max_amp])
set(ax2,'visible','off')
set(ax2,'position', [(1/3) 0.9-plot_h*2 (1/3) plot_h])


str = '';
for k = 1: len
    str = [str '(' num2str(a(k)) ')(' num2str(b(k)) ') + '];
end
str(end-1)  = '=';
str = [str num2str(sum(a.*b))];
r_ba = xcorr(a,b);

corr_calc_text = annotation('textbox',  [0 0.85-plot_h*2-text_h 1 text_h], 'linestyle','none','horizontalalignment','center' ,'string', {'correlation at zero lag is ' str}, 'fontsize', 8);

annotation('textbox',  [0.5 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', sprintf('%.2f',r_ba(len)),'color','red', 'fontsize', 8);


pause

x_inc= (1/3)/(len-1);
for k = 1:len-1

    str = '';
    for m = 1: len-k
        str = [str '(' num2str(a(m+k)) ')(' num2str(b(m)) ') + '];
    end
    str(end-1)  = '=';
    str = [str num2str(r_ba(len+k))];

    set(corr_calc_text,'string', {['correlation at lag of ' num2str(k) ' is '] str}, 'fontsize', 8);
    
    set(ax2,'position', [(1/3)+k*x_inc 0.9-plot_h*2 (1/3) plot_h])
    
    annotation('textbox',  [0.5+x_inc*k 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', sprintf('%.2f',r_ba(len+k)),'color','red', 'fontsize', 8);
    if(k ==1)
        pause
        annotation('textbox',  [0.5 0.01 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', ['   0'] ,'color','blue', 'fontsize', 8);
        annotation('textbox',  [0.001 0.01 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', ['Lag:'] ,'color','blue');
        annotation('textbox',  [0.5+x_inc*(len) 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', ']' ,'color','red');
        annotation('textbox',  [0.5-x_inc*(len-1)-x_inc/2 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', '[' ,'color','red');
        annotation('textbox',  [0.001 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','verticalalignment','middle','horizontalalignment','left' ,'string', {'Correlation' 'Sequence:'} ,'color','red');

    end
    annotation('textbox',  [0.5+x_inc*k 0.01 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', ['   ' num2str(k)] ,'color','blue', 'fontsize', 8);

    pause
end

for k = 1:len-1

    str = '';
    for m = 1: len-k
        str = [str '(' num2str(a(m)) ')(' num2str(b(m+k)) ') + '];
    end
    str(end-1)  = '=';
    str = [str num2str(r_ba(len-k))];

    set(corr_calc_text,'string', {['correlation at lag of ' num2str(-1*k) ' is '] str}, 'fontsize', 8);
    
    set(ax2,'position', [(1/3)-k*x_inc 0.9-plot_h*2 (1/3) plot_h])
    annotation('textbox',  [0.5-x_inc*k 0.8-plot_h*2-text_h*2 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', sprintf('%.2f',r_ba(len-k)),'color','red', 'fontsize', 8);
    annotation('textbox',  [0.5-x_inc*k 0.01 1 text_h], 'linestyle','none','horizontalalignment','left' ,'string', ['   ' num2str(k*-1)] ,'color','blue', 'fontsize', 8);

    pause
end

% Uncomment the next two lines if you would like to see a plot of the
% correlation sequence
% [corr_seq lags] =  xcorr(a,b);
% plot(lags,corr_seq)
% xlabel('lags');ylabel('correlation measure');

Matlab Fourier Demo

March 27, 2014 Leave a comment
% illustration of Fourier Theory using plots
%
% usage : fourier_demonstration(1) % a well defined signal
%          fourier_demonstration(2)  % a segment of speech signal (download from https://www.dropbox.com/s/bw4dpf93xxz1lyb/speech_seg.wav)
%          fourier_demonstration(3)  % a SQUARE WAVE
%          fourier_demonstration(4)  % an impulse
function fourier_demonstration(num)
if(num==1)

    %sum of sinusoids as input
    t = 0:1/16000:1-1/16000;
    s1 = cos(2*pi*1*t);%cosw(16000,1, 16000, 0);
    s2 = cos(2*pi*5*t)*5;%cosw(16000,5, 16000, 0)*5;
    s3 = cos(2*pi*10*t + pi/2+0.56)*3;%cosw(16000,10, 16000, pi/2+0.56)*3;
    s4 = cos(2*pi*8*t+pi)*3;%cosw(16000,8, 16000, pi)*3;
    s5 = cos(2*pi*12*t+pi/2.2)*3;%cosw(16000,12, 16000, pi/2.2)*3;
    s6 = cos(2*pi*3*t+pi/2+0.4);%cosw(16000,3, 16000, pi/2+0.4)*3;
    sig = s1+s2+s3+s2+s3+s4;
elseif(num==2)
     sig = wavread('speech_seg.wav')';   
elseif(num==3)    
    sig = [zeros(1,100) ones(1,100) zeros(1,100) ones(1,100) zeros(1,100) ones(1,100) zeros(1,100) ones(1,100) ];
     sig = (sig-0.5)*2; 
else 
    sig = [zeros(1, 200) 1 zeros(1,200)];
 
end
sig = sig - mean(sig);

N = length(sig);
ft = fft(sig);
ft(round(length(ft)/2)-2:end) = [];
mags = abs(ft);
phases = angle(ft);
dc_mag = mags(1);
mags(1) = [];
phases(1) = [];

[sorted_mags sorted_indices] = sort(mags,2);
% sort in decending order
sorted_mags = fliplr(sorted_mags);
sorted_indices = fliplr(sorted_indices);
sorted_phases = phases(sorted_indices);

synth_op = zeros(1, N);
sig = sig -dc_mag;
n = [0:N-1]; % sample numbers

ylim_max = max([ sorted_mags(1)/N*2 sig])*1.05;
ylim_min = min([ -sorted_mags(1)/N*2 sig])*1.05;
ylims = [ylim_min ylim_max ];
    subplot(3,1,1)
    plot(sig)
    set(gca,'Xticklabel','', 'YLim', ylims)
    set(gca,'Xticklabel','')
    ylabel('Amplitude')
    xlabel('Time')
    title('Example Signal');
pause
colors = 'rgkbm';
significant_freqs = find(sorted_mags > max(sorted_mags/100));
freq_vals_to_display = max(sorted_indices(1:length(significant_freqs))) +1 ;
length(mags)
for k  = 1: length(mags)
    omega = 2*pi*(sorted_indices(k))/N;
    sinusoid = cos(n*omega+sorted_phases(k))*sorted_mags(k)/N*2 ;
    if(sorted_mags(k) < 10^-6)
        break
    end
    synth_op = synth_op + sinusoid;
    subplot(3,1,1)
    plot(sig)
    set(gca,'Xticklabel','', 'YLim', ylims)
    hold on 
    plot(synth_op,'r')
    set(gca,'Xticklabel','')
    ylabel('Amplitude')
    xlabel('Time')
    if k ==1
        title('Example signal and sinusoid shown in lower plot');
    else
        title(['Example signal and ' num2str(k) ' sinusoids shown in middle plot added together.']);
    end
    hold off
    subplot(3,1,2)
    hold on
    plot(sinusoid,colors(rem(k,5)+1))
    set(gca,'Xticklabel','')
    %set(gca, 'Ylim', [-max(mags)/N*2 max(mags)/N*2]) 
    set(gca, 'Ylim', ylims) 
    ylabel('Amplitude')
    xlabel('Time')
    subplot(3,1,3);
    ft_mag_vals = ones(1, freq_vals_to_display)*NaN;
    sorted_indices(k) 
    if( sorted_indices(k) < freq_vals_to_display)
        ft_mag_vals(sorted_indices(k)) = sorted_mags(k)/N*2;
    end
    hold on
    
    %stem([0:freq_vals_to_display],[NaN ft_mag_vals],'^')
    hold off
    ylabel('Magnitude')
    xlabel('Normalised Frequency (1/(periods displayed))')    
    pause
    %plot(sinusoid,colors(rem(k,6)+1))
end
close all

Correlation implemented in matlab

February 24, 2014 Leave a comment

This is the code shown at the end of http://youtu.be/_r_fDlM0Dx0

% Code to calculate the correlation measurement between to 
% two signals of length N samples
% Available at https://dadorran.wordpress.com

a = [2.1 3.8 -3.6 4.1 -2.9];
b = [-1.1 3.2 -3.6 2.2 -4.2];
N = length(a); % must be the same as length(b)

corr_measure1 = 0;
for n = 1:N
    mult_result = a(n)*b(n);
    corr_measure1 = corr_measure1 + mult_result;
end

disp(['The correlation measurement is ' num2str(corr_measure1)])

% Alternative concise implementation
corrmeasure2 = sum(a.*b)



Plotting Frequency Spectrum using Matlab

February 20, 2014 8 comments

This post shows a variety of ways of how to plot the magnitude frequency content of a discrete signal using matlab.

Contents

Load Example Data

% download data from https://www.dropbox.com/s/n4kpd4pp2u3v9nf/tremor_analysis.txt
signal = load('tremor_analysis.txt');
N = length(signal);
fs = 62.5; % 62.5 samples per second
fnyquist = fs/2; %Nyquist frequency

Quick view of double-sided (two-sided) magnitude spectrum

When roughly interpreting this data half way along x-axis corresponds to half the sampling frequency

plot(abs(fft(signal)))
xlabel('Frequency (Bins - almost!)')
ylabel('Magnitude');
title('Double-sided Magnitude spectrum');
axis tight

plotting_frequency_spectrum_demo_01

Double-sided magnitude spectrum with frequency axis (in bins)

fax_bins = [0 : N-1]; %N is the number of samples in the signal
plot(fax_bins, abs(fft(signal)))
xlabel('Frequency (Bins)')
ylabel('Magnitude');
title('Double-sided Magnitude spectrum (bins)');
axis tight

plotting_frequency_spectrum_demo_02

Single-sided magnitude spectrum with frequency axis in bins

X_mags = abs(fft(signal));
fax_bins = [0 : N-1]; %frequency axis in bins
N_2 = ceil(N/2);
plot(fax_bins(1:N_2), X_mags(1:N_2))
xlabel('Frequency (Bins)')
ylabel('Magnitude');
title('Single-sided Magnitude spectrum (bins)');
axis tight

plotting_frequency_spectrum_demo_03

Single-sided magnitude spectrum with frequency axis in Hertz

Each bin frequency is separated by fs/N Hertz.

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_Hz = bin_vals*fs/N;
N_2 = ceil(N/2);
plot(fax_Hz(1:N_2), X_mags(1:N_2))
xlabel('Frequency (Hz)')
ylabel('Magnitude');
title('Single-sided Magnitude spectrum (Hertz)');
axis tight

plotting_frequency_spectrum_demo_04

Single-sided magnitude spectrum with frequency axis normalised

Normalised to Nyquist frequency. Very common to use this method of normalisation in matlab

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_norm = (bin_vals*fs/N)/fnyquist; % same as bin_vals/(N/2)
N_2 = ceil(N/2);
plot(fax_norm(1:N_2), X_mags(1:N_2))
xlabel({'Frequency (Normalised to Nyquist Frequency. ' ...
    '1=Nyquist frequency)'})
ylabel('Magnitude');
title('Single-sided Magnitude spectrum (Normalised to Nyquist)');
axis tight

plotting_frequency_spectrum_demo_05

Single-sided magnitude spectrum – frequency in rads per sample

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_rads_sample = (bin_vals/N)*2*pi;
N_2 = ceil(N/2);
plot(fax_rads_sample(1:N_2), X_mags(1:N_2))
xlabel('Frequency (radians per sample)')
ylabel('Magnitude');
title('Single-sided Magnitude spectrum (rads/sample)');
axis tight

plotting_frequency_spectrum_demo_06

Double-sided magnitude spectrum showing negative frequencies

See http://youtu.be/M1bLPZdNCRA for an explanation of negative frequencies

X_mags = abs(fftshift(fft(signal)));
bin_vals = [0 : N-1];
N_2 = ceil(N/2);
fax_Hz = (bin_vals-N_2)*fs/N;
plot(fax_Hz, X_mags)
xlabel('Frequency (Hz)')
ylabel('Magnitude');
title('Double-sided Magnitude spectrum (Hertz)');
axis tight

plotting_frequency_spectrum_demo_07

Single-sided magnitiude spectrum in decibels and Hertz

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_Hz = bin_vals*fs/N;
N_2 = ceil(N/2);
plot(fax_Hz(1:N_2), 10*log10(X_mags(1:N_2)))
xlabel('Frequency (Hz)')
ylabel('Magnitude (dB)');
title('Single-sided Magnitude spectrum (Hertz)');
axis tight

plotting_frequency_spectrum_demo_08

Single-sided power spectrum in decibels and Hertz

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_Hz = bin_vals*fs/N;
N_2 = ceil(N/2);
plot(fax_Hz(1:N_2), 20*log10(X_mags(1:N_2)))
xlabel('Frequency (Hz)')
ylabel('Power (dB)');
title('Single-sided Power spectrum (Hertz)');
axis tight

plotting_frequency_spectrum_demo_09

Single-sided power spectrum in dB and frequency on a log scale

X_mags = abs(fft(signal));
bin_vals = [0 : N-1];
fax_Hz = bin_vals*fs/N;
N_2 = ceil(N/2);
semilogx(fax_Hz(1:N_2), 20*log10(X_mags(1:N_2)))
xlabel('Frequency (Hz)')
ylabel('Power (dB)');
title({'Single-sided Power spectrum' ...
    ' (Frequency in shown on a log scale)'});
axis tight

plotting_frequency_spectrum_demo_10