|
This Project saves Servo Position Data to an external EEPROM and plays it back to syncronized
sound. The sound is played through a modified sound recorder from Radio Shack.
The three servos can be recorded while the sound is being played.
Selection of the servo to record is done with a resistor on pins 0,1 and 2 of PortC.
Playback uses pin 3 and the sound is controlled on pin 4 of PortC
I2C protocols allow for easy transfer of information to an external device.
the syntax in as follows
I2COUT Control, Address, ( Value{,Value})
I2COUT being the command
Control being the chip setup info.
1xxxxxxx, 16bit chip - 0xxxxxxxx, 8bit chip.
x1010xxx, chip specific. Look it up, the 24LC256 was 1010.
xxxxxXXX, device select bits.
Address being the memory location.
Values being the variable your playing with.
I2CIN is pretty much the same but reversed in function.
I2CIN Control, Address, Var{,Var}
One important consideration, it takes about 10ms for it to occur. Thus the pause after.
This project Requires the modification of the include file "PBL.INC".
It should be located in your compilers directory. Since I wanted to do
both analog and digital signals on PortA, I decided it would be best to
relocate the I2C protocols from the standard pins 0 and 1 to pins 4 and 5.
This way I could use pin 0 as an analog input.
Doing this is really quite easy. Simply open up pbl.inc with any text editor.
Scroll down to the I2C stuff (as shown)

Then change the port pins to whatever you want. In this case 4 and 5.

|
'******** Saving servo positions to an ***************
'************** External EEPROM ***********************
'******************************************************
'@ Platform: PicBasic
'@ Version: 1.0
'@ Author: Brian Patton (brianp@robodyssey.com)
' Robodyssey Systems, LLC. - www.robodyssey.com
'@ Last Updated: Feb, 20, 2004
'******************************************************
' This Program uses the 16F876
'*********Materials**************************************
' 1 Robodyssey PicPac MotherBoard
' 1 Pic16F876 or similar
' 1 Voltage Divider board
' 1 Variable Resistor (pot)or photoresistor
' 1 10k resistor to act as switch
' 1 I2C EEPROM (I used the 24LC256)
' PicBasic Compiler and a programmer
'******************************************************
' Register Locations
Symbol TRISA = $85 ' Register Location of TRISA
Symbol ADCON0 = $1F ' Register location of ADCON0
Symbol ADCON1 = $9F ' Register Location of ADCON1
Symbol ADRESH = $1E ' Register Location of ADRESH
Symbol TRISC = $87 ' Register Location of TRISC
Symbol PortC = 7 ' Register Location of PortC
'***** Variables *****************************************
Symbol addr = w0 ' The bigger EEPROMs need 16 bit addresses
Symbol addr2 = w1 ' The bigger EEPROMs need 16 bit addresses
Symbol addr3 = w2
Symbol cont = %11010000 ' EEPROM control byte
Symbol RPot = b7 'Range between Min and Max
Symbol ServoPos = b8 'Pulse the servos will use
symbol Nvalue = b9 'variable to hand off to
Symbol x = b10 'just a counter
Symbol MinMax = b11
Symbol value = b12 ' Place for the data
Symbol ADcon = b13 ' storag spot for A to D functions
Symbol ServoPos2 = b14
Symbol rec = b15
Symbol Cstatus = b16 ' Check state of Port C variable
Symbol MinPot = b17 'Value for the minimum of the pot
Symbol MaxPot = b18 'Value for the maximum of the pot
Symbol ServoPos3 = b19
'***** Initiation *****************************************
Init:
Dirs = %11111111 ' Set all Port B to output
Poke ADCON1,%00000100 ' Pins 0,1 and 3 analog input. Pins 2,4 and 5 digital.
' 0xxxxxxx Sets result to Left justified
' 1xxxxxxx Sets result to Right justified
Poke TRISC, %00001111 ' Set all PortC Input
Poke PortC, %00010000 'Keep sound off till ready.
'**********Main Code Block Area***************************
Pause 1000
rec = 0
' This works by grounding resistors that hold pins high on Port c
' Grounding different pins selects playback, record 1,2 or 3.
chk1:
Peek PortC,Cstatus 'Get the status of Port C
If Cstatus = %00011111 Then chk1 'If closed then Gather Data
'If open then Recall Data
If Cstatus = %00010111 Then recall 'If closed then Gather Data
'If open then Recall Data
If Cstatus = %00011011 Then recswitch 'If closed then Gather Data
'If open then Recall Data
If Cstatus = %00011101 Then recswitch 'If closed then Gather Data
'If open then Recall Data
If Cstatus = %00011110 Then recswitch 'If closed then Gather Data
'If open then Recall Data
goto chk1
'********** Sample and store Data **************************
recswitch:
If rec = 1 Then choose 'If already done once then don't bother to do it again
rec = 1 ' Darn, Gotta calibrate the pot
Pause 1000
high 2
Poke TRISA, %00000001 'Set pin0, PortA Input
MinMax = 1 'give it some start points
Maxmod:
MaxPot = MinMax 'give it some start points
MinMod:
MinPot = MinMax 'give it some start points
for x = 1 to 20 'Give you time to turn the pot
pause 100
poke ADCON0, %11000001 'Set A/D to RC Osc, Channel 0, A/D converter ready
'xx000xxx-Chan 0(RA0), xx001xxx-Chan 1(RA1),
'xx010xxx-Chan 2(RA2), xx011xxx-Chan 3(RA3),
'xx100xxx-Chan 4(RA4), xx101xxx-Chan 5(RA5),
'xx110xxx-Chan 6(RA6), xx111xxx-Chan 7(RA7),
ADcon = %11000101 'xxxxx1xx - on, xxxxx0xx - off
Poke ADCON0,ADcon ' Turn on the conversion at Bit 2
calfin:
Pause 5
Peek ADCON0,ADcon
If ADcon = %11000101 Then calfin ' Wait for low on bit-2 of ADCON0, conversion finished
Peek ADRESH, MinMax
If MinMax > MaxPot Then MaxMod 'Collect min and max values
If MinMax < MinPot then MinMod 'Collect min and max values
next
RPot = MaxPot - MinPot 'Calculate the range
RPot = 1200/RPot 'The 1200 comes from differece of the min pulse width and max pulse width recomended by the
'Servo manufacture time 10 in 10uSec units. The 10X is to keep the answer a 8 bit integer.
'So, a servo with a rated pulse of 0.0009 to 0.0021 is 90 to 210 ten uSec units.
'That is a difference of 120 uSec units. Times 10 is 1200.
Low 2
Pause 1000
'******************************************************
'******** Choosing the rec chan. ********************************
choose:
Poke PortC, %00010000
pause 100
Peek PortC,Cstatus 'Get the status of Port C
If Cstatus = %00011101 Then Servo2 'If closed then Servo1
'If open then Servo2
If Cstatus = %00011110 Then Servo3 'If closed then Servo1
'If open then Servo2
' If neither then must be Servo1
'*******************************************************
Servo1:
Pause 1000
addr2 = 3000
Poke PortC, %00100000
For addr = 1 to 2000 'addr is a 16 bit variable
Poke ADCON0, %11000001 'Set A/D to RC Osc, Channel 0, A/D converter ready
'xx000xxx-Chan 0(RA0), xx001xxx-Chan 1(RA1),
'xx010xxx-Chan 2(RA2), xx011xxx-Chan 3(RA3),
'xx100xxx-Chan 4(RA4), xx101xxx-Chan 5(RA5),
'xx110xxx-Chan 6(RA6), xx111xxx-Chan 7(RA7),
ADcon = %11000101 'xxxxx1xx - on, xxxxx0xx - off
Poke ADCON0,ADcon ' Turn on the conversion at Bit 2
Ser1fin:
Peek ADCON0,ADcon
If ADcon = %11000101 Then Ser1fin ' Wait for low on bit-2 of ADCON0, conversion finished
Peek ADRESH,value
'************ convert value and ******************
'************ drive the Servo ********************
Nvalue = MaxPot + 10 'Hand over the value and keep it from ever becoming 0
ServoPos = Nvalue - value 'Subtract found value from the Max possible
ServoPos = ServoPos / 10 'Correct the 10x thing from above
ServoPos = ServoPos * RPot 'Multiply it by the range
ServoPos = 240 - ServoPos '210 is the longest pulse in 10uSec intervals my servo will handle
Pulsout 4, ServoPos 'Pulse the Servo
'********** Play Memory and Write New************
addr2 = addr2 + 1
I2Cin cont,addr2,ServoPos2
Pulsout 5, ServoPos2 'Pulse the Servo
I2Cout cont,addr,(ServoPos)
Pause 10 'Need time to write
Next
Poke PortC, %00010000
goto chk1
End
'*******************************************************
Servo2:
Pause 2000
addr = 1
Poke PortC, %01000000
For addr2 = 3000 to 5000 'addr is a 16 bit variable
Poke ADCON0, %11000001 'Set A/D to RC Osc, Channel 0, A/D converter ready
'xx000xxx-Chan 0(RA0), xx001xxx-Chan 1(RA1),
'xx010xxx-Chan 2(RA2), xx011xxx-Chan 3(RA3),
'xx100xxx-Chan 4(RA4), xx101xxx-Chan 5(RA5),
'xx110xxx-Chan 6(RA6), xx111xxx-Chan 7(RA7),
ADcon = %11000101 'xxxxx1xx - on, xxxxx0xx - off
Poke ADCON0,ADcon ' Turn on the conversion at Bit 2
Ser2fin:
Peek ADCON0,ADcon
If ADcon = %11000101 Then Ser2fin ' Wait for low on bit-2 of ADCON0, conversion finished
Peek ADRESH,value
'************ convert value and ******************
'************ drive the Servo ********************
Nvalue = MaxPot + 10 'Hand over the value and keep it from ever becoming 0
ServoPos2 = Nvalue - value 'Subtract found value from the Max possible
ServoPos2 = ServoPos2 / 10 'Correct the 10x thing from above
ServoPos2 = ServoPos2 * RPot 'Multiply it by the range
ServoPos2 = 240 - ServoPos2 '210 is the longest pulse in 10uSec intervals my servo will handle
Pulsout 5, ServoPos2 'Pulse the Servo
'*****************************************************
addr = addr + 1
I2Cin cont,addr,ServoPos
Pulsout 4, ServoPos 'Pulse the Servo
I2Cout cont,addr2,(ServoPos2)
Pause 10 'Need time to write
Next
Poke PortC, %00010000
goto chk1
End
'************ Servo 3 ***********************************
Servo3:
Pause 1000
addr = 1
Poke PortC, %10000000
For addr3 = 6000 to 8000 'addr is a 16 bit variable
Poke ADCON0, %11000001 'Set A/D to RC Osc, Channel 0, A/D converter ready
'xx000xxx-Chan 0(RA0), xx001xxx-Chan 1(RA1),
'xx010xxx-Chan 2(RA2), xx011xxx-Chan 3(RA3),
'xx100xxx-Chan 4(RA4), xx101xxx-Chan 5(RA5),
'xx110xxx-Chan 6(RA6), xx111xxx-Chan 7(RA7),
ADcon = %11000101 'xxxxx1xx - on, xxxxx0xx - off
Poke ADCON0,ADcon ' Turn on the conversion at Bit 2
Ser3fin:
Peek ADCON0,ADcon
If ADcon = %11000101 Then Ser3fin ' Wait for low on bit-2 of ADCON0, conversion finished
Peek ADRESH,value
'************ convert value and ******************
'************ drive the Servo ********************
Nvalue = MaxPot + 10 'Hand over the value and keep it from ever becoming 0
ServoPos3 = Nvalue - value 'Subtract found value from the Max possible
ServoPos3 = ServoPos3 / 10 'Correct the 10x thing from above
ServoPos3 = ServoPos3 * RPot 'Multiply it by the range
ServoPos3 = 240 - ServoPos3 '210 is the longest pulse in 10uSec intervals my servo will handle
Pulsout 6, ServoPos3 'Pulse the Servo
'*****************************************************
addr = addr + 1
I2Cin cont,addr,ServoPos
Pulsout 4, ServoPos 'Pulse the Servo
I2Cout cont,addr3,(ServoPos3)
Pause 10 'Need time to write
Next
Poke PortC, %00010000
goto chk1
End
'*********** Get Data Back Out ****************************
recall:
Pause 1000
addr2 = 3000
addr3 = 6000
Poke PortC, %11100000
For addr=1 to 2000
addr2 = addr2 + 1
addr3 = addr3 + 1
I2Cin cont,addr,ServoPos
I2Cin cont,addr2,ServoPos2
I2Cin cont,addr3,ServoPos3
For x = 1 to 17
high 2
next
low 2
Pulsout 4, ServoPos 'Pulse the Servo
Pulsout 5, ServoPos2 'Pulse the Servo
Pulsout 6, ServoPos3 'Pulse the Servo
Pause 7
Next
Poke PortC, %00010000
goto chk1
End
|
Robodyssey Systems manufactures Robot Kits including Autonomous Mobile
Walking Robots, Wheeled Robots, Talking Robots, Expressive Robots, and
Social Robots. We also sell Robotics Accessories including Nexcell NiMH AA
Rechargeable Batteries, Nexcell NiMH AAA Rechargeable Batteries, Battery Holders,
Velcro Straps for Battery Packs, Battery Chargers, Robot Grippers, Hobby Servos,
Servos Modified for Continuous Rotation, Tail Wheels for all Rolling Robotic Platforms,
Polyurethane Skate Wheels with Servo Adapter Hubs, Sharp IR Sensors and Adjustable
Sensor Brackets, Sensor Cables, and Programming Cables. All of our Robot Kits
can be purchased as easy to assemble robot kits or as fully assembled stationary
or mobile robots. Robodyssey uses 1/8 inch aluminum and acetyl for most all of
our mobile robot components and robotics accessories. We provide classroom
training for teachers interested in integrating robotics, computer programming
and electronics into the classroom.
We hope you enjoy our web site. Feel free to use any robotic resources.
Robodyssey is your complete solution for Educational Robotics as well as Hobby Robotics.
|