This is another part of an implementation of a STEM project inspired and based on Hugh's Australian work.
Summary
This program controls a single GeekServo servo motor connected to an LGT8F328P microcontroller to operate a railway points system, such as a track switch. The servo, connected to SERVOOUTCHANNEL (PORTC.0), toggles between full clockwise (FULL_CW, 1.25ms) and full counterclockwise (FULL_CCW, 1.75ms) positions to switch the points, triggered by a debounced switch input on SWITCHIN (PORTE.3). A state machine with states CLOCKWISE and COUNTERCLOCKWISE manages servo movement, using pulse width modulation via an adapted PulseOut macro handling WORD time slices. The servo moves in 50µs steps with a 100µs delay for smooth operation. An indicator LED on INDICATOR_LED (PORTB.5) is on for the clockwise position and off for the counterclockwise position. The system enters low-power idle mode when no switch press is detected, reducing power consumption. A configuration script ensures valid pulse widths for the selected POINTSET2 (AVR-specific values) and issues errors or warnings for invalid settings. The choice of the LGT8F328P is not critical; the microcontroller and ports (e.g., SERVOOUTCHANNEL, SWITCHIN, INDICATOR_LED) can be changed to suit your configuration.
Code
Enjoy
/*AdemonstrationprogramforGCBASIC.--------------------------------------------------------------------------------------------------------------------------------ThisprogramcontrolsasingleGeekServoservomotoronanLGT8F328Pmicrocontroller,connectedtoSERVOOUTCHANNEL(PORTC.0).Ittogglestheservobetweenfullclockwise(FULL_CW,1.25ms)andfullcounterclockwise(FULL_CCW,1.75ms)positionsbasedonadebouncedswitchinput(SWITCHINonPORTE.3).Astatemachine,managedbyHandleServoState,usesstatesCLOCKWISEandCOUNTERCLOCKWISEtocontrolservomovement,triggeredbypollingtheswitchviafuncKeyPressedinthemainloop.Eachswitchpresstogglestheservodirection.Theservomovesin50µssteps(5units)witha100µsdelaybetweenpulsesforsmoothoperation.AnindicatorLEDonINDICATOR_LED(PORTB.5)isonfortheclockwisepositionandoffforthecounterclockwiseposition.Thesystementerslow-poweridlemodewhennoswitchpressisdetected,reducingpowerconsumption.AconfigurationscriptensuresvalidpulsewidthsfortheselectedPOINTSET2(AVR-specificvalues)andissueserrorsorwarningsforinvalidsettings.USARTisconfiguredat9600baudbutunused.KeyComponents:-Configuration:-Microcontroller:LGT8F328Pwith#option Explicit for strict variable declaration.-USART:Configuredat9600baudwithblockingtransmission,butnoserialoutputisused.-I/OPins:-SWITCHIN(PORTE.3):Inputforswitch,active-high(DOWN=1).-INDICATOR_LED(PORTB.5):OutputforLEDindicatingservodirection.-SERVOOUTCHANNEL(PORTC.0):Outputfortheservomotor.-Constants:-SERVO_PULSE_DELAY(100µs):Delaybetweenservopulses.-DEBOUNCE_DELAY(1ms):Delayforswitchdebouncing.-FULL_CW(125,1.25ms)andFULL_CCW(175,1.75ms):ServopulsewidthsforAVRunderPOINTSET2.-Script:EnsuresonlyonePOINTSETisdefined,setspulsewidths,andissueswarningsorerrors.-ENUM:ServoStatedefinesCLOCKWISEandCOUNTERCLOCKWISEforthestatemachine.-Variables:-PulseTime(WORD):Storesthecurrentservopulsewidth(in10µsunits).-ServoState(Byte):Tracksthestatemachinestate(CLOCKWISEorCOUNTERCLOCKWISE).-CurrentSwitchStateandLastSwitchState(Bit,localtofuncKeyPressed):Usedfordebouncing.-MainLoop:-PollsfuncKeyPressedtodetectswitchpresses.-Onavalidpress,togglesServoStatebetweenCLOCKWISEandCOUNTERCLOCKWISEandcallsHandleServoState.-Entersidlemodewhennoswitchpressisdetected,wakingonthenextloopiteration.-ThestatemachineishandledinHandleServoState.-FunctionsandSubroutines:-HandleServoState:Managesthestatemachine:-CLOCKWISE:MovesservofromFULL_CWtoFULL_CCW,setsINDICATOR_LEDon.-COUNTERCLOCKWISE:MovesservofromFULL_CCWtoFULL_CW,setsINDICATOR_LEDoff.-funcKeyPressed:Debouncestheswitch,returningTRUEonarisingedge(releasedtopressed)aftera1msdelay.-PulseOut(macro):GeneratesaservopulseforlocalPulseTime×10µs.-Operation:-Onstartup,theservomovestotheclockwiseposition(CLOCKWISE),andINDICATOR_LEDblinks10times,thenstayson.-ThemainloopcontinuouslypollsfuncKeyPressed.-AswitchpresstogglesServoStatebetweenCLOCKWISEandCOUNTERCLOCKWISE,callingHandleServoStatetomovetheservoandupdatetheLED.-Whennoswitchpressisdetected,thesystementerssleepmodetosavepower,wakingonthenextloopiteration.-Theservomovessmoothlybetweenpositionswith100µsdelays.-Notes:-Polling-BasedSwitchHandling:UsespollingwithfuncKeyPressedforsimplicity.-PowerManagement:Idlemodewhennoswitchpressisdetectedbalancespowersavingswithpollingresponsiveness.-StateMachine:TheServoStateENUMensurespropertogglingbetweenCLOCKWISEandCOUNTERCLOCKWISEpositions.-Debouncing:funcKeyPressedensuresrobustswitchdetectionwitha1msdelay.@authorEvanV@licenceGPL@version1.0e@date08.21.2025********************************************************************************///-----Configuration#chip LGT8F328P // Specify the microcontroller model (LGT8F328P)#option Explicit // Enforce variable declaration for better code reliability#DEFINE USART_BAUD_RATE 9600 // Set UART baud rate to 9600 for serial communication#DEFINE USART_TX_BLOCKING // Enable blocking mode for UART transmission#DEFINE USART_DELAY OFF // Disable additional USART delays//-----Constants//DefineI/Opins#DEFINE SWITCHIN PORTE.3 // Switch input connected to PORTE.3DirSWITCHINIn//SetPORTE.3asinput#DEFINE DOWN 1 // Switch active state (high)#DEFINE INDICATOR_LED PORTB.5 // Indicator LED connected to PORTB.5DIRINDICATOR_LEDOUT//SetPORTB.5asoutput#DEFINE SERVOOUTCHANNEL PORTC.0 // Servo connected to PORTC.0DIRSERVOOUTCHANNELOUT//SetPORTC.0asoutput//Servopulsewidthconstants(inunitsof10µs,specifictoGeekServoservo)#DEFINE POINTSET2 // Use POINTSET2 configuration for servo#DEFINE DISABLE1173 // Unused configuration flag#DEFINE SERVO_PULSE_DELAY 100 us // Delay between servo pulses for smooth movement#DEFINE DEBOUNCE_DELAY 1 ms // Delay for switch debouncing//DefineservostatemachinestatesENUMServoStateCLOCKWISE//ServoinfullclockwisepositionCOUNTERCLOCKWISE//ServoinfullcounterclockwisepositionEndEnum#scriptFULL_CW=0FULL_CCW=0TITLE=""IfDEF(POINTSET1)ThenFULL_CW=70//0.7msforclockwise(POINTSET1)FULL_CCW=120//1.2msforcounterclockwise(POINTSET1)TITLE="POINTSET1"Warning"POINTSET1 configuration"EndIfIfDEF(POINTSET2)ThenIfDEF(PIC)ThenFULL_CW=110//1.1msforclockwise(PIC,POINTSET2)FULL_CCW=160//1.6msforcounterclockwise(PIC,POINTSET2)EndIfIfDEF(AVR)ThenFULL_CW=125//1.25msforclockwise(AVR,POINTSET2)FULL_CCW=175//1.75msforcounterclockwise(AVR,POINTSET2)EndIfTITLE="POINTSET2"Warning"POINTSET2 configuration"EndIfIfDEF(POINTSET3)ThenFULL_CW=120//1.2msforclockwise(POINTSET3)FULL_CCW=170//1.7msforcounterclockwise(POINTSET3)Warning"POINTSET3 configuration"EndIfIfFULL_CW=0andFULL_CCW=0ThenError"No configuration"EndIf#endscript//-----VariablesDimPulseTimeAsWORD//Storesthecurrentpulsewidthforservocontrol(in10µsunits)DimServoStateAsByte//Trackstheservostate(CLOCKWISE,COUNTERCLOCKWISE)//-----Mainbodyofprogramcommenceshere.ServoState=CLOCKWISE//InitializeservostatetoCLOCKWISEDirINDICATOR_LEDOut//ConfigureINDICATOR_LEDasoutputfortheindicatorLEDRepeat10//BlinkINDICATOR_LED10timestosignalprogramstartINDICATOR_LED=!INDICATOR_LED//ToggleINDICATOR_LEDstateWait50ms//Wait50msbetweentogglesEndRepeatINDICATOR_LED=True//SetLEDonforinitialCLOCKWISEstate//InitializeservotoclockwisepositionHandleServoState//Moveservotoinitialposition(CLOCKWISE)//MainlooptomonitorandcontroltheservoDoIffuncKeyPressed()=TRUEThen//CheckfordebouncedswitchpressIfServoState=CLOCKWISEThen//Togglestate:CLOCKWISEtoCOUNTERCLOCKWISEServoState=COUNTERCLOCKWISEElseServoState=CLOCKWISE//Togglestate:COUNTERCLOCKWISEtoCLOCKWISEEndIfHandleServoState//MoveservotonewpositionElseSleep//EnteridlemodewhennoswitchpressisdetectedEndIfLoop//SubroutinetohandletheservostatemachineSubHandleServoStateSelectCaseServoStateCaseCLOCKWISE//CLOCKWISE:MoveservotofullclockwisepositionINDICATOR_LED=True//SetLEDonforclockwiseForPulseTime=FULL_CWToFULL_CCWStep5PulseOutSERVOOUTCHANNEL,PulseTime,10us//SendpulsetoservoWaitSERVO_PULSE_DELAY//DelayforsmoothmovementNextCaseCOUNTERCLOCKWISE//COUNTERCLOCKWISE:MoveservotofullcounterclockwisepositionINDICATOR_LED=False//SetLEDoffforcounterclockwiseForPulseTime=FULL_CCWToFULL_CWStep-5PulseOutSERVOOUTCHANNEL,PulseTime,10us//SendpulsetoservoWaitSERVO_PULSE_DELAY//DelayforsmoothmovementNextEndSelectEndSub//FunctiontodebounceanddetectswitchpressFunctionfuncKeyPressedAsBitDimCurrentSwitchStateAsBit//CurrentstateoftheswitchDimLastSwitchStateAsBit//PreviousstateoftheswitchWaitDEBOUNCE_DELAY//Waitfordebounceperiod//CheckifswitchispressedIfSWITCHIN=DOWNThenCurrentSwitchState=TRUE//SwitchispressedElseCurrentSwitchState=FALSE//SwitchisreleasedEndIf//Detectrisingedge(switchpressed)IfCurrentSwitchState<>LastSwitchStateANDCurrentSwitchState=TRUEThenfuncKeyPressed=TRUE//ReturnTRUEforvalidpressElsefuncKeyPressed=FALSE//NovalidpressdetectedEndIfLastSwitchState=CurrentSwitchState//UpdatelaststateEndFunction//MacrotogenerateapulseforservocontrolmacroPulseOut(Pin,localPulseTimeAsWORD,localTimeUnit)SetPinOn//SetthespecifiedpinhighRepeatlocalPulseTime//LoopforthespecifiedpulsedurationWait1localTimeUnit//Waitfor1unitoftime(10µs)EndRepeatSetPinOff//SetthepinlowtoendthepulseEndmacro
This is part of an implementation of a STEM project inspired and based on Hugh's Australian work.
The switch controller was specifically designed for the project. I have the design in Lego Studio and there is a complete bill of materials and build process. My thanks go to Jack Sisson who has designed this switch control with the a cheap GeekServo servo.
This is another part of an implementation of a STEM project inspired and based on Hugh's Australian work.
Summary
This program controls a single GeekServo servo motor connected to an LGT8F328P microcontroller to operate a railway points system, such as a track switch. The servo, connected to
SERVOOUTCHANNEL
(PORTC.0), toggles between full clockwise (FULL_CW
, 1.25ms) and full counterclockwise (FULL_CCW
, 1.75ms) positions to switch the points, triggered by a debounced switch input onSWITCHIN
(PORTE.3). A state machine with statesCLOCKWISE
andCOUNTERCLOCKWISE
manages servo movement, using pulse width modulation via an adaptedPulseOut
macro handling WORD time slices. The servo moves in 50µs steps with a 100µs delay for smooth operation. An indicator LED onINDICATOR_LED
(PORTB.5) is on for the clockwise position and off for the counterclockwise position. The system enters low-power idle mode when no switch press is detected, reducing power consumption. A configuration script ensures valid pulse widths for the selectedPOINTSET2
(AVR-specific values) and issues errors or warnings for invalid settings. The choice of the LGT8F328P is not critical; the microcontroller and ports (e.g.,SERVOOUTCHANNEL
,SWITCHIN
,INDICATOR_LED
) can be changed to suit your configuration.Code
Enjoy
Last edit: Anobium 13 hours ago
This is part of an implementation of a STEM project inspired and based on Hugh's Australian work.
The switch controller was specifically designed for the project. I have the design in Lego Studio and there is a complete bill of materials and build process. My thanks go to Jack Sisson who has designed this switch control with the a cheap GeekServo servo.
The views of the build.
Last edit: Anobium 13 hours ago