Yoikes, over a year since I last looked into this project... Time passes so quickly, I blame real life sadly along with a few computer games too including Star Wars amongst others... So anyway someone at work was talking about programming at home and as a result it got me interested again in the microprocessor project...
When I last left you I had been trying to get Timer interrupts to work and after a few hours of trying to copy samples and not actually getting anywhere I decided to have another look at it. And this time YAY I managed to get a timer to cause an interrupt. So I'll go through code and see if I can explain it all as I go...
First the plan is to have a main program just flashing the status LED, while we have a timer interrupt which increases a counter and then display the last four bits of that counter as a hex number on the LED display.
Originally I tried to get TIMER0 to work, however for some reason, (I think it was because I needed an external clock or something), timer0 didn't seem to be workable and so I changed to using the Timer1 counter to count clock cycles and increment the LED display each time the counter ticks over. Of course it helped when I finally realised that I needed to turn on the interrupt processing as well as turning on the Timer modules.
;******************************************************************************
; Filename: Timer_Interrupt.asm *
; Date: 20th July 2012 *
; Author: M.J.Andrews *
;******************************************************************************
LIST P=18F2455, F=INHX32 ; Directive to define processor
#include <P18F2455.INC> ; Processor specific variable definitions
#include <LED_Segment.INC> ; LED Segment Macro's
We'll still use the same old LED segment setting include file and the default P18F2455 include file to define all the constants we're going to want to be using.
;******************************************************************************
; Configuration bits
CONFIG FOSC = INTOSC_HS ;HS - HS OSCILLATOR
Still using the internal oscillator
;******************************************************************************
; Variable definitions
UDATA
WREG_TEMP RES 1 ; Variable in RAM for context saving
STATUS_TEMP RES 1 ; Variable in RAM for context saving
BSR_TEMP RES 1 ; Variable in RAM for context saving
UDATA_ACS
CNT_INNER RES 1 ; Delay procedure, Inner Loop Count
CNT_OUTER RES 1 ; Delay procedure, Outer Loop Count
CNT_TIMER RES 1 ; Timer Interrupt counter
We need variables to store the old values in the various registers while the interrupt service routines run. We also keep the inner and outer counters for our delay procedure from before and also a new counter which we will increment on each timer interrupt.
;******************************************************************************
; Reset vector's
RESET_VECTOR CODE 0x0000
goto Main ; Go to start of main code
HI_INT_VECTOR CODE 0x0008
bra HighInt ; Go to high priority interrupt routine
LOW_INT_VECTOR CODE 0x0018
bra LowInt ; Go to low priority interrupt routine
Standard code to provide the appropriate commands to point to the appropriate code points when starting u or receiving any high or low priority interrupt.
;******************************************************************************
;**** Start of the Program Code Section ****
;******************************************************************************
CODE
;******************************************************************************
; High priority interrupt routine
;******************************************************************************
HighInt:
MOVWF WREG_TEMP ; Save working register
MOVFF STATUS,STATUS_TEMP ; Save STATUS register
MOVFF BSR,BSR_TEMP ; Save BSR register
MOVFF CNT_TIMER, WREG ; Copy the current counter to W-REG
CALL DisplaySegments ; Display bottom 4 bits of the counter
INCF CNT_TIMER, F ; Increment the timer interrupt counter
BCF PIR1, TMR1IF ; Clear interrupt flag so ints continue
MOVFF BSR_TEMP,BSR ; Restore BSR register
MOVFF WREG_TEMP,WREG ; Restore working register
MOVFF STATUS_TEMP,STATUS ; Restore STATUS register
RETFIE FAST
Start the main code section with the High-priority interrupt routine. This starts by saving a number of registers which could contain data at the time of the interrupt. We then update the display segment with the number currently in the counter which we then increment. Clearing the interrupt flag lets the program continue and we then return the registers to their previous state, (hmmmm should the TMR1IF clear happen after returning the interrupts). Finally we return from the interrupt.
;******************************************************************************
; Low priority interrupt routine
;******************************************************************************
LowInt:
RETFIE
We skip the low priority interrupt as we;re not using it
;******************************************************************************
;**** M A I N C O D E ****
;******************************************************************************
Main:
Initialize
BCF TRISA, TRISA0 ; RA0 as an output for the "working" led
BCF TRISB, TRISB0 ; RB0 as an output for the 7-segment LED
BCF TRISB, TRISB1 ; RB1 as an output for the 7-segment LED
CLRF WREG ; Clear the Working Register
MOVWF TRISC ; W-REG to PORTC to set as all outputs
We initialise the registers so we can output the LED segments and the status led.
BSF OSCCON, IRCF2 ; Set the internal Fosc value to "111"
BSF OSCCON, IRCF1 ; which I believe results in an 8Mhz
BSF OSCCON, IRCF0 ; clock speed according to the specs
I noticed that there were three bits to set the internal oscillator speed which I set to "111" which may mean an 8Mhz clock speed, (although I need to check that).
RTCinit
; Default the start values for the counters
CLRF CNT_TIMER ; Initialize interrupt counter
CLRF TMR1H ; Start with a zero high bit (no update)
CLRF TMR1L ; Start with a zero low bit (& updates TMR0H)
; Set the base Interrupt registers to turn interrupts on
BSF RCON, IPEN ; Set IPEN bit to enable priority interrupts
BSF INTCON, GIEH ; Set GIEH bit to enable high prio ints
BCF INTCON, GIEL ; Clear GIEL bit to disable low prio ints
; Configure the TIMER1 settings
MOVLW b'00110001' ; Set T1CON settings
; * RD16 = 0 - 8-bit TIMER0 count
; * T1RUN = 0 - Clocked from ext source
; * T1CKPS1:T1CKPS0 = 11 - 1:8 prescaling
; * T10SCEN = 0 - Timer1 Oscillator off
; * T1SYNC = X - N/A with TMR1CS at 0
; * TMR1CS = 0 - Internal Clock (Fosc/4)
; * TMR1ON = 1 - Turn Timer1 on!
MOVWF T1CON ; Set the T1CON from W-Reg set last command
BSF PIR1, TMR1IF ; Timer1 Flag Bit
BSF IPR1, TMR1IP
BSF PIE1, TMR1IE ; Timer1 Enable Bit
SET_SEGMENT_TO_0
See the comments in the code above, but basically this initialises the timer and interrupt processing so that it all works... Finally strart the LED segment with a display of "0".
Start_Loop
TOGGLE_STATUS_LED
call Delay ; Call the delay procedure so we see value
goto Start_Loop ; Go back to the start of the loop
This is the main loop, it toggles the LED and then runs the delay procedure I used previously, (I copied this into the code file but won't re-show it here). After delaying this then goes back up to toggle the led again.
After all this playing I have the status LED flashing away while the LED segment counts up from 0 to F repeatedly over a constant time period showing that the interrupt is working correctly. It took a while but I'm glad I'm at this point. I now want to try and get the USB interface to work... Hopefully sometime in the next year this time though!
Electronic USB to DMX-512 Interface
Blog describing my efforts to learn how to program PIC Microprocessors and head towards a device to control Theatre lights using the DMX-512 Protocol.
Friday 20 July 2012
Monday 7 March 2011
Timer Module stuff...
Another weekend away, and I've not managed to get very far onwards. I've read a number of data sheet entries and sample programs in my time away. Little things like finding out that numbers starting with a full stop (e.g. ".123") are decimal values. Binary values can be displayed as b'11110000'.
Also there seem to be a number of commands which exist within the MASM compiler to make coding easier. For example it is possible to use the command "variable xyz" to make a variable instead of having to assign bytes to variables in the data section...
I did even try a bit of code in the DisplaySegments procedure:
variable TEST_VAR
andlw 0x0F
movff WREG, TEST_VAR
goto $ + (4 * TEST_VAR)
Unfortunately this didn't work, I still wonder if it is possible, since "goto $ + 8" does work, it may just be static references which work...
Also there seem to be a number of commands which exist within the MASM compiler to make coding easier. For example it is possible to use the command "variable xyz" to make a variable instead of having to assign bytes to variables in the data section...
I did even try a bit of code in the DisplaySegments procedure:
variable TEST_VAR
andlw 0x0F
movff WREG, TEST_VAR
goto $ + (4 * TEST_VAR)
Unfortunately this didn't work, I still wonder if it is possible, since "goto $ + 8" does work, it may just be static references which work...
Monday 28 February 2011
LED Segment Counter
After a little playing with the program, I've now managed to get the program to count up from 0 to F, then back to 0, while toggling the processing LED every time the LED display is changed. While this may be a simple program, it did teach me a few things about how to jump around code, (in order to display the value based on an entry in the working register there had to be the value multiplied by 4, then added to the Program Counter).
There's not much I can really say, other than posting the code, which doesn't quite feel like the place here to post, however I may as well post it, although the formatting may be a bit out where tabs are just transferred as spaces.
So anyway, the Macro Include file, (I put Macro's into a different include file):
;******************************************************************************
; Filename: LED Segment.asm *
; Date: 28th February 2011 *
; Author: M.J.Andrews *
;******************************************************************************
LIST P=18F2455, F=INHX32 ; Directive to define processor
#include <P18F2455.INC> ; Processor specific variable definitions
#include <LED_Segment.INC> ; Macro's for use with this program
;******************************************************************************
; Configuration bits
CONFIG FOSC = INTOSC_HS ;HS - HS OSCILLATOR
;******************************************************************************
; Variable definitions
UDATA
WREG_TEMP RES 1 ; Variable in RAM for context saving
STATUS_TEMP RES 1 ; Variable in RAM for context saving
BSR_TEMP RES 1 ; Variable in RAM for context saving
UDATA_ACS
CNT_INNER RES 1 ; Delay procedure, Inner Loop Count
CNT_OUTER RES 1 ; Delay procedure, Outer Loop Count
LED_SEGMENT_DISP RES 1 ; LED Segment counter variable
;******************************************************************************
; EEPROM data
DATA_EEPROM CODE 0xf00000
DE "Test Data",0,1,2,3,4,5
;******************************************************************************
; Reset vector's
RESET_VECTOR CODE 0x0000
goto Main ; Go to start of main code
HI_INT_VECTOR CODE 0x0008
bra HighInt ; Go to high priority interrupt routine
LOW_INT_VECTOR CODE 0x0018
bra LowInt ; Go to low priority interrupt routine
;******************************************************************************
;**** Start of the Program Code Section ****
;******************************************************************************
CODE
;******************************************************************************
; High priority interrupt routine
;******************************************************************************
HighInt:
retfie FAST
;******************************************************************************
; Low priority interrupt routine
;******************************************************************************
LowInt:
movff STATUS,STATUS_TEMP ;save STATUS register
movff WREG,WREG_TEMP ;save working register
movff BSR,BSR_TEMP ;save BSR register
; *** low priority interrupt code goes here ***
movff BSR_TEMP,BSR ;restore BSR register
movff WREG_TEMP,WREG ;restore working register
movff STATUS_TEMP,STATUS ;restore STATUS register
retfie
;******************************************************************************
;**** M A I N C O D E ****
;******************************************************************************
Main:
Initialize
bcf TRISA, TRISA0 ; RA0 as an output for the "working" led
bcf TRISB, TRISB0 ; RB0 as an output for the 7-segment LED
bcf TRISB, TRISB1 ; RB1 as an output for the 7-segment LED
clrf WREG ; Clear the Working Register
movwf TRISC ; W-REG to PORTC to set as all outputs
movlw 0x00 ; Start with 0 in the Working Register
movwf LED_SEGMENT_DISP ; Move the 0 to the Segment counter
Start_Loop
movff LED_SEGMENT_DISP, WREG ; Copy the value of the counter to W-REG
call DisplaySegments ; Call proc to display LED value in W-REG
call Delay ; Call the delay procedure so we see value
incf LED_SEGMENT_DISP ; Increment the LED counter
goto Start_Loop ; Go back to the start of the loop
;******************************************************************************
;**** P R O C E D U R E S ****
;******************************************************************************
; ----------------------------------------------------------------------
; Function: DisplaySegments
; Purpose : Procedure which can be called to display the low 4-bit value
; from the W-REG as a numeric value on the LED 7-Segment display.
; ----------------------------------------------------------------------
DisplaySegments
andlw 0x0F ; Ensure the value in W-REG is 0->F
mullw 0x04 ; Multiply W-REG to see how far to jump
movff PRODL, WREG ; Move the result back to the W-REG
addwf PCL ; Add the value to the Program counter
; This will skip forward to the goto
; command below to display the LED's
goto DISP_0
goto DISP_1
goto DISP_2
goto DISP_3
goto DISP_4
goto DISP_5
goto DISP_6
goto DISP_7
goto DISP_8
goto DISP_9
goto DISP_A
goto DISP_B
goto DISP_C
goto DISP_D
goto DISP_E
goto DISP_F
DISP_0 SET_SEGMENT_TO_0 ; Use the Macro to set the LED to '0'
return
DISP_1 SET_SEGMENT_TO_1 ; Use the Macro to set the LED to '1'
return
DISP_2 SET_SEGMENT_TO_2 ; Use the Macro to set the LED to '2'
return
DISP_3 SET_SEGMENT_TO_3 ; Use the Macro to set the LED to '3'
return
DISP_4 SET_SEGMENT_TO_4 ; Use the Macro to set the LED to '4'
return
DISP_5 SET_SEGMENT_TO_5 ; Use the Macro to set the LED to '5'
return
DISP_6 SET_SEGMENT_TO_6 ; Use the Macro to set the LED to '6'
return
DISP_7 SET_SEGMENT_TO_7 ; Use the Macro to set the LED to '7'
return
DISP_8 SET_SEGMENT_TO_8 ; Use the Macro to set the LED to '8'
return
DISP_9 SET_SEGMENT_TO_9 ; Use the Macro to set the LED to '9'
return
DISP_A SET_SEGMENT_TO_A ; Use the Macro to set the LED to 'A'
return
DISP_B SET_SEGMENT_TO_B ; Use the Macro to set the LED to 'b'
return
DISP_C SET_SEGMENT_TO_C ; Use the Macro to set the LED to 'C'
return
DISP_D SET_SEGMENT_TO_D ; Use the Macro to set the LED to 'd'
return
DISP_E SET_SEGMENT_TO_E ; Use the Macro to set the LED to 'E'
return
DISP_F SET_SEGMENT_TO_F ; Use the Macro to set the LED to 'F'
return
; ----------------------------------------------------------------------
; Function: Delay
; Purpose : Procedure to wait roughly 128*255 program cycles before
; continuing, so that we can see the changes of the LED's
; ----------------------------------------------------------------------
Delay
movlw 0x80 ; Initialize outer loop counter (0x40 - 128)
movwf CNT_OUTER,A ; Set outer loop variable to the counter
DelayOuter
movlw 0xFF ; Initialize inner loop counter (0xFF - 255)
movwf CNT_INNER,A ; Set inner loop variable to the counter
DelayInner
decfsz CNT_INNER,F,A ; Decrease Inner counter, skip next on 0
goto DelayInner ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
decfsz CNT_OUTER,F,A ; Decrease Outer counter, skip next on 0
goto DelayOuter ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
return ; Return back to the place which called this proc
;******************************************************************************
;**** E N D O F P R O G R A M ****
;******************************************************************************
END
And the current circuit diagram as updated in KiCAD for the current version.
There's not much I can really say, other than posting the code, which doesn't quite feel like the place here to post, however I may as well post it, although the formatting may be a bit out where tabs are just transferred as spaces.
So anyway, the Macro Include file, (I put Macro's into a different include file):
;***********************************************************************And the main application file:
; Filename: LED_Segment.inc
; Date: 28th February 2011
; Author: M.J.Andrews
; Purpose: Program to contain macro's for the LED Segment program.
;***********************************************************************
;***********************************************************************
;**** M A C R O ' S ****
;***********************************************************************
; ----------------------------------------------------------------------
; Macro : TOGGLE_STATUS_LED
; Purpose : Macro to toggle the processing LED. This is kept flashing
; while we run the program as it shows that the processor is
; working correctly and make it obvious if the code gets stuck.
; ----------------------------------------------------------------------
TOGGLE_STATUS_LED MACRO
btg LATA, RA0 ; Toggle the LED status
ENDM
; ----------------------------------------------------------------------
; Macro : SET_LATC
; Purpose : Macro to set the value of the LATC byte which is most of the
; 7-segment display entries. We also toggle the status LED so
; that we can see the LED flash to show the processor running.
; ----------------------------------------------------------------------
SET_LATC MACRO LATCValue
TOGGLE_STATUS_LED
MOVLW LATCValue
MOVWF LATC
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_0
; Purpose : Set the LED 7-Segment display to "0"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_0 MACRO
SET_LATC 0x80
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_1
; Purpose : Set the LED 7-Segment display to "1"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_1 MACRO
SET_LATC 0xFB
bcf LATB, 0
bsf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_2
; Purpose : Set the LED 7-Segment display to "2"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_2 MACRO
SET_LATC 0x44
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_3
; Purpose : Set the LED 7-Segment display to "3"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_3 MACRO
SET_LATC 0x41
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_4
; Purpose : Set the LED 7-Segment display to "4"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_4 MACRO
SET_LATC 0x03
bcf LATB, 0
bsf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_5
; Purpose : Set the LED 7-Segment display to "5"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_5 MACRO
SET_LATC 0x01
bsf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_6
; Purpose : Set the LED 7-Segment display to "6"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_6 MACRO
SET_LATC 0x00
bsf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_7
; Purpose : Set the LED 7-Segment display to "7"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_7 MACRO
SET_LATC 0xFB
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_8
; Purpose : Set the LED 7-Segment display to "8"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_8 MACRO
SET_LATC 0x00
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_9
; Purpose : Set the LED 7-Segment display to "9"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_9 MACRO
SET_LATC 0x01
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_A
; Purpose : Set the LED 7-Segment display to "A"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_A MACRO
SET_LATC 0x02
bcf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_B
; Purpose : Set the LED 7-Segment display to "b"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_B MACRO
SET_LATC 0x00
bsf LATB, 0
bsf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_C
; Purpose : Set the LED 7-Segment display to "C"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_C MACRO
SET_LATC 0x8C
bsf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_D
; Purpose : Set the LED 7-Segment display to "d"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_D MACRO
SET_LATC 0x40
bcf LATB, 0
bsf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_E
; Purpose : Set the LED 7-Segment display to "E"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_E MACRO
SET_LATC 0x04
bsf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_F
; Purpose : Set the LED 7-Segment display to "F"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_F MACRO
SET_LATC 0x06
bsf LATB, 0
bcf LATB, 1
ENDM
; ----------------------------------------------------------------------
; Macro : SET_SEGMENT_TO_CLEAR
; Purpose : Set the LED 7-Segment display to blank with no LED's lit
; ----------------------------------------------------------------------
SET_SEGMENT_TO_CLEAR MACRO
SET_LATC 0xFF
bsf LATB, 0
bsf LATB, 1
ENDM
;******************************************************************************
; Filename: LED Segment.asm *
; Date: 28th February 2011 *
; Author: M.J.Andrews *
;******************************************************************************
LIST P=18F2455, F=INHX32 ; Directive to define processor
#include <P18F2455.INC> ; Processor specific variable definitions
#include <LED_Segment.INC> ; Macro's for use with this program
;******************************************************************************
; Configuration bits
CONFIG FOSC = INTOSC_HS ;HS - HS OSCILLATOR
;******************************************************************************
; Variable definitions
UDATA
WREG_TEMP RES 1 ; Variable in RAM for context saving
STATUS_TEMP RES 1 ; Variable in RAM for context saving
BSR_TEMP RES 1 ; Variable in RAM for context saving
UDATA_ACS
CNT_INNER RES 1 ; Delay procedure, Inner Loop Count
CNT_OUTER RES 1 ; Delay procedure, Outer Loop Count
LED_SEGMENT_DISP RES 1 ; LED Segment counter variable
;******************************************************************************
; EEPROM data
DATA_EEPROM CODE 0xf00000
DE "Test Data",0,1,2,3,4,5
;******************************************************************************
; Reset vector's
RESET_VECTOR CODE 0x0000
goto Main ; Go to start of main code
HI_INT_VECTOR CODE 0x0008
bra HighInt ; Go to high priority interrupt routine
LOW_INT_VECTOR CODE 0x0018
bra LowInt ; Go to low priority interrupt routine
;******************************************************************************
;**** Start of the Program Code Section ****
;******************************************************************************
CODE
;******************************************************************************
; High priority interrupt routine
;******************************************************************************
HighInt:
retfie FAST
;******************************************************************************
; Low priority interrupt routine
;******************************************************************************
LowInt:
movff STATUS,STATUS_TEMP ;save STATUS register
movff WREG,WREG_TEMP ;save working register
movff BSR,BSR_TEMP ;save BSR register
; *** low priority interrupt code goes here ***
movff BSR_TEMP,BSR ;restore BSR register
movff WREG_TEMP,WREG ;restore working register
movff STATUS_TEMP,STATUS ;restore STATUS register
retfie
;******************************************************************************
;**** M A I N C O D E ****
;******************************************************************************
Main:
Initialize
bcf TRISA, TRISA0 ; RA0 as an output for the "working" led
bcf TRISB, TRISB0 ; RB0 as an output for the 7-segment LED
bcf TRISB, TRISB1 ; RB1 as an output for the 7-segment LED
clrf WREG ; Clear the Working Register
movwf TRISC ; W-REG to PORTC to set as all outputs
movlw 0x00 ; Start with 0 in the Working Register
movwf LED_SEGMENT_DISP ; Move the 0 to the Segment counter
Start_Loop
movff LED_SEGMENT_DISP, WREG ; Copy the value of the counter to W-REG
call DisplaySegments ; Call proc to display LED value in W-REG
call Delay ; Call the delay procedure so we see value
incf LED_SEGMENT_DISP ; Increment the LED counter
goto Start_Loop ; Go back to the start of the loop
;******************************************************************************
;**** P R O C E D U R E S ****
;******************************************************************************
; ----------------------------------------------------------------------
; Function: DisplaySegments
; Purpose : Procedure which can be called to display the low 4-bit value
; from the W-REG as a numeric value on the LED 7-Segment display.
; ----------------------------------------------------------------------
DisplaySegments
andlw 0x0F ; Ensure the value in W-REG is 0->F
mullw 0x04 ; Multiply W-REG to see how far to jump
movff PRODL, WREG ; Move the result back to the W-REG
addwf PCL ; Add the value to the Program counter
; This will skip forward to the goto
; command below to display the LED's
goto DISP_0
goto DISP_1
goto DISP_2
goto DISP_3
goto DISP_4
goto DISP_5
goto DISP_6
goto DISP_7
goto DISP_8
goto DISP_9
goto DISP_A
goto DISP_B
goto DISP_C
goto DISP_D
goto DISP_E
goto DISP_F
DISP_0 SET_SEGMENT_TO_0 ; Use the Macro to set the LED to '0'
return
DISP_1 SET_SEGMENT_TO_1 ; Use the Macro to set the LED to '1'
return
DISP_2 SET_SEGMENT_TO_2 ; Use the Macro to set the LED to '2'
return
DISP_3 SET_SEGMENT_TO_3 ; Use the Macro to set the LED to '3'
return
DISP_4 SET_SEGMENT_TO_4 ; Use the Macro to set the LED to '4'
return
DISP_5 SET_SEGMENT_TO_5 ; Use the Macro to set the LED to '5'
return
DISP_6 SET_SEGMENT_TO_6 ; Use the Macro to set the LED to '6'
return
DISP_7 SET_SEGMENT_TO_7 ; Use the Macro to set the LED to '7'
return
DISP_8 SET_SEGMENT_TO_8 ; Use the Macro to set the LED to '8'
return
DISP_9 SET_SEGMENT_TO_9 ; Use the Macro to set the LED to '9'
return
DISP_A SET_SEGMENT_TO_A ; Use the Macro to set the LED to 'A'
return
DISP_B SET_SEGMENT_TO_B ; Use the Macro to set the LED to 'b'
return
DISP_C SET_SEGMENT_TO_C ; Use the Macro to set the LED to 'C'
return
DISP_D SET_SEGMENT_TO_D ; Use the Macro to set the LED to 'd'
return
DISP_E SET_SEGMENT_TO_E ; Use the Macro to set the LED to 'E'
return
DISP_F SET_SEGMENT_TO_F ; Use the Macro to set the LED to 'F'
return
; ----------------------------------------------------------------------
; Function: Delay
; Purpose : Procedure to wait roughly 128*255 program cycles before
; continuing, so that we can see the changes of the LED's
; ----------------------------------------------------------------------
Delay
movlw 0x80 ; Initialize outer loop counter (0x40 - 128)
movwf CNT_OUTER,A ; Set outer loop variable to the counter
DelayOuter
movlw 0xFF ; Initialize inner loop counter (0xFF - 255)
movwf CNT_INNER,A ; Set inner loop variable to the counter
DelayInner
decfsz CNT_INNER,F,A ; Decrease Inner counter, skip next on 0
goto DelayInner ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
decfsz CNT_OUTER,F,A ; Decrease Outer counter, skip next on 0
goto DelayOuter ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
return ; Return back to the place which called this proc
;******************************************************************************
;**** E N D O F P R O G R A M ****
;******************************************************************************
END
And the current circuit diagram as updated in KiCAD for the current version.
Checking through the DMX connector's
I arrived back from my weekend away to find that the cables and connector's I'd ordered had arrived in the post from Canford. Before I describe the bits, I should say I found the location to get stuff from when I stumbled accross the a USB to DMX website. In this site, the connector they use is an XLR socket "NC5FDM3H" from Canford code 40-583, and I thought I may as well use this part as they come from a working system.
Anyway here's the picture of the bits I got:
Unfortunately since I failed on two counts with my order, I seem rather inept at ordering what I want! Firstly I got three 3-pin connector's, 2 female, one male. And secondly all of the connectors I got were vertical mounting, not horizontal which is what I was expecting! Of course if I'd have been thinking enough I'd have realised this before! So lets look at the part number used, "NC5FDM3H"...
First it looks like the "NC5" is the important bit for a 5-pin connector, (not the M3 on the letters near the end of the reference, as I thought since the image of the M3-H on the website had 5 pins). Secondly, despite the website saying Horizontally mounted pins, I for some reason went and got vertically mounting ones!
While this doesn't matter in the grand scheme of things since I'll just solder some wires to the connectors, and the lights I plan on getting all require 3-pin connector's anyway, it is still a little annoying!
It turns out the M3 version of the connector has M3 threaded holes in the connecting plate so that it can be behind the plastic outside with a bolt through, while the other one has counter-sunk holes. Of these, I definitely prefer the M3 version because it means that only the socket and screws will be visible.
Anyway here's the picture of the bits I got:
I had anopther N00B moment while looking at the individual connector's trying to figure out how they can be 'locked' into place. Eventually I realised that the entrance to the hole you can use a tiny screwdriver to turn the locking mechanism is actually at the front of the socket, not the back! Also it appears as though there is a fourth pin which is there purely so the locking mechanism doesn't get lost when unlocked, the pin appears removable once the component is all installed and locked properly.
Top Left: Female 3-Pin socket
Top Right: View of the pins for the socket
Bottom Left: You can just about see the screwdriver shaped slot in the 4th hole
Bottom Right: Opening the socket when unlocked
Friday 25 February 2011
DMX Cables & LED Segment
Last night I decided to get round to buying two cables, a 3-pin and a 5-pin female PCB socket connector, along with one 3-pin male connector. I could have got the cables as a length of wire, and a few end pieces but I was feeling a bit lazy. Two wires should be plenty for testing the DMX lights I'm going to buy in a bit, (the local theatre is buying some cheap LED parcans for the next show so I've said I'll buy two back after the show so they can reduce the budget and so I can get two lights to play with).. The LED pars have 3-pin DMX connectors, hence the 3-pin stuff. The 5-pin is because I believe that is the proper DMX connector. 2 wires to plug DMX from the circuit to one light, then the second for the wire between the two lights.
The company phoned this morning saying they didn't have 2meter cables in black, so I changed it to a red and a blue ire instead. I'd have preferred black, but when it comes to it they are only really meant for testing.
Anyway I'm off for an extended weekend, hence the day off work. I've been thinking about my problem setting the PortB bits on the circuit and programming in the LED segment. While I may be in a bit of a rush, I thought Meh, and sat down for an hour...
A little searching on the Microchip site shows that I should be setting the "LATB" register when I'm using the bsf and bcf methods to stop any inputs interferring or something... Changing that and it solved all my previous problems trying to set those LED segments, (wierd how something so simple wastes so much time).
Anyway I've now coded a few macro's based on how I've wired the chip at the moment so I can use the Macro's to set the LED segment to match a certain entry. It's a shame I couldn't use one full 8-bit port really as that would have meant just two processor instructions to set the segment. As it is, I need four, (and thinking about it maybe I should be using LATC instead of PORTC when setting it to a byte, however for now the macro's for the segment settings is shown below:
SET_PORTC MACRO PortCValue
MOVLW PortCValue
MOVWF PORTC
ENDM
SET_SEGMENT_TO_0 MACRO
SET_PORTC 0x80
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_1 MACRO
SET_PORTC 0xFB
bcf LATB, 0
bsf LATB, 1
ENDM
SET_SEGMENT_TO_2 MACRO
SET_PORTC 0x44
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_3 MACRO
SET_PORTC 0x41
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_4 MACRO
SET_PORTC 0x03
bcf LATB, 0
bsf LATB, 1
ENDM
SET_SEGMENT_TO_5 MACRO
SET_PORTC 0x01
bsf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_6 MACRO
SET_PORTC 0x00
bsf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_7 MACRO
SET_PORTC 0xFB
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_8 MACRO
SET_PORTC 0x00
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_9 MACRO
SET_PORTC 0x01
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_CLEAR MACRO
SET_PORTC 0xFF
bsf LATB, 0
bsf LATB, 1
ENDMI then wrote a little counter program to cycle through each of the numbers and blank entries listed above:
Start_Num_Loop
SET_SEGMENT_TO_CLEAR
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_0
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_1
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_2
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_3
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_4
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_5
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_6
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_7
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_8
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_9
call Delay ; Call the Delay procedure to wait a bit
Anyway that will do for now, no time to make it show A-F, and to use a slider as an input... Next time!
The company phoned this morning saying they didn't have 2meter cables in black, so I changed it to a red and a blue ire instead. I'd have preferred black, but when it comes to it they are only really meant for testing.
Anyway I'm off for an extended weekend, hence the day off work. I've been thinking about my problem setting the PortB bits on the circuit and programming in the LED segment. While I may be in a bit of a rush, I thought Meh, and sat down for an hour...
A little searching on the Microchip site shows that I should be setting the "LATB" register when I'm using the bsf and bcf methods to stop any inputs interferring or something... Changing that and it solved all my previous problems trying to set those LED segments, (wierd how something so simple wastes so much time).
Anyway I've now coded a few macro's based on how I've wired the chip at the moment so I can use the Macro's to set the LED segment to match a certain entry. It's a shame I couldn't use one full 8-bit port really as that would have meant just two processor instructions to set the segment. As it is, I need four, (and thinking about it maybe I should be using LATC instead of PORTC when setting it to a byte, however for now the macro's for the segment settings is shown below:
SET_PORTC MACRO PortCValue
MOVLW PortCValue
MOVWF PORTC
ENDM
SET_SEGMENT_TO_0 MACRO
SET_PORTC 0x80
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_1 MACRO
SET_PORTC 0xFB
bcf LATB, 0
bsf LATB, 1
ENDM
SET_SEGMENT_TO_2 MACRO
SET_PORTC 0x44
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_3 MACRO
SET_PORTC 0x41
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_4 MACRO
SET_PORTC 0x03
bcf LATB, 0
bsf LATB, 1
ENDM
SET_SEGMENT_TO_5 MACRO
SET_PORTC 0x01
bsf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_6 MACRO
SET_PORTC 0x00
bsf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_7 MACRO
SET_PORTC 0xFB
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_8 MACRO
SET_PORTC 0x00
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_9 MACRO
SET_PORTC 0x01
bcf LATB, 0
bcf LATB, 1
ENDM
SET_SEGMENT_TO_CLEAR MACRO
SET_PORTC 0xFF
bsf LATB, 0
bsf LATB, 1
ENDMI then wrote a little counter program to cycle through each of the numbers and blank entries listed above:
Start_Num_Loop
SET_SEGMENT_TO_CLEAR
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_0
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_1
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_2
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_3
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_4
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_5
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_6
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_7
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_8
call Delay ; Call the Delay procedure to wait a bit
SET_SEGMENT_TO_9
call Delay ; Call the Delay procedure to wait a bit
Anyway that will do for now, no time to make it show A-F, and to use a slider as an input... Next time!
Wednesday 23 February 2011
Crystal Oscillator and LED 8-Segment display
Another evening, and after originally thinking about ordering some Sockets and Cables for when I eventually get onto outputting DMX, instead I started rooting through my electronics toolbox and found another Crystal, and another of the sliding potentiometers, (100K resistance it turns out)...
So I took the crystal, added the same capacitors I had previously, and added them to the circuit board. I had to change the oscillator setting in the program to "HS", re-make, program and run the old circuit and yup, the LED flashes a lot lot faster...
The image above shows the crystal and capacitors added to the circuit. Since the HS Oscillator setting is a little too fast for what I'm doing at the moment I changed it back to "INTOSC_HS" which is meant to be the internal oscillator for program and HS for USB. Either way it's back to the internal oscillator for now.
Looking at the slider I had, the connection pins fit in nicely to the bread board, but there are four exra pins which I think are meant to be used to fix the slider on to a PCB board... Since I was thinking of programming in the slider again to show how to read inputs I needed to bend those pins back as shownb below:
However thinking about connecting the slider up, I don't actually have any method of telling where the slider is, except for perhaps changing the flash rate of the led... So since I have an 8-segment LED display in the box of LED's, perhaps I should wire that up and use that to display some numbers or letters based on the slider location.
First I needed to find out how to how to wire the LED segment. A little investigation shows a common +ve connected to pin 3 or 8, and I found all my 1K resistors, so some quick testing to check it out...
So LED's will be on when a pin is set to output and has a value of 0, a value of 1 being off. The question is where to connect the pions to on the chip... At first I thought to use PORTC as the pins are all down the bottom of the chip, and there are only 7 pins available, (I'm not going to use the decimal point so 7 not 8).
After connecting the segments up to the chip I found that I couldn't figure out how to set two pins, (apparently they could be configured to be outputs if the USB is turned off in one register, but I still failed to get them to output)... In the end I connected two bits from Port B in instead, and then had more fun failing to get those to work as expected... I think I must be using the wrong assembly command to set bits directly as setting the whole PORTB value worked, but not using bcf and bsf...
I have a feeling that I realised the 'obvious' bit set and clear commands didn't do what I expected them to do when I was last trying to learn assembly. Something to look at later, I've had enough for this evening. So here's the board layout I had at the end of my fiddling, while the connections are not ideal, for now they're all fine.
At least it looks fairly neat and tidy... Yes I could have just thrown in any old wires, but I like wires all being the right length.. Maybe a bit OCDish, but at least you can follow the wires easily. If it was wires all-over the place then it can very easily become very confusing!
Oh one thing I almost forgot to say... Trying to connect the board direct to power seems to fail now for some reason, so I must have messed up something somewhere, but it all still works when the programmer is connected with the RESET cleared... so probably something linked to that and maybe the Oscillator... Something to look at another day!
So I took the crystal, added the same capacitors I had previously, and added them to the circuit board. I had to change the oscillator setting in the program to "HS", re-make, program and run the old circuit and yup, the LED flashes a lot lot faster...
The image above shows the crystal and capacitors added to the circuit. Since the HS Oscillator setting is a little too fast for what I'm doing at the moment I changed it back to "INTOSC_HS" which is meant to be the internal oscillator for program and HS for USB. Either way it's back to the internal oscillator for now.
Looking at the slider I had, the connection pins fit in nicely to the bread board, but there are four exra pins which I think are meant to be used to fix the slider on to a PCB board... Since I was thinking of programming in the slider again to show how to read inputs I needed to bend those pins back as shownb below:
However thinking about connecting the slider up, I don't actually have any method of telling where the slider is, except for perhaps changing the flash rate of the led... So since I have an 8-segment LED display in the box of LED's, perhaps I should wire that up and use that to display some numbers or letters based on the slider location.
First I needed to find out how to how to wire the LED segment. A little investigation shows a common +ve connected to pin 3 or 8, and I found all my 1K resistors, so some quick testing to check it out...
So LED's will be on when a pin is set to output and has a value of 0, a value of 1 being off. The question is where to connect the pions to on the chip... At first I thought to use PORTC as the pins are all down the bottom of the chip, and there are only 7 pins available, (I'm not going to use the decimal point so 7 not 8).
After connecting the segments up to the chip I found that I couldn't figure out how to set two pins, (apparently they could be configured to be outputs if the USB is turned off in one register, but I still failed to get them to output)... In the end I connected two bits from Port B in instead, and then had more fun failing to get those to work as expected... I think I must be using the wrong assembly command to set bits directly as setting the whole PORTB value worked, but not using bcf and bsf...
I have a feeling that I realised the 'obvious' bit set and clear commands didn't do what I expected them to do when I was last trying to learn assembly. Something to look at later, I've had enough for this evening. So here's the board layout I had at the end of my fiddling, while the connections are not ideal, for now they're all fine.
At least it looks fairly neat and tidy... Yes I could have just thrown in any old wires, but I like wires all being the right length.. Maybe a bit OCDish, but at least you can follow the wires easily. If it was wires all-over the place then it can very easily become very confusing!
Oh one thing I almost forgot to say... Trying to connect the board direct to power seems to fail now for some reason, so I must have messed up something somewhere, but it all still works when the programmer is connected with the RESET cleared... so probably something linked to that and maybe the Oscillator... Something to look at another day!
Tuesday 22 February 2011
Flashing LED
Well I'm going out to one of the weekly theatre set build evenings in an hour, so just enough time to update the program so that we can flash the LED... A little lookign through the assembly commands, and looking back at some of my old applications which were probably based on the PICkit examples, I did the following:
1) Added two new variables so we can have a loop which loops a certain number of times before we next change the LED. Since the Processor will be running many many commands a second, we need to wait a number of oscillator ticks before changing the LED state. So adding two variables after the UDATA_ACS line:
UDATA_ACS
CNT_INNER RES 1 ; Inner Loop Count
CNT_OUTER RES 1 ; Outer Loop Count
2) Added code to the Mains ection of the program which initializes the LED, (we have that code already), then to turn the LED on, followed by a call to a Delay procedure to wait a bit. This is followed by turning the LED off and another delay procedure call...
Main:
Initialize
clrf WREG ; Clear the W-Register
movwf TRISA ; W-REG to PORTA to set as all outputs
Turn_LED_ON
movlw 0xFF ; Set all bits in the WREG
movwf PORTA ; Update PORTA to turn the LED on
call Delay ; Call the Delay procedure to wait a bit
Turn_LED_OFF
clrf WREG ; Clear the WREG
movwf PORTA ; Update PORTA to turn the LED off
call Delay ; Call the Delay procedure to wait a bit
goto Turn_LED_ON ; Go back to the LED ON for an Infinite loop
3) Of course we then need to have the Delay procedure somewhere, so I'll place it after the command to go back to the turning the LED on label...
Delay
movlw 0x40 ; Initialize outer loop counter (0x40 - 128)
movwf CNT_OUTER,A ; Set outer loop variable to the counter
DelayOuter
movlw 0xFF ; Initialize inner loop counter (0xFF - 255)
movwf CNT_INNER,A ; Set inner loop variable to the counter
DelayInner
decfsz CNT_INNER,F,A ; Decrease Inner counter, skip next on 0
goto DelayInner ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
decfsz CNT_OUTER,F,A ; Decrease Outer counter, skip next on 0
goto DelayOuter ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
return ; Return back to the place which called this proc
Compiling it, it succeeded! So program the chip, then release from reset, and yay a flashing LED...
1) Added two new variables so we can have a loop which loops a certain number of times before we next change the LED. Since the Processor will be running many many commands a second, we need to wait a number of oscillator ticks before changing the LED state. So adding two variables after the UDATA_ACS line:
UDATA_ACS
CNT_INNER RES 1 ; Inner Loop Count
CNT_OUTER RES 1 ; Outer Loop Count
2) Added code to the Mains ection of the program which initializes the LED, (we have that code already), then to turn the LED on, followed by a call to a Delay procedure to wait a bit. This is followed by turning the LED off and another delay procedure call...
Main:
Initialize
clrf WREG ; Clear the W-Register
movwf TRISA ; W-REG to PORTA to set as all outputs
Turn_LED_ON
movlw 0xFF ; Set all bits in the WREG
movwf PORTA ; Update PORTA to turn the LED on
call Delay ; Call the Delay procedure to wait a bit
Turn_LED_OFF
clrf WREG ; Clear the WREG
movwf PORTA ; Update PORTA to turn the LED off
call Delay ; Call the Delay procedure to wait a bit
goto Turn_LED_ON ; Go back to the LED ON for an Infinite loop
3) Of course we then need to have the Delay procedure somewhere, so I'll place it after the command to go back to the turning the LED on label...
Delay
movlw 0x40 ; Initialize outer loop counter (0x40 - 128)
movwf CNT_OUTER,A ; Set outer loop variable to the counter
DelayOuter
movlw 0xFF ; Initialize inner loop counter (0xFF - 255)
movwf CNT_INNER,A ; Set inner loop variable to the counter
DelayInner
decfsz CNT_INNER,F,A ; Decrease Inner counter, skip next on 0
goto DelayInner ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
decfsz CNT_OUTER,F,A ; Decrease Outer counter, skip next on 0
goto DelayOuter ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
return ; Return back to the place which called this proc
Compiling it, it succeeded! So program the chip, then release from reset, and yay a flashing LED...
Subscribe to:
Posts (Atom)