{{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter 02 Prog 01 This program turns an LED ON and OFF, with a programmable delay It demonstrates the use of methods in an absolutely minimal way. Since the clock is 10 MHz Define the constants we will use. }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency inv_high =0 'define the inverted High state inv_low =1 'define the inverted Low state waitPeriod =6_000_000 'about 1/2 sec switch cycle output_pin =27 'line the led is on 'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~~ 'makes the pin high repeat 'repeat forever, no number after repeat turnOff_LED 'method call wait 'method call turnOn_LED 'method call wait 'method call PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED 'method to set the LED line low outa[output_pin] :=inv_low 'line that actually sets the LED low PRI wait 'delay method waitCnt(waitPeriod + cnt) 'delay is specified by the waitPeriod {{ Aug 31 09 Harprit Sandhu FreqGen8.Spin Propeller Tool Ver. 1.2.6 Chapter 03 Prog 01 This program generates 8 frequencies starting at 440 cycles/sec. Depends on the position of Pot 1 }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'Crystal freq Output = 26 'output line for the speaker Repfactor = 100 'number of times to toggle line VAR {RAM assignment for cogs} long Stack1[50] 'this RAM will be assigned to COG1 long Stack2[50] 'this RAM will be assigned to COG2 {variables used for reading pot} word PotValue 'value of the pot reading long NoteFreq 'actual frequency of the note long NoteDelay 'delay in cycles {variables used in displaying LCD in Cog2} 'none {variables used in GetTone} Byte toneNumber OBJ 'The Objects we will need for our calls LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods DAT Tone word 440, 494, 523, 587, 659, 698, 784, 880 PUB GO 'The main method in this program 'the potentiometer is read in this cog cognew (COG_LCD, @Stack1) 'create COG_TWO for LCD display cognew (COG_PLAY, @Stack2) 'create COG_THREE for toggling output repeat 'start repeat loop PotValue:=UTIL.Read3202_0 'get potValue from the utilities ToneNumber:=Potvalue/512 +1 'This reduces the value to 0-15 PRI COG_LCD 'Handles display to the LCD LCD.INITIALIZE_LCD 'set up the LCD REPEAT 'repeat write to the LCD LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("PotPos =")) 'Potentiometer position LCD.PRINT_DEC(ToneNumber) 'print the tune number LCD.SPACE(2) 'erase over overflows LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("FreqOut=")) 'frequency label printed LCD.PRINT_DEC(NoteFreq) 'print note cps LCD.SPACE(2) 'erase over overflows PRI COG_PLAY 'output for speaker dira[Output]~~ 'output pin repeat 'outer loop repeat RepFactor 'inner loop and repeat # GetTone 'gets value for NoteFre !OUTA[output] 'toggle output line NoteDelay:=12_000_000/(NoteFreq*2) 'calculate the delay waitcnt(NoteDelay +cnt) 'wait for delay to synthesize freq waitcnt(clkfreq/2+cnt) PUB GetTone 'gets the frequency to be played NoteFreq := Tone[toneNumber-1] 'looks up position in DAT statements {{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter04 Program 01 This program turns an LED ON and OFF, with a programmable delay It demonstrates the use of methods in an absolutely minimal way. Since the clock is 10 MHz Define the constants we will use. }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency inv_high =0 'define the inverted High state inv_low =1 'define the inverted Low state waitPeriod =6_000_000 'about 1/2 sec switch cycle output_pin =27 'line the led is on 'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~~ 'makes the pin high repeat 'repeat forever, no number after repeat turnOff_LED 'method call wait 'method call turnOn_LED 'method call wait 'method call PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED 'method to set the LED line low outa[output_pin] :=inv_low 'line that actually sets the LED low PRI wait 'delay method waitCnt(waitPeriod + cnt) 'delay is specified by the waitPeriod {Chapter 7 Program 1 } PRI repeat 'power PWM routine. phsa:=PulseWidth 'Send a high pulse for PulseWidth counts period:=period + Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time {{14 Sep 09 Harprit Sandhu PWM.spin Propeller Tool Ver 1.2.6 Chapter 07 Program 02 This program generates a fixed PWM. Meaning that as programmed the width does not vary. (Set at 50%) It is easy to recognise }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal frequency VAR long pulsewidth ' long cycle_time ' long period ' ' PUB Go dira[7]~~ 'set output line ctra[30..26]:=%00100 'run PWM mode ctra[5..0]:=7 'Set the "A pin" of this cog frqa:=1 'Set this counter's frqa value to 1 PulseWidth:=-5000 'Start with position=5_000 Cycle_time:=clkfreq/1000 'Set the time for the pulse width to 1 ms period:=cnt 'Store the current value of the counter repeat 'PWM routine. phsa:=PulseWidth 'Send a high pulse for PulseWidth counts period:=period + Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time {{14 Sep 09 Harprit Sandhu PWM1.spin Propeller Tool Ver 1.2.6 Chapter 07 Progarm 03 This program generates a variable PWM signal. Based on a potentiometer reading }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal frequency VAR long stack1[25] 'space for motor long stack2[25] 'space for LCD long pulsewidth ' word pot ' OBJ LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go cognew(RunMotor(7),@Stack1) cognew(LCD_manager,@stack2) repeat Pot:=UTIL.read3202_0 'read the pot at MCP3202 line 0 PUB RunMotor(Pin)|Cycle_time,period 'method to toggle the output dira[7]~~ 'gain access to these three amplifier lines dira[19..20]~ 'potentiometer location ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin frqa:=1 'Set this counter's frqa value to 1 PulseWidth:=50 'Start with position=50 Cycle_time:=clkfreq/1000 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-(pot*244/100) 'Send a high pulse for PulseWidth counts period:=period+Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time to complete PRI LCD_manager LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot=" )) 'Potentiometer position ID LCD.PRINT_DEC(pot) 'print the pot reading LCD.SPACE(5) 'erase over old data {Chapter 9 Program 1 } PRI repeat 'movement loop iters:=pot2 'set number of iterations to perform index:=0 'reset index repeat iters 'do iterations index:=index+1 'increment index targetPosition:=targetPosition+index 'set new position waitcnt(clkfreq/Pot1+cnt) 'wait time for iteration repeat iters 'now do the slow down index:=index-1 targetPosition:=targetPosition+index waitcnt(clkfreq/Pot1+cnt) repeat while startFlag==0 'wait till done waitcnt(clkfreq+cnt) 'delay to see stop targetPosition:=startPosition 'set to go back waitcnt(24_000+cnt) 'wait to get done repeat while startFlag==0 'wait till done waitcnt(clkfreq+cnt) 'delay to see stop {{04 June 09 Harprit Sandhu BlinkMethod.spin Propeller Tool Ver. 1.2.6 Chapter 10 Program 01 Blinking an LED This program turns an LED ON an OFF and demonstrates the use of subroutines in an absolutely minimal way. Define the constants we will use. Propeller font schematic: ¦ 100 O 21+---????---??----+ ¦ LED ¦ ? GND }} CON 'CON defines the constants _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'external crystal pin =27 'select the pin to be used for the LED waitPeriod =500 'set the wait period high =1 'define the High state low =0 'define the Low state {{ The following PUB Go is the main part of the program. Everything else is in the 3 called Methods }} PUB Go dira [pin]~~ 'sets pin to an output line with the ~~ notation repeat 'specifies times to repeat. Blank=forever turnOn_LED 'these 4 Methods are called by name alone wait 'these 4 Methods are called by name alone turnOff_LED 'these 4 Methods are called by name alone wait 'these 4 Methods are called by name alone PRI turnOn_LED 'Method to set the LED line high outa[pin] :=high 'line that actually sets the LED high PRI turnOff_LED 'Method to set the LED line low outa[pin] :=low 'line that actually sets the LED low PRI wait 'Method defines the delay waitCnt((Clkfreq/1000)*waitperiod +cnt) 'wait till counter reaches this value {{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter13 Program 1 This program turns an LED ON and OFF, with a programmable delay It demonstrates the use of methods in an absolutely minimal way. Since the clock is 10 MHz Define the constants we will use. }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency inv_high =0 'define the inverted High state inv_low =1 'define the inverted Low state waitPeriod =6_000_000 'about 1/2 sec switch cycle output_pin =27 'line the led is on 'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~~ 'makes the pin high repeat 'repeat forever, no number after repeat turnOff_LED 'method call wait 'method call turnOn_LED 'method call wait 'method call PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED 'method to set the LED line low outa[output_pin] :=inv_low 'line that actually sets the LED low PRI wait 'delay method waitCnt(waitPeriod + cnt) 'delay is specified by the waitPeriod {{11 Sep 09 Harprit Sandhu LCDminimal.spin Propeller Tool Ver 1.2.6 Chapter 14 Program 1 PROGRAM TO BEGIN USING THE LCD A minimal LCD implementation to allow us to use the LCD in our experiments immediately. This program is an absolutely minimal implementation to make the LCD usable. You can work on improving it. We will improve it later +------------+ Schematic ¦ +--------+ ¦ ¦ ¦ +----+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ POWER ETC: +----------------------------------------+ ¦ ¦ ¦ BASIC CONNECTIONS ¦ 1 0 9 8 7 6 5 4¦3 X X G¦3 2 1 0 9 8 7 6¦ ¦ ¦ ¦ FOR THE EDUCATION ¦ ¦ ¦ ¦ ¦ ¦ ¦ KIT ARE STANDARD ¦ Propeller ¦ ¦ CHIP ¦ ¦ ¦ ¦ CONNECTIONS AND ARE ¦ 0 1 2 3 4 5 6 7¦G B R 3¦8 9 0 1 2 3 4 5¦ ¦ ¦ ¦ NOT SHOWN HERE +----------------------------------------+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +-----+-+-+-+-+-+-+-+----+-+-+ ¦ +---+-+-+-+-+-+-+-+----+-+ 5VDC ¦ ¦ +-+-+-+-+-+-+-+-+----+ ? ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +----------?-+-+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +-------------------------------------------------+ ¦ ¦ G 5 G S W E 0 1 2 3 4 5 6 7 ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ +-------------------------------------------------+ ¦ 16 CHAR BY 2 LINE LCD DISPLAY ? GND 8 BIT MODE Revisions Pin assignment are assigned as constants because the pins are fixed. These numbers reflect the actual wiring on the board between the Propeller and the 16x2 LCD display. If you want the LCD on other lines, that would have to be specified here. We are going to use 8 bit mode to transfer data for now. All these numbers refer to lines on the Propeller }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency RegSelect = 16 ReadWrite = 17 Enable = 18 DataBit0 = 8 DataBit7 = 15 waitPeriod =500_000 'set the wait period high =1 'define the High state low =0 'define the Low state {{ Defining high and low states will allow us to invert these when we use buffers to amplify the output from the prop chip. We will then make low=1 and high=0 thus inverting all the values throughout the program }} PUB Go DIRA[DataBit7..DataBit0]:=%11111111 'the lines for the LCD are outputs DIRA[RegSelect] := High 'the lines for the LCD are outputs DIRA[ReadWrite] := High 'the lines for the LCD are outputs DIRA[Enable] := High 'the lines for the LCD are outputs INITIALIZE_LCD 'initialize the LCD waitcnt(1_000_000+cnt) 'wait for LCD to start up CLEAR 'clear the LCD repeat 4 'print 4 'A's SEND_CHAR ("A") repeat 4 'print 4 'a's SEND_CHAR ("b") POSITION (1,2) 'move to POSITION: line 2, space 1 repeat 4 'print 4 'B's SEND_CHAR ("C") repeat 4 'print 4 'b's SEND_CHAR ("d") repeat 'this is a parking loop to keep the system 'from shutting down. It just loops here 'see what cursor does if it is omitted PRI INITIALIZE_LCD 'The addresses and data used here are waitcnt(500_000+cnt) 'specified in the Hitachi data sheet for 'display. YOU MUST CHECK THIS FOR YOURSELF OUTA[RegSelect] := Low 'these three lines are specified to write OUTA[ReadWrite] := Low 'the initial set up bits for the LCD OUTA[Enable] := Low 'See Hitachi HD44780 data sheet 'display. YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011_0000) 'Send 1st waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 2nd waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 3rd waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_1111) 'Display on, Cursor on, Blink on SEND_INSTRUCTION (%0000_0001) 'clear LCD SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) PUB POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION 'Position cursor 'HOR_POSITION : Horizontal Position : 1 to 16 'LINE_NUMBER : Line Number : 1 or 2 CHAR_LOCATION := (HOR_POSITION-1) * 64 'figure location CHAR_LOCATION += (LINE_NUMBER-1) + 128 'figure location SEND_INSTRUCTION (CHAR_LOCATION) 'send the instr to position cursor PUB SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := High 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := Low 'Toggle the bit H>L PUB CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := High 'Set to read the busy bit OUTA[RegSelect] := Low 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 'Set the entire port to be an input REPEAT 'Keep doing it till clear OUTA[Enable] := High 'set to 1 to get ready to toggle H>L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read OUTA[Enable] := Low 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'set the data port back to outputs PUB SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := Low 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := Low 'Toggle the bit H>L {{12 Sep 09 Harprit Sandhu ButtonLED.spin Propeller Tool 1.2.6 Chapter 15 Prog 01 This program turns an LED ON if an input that has been pulled up is grounded It demonstrates the use of subroutines in an absolutely minimal way. First define the constants we will use. }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 input_pin =23 'select the pin to be used for input output_pin =27 'select the pin to be used for the LED inv_high =0 'define the inverted High state inv_low =1 'define the inverted Low state 'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the output PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~ 'makes the pin a low output dira [input_pin]~ 'sets pin to an input line with the ~ notation repeat 'repeat forever because there is no number after repeat if ina[input_pin]==0 'check pin for high or low turnOn_LED 'subroutine call else turnOff_LED 'subroutine call PRI turnOn_LED 'subroutine to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED 'subroutine to set the LED line low outa[output_pin] :=inv_low 'line that actually sets the LED low {{Aug 31 09 Harprit Sandhu ReadPot.spin Propeller Tool Version 1.2.6 Chapter 16 Prog 01 READING A POTENTIOMETER This routine ready a 10K pot with a 10 mfd cap This routine is what is used in the utilities to read the pot Pot is always read from the same line }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'Crystal spec PotLine = 19 'line the pot it on OBJ LCD : "LCDRoutines4" 'We will be using these METHODS in this program VAR 'these are the variables we will use. long startCnt 'count at start long endCount 'count at end long delay 'time difference long PotValue 'Value of the pot reading PUB Go LCD.INITIALIZE_LCD 'set up the LCD repeat 'loop dira[PotLine]~~ 'set potline as output outa[PotLine]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine]~ 'make potline an input. line switches H>L startCnt:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine]~~ 'keep doing it as long as the potline is high EndCount := cnt 'read the counter at end of cycle and store delay := ((EndCount-StartCnt)-1184) 'calculate time for line to go H>L if delay>630000 'max permitted delay delay:=630000 'clamp delay PotValue:=(delay/2220) 'This reduces the value to 0-255 or 1 byte PotValue <#=255 'clamp range PotValue #>=1 'clamp range LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("PotPos =")) 'Potentiometer position LCD.PRINT_DEC(PotValue) 'print value LCD.SPACE(3) 'erase over overflows LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Delay =")) 'Print LCD.PRINT_DEC(delay) 'print value LCD.SPACE(3) 'erase over overflows {{11 Sep 09 Harprit Sandhu Segment Propeller Tool Ver 1.2.6 Chapter 16 Program 2 }} PUB GetPotVal dira[PotLine]~~ 'set potline as output valutotal:=0 'clear total repeat repval 'repeat dira[PotLine]~~ 'set potline as output outa[PotLine]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine]~ 'make potline an input. line switches H>L startCnt:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine]~~ 'keep doing it as long as the potline is high EndCount := cnt 'read the counter at end of cycle and store delay := ((EndCount-StartCnt)-1184) 'calculate time for line to go H>L if delay>610_000 'max permitted delay delay:=610_000 'clamp delay PotValue:=(delay/2300) 'This reduces the value to 0-255 or 1 byte valutotal:=valutotal+potvalue 'figures total potvalue:=valutotal/repval 'figure average potvalue <#=255 potvalue #>=0 result:=PotValue 'figure average {{03 Nov 09 Harprit Sandhu MCP3202Read1.Spin Version 1.00.00 Propeller Tool 1.2.6 Chapter 16 Prog 03 All the code in this program is in SPIN This program reads channel 0 of the MCP3202 and displays the results on the LCD both as a decimal value and as a binary value so that you can see the bits flip as you turn the potentiometer. The 3202 chip is connected as follows: 1 Chip select P21 2 Channel 0 for voltage input from Pot Pot wiper 3 Channel 1 for voltage input from Pot, not used Ground it 4 Ground Vss Ground 5 Data into 3202 for setup P19 6 Data out from 3202 to be read into Propeller P22 7 Clock to read in the data P20 8 Power 5 volts Vdd 5 volts The Potentiometer is connected as follows: Left Ground Center To pin 2 of the 3202 Right Power 5 volts I used a 50K Pot The connections to the LCD are as follows: 1 Ground 2 Power 5 volts 3 Ground 4 P16 5 P17 6 P18 7 Not connected, using 4 bit mode for data Xfer 8 Not connected, using 4 bit mode for data Xfer 9 Not connected, using 4 bit mode for data Xfer 10 Not connected, using 4 bit mode for data Xfer 11 Data high nibble 12 Data high nibble 13 Data high nibble 14 Data high nibble STANDARD EDUCATION KIT SET UP. Used as base Revisions: Error Reporting: Please report errors to harprit.sandhu@gmail.com }} OBJ LCD : "LCDRoutines4" 'for the LCD methods CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal spec BitsRead =12 chipSel = 19 chipClk = chipSel+1 chipDout = chipSel+2 chipDin = chipSel+3 VAR long stack2[25] word PotReading word DataRead PUB Go cognew(Cog_LCD, @stack2) DIRA[0..7]~ DIRA[chipSel]~~ 'osc once to set up 3202 DIRA[chipDin]~~ 'data set up to the chip DIRA[chipDout]~ 'data from the chip to the Propeller DIRA[chipClk]~~ 'oscillates to read in data from internals repeat DataRead:=0 'Clear out old data outa[chipSel]~~ 'Chip select has to be high to start off outa[chipSel]~ 'Go low to start process outa[chipClk]~ 'Clock MUST be low to load data outa[chipDin]~~ 'must start with Din high to set up 3202 outa[chipClk]~~ 'Clock high to read data in outa[chipClk]~ 'Low to load outa[chipDin]~~ 'High single mode outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~ 'Odd = low channel 0 outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~~ 'msbf high = MSB first outa[chipClk]~~ 'High to read outa[chipDin]~ 'making line low for rest of cycle outa[chipClk]~ 'Low to load Read/discard the null bit outa[chipClk]~~ 'High to read repeat BitsRead 'Reads the data into DataRead in 12 steps DataRead <<= 1 'Move data by shifting left 1 bit. Ready for next bit outa[chipClk]~ 'Low to load DataRead:=DataRead+ina[chipDout] 'Xfer the data from pin chipDout outa[chipClk]~~ 'High to read outa[chipSel]~~ 'Put chip to sleep, for low power PotReading:=DataRead 'Finished data read for display PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot=" )) 'Print Label LCD.PRINT_DEC(PotReading) 'print decimal value LCD.SPACE(4) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT_BIN(PotReading,BitsRead) 'Print it as bits. {{12 Sep 09 Harprit Sandhu BlinkLEDpot.spin Propeller Tool Ver. 1.2.6 Chapter 16 Program 04 This program turns an LED ON and OFF, with a pot set delay Define the constants we will use }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency inv_high =0 'define the inverted High state inv_low =1 'define the inverted Low state output_pin =27 'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output VAR long Potvalue long WaitPeriod byte div 'dividing factor for clock freq OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~~ 'makes the pin high LCD.INITIALIZE_LCD 'initialize the LCD repeat 'repeat forever, no number after repeat PotValue:=UTIL.read3202_0 'reads the potentiometer DIV:=1+PotValue/64 'adding 1 keeps value from going to zero turnOff_LED 'method call wait 'method call turnOn_LED 'method call wait 'method call LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot=" )) 'dividing value LCD.PRINT_DEC(PotValue) 'print value LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Div=" )) 'dividing value LCD.PRINT_DEC(div) 'print value LCD.SPACE(2) 'erase over old data PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED 'method to set the LED line low outa[output_pin] :=inv_low 'line that actually sets the LED low PRI wait 'delay method waitCnt(clkfreq/div + cnt) 'delay is specified by the div {{11 Sep 09 Harprit Sandhu Segment Propeller Tool Ver 1.2.6 Chapter 17 Program 1 }} PUB segment dira[output]~~ 'output pin repeat 'loop !OUTA[output] 'toggle output line waitcnt(11_364 +cnt) 'wait for the A4 freq {{12 Sep 09 Harprit Sandhu Play8Notes.spin Propeller Tool Ver. 1.2.6 Chapter 17 Program 02 This program plays 8 notes, bare bones Define the constants we will use }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the crystal frequency repfactor =500 'number of times repeated delayfact =1_000_000 'delay between notes output = 25 PUB Go dira[output]~~ 'output pin repeat 'outer loop repeat repfactor !OUTA[output] 'toggle output line waitcnt(13_636 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(12_170 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(11470 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(10221 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(9104 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(8595 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(7639 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait repeat repfactor !OUTA[output] 'toggle output line waitcnt(6818 +cnt) 'wait to synthesize freq waitcnt(delayfact+cnt) 'wait {{ Aug 31 09 Harprit Sandhu FreqGen8.Spin Propeller Tool Ver. 1.2.6 Chapter 17 Program 3 This program generates 8 frequencies starting at 440 cycles/sec. Depends on the position of Pot 1 }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'Crystal freq Output = 26 'output line for the speaker Repfactor = 100 'number of times to toggle line VAR {RAM assignment for cogs} long Stack1[50] 'this RAM will be assigned to COG1 long Stack2[50] 'this RAM will be assigned to COG2 {variables used for reading pot} word PotValue 'value of the pot reading long NoteFreq 'actual frequency of the note long NoteDelay 'delay in cycles {variables used in displaying LCD in Cog2} 'none {variables used in GetTone} Byte toneNumber OBJ 'The Objects we will need for our calls LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods DAT Tone word 440, 494, 523, 587, 659, 698, 784, 880 PUB GO 'The main method in this program 'the potentiometer is read in this cog cognew (COG_LCD, @Stack1) 'create COG_TWO for LCD display cognew (COG_PLAY, @Stack2) 'create COG_THREE for toggling output repeat 'start repeat loop PotValue:=UTIL.Read3202_0 'get potValue from the utilities ToneNumber:=Potvalue/512 +1 'This reduces the value to 0-15 PRI COG_LCD 'Handles display to the LCD LCD.INITIALIZE_LCD 'set up the LCD REPEAT 'repeat write to the LCD LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("PotPos =")) 'Potentiometer position LCD.PRINT_DEC(ToneNumber) 'print the tune number LCD.SPACE(2) 'erase over overflows LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("FreqOut=")) 'frequency label printed LCD.PRINT_DEC(NoteFreq) 'print note cps LCD.SPACE(2) 'erase over overflows PRI COG_PLAY 'output for speaker dira[Output]~~ 'output pin repeat 'outer loop repeat RepFactor 'inner loop and repeat # GetTone 'gets value for NoteFre !OUTA[output] 'toggle output line NoteDelay:=12_000_000/(NoteFreq*2) 'calculate the delay waitcnt(NoteDelay +cnt) 'wait for delay to synthesize freq waitcnt(clkfreq/2+cnt) PUB GetTone 'gets the frequency to be played NoteFreq := Tone[toneNumber-1] 'looks up position in DAT statements {{05 Oct 09 Harprit Sandhu FreqCounter.Spin Propeller Tool Ver 1.2.6 Chapter 17 Prog 04 The program reads the frequency of a signal on the Input line and displays it on the LCD. The signal is read as the number of waves in 1 second. Controlled by Pot 1 Four Cogs are used COG GO reads the frequency COG COG_LCD displays values on LCD COG FREQ_GEN generates the frequency COG COG_OUT generates the 5 freq }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal freq5 =25 '5X freq line input =26 'line for input for what is to be read output =27 'line for output of what is generated VAR 'these are the variables long Stack[50] 'For CogOne long Stack1[50] 'For freq_gen long Stack2[50] 'For freq_out long Freq 'read frequency long startTMR long StopTMR long elapsed long pot OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods PUB GO 'This the main method in this program Cognew (COG_LCD, @Stack) 'create Cog_TWO Cognew (FREQ_GEN, @Stack1) 'create freq generator Cognew (COG_OUT, @Stack2) 'create freq out dira[input]~ repeat repeat while ina[input]==0 'hold at low startTMR:=cnt 'start timer repeat while ina[input]==1 'hold at high repeat while ina[input]==0 'hold at low stopTMR:=cnt 'read timer elapsed:=stopTMR-startTMR freq:=10_000_000/elapsed pot:=util.read3202_0 'read Pot 1 PRI COG_LCD 'This is the display, the LCD LCD.INITIALIZE_LCD 'initialize up the LCD REPEAT 'Routine to write to the LCD LCD.POSITION (1,1) ' LCD.PRINT(STRING("FRQ=")) 'Frequency LCD.PRINT_DEC(Freq) 'print freq LCD.SPACE(2) 'erase old data LCD.POSITION (2,1) ' LCD.PRINT(STRING("POT=")) 'Frequency LCD.PRINT_DEC(Pot) 'print Pot reading LCD.SPACE(2) 'erase old data PRI FREQ_GEN 'Freq generation based on pot reading dira[output]~~ 'set output line pot:=1000 'arbitrary non zero value repeat 'loop outa[output]~~ 'make line high waitcnt(clkfreq/pot+cnt) 'wait based on pot outa[output]~ 'make line low waitcnt(clkfreq/pot+cnt) 'wait based on pot PRI COG_OUT 'output signal generation. dira[freq5]~~ 'Set pin direction as output freq:=1000 'arbitrary non zero value repeat 'loop outa[freq5]~~ 'make line high waitcnt(clkfreq/freq/5+cnt) 'wait 1/5 time for 5X freq outa[freq5]~ 'Make line low waitcnt(clkfreq/freq/5+cnt) 'wait 1/5 time for 5X freq {{13 Sep 09 Harprit Sandhu MemsicWidth.spin Propeller Tool Ver 1.2.6 Chapter 18 Prog 01 This program measures the pulse width and wave length output from a Memsic 2125 gravity sensor as it is tilted from the horizontal plane to the vertical plane COG_LCD manages the LCD output COG_0 measures the pulse }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal frequency xaxis = 25 ' output = 26 VAR long Stack[55] 'FOR LCD COG long Stack1[55] 'FOR OUTPUT COG long startWave ' long endPulse ' long endWave ' long PulseLen ' long waveLen ' long frequency OBJ 'These are the Objects we will need LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods collection PUB go 'Cog_0 cognew (COG_LCD, @Stack) 'starting up Cog LCD cognew (COG_OUT, @Stack1) 'starting up Cog OUT DIRA[25]~ 'Make pin input repeat 'Set up the control loop repeat while ina[xaxis]==1 'wait for line 1 to go low. See Manual repeat while ina[xaxis]==0 'wait for line 1 to go low. See Manual 'the above 2 lines make sure that we see 'aa full wave when we start measuring repeat while ina[xaxis]==1 'wait for line 1 to go low. See Manual startWave:=CNT 'read the timer count repeat while ina[xaxis]==0 'wait for line 1 to go low. See Manual endPulse:=CNT 'read the timer count for second time repeat while ina[xaxis]==1 'wait for line 1 to go low. See Manual. endWave:=cnt PulseLen:=endPulse-startWave 'figure the pulse waveLen:=endWave-startWave 'figure the wave Len frequency:=10_000_000/waveLen 'figure the freq waitcnt(clkfreq/25+cnt) PRI COG_LCD 'This is running in the new cog LCD.INITIALIZE_LCD 'set up the LCD u repeat 'Print to LCD routine LCD.POSITION (1,1) 'Position LCD cursor LCD.PRINT(String("PL=")) 'Pulse ' LCD.PRINT_DEC((startWave)) 'print value ' LCD.SPACE(2) 'write over old data LCD.PRINT_DEC((pulselen)) 'print data LCD.SPACE(2) 'write over old data LCD.POSITION (2,1) 'Position LCD cursor LCD.PRINT(String("WL=")) 'Wave Length LCD.PRINT_DEC((wavelen)) 'print value LCD.SPACE(2) 'write over old data LCD.POSITION (2,11) 'Position LCD cursor LCD.PRINT(String("FR=")) 'Frequency LCD.PRINT_DEC((frequency)) 'print value LCD.SPACE(4) 'write over old data PRI COG_OUT 'output signal generation. dira[output]~~ 'Set pin direction as output repeat 'loop outa[output]~~ 'make line high waitcnt(pulselen/10+cnt) 'Create hi part of wave outa[output]~ 'Make line low waitcnt(100_000-pulselen+cnt)'Create rest of wave {Chapter 18 Program 2 } PRI COG_OUT 'output signal generation. dira[output]~~ 'Set pin direction as output repeat 'loop outa[output]~~ 'make line high waitcnt(pulselen/5+cnt) 'Create hi part of wave outa[output]~ 'Make line low waitcnt(200_000-pulselen+cnt) 'Create rest of wave {{05 Oct 09 Harprit Sandhu FreqCounter.Spin Propeller Tool Ver 1.2.6 Chapter 18 Program 3 The program reads the frequency of a signal on the Input line and displays it on the LCD. The signal is read as the number of waves in 1 second. Controlled by Pot 1 Four Cogs are used COG GO reads the frequency COG COG_LCD displays values on LCD COG FREQ_GEN generates the frequency COG COG_OUT generates the 5 freq }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal freq5 =25 '5X freq line input =26 'line for input for what is to be read output =27 'line for output of what is generated VAR 'these are the variables long Stack[50] 'For CogOne long Stack1[50] 'For freq_gen long Stack2[50] 'For freq_out long Freq 'read frequency long startTMR long StopTMR long elapsed long pot OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods PUB GO 'This the main method in this program Cognew (COG_LCD, @Stack) 'create Cog_TWO Cognew (FREQ_GEN, @Stack1) 'create freq generator Cognew (COG_OUT, @Stack2) 'create freq out dira[input]~ repeat repeat while ina[input]==0 'hold at low startTMR:=cnt 'start timer repeat while ina[input]==1 'hold at high repeat while ina[input]==0 'hold at low stopTMR:=cnt 'read timer elapsed:=stopTMR-startTMR freq:=10_000_000/elapsed pot:=util.read3202_0 'read Pot 1 PRI COG_LCD 'This is the display, the LCD LCD.INITIALIZE_LCD 'initialize up the LCD REPEAT 'Routine to write to the LCD LCD.POSITION (1,1) ' LCD.PRINT(STRING("FRQ=")) 'Frequency LCD.PRINT_DEC(Freq) 'print freq LCD.SPACE(2) 'erase old data LCD.POSITION (2,1) ' LCD.PRINT(STRING("POT=")) 'Frequency LCD.PRINT_DEC(Pot) 'print Pot reading LCD.SPACE(2) 'erase old data PRI FREQ_GEN 'Freq generation based on pot reading dira[output]~~ 'set output line pot:=1000 'arbitrary non zero value repeat 'loop outa[output]~~ 'make line high waitcnt(clkfreq/pot+cnt) 'wait based on pot outa[output]~ 'make line low waitcnt(clkfreq/pot+cnt) 'wait based on pot PRI COG_OUT 'output signal generation. dira[freq5]~~ 'Set pin direction as output freq:=1000 'arbitrary non zero value repeat 'loop outa[freq5]~~ 'make line high waitcnt(clkfreq/freq/5+cnt) 'wait 1/5 time for 5X freq outa[freq5]~ 'Make line low waitcnt(clkfreq/freq/5+cnt) 'wait 1/5 time for 5X freq {{28 Sep 09 Harprit Sandhu 7SegDisplay.spin 7SegDisplay.spin Propeller Tool Ver 1.2.6 Chapter 19 Program 1 Program controls the segments on one 7 segment display Pot is used to change the delay time Place Segment Display on perf board as sown in Pictures. }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ =5_000_000 '10 MHz VAR 'these are the variables we will use. long stack1[35] 'space for 7 Seg driver word delay 'duration for each number byte index 'numbering index OBJ 'These are the methods we will need UTIL : "Utilities" 'for general methods PUB Go 'main cog cognew(SevSeg,@Stack1) 'start new cog for segs repeat 'this main cog's main loop delay:=util.getpotval*8 PRI SevSeg ' dira[8..15]~~ index:=0 repeat index+=1 'index:=8 'can freeze index at 8 to see all segs on case index 1: repeat delay outa[8..15]:=%01_111_111 'These numbers build outa[8..15]:=%11_111_111 'up the numbers shown outa[8..15]:=%11_011_111 'segment at a time outa[8..15]:=%11_111_111 'number at a time. outa[8..15]:=%11_111_111 'a ZERO turns a segment on outa[8..15]:=%11_111_111 'in a common anode system outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_110 2: repeat delay outa[8..15]:=%11_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_011_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_110 3: repeat delay outa[8..15]:=%11_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_110 4: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_110 5: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_110 6: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_011_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 7: repeat delay outa[8..15]:=%11_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 8: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_011_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_111 9: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_110_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_111 10: repeat delay outa[8..15]:=%01_111_111 outa[8..15]:=%10_111_111 outa[8..15]:=%11_011_111 outa[8..15]:=%11_101_111 outa[8..15]:=%11_111_111 outa[8..15]:=%11_111_011 outa[8..15]:=%11_111_101 outa[8..15]:=%11_111_111 11: repeat delay*20 'blanks display for a while outa[8..15]:=%11_111_111 if index>11 'index reset value index:=0 {{29 Sep 09 Harprit Sandhu Metronom1.Spin Propeller Tool Ver 1.2.6 Chapter 20 Prog 1 Creating pulses An electronic metronome. Standard is 40 to 208 BPM (beats per minute) 4 Cogs are used Cog0 GO, toggles power line once a sec Cog1 LCD, displays values on LCD Cog2 Counts, toggles the speaker Cog3 Calc, calculates the beats }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal rate Clickline = 25 'Clicks speaker LED2Line = 26 'Toggles the 2nd LED ledLine = 27 'the ON led, 1 sec cycle VAR 'these are the variables we use. long Stack [40] 'for lcd long Stack2[40] 'for counts long Stack3[40] 'for spkr long Stack4[40] 'for click long Pot 'for potentiometer reading long bpm 'beats per minute OBJ 'These are the methods we need LCD : "LCDRoutines4" 'for controlling the LCD UTIL : "Utilities" 'for general methods, read potentiomter PUB GO 'This the main method in this program cognew (lcd_COG, @Stack) 'create COG for LCD cognew (Counts_COG, @Stack2) 'create COG for speaker cognew (Calc_COG, @Stack3) 'create COG for calculations dira[ledLine]~~ 'Power indicator repeat 'The main cog blinks an LED only outa[ledLine]~ 'These lines just blink an LED waitcnt(clkfreq/2+cnt) 'as an ON indicator as a one outa[ledLine]~~ 'second reference waitcnt(clkfreq/2+cnt) 'line 27 PRI lcd_COG 'This is the display to the LCD LCD.INITIALIZE_LCD 'set up the LCD REPEAT 'Routine to write to the LCD LCD.POSITION (1,1) 'Position cursor LCD.PRINT(STRING("POT VAL=")) 'identify signal LCD.PRINT_DEC(pot) 'print the Pot reading LCD.SPACE(4) 'write over old data LCD.POSITION (2,1) 'Position cursor LCD.PRINT(STRING("BEATS/M=")) 'Identify signal LCD.PRINT_DEC(bpm) 'print the beats/min LCD.SPACE(4) 'write over old data ' PRI Counts_COG 'This COG Toggles the speaker dira[LED2Line]~~ '26 bpm:=60 'this initializes the value repeat 'repeat loop outa[LED2Line]~~ 'toggle second LED waitcnt(clkfreq/(bpm/30)+cnt) 'wait time Click_Speaker 'calls method for this outa[LED2Line]~ 'turn it off waitcnt(clkfreq/(bpm/30)+cnt) 'wait time PRI Calc_COG 'This COG calculates the beats pot:=10 'this initializes the value bpm:=60 'this initializes the value repeat 'repeat loop pot:=util.Read3202_0 'read the potentiometer bpm:=40+(10*pot)*(208-40)/40950 'calculate beats from pot reading PRI Click_speaker 'makes the click sound dira[Clickline]~~ 'line 25 outa[Clickline]~~ 'turn on outa[Clickline]~ 'turn off {{Chapter 21 Program 01 }} PRI INITIALIZE_LCD 'The addresses and data used here are waitcnt(150_000+cnt) 'specified in the Hitachi data sheet for the 'display. YOU MUST CHECK THE DATA SHEET. OUTA[RegSelect] := 0 'three lines are specified so we can write OUTA[ReadWrite] := 0 'the initial set up bits for the LCD OUTA[Enable] := 0 'See Hitachi HD44780 data sheet ' SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font waitcnt(50_000+cnt)’ 'wait for instruction to execute SEND_INSTRUCTION (%0000_1111) 'Display on, Cursor on, Blink on waitcnt(12_000+cnt) 'wait for instruction to execute SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display waitcnt(12_000+cnt) 'wait for instruction to execute {{Chapter 21 Program 02 }} PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) 'to the 1,1 position {{Chapter 21 Program 03 }} PUB POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION 'Position the cursor at location 'HOR_POSITION : Horizontal Position : 1 to 16 'LINE_NUMBER : Line Number : 1 or 2 CHAR_LOCATION := (HOR_POSITION-1) * 64 'figure location CHAR_LOCATION += (LINE_NUMBER-1) + 128 'figure location SEND_INSTRUCTION (CHAR_LOCATION) 'send the instruction to position cursor {{Chapter 21 Program 04 }} PRI CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := 1 'Set to read the busy bit OUTA[RegSelect] := 0 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 'Set the entire port to be an input REPEAT 'Keep doing it till clear OUTA[Enable] := 1 'set to 1 to get ready to toggle H>L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read OUTA[Enable] := 0 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'done, set the data port back to output {{Chapter 21 Program 05 }} PRI SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 1 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := 0 'Toggle the bit H>L {{Chapter 21 Program 06 }} PRI SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L {{11 Sep 09 Harprit Sandhu LCDminimal.spin Propeller Tool Ver 1.2.6 PROGRAM TO BEGIN USING THE LCD A minimal LCD implementation to allow us to use the LCD in our experiments immediately. This program is an absolutely minimal implementation to make the LCD usable. You can work on improving it. +------------+ Schematic ¦ +--------+ ¦ ¦ ¦ +----+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ POWER ETC: +----------------------------------------+ ¦ ¦ ¦ BASIC CONNECTIONS ¦ 1 0 9 8 7 6 5 4¦3 X X G¦3 2 1 0 9 8 7 6¦ ¦ ¦ ¦ FOR THE EDUCATION ¦ ¦ ¦ ¦ ¦ ¦ ¦ KIT ARE STANDARD ¦ PROPELLER ¦ ¦ CHIP ¦ ¦ ¦ ¦ CONNECTIONS AND ARE ¦ 0 1 2 3 4 5 6 7¦G B R 3¦8 9 0 1 2 3 4 5¦ ¦ ¦ ¦ NOT SHOWN HERE +----------------------------------------+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +-----+-+-+-+-+-+-+-+----+-+-+ ¦ +---+-+-+-+-+-+-+-+----+-+ 5VDC ¦ ¦ +-+-+-+-+-+-+-+-+----+ ? ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +----------?-+-+ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +-------------------------------------------------+ ¦ ¦ G 5 G S W E 0 1 2 3 4 5 6 7 ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ ¦ +-++-++-++-++-++-++-++-++-++-++-++-++-++-++-+ ¦ ¦ +-------------------------------------------------+ ¦ 16 CHAR BY 2 LINE LCD DISPLAY ? GND 8 BIT MODE Revisons }} CON {{ Pin assignment are assigned as constants because the pins are fixed. These numbers reflect the actual wiring on the board between the Propeller and the 16x2 LCD display. If you want the LCD on other lines, that would have to be specified here. We are going to use 8 bit mode to transfer data All these numbers refer to lines on the Propeller }} _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the oscillator frequency RegSelect = 16 ReadWrite = 17 Enable = 18 DataBit0 = 8 DataBit7 = 15 waitPeriod =500_000 'set the wait period in Milliseconds high =1 'define the High state low =0 'define the Low state {{ Defining high and low states will allow us to invert these when we use buffers to amplify the output from the prop chip. We will then make low=1 and high=0 thus inverting all the values throughout the program }} PUB Go DIRA[DataBit7..DataBit0]:=%11111111 'the lines for the LCD are outputs DIRA[RegSelect] := High 'the lines for the LCD are outputs DIRA[ReadWrite] := High 'the lines for the LCD are outputs DIRA[Enable] := High 'the lines for the LCD are outputs INITIALIZE_LCD 'initialize the LCD waitcnt(5_000_000+cnt) 'wait for LCD to start up CLEAR 'clear the LCD repeat 'repeat forever clear repeat 4 'print 4 'A's SEND_CHAR ("A") repeat 4 'print 4 'a's SEND_CHAR ("b") POSITION (1,2) 'move to POSITION: line 2, space 1 repeat 4 'print 4 'B's SEND_CHAR ("C") repeat 4 'print 4 'b's SEND_CHAR ("d") waitcnt(10_000_000+cnt) PRI INITIALIZE_LCD 'The addresses and data used here are waitcnt(500_000+cnt) 'specified in the Hitachi data sheet for 'display. YOU MUST CHECK THIS FOR YOURSELF OUTA[RegSelect] := Low 'these three lines are specified to write OUTA[ReadWrite] := Low 'the initial set up bits for the LCD OUTA[Enable] := Low 'See Hitachi HD44780 data sheet 'YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011_0000) 'Send 1sr waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 2nd waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 3rd waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_1111) 'Display on, Cursor on, Blink on SEND_INSTRUCTION (%0000_0001) 'clear LCD SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) PUB POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION 'Position cursor 'HOR_POSITION : Horizontal Position : 1 to 16 'LINE_NUMBER : Line Number : 1 or 2 CHAR_LOCATION := (HOR_POSITION-1) * 64 'figure location CHAR_LOCATION += (LINE_NUMBER-1) + 128 'figure location SEND_INSTRUCTION (CHAR_LOCATION) 'send the instr to position cursor PUB SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := High 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := Low 'Toggle the bit H>L PUB CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := High 'Set to read the busy bit OUTA[RegSelect] := Low 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 'Set the entire port to be an input REPEAT 'Keep doing it till clear OUTA[Enable] := High 'set to 1 to get ready to toggle H>L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read OUTA[Enable] := Low 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'set the data port back to outputs PUB SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := Low 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := Low 'Toggle the bit H>L {{11 Sep 09 Harprit Sandhu LCDminimal2.spin Propeller Tool Ver 1.2.6 Chapter 21 Program 8 LCD control. Comprehensive. Here are the improvement to program Can now send DECIMAL values to the LCD Can now send HEX values to the LCD Can now send BINARY values to the LCD Delays in the print routines have been eliminate to speed things up The output blinks "Hello world" and 1234567890”on the two lines }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the oscillator frequency DataBit0 = 8 'Data uses 8 bits from DataBit7 = 15 'lines 8 to 15 RegSelect = 16 'The three control lines, register select ReadWrite = 17 'Read Write and Enable = 18 'Enable line waitPeriod =5_000_000 'set the wait period, about 1/2 sec high =1 'define the High state low =0 'define the Low state VAR long index 'used to count the chars in the string long char_index 'used to count the chars in the string PUB START DIRA[16..18]~~ 'set these 8 lines to outputs INITIALIZE_LCD 'this METHOD initializes on the LCD DIRA[DataBit7..DataBit0] := %1111_1111 '11 lines control the LCD as outputs DIRA[RegSelect] := 1 'select the register for the LCD DIRA[ReadWrite] := 1 'set to write DIRA[Enable] := 1 'enable operation repeat 'this loops forever initialize_lcd 'init the LCD waitCnt(waitPeriod + cnt) 'wait to see it clear position (1,1) ' go to pos 1,1 PRINT(string("Hello world")) 'display text message POSITION (2, 1) 'pos to line 2 position 1 PRINT_DEC (1234567890) 'print the number waitCnt(waitPeriod + cnt) 'wait a while before looping PRI INITIALIZE_LCD 'The addresses and data used here are waitcnt(500_000+cnt) 'specified in the Hitachi data sheet for the 'display. YOU MUST CHECK THIS FOR YOURSELF. OUTA[RegSelect] := 0 'three lines are specified so we can write OUTA[ReadWrite] := 0 'the initial set up bits for the LCD OUTA[Enable] := 0 'See Hitachi HD44780 data sheet SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_0001) 'clears the LCD SEND_INSTRUCTION (%0000_1100) 'Display on, Cursor off, Blink off SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display {this blank line ends this method} PRI CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) 'This is the clear screen and go home command {this blank line ends this method} PRI PRINT (the_line) 'routine handles more Chars at a time 'called as PRINT(string("the_line")) “ 'the line" contains the pointer to the line. 'because we have to point to the line 'zero terminated but we will not use that. 'We will use the string size instead. 'This was is easier to understand index:=0 'Reset the counter to count chars sent repeat 'repeat for all chars in the list char_index:= byte[the_line][index++] 'char_index contains the char/byte 'pointed to by the index SEND_CHAR (char_index) 'send the 'pointed to' char to the LCD while indexL OUTA[DataBit7..DataBit0] := DISPLAY_CHAR 'Ready to SEND data in OUTA[Enable] := 0 'Toggle the bit H>L PRI CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := 1 'Set to read the busy bit OUTA[RegSelect] := 0 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 'Set the entire port to be an input REPEAT 'Keep doing it till clear OUTA[Enable] := 1 'set to 1 to get ready to toggle H>L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read 'INA is the 32 input pins on the PROP and we 'are reading data bit 7 which is on pin 15! OUTA[Enable] := 0 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'done set the data port back to outputs PRI SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L PRI PRINT_DEC (VALUE) | TEST_VALUE 'for printing values in decimal format IF (VALUE < 0) 'if it is a negative value -VALUE 'change it to a positive SEND_CHAR("-") 'and print a - sign on the LCD TEST_VALUE := 1_000_000_000 'we get individual digits by comp to this 'value REPEAT 10 'There are 10 digits maximum IF (VALUE => TEST_VALUE) 'see if our num is bigger than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") 'if it is divide to get the digit VALUE //= TEST_VALUE 'figure the nxt val for the nxt digit RESULT~~ 'result so we can pass it on ELSEIF (RESULT OR TEST_VALUE == 1) 'if the result 1 then division was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 'we div by 10 to test the next digit PRI PRINT_HEX (VALUE, DIGITS) 'for printing values in HEX format VALUE <<= (8 - DIGITS) << 2 'you can specify up to 8 digits or 'FFFFFFFF max REPEAT DIGITS 'do each digit SEND_CHAR(LOOKUPZ((VALUE <-= 4) & $F : "0".."9", "A".."F")) 'use look up table to select character PRI PRINT_BIN (VALUE, DIGITS) 'for printing values in BINARY format VALUE <<= 32 - DIGITS '32 digits is the max for our system REPEAT DIGITS 'Repeat for digits desired SEND_CHAR((VALUE <-= 1) & 1 + "0") 'send a 1 or a 0 {this blank line ends this method} {{ 21 - 09}} OBJ LCD : "LCDRoutines" 'We will be using these METHODS in this program UTIL : "Utilities" 'We will be using these METHODS in this program {{21 Sep 09 Harprit Sandhu LCDRoutines.spin Propeller Tool Ver 1.2.6 Chapter 21 Program 10 LCD ROUTINES The following are the names of the methods described in this program INITIALIZE_LCD INITIALIZE_LCD4 not yet working right. PRINT (the_line) POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION SEND_CHAR (DISPLAY_CHAR) SEND_CHAR (DISPLAY_CHAR) PRINT_DEC (VALUE) | TEST_VALUE PRINT_HEX (VALUE, DIGITS) PRINT_BIN (VALUE, DIGITS) CLEAR HOME SPACE (QTY) Revisions 04 Oct 09 Initialize made more robust, misc unnecessary calls removed. }} CON 'all the constants used by all the METHODS 'in this program have to be listed here _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 '10 Mhz DataBit0 = 8 'Data uses 8 bits from here on DataBit1 = 9 DataBit2 = 10 DataBit3 = 11 'All these bits dont need to be named but DataBit4 = 12 'are named so that they can be called by DataBit5 = 13 'name if the need ever arises DataBit6 = 14 DataBit7 = 15 RegSelect = 16 'The three control lines ReadWrite = 17 ' Enable = 18 ' high =1 {define the High state} low =0 {define the Low state} VAR 'these are the variables we will use. byte temp 'for use as a pointer byte index 'to count characters PUB Go INITIALIZE_LCD repeat print(String("1234567890 L1")) position(2,1) print(String("On second line")) waitcnt(3_000_000+cnt) clear waitcnt(3_000_000+cnt) '================================================================================ {{initialize the LCD to use 8 lines of data Includes a half second delay, clears the display and positons to 1,1 no variables used }} PUB INITIALIZE_LCD 'The addressses and data used here are waitcnt(5_000_000+cnt) 'specified in the Hitachi data sheet DIRA[DataBit0..Enable]~~ 'YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011_0000) 'Send 1 waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 2 waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 3 waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_1110) 'Display on, Blink on, Sq Cursor off SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display SEND_INSTRUCTION (%0000_0001) 'clears the LCD POSITION (1,1) '================================================================================ {{Sends instructions as opposed to a character to the LCD no variables are used }} PUB SEND_INSTRUCTION (D_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear b OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data '================================================================================ {{Sends a character to the LCD }} PUB SEND_CHAR (D_CHAR) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 1 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := D_CHAR 'Ready to SEND data in OUTA[Enable] := 0 'Toggle the bit H>L '================================================================================ {{Print a line of characters to the LCD uses variables index and temp }} PUB PRINT (the_line) 'This routine handles more than one Char 'called as PRINT(string("the_line")) '"the_line" contains the pointer to line. 'because we have to point to the line 'zero terminated but will not use that. 'use the string size instead. Easier index:=0 'Reset the counter we are using repeat 'repeat for all chars in the list temp:= byte[the_line][index++]'temp contains the char pointed by index SEND_CHAR (temp) 'send the 'pointed to' char to the LCD while indexL this bit BUSY_BIT := INA[DataBit7] 'the busybit is bit 7 of the byte read 'INA is the 32 input pins on the PROP and we 'are reading data bit 7 which is on pin 15! OUTA[Enable] := 0 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'set the data port back to outputs '================================================================================ {{Print decimal }} PUB PRINT_DEC (VALUE) | TEST_VALUE'for printing values in decimal format IF (VALUE < 0) 'if it is a negative value -VALUE 'change it to a positive SEND_CHAR("-") 'and print a - sign on the LCD ' TEST_VALUE := 1_000_000_000 'we get individual digits by comp to this 'value and then div by 10 to get the nxt val REPEAT 10 'There are 10 digits maximum in our system IF (VALUE => TEST_VALUE) 'see if our number is bigger than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") 'if it is, divide to get the digit VALUE //= TEST_VALUE 'figure the next value for the next digit RESULT~~ 'result we can pass it on below ELSEIF (RESULT OR TEST_VALUE == 1) 'if the result was a 1 then div was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 'we divide by 10 to test for the next digit '================================================================================ {{Print Hex }} PUB PRINT_HEX (VALUE, DIGITS) 'for printing values in HEX format VALUE <<= (8 - DIGITS) << 2 'you can specify up to 8 digits or FFFFFFFF max REPEAT DIGITS 'do each digit SEND_CHAR(LOOKUPZ((VALUE <-= 4) & $F : "0".."9", "A".."F")) 'use lookup table to select character '================================================================================ {{Print Binary }} ' PUB PRINT_BIN (VALUE, DIGITS) 'for printing values in BINARY format VALUE <<= 32 - DIGITS '32 binary digits is the max for our system REPEAT DIGITS 'Repeat for each digit desired SEND_CHAR((VALUE <-= 1) & 1 + "0") 'send a 1 or a 0 '================================================================================ {{Clear screen }} PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) 'This is the clear screen and go home command '================================================================================ {{Go to position 1,1 }} PUB HOME 'go to position 1,1. SEND_INSTRUCTION (%0000_0011) 'Not cleared '================================================================================ {{Print spaces }} PUB SPACE (qty) 'Prints spaces, for between numbers repeat (qty) PRINT(STRING(" ")) '================================================================================ {{ }} {{11 Oct 09 Harprit Sandhu LCDTester.Spin Propeller Tool Ver. 1.2.6 Chapter 21 Program 11 Test program for LCD Routines }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 high =1 'define the High state low =0 'define the Low state VAR byte index 'used as counter for various uses OBJ LCD : "LCDRoutines" 'Using their METHODS in this program UTIL : "Utilities" 'Using their METHODS in this program PUB Go LCD.initialize_lcd LCD.print (string("Initialized OK")) LCD.position(2,1) LCD.print (string("Print test")) UTIL.pause (1500) LCD.clear LCD.position (1,1) LCD.print (string("this is 1st line")) UTIL.pause (300) LCD.position(2,1) LCD.print (string("ok is on line 2")) UTIL.pause (1500) LCD.clear LCD.print (string("Position test")) UTIL.pause (1500) index:=0 repeat 16 index := index +1 LCD.clear LCD.position (1,index) LCD.print (string("X")) UTIL.pause (300) index:=0 repeat 16 index := index +1 LCD.clear LCD.position (2,index) LCD.print (string("X")) UTIL.pause (300) LCD.clear LCD.print (string("End")) repeat {{21 Sep 09 Harprit Sandhu Utilities0.spin Propeller Tool Ver 1.2.6 Chapter 21 Program 12 Program UTILITIES Flash flashes a pin once, toggles it slowly Pause pause in milliseconds }} CON high =1 low =0 waitperiod =100 PUB FLASH (color) 'routine to flash an LED by color outa[color] :=high 'line that actually sets the LED high waitCnt(waitPeriod +cnt) 'wait till counter reaches this value outa[color] :=low 'line that actually sets the LED low waitCnt(waitPeriod +cnt) 'wait till counter reaches this value ' PUB PAUSE(millisecs) 'As set up here it is .25 millisceconds waitcnt((clkfreq/1000)*millisecs +cnt) 'based on Osc freq {{21 Sep 09 Harprit Sandhu LCDRoutines4.spin Propeller Tool Version 1.2.6 Chapter 21 Program 13 and Appendix LCD ROUTINES for a 4 bit data path. The following are the names of the methods described in this program INITIALIZE_LCD PRINT (the_line) POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION SEND_CHAR (DISPLAY_CHAR) SEND_CHAR (DISPLAY_CHAR) PRINT_DEC (VALUE) | TEST_VALUE PRINT_HEX (VALUE, DIGITS) PRINT_BIN (VALUE, DIGITS) CLEAR HOME SPACE (QTY) Revisions 04 Oct 09 Initialize made more robust, misc unnecessary calls removed. }} CON 'all the constants used by all the METHODS 'in this program have to be listed here _CLKMODE=XTAL1 + PLL2X 'The system clock spec. 2 X multiplier _XINFREQ = 5_000_000 'ext crystal is 5 Mhz, so 10 Mhz operation DataBit4 = 12 'are named so that they can be called by DataBit5 = 13 'name if the need ever arises DataBit6 = 14 ' DataBit7 = 15 ' RegSelect = 16 'The three control lines ReadWrite = 17 'The three control lines Enable = 18 'The three control lines high =1 'define the High state low =0 'define the Low state Inv_high =0 'define the Inverted High state Inv_low =1 'define the Inverted Low state VAR 'these are the variables we will use byte temp 'for use as a pointer byte index 'to count characters PUB Go INITIALIZE_LCD repeat print(String("4bit mode line 1")) position(2,1) print(String("4bit mode line 2")) waitcnt(clkfreq/4+cnt) clear waitcnt(clkfreq/4+cnt) {{initialize the LCD to use 4 lines of data Includes the half second delay, clears the display and positons to 1,1 no variables used }} PUB INITIALIZE_LCD 'The addresses and data used here are waitcnt(150_000+cnt) 'specified in the Hitachi data sheet for the DIRA[DataBit4..Enable]~~ 'display. YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011) 'Send 1st waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011) 'Send 2nd waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011) 'Send 3rd waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0010) 'set for 4 bit mode waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION2 (%0010_1000) 'Sets DL=4 bits, N=2 lines, F=5x7 font ' waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION2 (%0000_1110) 'Display on, Blink on, Sq Cursor off ' waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION2 (%0000_0110) 'Move Cursor, Do not shift display ' waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION2 (%0000_0001) 'clears the LCD 'waitcnt(12_000+cnt) 'wait POSITION (1,1) {{Sends instructions as opposed to a character to the LCD no variables are used }} PUB SEND_INSTRUCTION (D_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data {{Sends an instruction as opposed to a character to the LCD no variables are used }} PUB SEND_INSTRUCTION2 (D_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA>>4 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data {{Sends a single character to the LCD in two halves }} PUB SEND_CHAR (D_CHAR) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to send data OUTA[RegSelect] := 1 'Set up to send data OUTA[Enable] := 1 'go high OUTA[DataBit7..DataBit4] := D_CHAR>>4 'Send high 4 bits OUTA[Enable] := 0 'Toggle the bit H>L OUTA[Enable] := 1 'go high again OUTA[DataBit7..DataBit4] :=D_CHAR 'send low 4 bits OUTA[Enable] := 0 'Toggle the bit H>L {{Print a line of characters to the LCD uses variables index and temp }} PUB PRINT (the_line) 'This routine handles more than one Char at a time 'called as PRINT(string("the_line")) '"the_line" contains the pointer to line. Line is 'because we have to point to the line 'zero terminated but we will not use that. We will 'use the string size instead. Easier to understand index:=0 'Reset the counter we are using to count chars sent repeat 'repeat for all chars in the list temp:= byte[the_line][index++] 'temp contains the char/byte pointed by index SEND_CHAR (temp) 'send the 'pointed to' char to the LCD while indexL this bit BUSY_BIT := INA[DataBit7] 'the busybit is bit 7 of the byte read 'INA is the 32 input pins on the PROP and we 'are reading data bit 7 which is on pin 15! OUTA[Enable] := 0 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit4] := %1111 'done, so set the data port back to outputs {{Print a decimal value, whole numbers only }} PUB PRINT_DEC (VALUE) | TEST_VALUE 'for printing values in decimal format IF (VALUE < 0) 'if it is a negative value -VALUE 'change it to a positive SEND_CHAR("-") 'and print a - sign on the LCD TEST_VALUE := 1_000_000_000 'we get individual digits by comparing to this 'value and then dividing by 10 to get next value REPEAT 10 'There are 10 digits maximum in our system IF (VALUE => TEST_VALUE) 'see if our number is bigger than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") 'if it is, divide to get the digit VALUE //= TEST_VALUE 'figure the next value for the next digit RESULT~~ 'result of what just did pass it on below ELSEIF (RESULT OR TEST_VALUE == 1) 'if the result was a 1 then div was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 'we divide by 10 to test for the next digit {{Print a Hexadecimal value }} PUB PRINT_HEX (VALUE, DIGITS) 'for printing values in HEX format VALUE <<= (8 - DIGITS) << 2 'you can specify up to 8 digits or FFFFFFFF max REPEAT DIGITS 'do each digit SEND_CHAR(LOOKUPZ((VALUE <-= 4) & $F : "0".."9", "A".."F")) 'use lookup table to select character {{Print a Binary value }} ' PUB PRINT_BIN (VALUE, DIGITS) 'for printing values in BINARY format VALUE <<= 32 - DIGITS '32 binary digits is the max for our sys REPEAT DIGITS 'Repeat for each digit desired SEND_CHAR((VALUE <-= 1) & 1 + "0") 'send a 1 or a 0 {{Clear screen }} PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION2 (%0000_0001) 'This is the clear screen and go home command {{Go to position 1,1 Does not clear the screen }} PUB HOME 'go to position 1,1. SEND_INSTRUCTION2 (%0000_0011) 'Not cleared {{Print spaces }} PUB SPACE (qty) 'Prints spaces, for between numbers repeat (qty) PRINT(STRING(" ")) {{Dec 31 09 Harprit Sandhu Chapter 24 Program 01 outa[ServoLine]~ waitcnt((166,667-(PotValue * 15000 / 4095) + 7500 + cnt) outa[ServoLine]~~ waitcnt((PotValue * 15000 / 4095))+ 7500 + cnt) {{ 06 Sep 09 Harprit Sandhu RC_ServoPosition.spin Propeller Tool Version 1.2.6 Chapter 24 Program 02 READING A SERVO'S POSITION uses pin 23 This program allows you to tie the signal sent to an R/C servo to the position that it goes to. Connections White P23 signal from Prop Red 5 volts Black ground }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 outPin =23 'line the servo is on VAR 'these are the variables we will use. long ServoPos 'The program will read this variable from 'the main Hub RAM to determine the 'servo signal's high pulse duration long stack [15] 'space for Cog for LCD long stack2[50] 'space for Move Motor Cog long pcount ' OBJ 'These are the methods we will need for our calls LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods, pot PUB Go 'main cog dira[outPin]~~ 'set direction for amplifier cognew(MoveMotor(outPin),@Stack) 'start a new cog and run the MoveMotor method 'on it and output pulses on Pin 23 'The new cog that is started above continuously 'reads the "position" variable as it's changed 'by the example Spin code below cognew(cog_two, @stack2) 'start new cog for the LCD repeat 'this is the Cog's main loop pcount:=UTIL.Read3202_0 'get the pot reading from the utilities ServoPos:=7200+pcount*4 'calculate position count Pub cog_two 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot Pos=")) 'Potentiometer position ID LCD.PRINT_DEC(Pcount) 'print the pot reading LCD.SPACE(2) 'erase over old text PUB MoveMotor(Pin)|LowTime,period 'method to toggle the output line, set 'up first dira[Pin]~~ 'Set the direction of "Pin" to be an output ctra[30..26]:=%00100 'Set this cog's "A Counter" in single 'ended NCO/PWM mode (where frqa always 'accumulates to phsa and the Apin output 'state is bit 31 of the phsa value) ctra[5..0]:=Pin 'Set the "A pin" of this cog's "A Counter" 'to be "Pin" frqa:=1 'Set this counter's frqa value to 1 (so 1 'will be added to phsa on each clock pulse) ServoPos:=0 'Start with position=0 (until the position 'value is changed by another cog) LowTime:=clkfreq/60 'Set the time that the pulse will be low 'to 16ms = 1/60 secs period:=cnt 'Store current value of the system counter repeat 'line toggling routine. phsa:=-ServoPos 'Send a high pulse for "position" number of 'clock cycles. Note negative sign period:=period+LowTime 'Calculate what system clock's value will 'be at the end of this cycle's period waitcnt(period) 'Wait for the system counter to reach the '"period" value (end of cycle) {{04 Sep 09 Harprit Sandhu RunMotorOnly.spin Propeller Tool Version 1.2.6 Chapter 25 Program 01 RUNNING A DC MOTOR. ON CONTROL ONLY TO CONFIRM CONNECTIONS This program runs the motor if turned on Lines on Xavien amp as identified in the diagram are line 1 Brake tie it to ground to turn it off line 2 PWM signal line 6 on Prop line 3 Direction line 7 on Prop Connections are Amplifier brake P5 Amplifier PWM P6 Amplifier direction P7 }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal BRK = 2 PWM = BRK + 1 DIR = PWM + 1 PUB Go 'main Cog dira[BRK..DIR]~~ 'set direction for 3 lines outa[BRK..DIR]:=%000 'make the lines low at start repeat outa[PWM]~~ 'turn on the PWM 100% {{04 Sep 09 Harprit Sandhu ReadDisplayPot.spin Propeller Tool Version 1.2.6 Chapter 25 program 2 RUNNING A MOTOR, Read Pot/NO SPEED CONTROL This program runs the motor backward or forward at full speed based on the potentiometer position. Reverses at 2048 Pot position is displayed on the LCD Lines on Xavien amp as identified in the diagram are line 1 Brake tie it to ground to turn it off line 2 PWM signal line 6 on Prop line 3 Direction line 7 on Prop Connections are Amplifier brake P5 Amplifier PWM P6 Amplifier direction P7 }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 ' BRK = 5 PWM = BRK+1 DIR = BRK+2 VAR long position long stack2[50] 'space for Cog two long pcount 'potentiometer reading. long potpos OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main Cog dira[BRK..DIR]~~ 'set direction for lines outa[BRK..DIR]:=%011 'make the lines high, brake off Cognew(cog_two, @stack2) 'start new Cog for the LCD repeat 'this Cog's main loop pcount:=UTIL.Read3202_0 'get he pot reading from the utilities if pcount<2048 'check for center position outa[DIR]~ 'forward direction set pcount:=(2048-pcount)*2 'set center and double the 127 to get near 255 else 'or outa[DIR]~~ 'reverse direction pcount:=(pcount-2048)*2 'set center and double the 127 to get near 255 potpos:=pcount Pub Cog_two 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot position")) 'Potentiometer position ID LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT_DEC(Potpos) 'print the pot reading LCD.SPACE(2) 'erase over old data {{07 Sep 09 Harprit Sandhu MotorFromPot.spin RUNNING A DC MOTOR FROM A POTENTIOMETER Chapter 25 Program 3 This program allows you to control the speed and the direction of a motor from a potentiometer Lines on Xavien amp as identified in the diagram are line 1 Brake tie it to ground to turn it off line 2 PWM signal line 6 on Prop line 3 Direction line 7 on Prop Connections are Amplifier brake P5 Amplifier PWM P6 Amplifier direction P7 }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 'crystal ' BRK = 5 PWM = BRK+1 DIR = BRK+2 PotMax = 1000 'The maximum power to the motor OUT OF 4095 PotMin = 40 'The minimum power to the motor OUT OF 4095 VAR 'these are the variables we will use. long PulsWidth 'The assembly program will read this variable from 'the main Hub RAM to determine the 'servo signal's high pulse duration long stack [50] 'space for Cog managing the motor pulses long stack2[50] 'space for Cog two long pcount 'potentiometer reading. byte arrow 'motor direction arrow OBJ 'These are the methods we need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main cog dira[BRK..DIR]~~ 'set direction for amplifier outa[BRK..DIR]:=%000 cognew(MoveMotor(6),@Stack) 'start a new cog and run the MoveMotor method 'on it and output pulses on Pin 7 'The new cog that is started above continuously 'reads the "position" variable as it's changed 'by the example Spin code below cognew(cog_two, @stack2) 'start new cog for the LCD repeat 'this cog's main loop pcount:=UTIL.Read3202_0 'get he pot reading from the utilities if pcount<2047 'check for center position outa[DIR]~ 'forward direction set arrow:=0 'direction arrow pcount:=(2047-pcount)*2 'set center and double the 127 to get near 255 else 'or outa[DIR]~~ 'reverse direction arrow:=1 'direction arrow pcount:=(pcount-2047)*2 'set center and double the 127 to get near 255 if pcountPotMax 'check Max value pcount:=Potmax 'check Max value PulsWidth:=pcount*24 'multiply reading to get 4095 '(10000/4096=24) PUB cog_two 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pos=")) 'Potentiometer position ID LCD.PRINT_DEC(pulsWidth/24) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (1,11) 'Go to 1st line 1st space LCD.PRINT(STRING("Dir=")) 'Potentiometer position ID LCD.PRINT_DEC(arrow) 'print the pot reading LCD.SPACE(2) 'erase over old data PUB MoveMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set 'up first dira[Pin]~~ 'Set the direction of "Pin" to be an output ctra[30..26]:=%00100 'Set this cog's "A Counter" to run in single 'ended NCO/PWM mode (where frqa always 'accumulates to phsa and the Apin output 'state is bit 31 of the phsa value) ctra[5..0]:=Pin 'Set the "A pin" of this cog's "A Counter" 'to be "Pin" frqa:=1 'Set this counter's frqa value to 1 (so 1 'will be added to phsa on each clock pulse) PulsWidth:=1000 'Start with position=0 (until the position 'value is changed by another cog) WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the system counter repeat 'line toggling routine. phsa:=-PulsWidth 'Send a high pulse for "position" number of 'clock cycles. NOTE minus sign on PulseWidth. period:=period+WaveLength 'Calculate what the system clock's value will 'be at the end of this cycle's period waitcnt(period) 'Wait for the system counter to reach the '"period" value (end of cycle) {{09 Sep 09 Harprit Sandhu StepperFromPot.spin Propeller Tool Ver 1.2.6 Chapter 26 Program 4 RUNNING A STEPPER MOTOR FROM A POTENTIOMETER UNI-DIRECTIONAL CONTROL This program allows you to control the speed of a STEPPER motor from a potentiometer Xavien amplifier lines are Coil #1 Brake is on line P2 of the propeller PWM is on line P3 of the propeller Direction is on line P4 of the propeller Coil #2 Brake is on line P5 of the propeller Direction is on line P6 of the propeller PWM is on line P7 of the propeller }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 Brk1=2 Pwm1=Brk1+1 Dir1=Brk1+2 Dir2=Brk1+3 Brk2=Brk1+4 Pwm2=Brk1+5 VAR 'these are the variables we will use. long stack1[35] 'space for Cog_LCD long stack2[35] 'space for Cog MoveStepper word Pcount 'potentiometer reading OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main cog cognew(MoveStepper,@Stack1) cognew(cog_LCD, @stack2) 'start a new cog for the LCD repeat 'this main cog's main loop pcount:=UTIL.read3202_0 + 1 'get the pot reading from the utilities 'the 1 eliminates a 0 reading Pub cog_LCD 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Div Fac=" )) 'Potentiometer position ID LCD.PRINT_DEC(pcount) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Mtr Rpm=" )) 'Potentiometer position ID LCD.PRINT_DEC(6*pcount/10) 'print rpm LCD.SPACE(2) 'erase over old data PUB MoveStepper dira[Brk1..Pwm2]~~ pcount:=50 repeat 'BPD DBP B=Brake, P=PWM, D=direction. outa[Brk1..Pwm2]:=%011_010 'on off waitcnt(clkfreq/(pcount)+cnt) ' outa[Brk1..Pwm2]:=%100_101 'off on waitcnt(clkfreq/(pcount)+cnt) ' outa[Brk1..Pwm2]:=%010_010 'rev off waitcnt(clkfreq/(pcount)+cnt) ' outa[Brk1..Pwm2]:=%100_001 'off rev waitcnt(clkfreq/(pcount)+cnt) ' {{09 Sep 09 Harprit Sandhu StepperFwdRev.spin Propeller Tool Ver 1.2.6 Chapter 26 Program 5 RUNNING A STEPPER MOTOR FROM A POTENTIOMETER Fwd-Rev control From Pot 1 Speed control from Pot 2 Xavien amplifier lines are Coil #1 Brake is on line P2 of the propeller PWM is on line P3 of the propeller Direction is on line P4 of the propeller Coil #2 Brake is on line P5 of the propeller Direction is on line P6 of the propeller PWM is on line P7 of the propeller }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 Brk1=2 'line assignments Pwm1=Brk1+1 Dir1=Brk1+2 Dir2=Brk1+3 Brk2=Brk1+4 Pwm2=Brk1+5 divmin = 4 divmax = 4500 VAR 'these are the variables we will use. long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog MoveStepper byte Pcount 'potentiometer reading. word divider 'divides clkfreq for delays byte direction 'stepper direction long range OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main Cog Cognew(MoveStepper,@Stack3) Cognew(cog_LCD, @stack2) 'start a new Cog for the LCD repeat 'this main Cog's main loop pcount:=UTIL.Read3202_0/16 'get the pot reading from the utilities range:=UTIL.Read3202_1+10 'get the pot reading for range if pcount<128 pcount:=127-pcount direction:=0 else pcount:=pcount-128 direction:=1 if rangedivmax 'check max range:=divmax 'set max divider:=range 'set divider value Pub cog_LCD 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Div Fac=" )) 'Potentiometer position ID LCD.PRINT_DEC(pcount) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Mtr Rpm=" )) 'Potentiometer position ID LCD.PRINT_DEC(range) 'print range/pot LCD.SPACE(2) 'erase over old data PUB MoveStepper dira[Brk1..Pwm2]~~ outa[Brk1..Pwm2]~~ divider:=500 repeat if direction==0 outa[Brk1..Pwm2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' else ' outa[Brk1..Pwm2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' {{10 Sep 09 Harprit Sandhu StepperDistPot.spin Propeller Tool Ver 1.2.6 Chapter 26 Program 6 RUNNING A STEPPER MOTOR FROM A POTENTIOMETER STEPPER position FOLLOWS POT position This program allows you to control the speed of a STEPPER motor from a potentiometer and run motor back and forth Xavien amplifier lines are Coil #1 Brake is on line P2 of the propeller PWM is on line P3 of the propeller Direction is on line P4 of the propeller Coil #2 Brake is on line P5 of the Propeller Direction is on line P6 of the Propeller PWM is on line P7 of the propeller }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 Brk1=2 'line assignments Pwm1=Brk1+1 Dir1=Brk1+2 Dir2=Brk1+3 Brk2=Brk1+4 Pwm2=Brk1+5 VAR 'these are the variables we will use. long stack2[35] 'space for Cog_LCD long stack3[35] 'space for Cog MoveStepper byte Pcount 'potentiometer reading. word divider 'divides clkfreq for delays byte servopos 'servo position OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main Cog Cognew(MoveStepper,@Stack3) Cognew(cog_LCD, @stack2) 'start a new Cog for the LCD servopos:=32 'any non 0 OK repeat 'this main Cog's main loop pcount:=UTIL.Read3202_0/16 'get the pot reading from the utilities repeat 8 'do 8 at at ime to speed thing up MoveStepper 'move motor Pub Cog_LCD 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Target =" )) 'Potentiometer position ID LCD.PRINT_DEC(pcount) 'print the pot reading LCD.SPACE(5) 'erase over old data LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Position=" )) 'Potentiometer position ID LCD.PRINT_DEC(servoPos) 'print the pot reading LCD.SPACE(5) 'erase over old data Pub MoveStepper 'stepper move routine dira[Brk1..Pwm2]~~ 'set at outputs outa[Brk1..Pwm2]~~ 'set high divider:=750 'max acceptable divider case servopos-pcount 'this is the error in the position -1..-255: 'neg error move to + direction outa[Brk1..Pwm2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' servoPos:=servoPos+1 0: 'no error so do nothing 1..255: 'pos error so move in- direction outa[Brk1..Pwm2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[Brk1..Pwm2]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' servoPos:=servoPos-1 {{10 Sep 09 Harprit Sandhu StepBackForthPot.spin Propeller Tool Ver 1.2.6 Chapter 26 Program 8 RUNNING A STEPPER MOTOR FROM A POTENTIOMETER MOVES BACK AND FORTH Po1 1 controls distance Pot 2 controls max speed. Xavien amplifier lines are same as before Coil #1 Brake is on line P2 of the propeller PWM is on line P3 of the propeller Direction is on line P4 of the propeller Coil #2 Brake is on line P5 of the Propeller Direction is on line P6 of the Propeller PWM is on line P7 of the propeller }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 Brk1=2 'line assignments Pwm1=Brk1+1 Dir1=Brk1+2 Dir2=Brk1+3 Brk2=Brk1+4 Pwm2=Brk1+5 divstt = 200 'starting speed VAR 'these are the variables we will use. long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog MoveStepper word Pcount 'potentiometer reading. word divider 'divides clkfreq for delays word divmax ' OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main Cog Cognew(MoveStepper,@Stack3) 'start new Cog for stepper moves Cognew(cog_LCD, @stack2) 'start a new Cog for the LCD repeat 'this main Cog's main loop pcount:=UTIL.Read3202_0/4 ' divmax:=100*UTIL.Read3202_1*2/82+2 'max ia 10000 Pub Cog_LCD 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Div =" )) 'Potentiometer position ID LCD.PRINT_DEC(divider) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (1,12) 'Go to 1st line 1st space LCD.PRINT_DEC(divmax) 'max division LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Dist=" )) 'Potentiometer position ID LCD.PRINT_DEC(pcount) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,12) 'Go to 1st line 1st space LCD.PRINT(STRING("Max")) 'max division LCD.SPACE(2) 'erase over old data PUB MoveStepper dira[BRK1..PWM2]~~ outa[BRK1..PWM2]~~ divider:=divstt repeat repeat pcount divider:=divider*divstt/(divstt-10) if divider>divmax divider:=divmax 'BPD DBP B=Brake,P=PWM,D=direction. outa[BRK1..PWM2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' divider:=divstt waitcnt(clkfreq/3+cnt) repeat pcount divider:=divider*divstt/(divstt-10) if divider>divmax divider:=divmax outa[BRK1..PWM2]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%100_001 'off on waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[BRK1..PWM2]:=%100_101 'off rev waitcnt(clkfreq/divider+cnt) ' divider:=divstt waitcnt(clkfreq/3+cnt) {{24 Sep 09 Harprit Sandhu StepFromPot.spin Propeller Tool Ver. 1.2.6 Chapter 26 Program 9 Running a stepper motor from a potentiometer Moves back and forth a variable distance Max speed fixed but can be changed at divmax constant Control distance moved with the potentiometer. Finished program This program allows you to control the distance moved by a STEPPER motor from a potentiometer as it moves back and forth automatically The number of steps it goes up and down is determined by the pot and is initially set for a maximum move of ~100 turns for a motor with 100 steps per revolution. (which I was using). Display shows the divider value used and Pot reading Xavien amplifier lines Coil #1 Brake is on line P2 of the propeller PWM is on line P3 of the propeller Direction is on line P4 of the propeller Coil #2 Brake is on line P5 of the Propeller Direction is on line P6 of the Propeller PWM is on line P7 of the propeller }} CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ =5_000_000 divmax =8000 'the higher this is the faster the speed divstart =200 'starting speed divDecrement =20 'rate at which speed changes VAR 'these are the variables we will use. long stack1[35] 'space for Cog_LCD long stack2[35] 'space for Cog MoveStepper word Pcount 'potentiometer reading. word divider 'divides clkfreq for delays OBJ 'These are the methods we will need LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods PUB Go 'main Cog Cognew(cog_LCD, @stack1) 'start a new Cog for the LCD Cognew(MoveStepper,@Stack2) 'start new Cog for stepper moves repeat 'this is main Cogs main loop pcount:=UTIL.read3202_0/4+1 'get the pot reading from the utilities PRI Cog_LCD 'set up and run the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Div =" )) 'dividing value LCD.PRINT_DEC(divider) 'print valoue LCD.SPACE(5) 'erase over old data LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Dist=" )) 'Distance moved LCD.PRINT_DEC(pcount) 'print value LCD.SPACE(5) 'erase over old data PRI MoveStepper ' dira[2..7]~~ 'all outputs outa[2..7]~~ 'all high divider:=divstart 'set starting point for div repeat 'outer loop repeat pcount 'move loop, forward divider:=divider*divstart/(divstart-divDecrement) if divider>divmax 'check div divider:=divmax 'clamp div outa[2..7]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_101 'off on waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_001 'off rev waitcnt(clkfreq/divider+cnt) ' divider:=divstart 'reset divider waitcnt(clkfreq/8+cnt) repeat pcount 'move loop, backwards divider:=divider*divstart/(divstart-divDecrement) if divider>divmax 'check div divider:=divmax 'clamp div outa[2..7]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_001 'off on waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_101 'off rev waitcnt(clkfreq/divider+cnt) divider:=divstart 'reset divider waitcnt(clkfreq/8+cnt) {{4 Sep 09 Harprit Sandhu MotorHoldPos.Spin Propeller Tool Version 1.2.6 Chapter 27 Program 01, 02, 03 depending on gain algorithm in use This program holds and encoded motor at the starting position. If you disturb the motor it will return to its initial position. You may have to adjust the gain variable for your particular motor You adjust it with POT1. Low values are needed or the motor oscillates Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer read through MCP3202 at P18..P21 LCD on the usual P12..P18 standard. Set Up. Revisions OCT 29 08 Revisions to make variable universal added software runaway IF on motor direction DEC 24 09 Changed to 3202 pots. Uses PotOne }} OBJ Encoder : "Quadrature Encoder" 'for encoder readings LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 MotorRev =1 'set this to 0 to reverse a runaway motor 'set to 1 for normal operations. 'You can also fix this runaway by reversing 'the encoder leads S1 and S2. BRK =2 'Connections to the amplifier PWM =BRK+1 'next line DIR =BRK+2 'next line VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long Pulswidth 'pulse width long PresPosition 'Present Position long TargetPosition 'Target Position long PositionError 'Positional errro long MinGain 'Minimum gain long Gain 'Actual gain used long MaxGain 'Maxim gain permitted long Index 'Countin ginded word Integ 'Integration value word PotOne 'Potentiometer reading PUB Go cognew(Cog_LCD, @stack2) cognew(Cog_SetMotPower, @stack3) cognew(Cog_RunMotor(PWM), @Stack4) cognew(Cog_FigGain, @stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position MaxGain:=2000 'Maxim gain MinGain:=100 'Minimum gain repeat PotOne:=UTIL.Read3202_0 'Read pot PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Err=" )) 'Error id LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(gain) 'print the gain LCD.SPACE(2) 'erase over old data LCD.POSITION (1,11) 'Go to 2nd line 1st space LCD.PRINT(STRING("Integ")) 'integrated value LCD.SPACE(1) 'set position for cursor LCD.POSITION (2,11) 'Go to 2nd line 1st space LCD.PRINT_DEC(Integ) 'print the integ LCD.SPACE(2) 'erase over old data PUB Cog_SetMotPower dira[BRK..DIR]~~ 'These pins control the motor amp TargetPosition:=0 'we want to stay where we are outa[BRK]~ 'turn off the amp brake repeat 'loop PresPosition:=pos[0] 'reads the encoder position PositionError:=TargetPosition-PresPosition case PositionError 'decision variable -1_000_000..-1: 'range if MotorRev 'negative range outa[DIR]~~ 'move positive else 'decide outa[DIR]~ 'move negative PULSWIDTH:=gain*244/10 'set gain -0..0 : 'range for stopping PULSWIDTH:=0 'gain is set to 0 1..1_000_000: 'range if MotorRev 'positive range outa[DIR]~ 'move negative else 'decide outa[DIR]~~ 'move positive PULSWIDTH:=gain*244/10 'set gain PUB Cog_RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line dira[BRK..DIR]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin# here frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with pulsewidth=0 WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength PRI Cog_FigGain 'The Cog we are playing with repeat 'loop gain:=PotOne 'how we define gain here {{EXERCISE: Play with the equation on the last line to see what happens to the motor response. Turn power to motor off and then turn motor by hand and watch what the LCD shows and look at PWM line P3 to see what the power to the motor does while you turn POT1 We will be using this set up a lot so leave it all hooked up }} {{4 Sep 09 Harprit Sandhu MotorHoldPotPos.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 01 This program moves the encoded motor to a position controlled by a potentiometer. Range is 4095 encoder counts. This makes a servo like an R/C hobby servo only much much more powerful. You may have to adjust the gain variable for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer 3202 P19..P22 LCD on the usual P12..P18 Revisions Oct 09 08 Revisions to make variables universal Added software runaway fin on motor direction Dec 24 09 Changed over to 4095 pots }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 MotorRev =1 'set this to 0 to reverse a runaway motor 'set to 1 for normal operations. 'You can also fix this runaway by reversing 'encoder leads. BRK =2 PWM =BRK+1 DIR =BRK+2 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long Pulswidth ' long PresPosition ' long initPosition ' long TargetPosition ' long PositionError ' long MinGain ' long Gain ' long MaxGain ' long Index ' word Integ ' word PotOne ' PUB Go cognew(Cog_LCD, @stack2) cognew(Cog_SetMotPower, @stack3) cognew(Cog_RunMotor(PWM), @Stack4) cognew(Cog_FigGain, @stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position MaxGain:=2000 MinGain:=100 repeat PotOne:=UTIL.Read3202_0 PRI cog_LCD 'manage the LCD pulswidth:=89 LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Err=" )) 'Error LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(gain) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (1,11) 'Go to 2nd line 1st space LCD.PRINT(STRING("Integ")) LCD.SPACE(1) 'set position for cursor LCD.POSITION (2,11) 'Go to 2nd line 1st space LCD.PRINT_DEC(Integ) 'print the index LCD.SPACE(2) 'erase over old data PUB Cog_SetMotPower dira[BRK..DIR]~~ 'These pins control the motor amp outa[BRK]~ 'turn off the amp brake repeat 'loop PresPosition:=pos[0] 'reads the encoder position TargetPosition:=InitPosition+PotOne PositionError:=TargetPosition-PresPosition case PositionError 'decisions variable -1000000..-2: if MotorRev 'negative range outa[DIR]~~ 'move positive else outa[DIR]~ 'move negative PULSWIDTH:=gain*244/10 'set gain -1..0 : 'range for stopping PULSWIDTH:=0 'gain is set to 0 1..1000000: if MotorRev 'positive range outa[DIR]~ 'move negative else outa[DIR]~~ 'move positive PULSWIDTH:=gain*244/10 'set gain PUB Cog_RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[BRK..DIR]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin# here frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with pulsewidth=0 WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength PRI Cog_FigGain repeat 'loop if ||PositionError=<1 'if no error ‘ Integ:=0 'set the variables to zero Index:=0 'set the variables to zero Else 'Otherwise index:=index+1 'increment the index counter If index==5 'when it reaches set value integ:=integ+1 'increase the integrating function index:=0 'and reset the index to 0 if integ > 2000 'set limit on integrated gain integ:=2000 'clamp value gain:=8+||positionError+integ 'add it all up for the gain. gain:=gain <# MaxGain 'gain must be less than MaxGain {{EXERCISES: Play with the equation on the last few line to see what happens to the motor response to the error signal. Adjust the TargetPosition:=InitPosition+PotOnne line to see what happens Work on making the response faster. There is a delay right now. How do you handle the overshoot when the gain has to increase real fast? Disconnect power to motor and turn shaft and watch the LCD and the oscilloscope to see how the gain changes as the error changes. This is very instructive and very important to understand well. }} {{4 Sep 09 Harprit Sandhu MotorHoldPotSpd.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 04 This program controls the speed of the motor from a potentiometer. You may have to adjust the gain variable for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P12..P18 Revisions Oct 09 08 Revisions to make variables universal Added software runaway fin on motor direction Dec 24 09 Changed over to 4095 pots }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 MotorRev =1 'set this to 0 to reverse a runaway motor 'set to 1 for normal operations. 'You can also fix this runaway by reversing 'encoder leads. BRK =2 PWM =BRK+1 DIR =BRK+2 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long Pulswidth ' long PresPosition ' long initPosition long TargetPosition ' long PositionError ' long MinGain ' long Gain ' long MaxGain ' long Index ' word Integ ' word PotOne ' PUB Go cognew(Cog_LCD, @stack2) cognew(Cog_SetMotPower, @stack3) cognew(Cog_RunMotor(PWM), @Stack4) cognew(Cog_FigGain, @stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position MaxGain:=2000 MinGain:=100 TargetPosition:=0 'we want to stay where we are repeat PotOne:=UTIL.Read3202_0 PRI cog_LCD 'manage the LCD pulswidth:=89 LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Err=" )) 'Error LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(gain) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (1,11) 'Go to 2nd line 1st space LCD.PRINT(STRING("Integ")) LCD.SPACE(1) 'set position for cursor LCD.POSITION (2,11) 'Go to 2nd line 1st space LCD.PRINT_DEC(Integ) 'print the index LCD.SPACE(2) 'erase over old data PUB Cog_SetMotPower dira[BRK..DIR]~~ 'These pins control the motor amp outa[BRK]~ 'turn off the amp brake repeat 'loop PresPosition:=pos[0] 'reads the encoder position TargetPosition:=TargetPosition+PotOne/256/3 PositionError:=TargetPosition-PresPosition case PositionError 'decision variable -1_000_000..-1: if MotorRev 'negative range outa[DIR]~~ 'move positive else outa[DIR]~ 'move negative PULSWIDTH:=gain*244/10 'set gain -0..0 : 'range for stopping PULSWIDTH:=0 'gain is set to 0 1..1_000_000: if MotorRev 'positive range outa[DIR]~ 'move negative else outa[DIR]~~ 'move positive PULSWIDTH:=gain*244/10 'set gain PUB Cog_RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[BRK..DIR]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin# here frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with pulsewidth=0 WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength PRI Cog_FigGain repeat 'loop if ||PositionError=<1 'if no error ‘ Integ:=0 'set the variables to zero Index:=0 'set the variables to zero Else 'Otherwise index:=index+1 'increment the index counter If index==5 'when it reaches set value integ:=integ+1 'increase the integrating function index:=0 'and reset the index to 0 if integ > 2000 'set limit on integrated gain integ:=2000 'clamp value gain:=8+||positionError+integ/4 'add it all up for the gain. gain:=gain <# MaxGain 'gain must be less than MaxGain {{EXERCISES: Play with the equation on the last few line to see what happens to the motor response to the error signal. Adjust the TargetPosition:=TargetPosition+PotOne line to see what happens Work on making the response faster. There is a delay right now. How do you handle the overshoot when the gain has to increase real fast? Disconnect power to motor and turn shaft and watch the LCD and the oscilloscope to see how the gain changes as the error changes. This is very instructive and very important to understand well. }} {{4 Sep 09 Harprit Sandhu HoldMotorPotSpd.Spin Propeller Tool Version 1.2.6 Chapter 28sProgram 05 This program controls the speed of the motor from a potentiometer. You may have to adjust the gain variable for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P12..P18 Revisions Oct 09 08 Revisions to make variables universal Added software runaway fin on motor direction Dec 24 09 Changed over to 4095 pots }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 MotorRev =1 'set this to 0 to reverse a runaway motor 'set to 1 for normal operations. 'You can also fix this runaway by reversing 'encoder leads. BRK =2 PWM =BRK+1 DIR =BRK+2 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long Pulswidth ' long PresPosition ' long initPosition long TargetPosition ' long PositionError ' long MinGain ' long Gain ' long MaxGain ' long Index ' word Integ ' word PotOne ' PUB Go cognew(Cog_LCD, @stack2) cognew(Cog_SetMotPower, @stack3) cognew(Cog_RunMotor(PWM), @Stack4) cognew(Cog_FigGain, @stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position MaxGain:=2000 MinGain:=100 TargetPosition:=0 'we want to stay where we are repeat PotOne:=UTIL.Read3202_0 PRI cog_LCD 'manage the LCD pulswidth:=89 LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Err=" )) 'Error LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(gain) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (1,11) 'Go to 2nd line 1st space LCD.PRINT(STRING("Integ")) LCD.SPACE(1) 'set position for cursor LCD.POSITION (2,11) 'Go to 2nd line 1st space LCD.PRINT_DEC(Integ) 'print the index LCD.SPACE(2) 'erase over old data PUB Cog_SetMotPower dira[BRK..DIR]~~ 'These pins control the motor amp outa[BRK]~ 'turn off the amp brake repeat 'loop PresPosition:=pos[0] 'reads the encoder position TargetPosition:=TargetPosition+PotOne/256/3 PositionError:=TargetPosition-PresPosition case PositionError 'decision variable -1_000_000..-1: if MotorRev 'negative range outa[DIR]~~ 'move positive else outa[DIR]~ 'move negative PULSWIDTH:=gain*244/10 'set gain -0..0 : 'range for stopping PULSWIDTH:=0 'gain is set to 0 1..1_000_000: if MotorRev 'positive range outa[DIR]~ 'move negative else outa[DIR]~~ 'move positive PULSWIDTH:=gain*244/10 'set gain PUB Cog_RunMotor(Pin)|Cycle_time,period 'subroutine to toggle the output line, set dira[BRK..DIR]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin# here frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with pulsewidth=0 Cycle_time:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time PRI Cog_FigGain repeat 'loop if ||PositionError=<1 'if no error ‘ Integ:=0 'set the variables to zero Index:=0 'set the variables to zero Else 'Otherwise index:=index+1 'increment the index counter If index==5 'when it reaches set value integ:=integ+1 'increase the integrating function index:=0 'and reset the index to 0 if integ > 2000 'set limit on integrated gain integ:=2000 'clamp value gain:=8+||positionError+integ/4 'add it all up for the gain. gain:=gain <# MaxGain 'gain must be less than MaxGain {{EXERCISES: Play with the equation on the last few line to see what happens to the motor response to the error signal. Adjust the TargetPosition:=TargetPosition+PotOne line to see what happens Work on making the response faster. There is a delay right now. How do you handle the overshoot when the gain has to increase real fast? Disconnect power to motor and turn shaft and watch the LCD and the oscilloscope to see how the gain changes as the error changes. This is very instructive and very important to understand well. }} {{14 Sep 09 Harprit Sandhu MotorHoldPotSpdDir.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 6 This program runs the motor back or forth at a speed and direction as controlled by the potentiometer. You may have to adjust the gain variable for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P12..P18 Revisions }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods VAR long Pos[3] 'Create buffer for two encoders 'plus room for delta position support of 1st encoder) long stack2[35] 'space for Cog long stack3[35] 'space for Cog long stack4[35] 'space for Cog word pcount ' long pulswidth ' word dcount CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 PotMax = 100 'The maximum power to the motor OUT OF 255 PotMin = 0 'The minimum power to the motor OUT OF 255 AmpBrk = 2 AmpPWM = AmpBrk+1 AmpDir = AmpBrk+2 PUB Go cognew(cog_LCD, @stack2) 'start a new cog cognew(SetMotorPower, @stack3) 'start a new cog cognew(RunMotor(AmpPWM),@Stack4) 'start a new cog Encoder.Start(0, 1, 0, @Pos) 'read encoder dira[AmpBrk]~~ 'make output outa[AmpBrk]~ 'turn brake off PUB SetMotorPower dira[AmpDir]~~ pos[0]:=0 repeat pcount:=UTIL.Read3202_0/16 'get the pot reading from the utilities case pcount 'depends on pcount 0..127: 'check for center position outa[AmpDir]~ 'forward direction set pcount:=(127-pcount)*2 'set center and double the 127 to get near 255 128..129: 'zero position pcount:=0 'clamp to 0 130..255: 'or outa[AmpDir]~~ 'reverse direction pcount:=(pcount-128)*2 'set center and double the 127 to get near 255 if pcountPotMax 'check Max value pcount:=Potmax 'clamp to Max value PulsWidth:=pcount*450 'multiply reading to get higher count needed dcount:=pcount PRI cog_LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("EncCnt=" )) 'Potentiometer position ID LCD.PRINT_DEC(Pos[0]) 'print the pot reading LCD.SPACE(3) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Pot =" )) 'Potentiometer position ID LCD.PRINT_DEC(dcount) 'print the pot reading LCD.SPACE(3) 'erase over old data PUB RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[2..4]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with position=0 WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength {{04 Nov 09 Harprit Sandhu MotorBckForPotGain.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 7 This program runs the motor back and forth a while you vary the gain and distance moved with two potentiometers. Pot1 controls the distance and Pot2 controls the gain. How we control the gain is determined by the method that sets the gain at the bottom of the programs We will use the information gained here to design the equations to set the gain to make the move as fast as possible without overshoot. You may have to adjust the parameters for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P8..P18 }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long stack6[25] 'space for Cog_Start long stack7[25] 'space for readpots long pulswidth ' long PresentPosition ' long TargetPosition ' long PositionError ' long gain ' long dgain 'displayed gain word PotReading ' word startFlag ' long startPosition ' long distance ' long pot1 ' long Pot2 ' PUB Go cognew(cog_LCD, @stack2) cognew(SetMotorPower, @stack3) cognew(RunMotor(3),@Stack4) cognew(figureGain, @stack5) cognew(StrtFlag, @stack6) cognew(ReadPots, @stack7) Encoder.Start(0, 1, 0, @Pos) 'Reads the encoder position startPosition:=Pos[0] 'position read distance:=42*0 'number of 1/4th revs is 8 for 1 rev repeat targetPosition:=StartPosition+distance waitcnt(24_000+cnt) repeat while startFlag==0 {The start flag is needed to make sure that one instruction gets done before the nexst instructions starts. This is managed with the start flag. Try eliminating these instructions to see what happens. Is there a better way to manage this. As long as the start flag is 0 the program holds at this line. It took me a while to get this one figured out! } waitcnt(2_000_000+cnt) targetPosition:=startPosition waitcnt(24_000+cnt) repeat while startFlag==0 waitcnt(2_000_000+cnt) PRI SetMotorPower dira[2..4]~~ 'These pins control the motor amp repeat 'loop PresentPosition:=pos[0] 'read the encoder position PositionError:=TargetPosition-PresentPosition case PositionError 'decision variable -100_000_000..-2: 'negative range outa[4]~~ 'move in position direction PULSWIDTH:=gain*450 'set gain -1..1 : 'range for stopping PULSWIDTH:=0*450 'gain is 0 2..100_000_000: 'positive range OUTA[4]~ 'move in negative direction PULSWIDTH:=gain*450 'set gain PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Er=" )) 'Error LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (1,10) 'Go to 1st line 1st space LCD.PRINT_DEC(pot1) 'print error LCD.SPACE(2) 'erase over old data LCD.POSITION (1,14) 'Go to 1st line 1st space LCD.PRINT_DEC(pot2) 'erase over old data LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(dgain) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,10) 'Go to 2nd line 1st space LCD.PRINT(STRING("Start=" )) 'Potentiometer LCD.PRINT_DEC(StartFlag) 'print the pot reading distance:=pot1*21 PRI RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[2..4]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin=3 frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with position=0 WaveLength:=clkfreq/100 'Set the time for the wave L to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for end of wavelength PRI StrtFlag 'used to determine if motor completed move repeat if ||PositionError<2 'is move almost done startFlag:=1 'if it is its ok to start else '1f not startFlag:=0 'do not start next move PUB figureGain 'power to motor repeat 'loop case ||PositionError 'pot is NOT READ 0..20:gain:=pot2/10 'in these comparisons 21..80:gain:=pot2/4 'the gain is set by the 81..200:gain:=pot2/2 'amount of the error 101..80000:gain:=pot2 'in the position. gain#>=8 dgain:=gain PRI Readpots repeat pot1:=UTIL.Read3202_0/16 pot2:=UTIL.Read3202_1/16 {{14 Sep 09 Harprit Sandhu MotorBakForPlayGain.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 8 This program runs the motor back and forth a fixed number of counts while you can vary the gain with the equations at the bottom of the programs to see what happens to the motor dampening function. We will use the information gained here to design the equations to set the gain to make the move as fast as possible without overshoot. You may have to adjust the parameters for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P8..P18 }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 distance =168*8 'full revs VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long stack6[25] 'space for Cog_Start long pulswidth ' long PresentPosition ' long gain ' long TargetPosition ' long PositionError ' byte startFlag ' long startPosition ' PUB Go cognew(cog_LCD, @stack2) cognew(SetMotorPower, @stack3) cognew(RunMotor(3),@Stack4) cognew(figureGain, @stack5) cognew(StaartFlag, @stack6) Encoder.Start(0, 1, 0, @Pos) 'Reads the encoder position startPosition:=Pos[0] repeat targetPosition:=StartPosition+distance waitcnt(10000+cnt) repeat while startFlag==0 waitcnt(2_000_000+cnt) targetPosition:=startPosition waitcnt(10000+cnt) repeat while startFlag==0 waitcnt(2_000_000+cnt) PUB SetMotorPower dira[2..4]~~ 'These pins control the motor amp repeat 'loop PresentPosition:=pos[0] 'read the encoder position PositionError:=TargetPosition-PresentPosition case PositionError 'decision variable -100_000_000..-2: 'negative range outa[4]~~ 'move in position direction PULSWIDTH:=gain*450 'set gain -1..1 : 'range for stopping PULSWIDTH:=0*450 'gain is 0 2..100_000_000: 'positive range OUTA[4]~ 'move in negative direction PULSWIDTH:=gain*450 'set gain PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Err=" )) 'Error LCD.PRINT_DEC(PositionError) 'print error LCD.SPACE(5) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'gain LCD.PRINT_DEC(gain) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,10) 'Go to 2nd line 1st space LCD.PRINT(STRING("Start=" )) 'Flag LCD.PRINT_DEC(StartFlag) 'print flag status PUB RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[2..4]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with position=0 WaveLength:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength PUB figureGain 'power to motor 0-255 repeat 'loop case ||PositionError 'pot is NOT READ 1..20:gain:=6 'in these comparisons 21..80:gain:=10 'the gain is set by the 81..200:gain:=40 'amount of the error 101..80000:gain:=80 'in the position. PRI StaartFlag 'The start flag is used to inhibit the execution of repeat 'the next move to make sure that each move executes if ||PositionError<2 'fully. Then the wait command lets you see that the startFlag:=1 'motor actually stopped before proceeding to reversing else 'the motor. See main Cog above for more. startFlag:=0 {{14 Sep 09 Harprit Sandhu MotorPotSpeedTable.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 9 This program controls speed of motor from the pot. Displays speed and pot setting You may have to adjust the gain variable for your particular motor Connections are Encoder 1 P0 Encoder 2 P1 Encoder 3 5 Volts Encoder 4 Ground Also need power and ground for encoder connected Amplifier brake P2 Xavien 1 Amplifier PWM P3 Xavien 2 Amplifier direction P4 Xavien 3 Potentiometer P19 LCD on the usual P8..P18 The values read are based on a 13.5 volts power supply for the motor. (Table in book) }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long pulswidth ' long speed ' long start ' long end ' PUB Go cognew(cog_LCD, @stack2) cognew(SetMotorPower, @stack3) cognew(RunMotor(3),@Stack4) cognew(FigureCounts, @stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position PUB SetMotorPower dira[2..4]~~ 'These pins control the motor amp repeat 'loop PulsWidth:=Util.Read3202_0/16 'read the 4095 pot position to a byte PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Speed=" )) 'Error LCD.PRINT_DEC(Speed) 'print error LCD.SPACE(3) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain =" )) 'Potentiometer LCD.PRINT_DEC(pulswidth) 'print the pot reading LCD.SPACE(3) 'erase over old data PUB RunMotor(Pin)|Cycle_time,period 'subroutine to toggle the output line, set dira[2..4]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with position=0 Cycle_time:=clkfreq/100 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth*24*16 'Send a high pulse for Pulsewidth counts period:=period+Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time PUB FigureCounts 'encoder counts repeat 'loop start:=Pos[0] 'read encoder waitcnt(clkfreq+cnt) 'pause 1 sec end:=Pos[0] 'read encoder speed:=(end-start) 'counts moved {{ Chapter 28 Prog 10 }} PUB FigureGain 'power to motor repeat 'loop Case time 'base the gain on the time segment number 0..50: 'first 50 segments gain:=20 'slow speed 51..150: 'next 100 segments gain:=100 'fast speed 151..200: 'next 50 segments gain:=20 'slow speed 201..300: 'next 100 segments gain:=0 'Gain=0 means stop for a while waitcnt(120_000+cnt) 'define length of each time segment as 0.1 secs time:=time+1 'add to time segment number if time==300 'check top time value time:=0 'reset time counter {{4 Sep 09 Harprit Sandhu MotorSloFstSlo.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 11 This program moves the motor in a slow, fast ,slow, stop sequence to demonstrate the control of the speed over a period of equal time segments. This is an absolutely minimal ramping demonstration. Only two speeds are used. This could be expanded to a very complicated algorithm with lots of gains and speed specifications. We are not using the encoder or the potentiometers in this program. Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Potentiometer P19 LCD on the usual P12..P18 4 bit mode Revisions }} OBJ LCD : "LCDRoutines4" 'for the LCD methods CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 AmpBrake =2 AmpPWM =3 MotorDir =4 VAR long Pos[3] 'Create buffer for encoder long stack2[25] 'space for Cog_LCD long stack3[25] 'space for Cog_SetMotorPower long stack4[25] 'space for Cog_RunMotor long stack5[25] 'space for Cog_FigureGain long gain ' long time long pulswidth PUB Go cognew(cog_LCD, @stack2) cognew(SetMotorPower, @stack3) cognew(RunMotor(AmpPWM),@Stack4) cognew(FigureGain, @stack5) repeat PRI cog_LCD 'manage the LCD LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Time=" )) 'Error LCD.PRINT_DEC(time) 'print the pot reading LCD.SPACE(2) 'erase over old data LCD.POSITION (2,1) 'Go to 2nd line 1st space LCD.PRINT(STRING("Gain=" )) 'Potentiometer LCD.PRINT_DEC(gain) 'print the pot reading LCD.SPACE(2) 'erase over old data PUB SetMotorPower dira[AmpBrake..MotorDir]~~ 'These pins control the motor amp outa[AmpBrake]~ 'turn off the amp brake repeat 'loop outa[MotorDir]~ 'move negative PULSWIDTH:=gain*450 'set gain PUB RunMotor(Pin)|WaveLength,period 'subroutine to toggle the output line, set dira[AmpBrake..MotorDir]~~ 'gain access to these three amplifier lines ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin# here frqa:=1 'Set this counter's frqa value to 1 PulsWidth:=0 'Start with pulsewidth=0 WaveLength:=clkfreq/50 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-PulsWidth 'Send a high pulse for Pulsewidth counts period:=period+WaveLength 'Calculate wave length waitcnt(period) 'Wait for the wavelength PUB FigureGain 'power to motor repeat 'loop Case time 'base the gain on the time segment number 0..100: 'first 50 segments gain:=30 'slow speed 101..200: 'next 100 segments gain:=200 'fast speed 201..300: 'next 50 segments gain:=30 'slow speed 301..399: 'next 100 segments gain:=0 'Gain=0 means stop for a while waitcnt(120_000+cnt) 'define length of each time segment as 0.1 secs time:=time+1 'add to time segment number if time==400 'check top time value for reset waitcnt(clkfreq/4+cnt) 'wait to look at LCD time:=0 'reset time counter {{14 Sep 09 Harprit Sandhu MotorPositionRC.Spin Propeller Tool Version 1.2.6 Chapter 28 Program 14 This program Positions the DC motor from a hobby R/C transmitter just like it would a R/C hobby servo, but many revs You may have to adjust the parameters for your particular motor Connections are Amplifier brake P2 Amplifier PWM P3 Amplifier direction P4 Radio signal in P24 LCD on the usual P8..P18 }} OBJ Encoder : "Quadrature Encoder" LCD : "LCDRoutines4" 'for the LCD methods UTIL : "Utilities" 'for general methods CON _CLKMODE=XTAL1+ PLL2X 'The system clock spec _XINFREQ = 5_000_000 BRK =2 PWM =BRK+1 DIR =BRK+2 PulseIn =24 VAR long Pos[3] 'Create buffer for encoder long stack2[35] 'space for Cog_LCD long stack3[35] 'space for Cog_SetMotorPower long stack4[35] 'space for Cog_RunMotor long stack5[35] 'space for Cog_Encoder long startcycle ' long endPulse ' long endCycle ' long CycleLen ' long PulseLen ' long pulswidth long freq ' long MotPwr ' long PresPos long TargPos PUB Go cognew(cog_LCD, @stack2) cognew(SetMotorPower, @stack3) cognew(PosMotor(3), @Stack4) cognew(Enco, @Stack5) Encoder.Start(0, 1, 0, @Pos) 'Read the encoder position Dira[PulseIn]~ repeat waitpeq(|L OUTA[DataBit7..DataBit4] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data PUB SEND_INSTRUCTION2 (D_DATA) 'set up for writing instructions {{Sends a character to the LCD no variables are used}} CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA>>4 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to xfer the data PUB SEND_CHAR (D_CHAR) 'set up for writing to the display {{Sends a single character to the LCD in two halves}} CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to send data OUTA[RegSelect] := 1 'Set up to send data OUTA[Enable] := 1 'go high OUTA[DataBit7..DataBit4] := D_CHAR>>4 'Send high 4 bits OUTA[Enable] := 0 'Toggle the bit H>L OUTA[Enable] := 1 'go high again OUTA[DataBit7..DataBit4] :=D_CHAR 'send low 4 bits OUTA[Enable] := 0 'Toggle the bit H>L PUB PRINT (the_line) {{Print a line of characters to the LCD uses variables index and temp}} 'This routine handles more than one Char at a time 'called as PRINT(string("the_line")) ' "the_line" contains the pointer to line. Line is 'because we have to point to the line 'zero terminated but we will not use that. We will 'use the string size instead. Easier to understand index:=0 'Reset the counter we are using to count chars sent repeat 'repeat for all chars in the list temp:= byte[the_line][index++] 'temp contains the char/byte pointed by index SEND_CHAR (temp) 'send the 'pointed to' char to the LCD while indexL this bit BUSY_BIT := INA[DataBit7] 'the busybit is bit 7 of the byte read 'INA is the 32 input pins on the PROP and we 'are reading data bit 7 which is on pin 15! OUTA[Enable] := 0 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit4] := %1111 'done, so set the data port back to outputs PUB PRINT_DEC (VALUE) | TEST_VALUE 'for printing values in decimal format {{Print a decimal value, whole numbers only}} IF (VALUE < 0) 'if it is a negative value -VALUE 'change it to a positive SEND_CHAR("-") 'and print a - sign on the LCD TEST_VALUE := 1_000_000_000 'we get individual digits by comparing to this 'value and then dividing by 10 to get next value REPEAT 10 'There are 10 digits maximum in our system IF (VALUE => TEST_VALUE) 'see if our number is bigger than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") 'if it is, divide to get the digit VALUE //= TEST_VALUE 'figure the next value for the next digit RESULT~~ 'result of what just did pass it on below ELSEIF (RESULT OR TEST_VALUE == 1) 'if the result was a 1 then div was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 'we divide by 10 to test for the next digit PUB PRINT_HEX (VALUE, DIGITS) 'for printing values in HEX format {{Print a Hexadecimal value}} VALUE <<= (8 - DIGITS) << 2 'you can specify up to 8 digits or FFFFFFFF max REPEAT DIGITS 'do each digit SEND_CHAR(LOOKUPZ((VALUE <-= 4) & $F : "0".."9", "A".."F")) 'use lookup table to select character ' PUB PRINT_BIN (VALUE, DIGITS) 'for printing values in BINARY format {{Print a Binary value}} VALUE <<= 32 - DIGITS '32 binary digits is the max for our sys REPEAT DIGITS 'Repeat for each digit desired SEND_CHAR((VALUE <-= 1) & 1 + "0") 'send a 1 or a 0 {{Clear screen}} PUB CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION2 (%0000_0001) 'This is the clear screen and go home command PUB HOME 'go to position 1,1. {{Go to position 1,1 Does not clear the screen}} SEND_INSTRUCTION2 (%0000_0011) 'Not cleared PUB SPACE (qty) 'Prints spaces, for between numbers {{Print spaces}} repeat (qty) PRINT(STRING(" ")) {{21 Sep 09 Harprit Sandhu Utilities.spin Propeller Tool Ver 1.2.6 Appendix Program UTILITIES Flash flashes a pin once, toggles it slowly Pause pause in milliseconds GetPotValue returns PotValue 0-255 GetPotValue2 returns PotValue 0-255 Read3202_0 reads Channel 0 on the 3202, 0-4095 Read3202_1 reads Channel 1 on the 3202, 0-4095 Since the pot readers are an important part of the utilities, they are read separately Using two methods allows you to use two different pot values one for each pot. Potentiometer connections are as follows 3202 connections 1 Chip select 2 Pot 1 xxxxxxxxxxxxxxxxx 3 Pot 2 xxxxxxxxxxxxxxxxx 4 Ground 5 Data In 6 Data out 7 Clock 8 5 Volts Prop connections from 3202 are chipSel = 19 chipClk = chipSel+1 chipDout = chipSel+2 chipDin = chipSel+3 Revisions 21 Sep 09 Set min and max for Pot readings, reduced delay div from 2920 to 2900 Displays both pots and both delays now. Using two routines to read the pots allows two pots with different values to be set used. Have to be set up. Currently they are identical. New Xtal changes made. 14 Nov 09 Added potvalue2 to read second pot. Added ReadChannel,X to read any of 2 channels from a MCP 3202 14 Nov 09 Added independent routines to read the two lines of A2D on the MCP3202. 18 May 10 Added connections comments above. Error Reporting: Please report errors to harprit.sandhu@gmail.com }} CON _CLKMODE=XTAL1 + PLL2X 'The system clock spec _XINFREQ = 5_000_000 'the oscillator frequency high =1 low =0 PotLine =19 PotLine2 =20 repval =2 repval2 =2 BitsRead =12 BitsRead2=12 BitsRead3 =12 BitsRead4=12 chipSel = 19 chipClk = chipSel+1 chipDout = chipSel+2 chipDin = chipSel+3 chipSel2 = 23 chipClk2 = chipSel2+1 chipDout2 = chipSel2+2 chipDin2 = chipSel2+3 VAR long startCnt long startCnt2 long endCount long endCount2 long delay long delay2 long PotValue long PotValue2 long ValuTotal long ValuTotal2 word PotReading1 word PotReading2 word PotReading3 word PotReading4 word DataRed OBJ 'The methods we will need LCD : "LCDRoutines4" 'for controlling the LCD PUB Go LCD.INITIALIZE_LCD 'set up the LCD repeat LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot1=")) 'Potentiometer position LCD.PRINT_DEC(PotReading1) 'print pot value LCD.SPACE(3) 'erase over old data LCD.POSITION (2,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot2=")) 'Potentiometer position LCD.PRINT_DEC(PotReading2) 'print pot value LCD.SPACE(3) 'erase over old data LCD.POSITION (3,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot3=")) 'Potentiometer position LCD.PRINT_DEC(PotReading3) 'print pot value LCD.SPACE(3) 'erase over old data LCD.POSITION (4,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot4=")) 'Potentiometer position LCD.PRINT_DEC(PotReading4) 'print pot value LCD.SPACE(3) 'erase over old data Read3202_0 'Read Pot routine Read3202_1 'Read Pot routine2 Read3202_2 'Read Pot routine3 Read3202_3 'Read Pot routine4 PUB FLASH (color) 'routine to flash an LED by color outa[color] :=high 'line that actually sets the LED high pause (200) 'wait till counter reaches this value outa[color] :=low 'line that actually sets the LED low pause (200) 'wait till counter reaches this value ' PUB PAUSE(millisecs) 'As set up here it is 1.0 millisecconds if millisecs>0 waitcnt((clkfreq/1_000)*millisecs +cnt) 'ms based on Osc freq PUB GetPotVal dira[PotLine]~~ 'set potline as output valutotal:=0 'clear total repeat repval 'repeat dira[PotLine]~~ 'set potline as output outa[PotLine]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine]~ 'make potline an input. line switches H>L startCnt:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine]~~ 'keep doing it as long as the potline is high EndCount := cnt 'read the counter at end of cycle and store delay := ((EndCount-StartCnt)-1184) 'calculate time for line to go H>L if delay>610_000 'max permitted delay delay:=610_000 'clamp delay PotValue:=(delay/2000) 'This reduces the value to 0-255 or 1 byte valutotal:=valutotal+potvalue 'figures total potvalue:=valutotal/repval 'figure average potvalue <#=255 potvalue #>=0 result:=PotValue 'figure average PUB GetPotVal2 dira[PotLine2]~~ 'set potline as output valutotal2:=0 'clear total repeat repval2 'repeat dira[PotLine2]~~ 'set potline as output outa[PotLine2]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine2]~ 'make potline an input. line switches H>L startCnt2:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine2]~~ 'keep doing it as long as the potline is high EndCount2 := cnt 'read the counter at end of cycle and store delay2:= ((EndCount2-StartCnt2)-1184) 'calculate time for line to go H>L if delay2>610_000 'max permitted delay delay2:=610_000 'clamp delay PotValue2:=(delay2/2300) 'This reduces the value to 0-255 or 1 byte valutotal2:=valutotal2+potvalue2 'figures total potvalue2:=valutotal2/repval2 'figure average potvalue2 <#=255 'clamp at 255 potvalue2 #>=0 'clamp at 0 result:=Potvalue2 'use average PUB Read3202_0 DIRA[chipSel]~~ 'osc once to set up 3202 DIRA[chipDin]~~ 'data set up to the chip DIRA[chipDout]~ 'data from the chip to the Propeller DIRA[chipClk]~~ 'oscillates to read in data DataRed:=0 'Clear out old data outa[chipSel]~~ 'Chip select has to be high to start off outa[chipSel]~ 'Go low to start process outa[chipClk]~ 'Clock needs to be low to load data outa[chipDin]~~ 'must start with Din low to set up 3202 outa[chipClk]~~ 'Clock high to read data in outa[chipClk]~ 'Low to load outa[chipDin]~~ 'High single mode outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~ 'low channel 0 outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~~ 'msbf high = MSB first outa[chipClk]~~ 'High to read outa[chipDin]~ 'making line low for rest of cycle outa[chipClk]~ 'Low to load Read the null bit, not stored outa[chipClk]~~ 'High to read repeat BitsRead 'Reads the data into DataRed in 12 steps DataRed <<= 1 'Move data by shifting left 1 bit. Ready for next bit outa[chipClk]~ 'Low to load DataRed:=DataRed+ina[chipDout] 'Xfer the data from pin chipDout outa[chipClk]~~ 'High to read outa[chipSel]~~ 'Put chip to sleep, for low power PotReading1:=DataRed 'Finished data read for display result:=dataRed PUB Read3202_1 DIRA[chipSel]~~ 'osc once to set up 3202 DIRA[chipDin]~~ 'data set up to the chip DIRA[chipDout]~ 'data from the chip to the Propeller DIRA[chipClk]~~ 'oscillates to read in data DataRed:=0 'Clear out old data outa[chipSel]~~ 'Chip select has to be high to start off outa[chipSel]~ 'Go low to start process outa[chipClk]~ 'Clock needs to be low to load data outa[chipDin]~~ 'must start with Din low to set up 3202 outa[chipClk]~~ 'Clock high to read data in outa[chipClk]~ 'Low to load outa[chipDin]~~ 'High single mode outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~~ 'high channel 1 outa[chipClk]~~ 'High to read outa[chipClk]~ 'Low to load outa[chipDin]~~ 'msbf high = MSB first outa[chipClk]~~ 'High to read outa[chipDin]~ 'making line low for rest of cycle outa[chipClk]~ 'Low to load Read the null bit, not stored outa[chipClk]~~ 'High to read repeat BitsRead2 'Reads the data into DataRed in 12 steps DataRed <<= 1 'Move data by shifting left 1 bit. Ready for next bit outa[chipClk]~ 'Low to load DataRed:=DataRed+ina[chipDout] 'Xfer the data from pin chipDout outa[chipClk]~~ 'High to read outa[chipSel]~~ 'Put chip to sleep, for low power PotReading2:=DataRed 'Finished data read for display result:=dataRed PUB Read3202_2 DIRA[chipSel2]~~ 'osc once to set up 3202 DIRA[chipDin2]~~ 'data set up to the chip DIRA[chipDout2]~ 'data from the chip to the Propeller DIRA[chipClk2]~~ 'oscillates to read in data DataRed:=0 'Clear out old data outa[chipSel2]~~ 'Chip select has to be high to start off outa[chipSel2]~ 'Go low to start process outa[chipClk2]~ 'Clock needs to be low to load data outa[chipDin2]~~ 'must start with Din low to set up 3202 outa[chipClk2]~~ 'Clock high to read data in outa[chipClk2]~ 'Low to load outa[chipDin2]~~ 'High single mode outa[chipClk2]~~ 'High to read outa[chipClk2]~ 'Low to load outa[chipDin2]~~ 'high channel 0 outa[chipClk2]~~ 'High to read outa[chipClk2]~ 'Low to load outa[chipDin2]~~ 'msbf high = MSB first outa[chipClk2]~~ 'High to read outa[chipDin2]~ 'making line low for rest of cycle outa[chipClk2]~ 'Low to load Read the null bit, not stored outa[chipClk2]~~ 'High to read repeat BitsRead3 'Reads the data into DataRed in 12 steps DataRed <<= 1 'Move data by shifting left 1 bit. Ready for next bit outa[chipClk2]~ 'Low to load DataRed:=DataRed+ina[chipDout2] 'Xfer the data from pin chipDout outa[chipClk2]~~ 'High to read outa[chipSel2]~~ 'Put chip to sleep, for low power PotReading3:=DataRed 'Finished data read for display result:=dataRed PUB Read3202_3 DIRA[chipSel2]~~ 'osc once to set up 3202 DIRA[chipDin2]~~ 'data set up to the chip DIRA[chipDout2]~ 'data from the chip to the Propeller DIRA[chipClk2]~~ 'oscillates to read in data DataRed:=0 'Clear out old data outa[chipSel2]~~ 'Chip select has to be high to start off outa[chipSel2]~ 'Go low to start process outa[chipClk2]~ 'Clock needs to be low to load data outa[chipDin2]~~ 'must start with Din low to set up 3202 outa[chipClk2]~~ 'Clock high to read data in outa[chipClk2]~ 'Low to load outa[chipDin2]~~ 'High single mode outa[chipClk2]~~ 'High to read outa[chipClk2]~ 'Low to load outa[chipDin2]~ 'low channel 1 outa[chipClk2]~~ 'High to read outa[chipClk2]~ 'Low to load outa[chipDin2]~~ 'msbf high = MSB first outa[chipClk2]~~ 'High to read outa[chipDin2]~ 'making line low for rest of cycle outa[chipClk2]~ 'Low to load Read the null bit, not stored outa[chipClk2]~~ 'High to read repeat BitsRead4 'Reads the data into DataRed in 12 steps DataRed <<= 1 'Move data by shifting left 1 bit. Ready for next bit outa[chipClk2]~ 'Low to load DataRed:=DataRed+ina[chipDout2] 'Xfer the data from pin chipDout outa[chipClk2]~~ 'High to read outa[chipSel2]~~ 'Put chip to sleep, for low power PotReading4:=DataRed 'Finished data read for display result:=dataRed