Bit Banged Servo drive from the 20M2 A.0 pin

rq3

Senior Member
I have an existing board with a surface mount Picaxe20M2, which I wanted to "re-purpose" to control some remote controlled tweezers. Because the I/O of the existing board is physically limited, I use the "serout" pin (A.0) as the servo data port. My initial attempt using "servo" and "servopos" was a bit twitchy and glitchy, so I decided to just use raw high and low commands with the appropriate timing. The 20M2 clock is set to 32 MHz, so each pauseus is only 1.25 uSec, giving much finer control of the servo (a Spektrum A3040 micro servo) position. There's other extraneous stuff like turning on an LED to show that the board is powered. With this technique, the tips of the tweezers can be set within about 0.0005 inch by changing the "open" and "close" variables.

This works very well and repeatably with this particular servo, which is driven from the same on-board +5 volt regulator as powers the 20M2. I have not tried this with other servos. I did notice that the servo seems, subjectively, much "happier" (smoother and quieter), than with the standard servo and servopos commands on a "normal" output pin.

And yes, the servo does freak out a bit during a download, but not at a damaging level. Your mileage may vary.

Code:
[COLOR=Navy]#Picaxe [/COLOR][COLOR=Black]20M2                           [/COLOR][COLOR=Green];Picaxe type[/COLOR]
[COLOR=Navy]#no_data                               [/COLOR][COLOR=Green];do not load data[/COLOR]
[COLOR=Navy]#no_end                                [/COLOR][COLOR=Green];do not auto-end[/COLOR]
[COLOR=Blue]disconnect                             [/COLOR][COLOR=Green];do not allow new downloads[/COLOR]
[COLOR=Blue]disablebod                             [/COLOR][COLOR=Green];disable brownout detection to prevent servo glitch[/COLOR]
[COLOR=Blue]setfreq M32                            [/COLOR][COLOR=Green];clock frequency 32 MHz[/COLOR]
[COLOR=Blue]pullup [/COLOR][COLOR=Navy]%0000010000000000               [/COLOR][COLOR=Green];apply weak pull-up to C.2 for switch[/COLOR]

[COLOR=Blue]symbol [/COLOR][COLOR=Black]open[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]1430                       [/COLOR][COLOR=Green];open servo pulsewidth:  1.7875 msec[/COLOR]
[COLOR=Blue]symbol [/COLOR][COLOR=Black]close[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]922                       [/COLOR][COLOR=Green];close servo pulsewidth: 1.1525 msec[/COLOR]

[COLOR=Black]init:[/COLOR]
[COLOR=Blue]high B.0                               [/COLOR][COLOR=Green];turn on power LED[/COLOR]
[COLOR=Blue]pwmout B.1[/COLOR][COLOR=Black],[/COLOR][COLOR=Navy]24[/COLOR][COLOR=Black],[/COLOR][COLOR=Navy]95                       [/COLOR][COLOR=Green];dim at 5% duty cycle[/COLOR]
[COLOR=Blue]do
   high A.0                            [/COLOR][COLOR=Green];initialize servo (open)
      [/COLOR][COLOR=Blue]pauseus [/COLOR][COLOR=Black]open
   [/COLOR][COLOR=Blue]low A.0  
      pause [/COLOR][COLOR=Navy]160                        [/COLOR][COLOR=Green];20 msec delay[/COLOR]
[COLOR=Blue]loop until [/COLOR][COLOR=Purple]pinC.2[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]0  
   [/COLOR]
[COLOR=Black]main:[/COLOR]
[COLOR=Blue]do
   if [/COLOR][COLOR=Purple]pinC.2[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]0 [/COLOR][COLOR=DarkCyan]and [/COLOR][COLOR=Purple]b0[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]0 [/COLOR][COLOR=Blue]then           [/COLOR][COLOR=Green];if button is pressed and tweezers are open
      [/COLOR][COLOR=Blue]pause [/COLOR][COLOR=Navy]160                        [/COLOR][COLOR=Green];20 msec switch debounce
         [/COLOR][COLOR=Blue]for [/COLOR][COLOR=Purple]w1[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Black]open [/COLOR][COLOR=Blue]to [/COLOR][COLOR=Black]close [/COLOR][COLOR=Blue]step [/COLOR][COLOR=DarkCyan]-[/COLOR][COLOR=Navy]1  [/COLOR][COLOR=Green];servo signal from open to close 
            [/COLOR][COLOR=Blue]high A.0                   [/COLOR][COLOR=Green];slowly rotate servo clockwise (close)
               [/COLOR][COLOR=Blue]pauseus [/COLOR][COLOR=Purple]w1
            [/COLOR][COLOR=Blue]low A.0     
               pause [/COLOR][COLOR=Navy]50                [/COLOR][COLOR=Green];set closing speed
         [/COLOR][COLOR=Blue]next [/COLOR][COLOR=Purple]w1
            b0[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]1                       [/COLOR][COLOR=Green];set position flag
   [/COLOR][COLOR=Blue]endif 
   
   if [/COLOR][COLOR=Purple]pinC.2[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]0 [/COLOR][COLOR=DarkCyan]and [/COLOR][COLOR=Purple]b0[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]1 [/COLOR][COLOR=Blue]then           [/COLOR][COLOR=Green];if button is pressed and tweezers are closed
      [/COLOR][COLOR=Blue]pause [/COLOR][COLOR=Navy]160                        [/COLOR][COLOR=Green];20 msec switch debounce
         [/COLOR][COLOR=Blue]for [/COLOR][COLOR=Purple]w1[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Black]close [/COLOR][COLOR=Blue]to [/COLOR][COLOR=Black]open [/COLOR][COLOR=Blue]step [/COLOR][COLOR=Navy]10  [/COLOR][COLOR=Green];servo signal from close to open
            [/COLOR][COLOR=Blue]high A.0                   [/COLOR][COLOR=Green];rotate servo counterclockwise (open)
               [/COLOR][COLOR=Blue]pauseus [/COLOR][COLOR=Purple]w1
            [/COLOR][COLOR=Blue]low A.0     
               pause [/COLOR][COLOR=Navy]16                [/COLOR][COLOR=Green];delay 2 msec for servo stability
         [/COLOR][COLOR=Blue]next [/COLOR][COLOR=Purple]w1
            b0[/COLOR][COLOR=DarkCyan]=[/COLOR][COLOR=Navy]0                       [/COLOR][COLOR=Green];set position flag
   [/COLOR][COLOR=Blue]endif
loop[/COLOR]
 
Top