This program controls two servo motors connected to an LGT8F328P microcontroller to operate a barrier system, such as a gate or crossing arm. It uses a reed switch under the track to detect the barrier's state (open/closed) and controls the servos to sweep back and forth. The servos move sequentially (one after the other) using pulse width modulation via an adapted PulseOut macro handling WORD time slices. An indicator LED reflects the switch state, and an interrupt handles switch events.
The choice of the LGT8F328P is not important. Just change the chip and ports to suit you confiugration.
Code
This program uses the new features of GCBASIC ENUMs. The code is fully documented. I will add to the demos shortly.
Enjoy
/*AprogramforGCBASIC.--------------------------------------------------------------------------------------------------------------------------------AttachaservomotortotheportspecifiedintheconstantSERVOOUTCHANNEL1andSERVOOUTCHANNEL2ThisprogramwillmaketheservosweepbackandforthThisisalsoincludesanadaptedPulseOuttohandleWORDtimeslices.Summary:ThisprogramcontrolstwoservomotorsconnectedtoanLGT8F328Pmicrocontrollertooperateabarriersystem,suchasagateorcrossingarm.Itusesareedswitch(REEDSWITCH1)todetectthebarrier's state (open/closed)andcontrolstheservostoraiseorlowerthebarriersimultaneously.Theservosmovewithinasharedpulserange(calculatedfrompredefinedconstants)toensuresynchronizedoperation.Astatemachine,managedbyHandleBarrierState,controlsthebarrierwithstatesIDLE,TRIGGERED,WAITING,andRAISING:loweringwhentheswitchistriggered,waitingforatimeout,andraisingafteradelay.AnindicatoronINDICATOR_LEDreflectstheswitchstate.Thesystementerslow-poweridlemodeduringIDLEandWAITINGstates,wakingonREEDSWITCH1interrupts.@authorEvanV@licenceGPL@version1.0g@date08.21.2025********************************************************************************///-----Configuration#chip LGT8F328P // Specify the microcontroller model (LGT8F328P)#option explicit // Enforce variable declaration for better code reliability#DEFINE USART_BAUD_RATE 115200 // Set UART baud rate to 115200 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 SERVOOUTCHANNEL1 PORTC.0 // Servo 1 connected to PORTC.0DIRSERVOOUTCHANNEL1OUT//SetPORTC.0asoutput#DEFINE SERVOOUTCHANNEL2 PORTC.1 // Servo 2 connected to PORTC.1DIRSERVOOUTCHANNEL2OUT//SetPORTC.1asoutput#DEFINE REEDSWITCH1 PORTD.2 // Reed switch connected to PORTD.2#DEFINE INDICATOR_LED PORTB.5 // Indicator LED connected to PORTB.5#DEFINE TIMEOUT_COUNT 30000 // Timeout count for ~3 seconds (30,000 × 100µs)//Servopulsewidthconstants(inunitsof10µs,specifictoTowerProSG90servo)#DEFINE UPPER1 160 // Maximum pulse width for servo 1 (vertical position, 1.6ms)#DEFINE LOWER1 88 // Minimum pulse width for servo 1 (horizontal position, 0.88ms)#DEFINE UPPER2 153 // Maximum pulse width for servo 2 (vertical position, 1.53ms)#DEFINE LOWER2 88 // Minimum pulse width for servo 2 (horizontal position, 0.88ms)//DefinebarrierstatemachinestatesENUMBarrierStateIDLE//Idlestate,noactionpendingTRIGGERED//Reedswitchtriggered,lowerbarrierWAITING//WaitingfortimeoutafterloweringRAISING//RaisingbarrieraftertimeoutEndEnum//-----VariablesDimPulseTimeAsWORD//Storesthecurrentpulsewidthforservocontrol(in10µsunits)DimMinPulseAsWORD//StorestheminimumpulsewidthacrossbothservosDimMaxPulseAsWORD//StoresthemaximumpulsewidthacrossbothservosDimBarrierStateAsByte//Tracksthestateofthebarrier(IDLE,TRIGGERED,WAITING,RAISING)DimTimeCountAsWord//CounterfortimingdelayinWAITINGstateDimInterruptStateAsBit//Tracksiftheinterruptisenabled(True)ordisabled(False)//-----Mainbodyofprogramcommenceshere.DirREEDSWITCH1In//ConfigureREEDSWITCH1asinputforthereedswitchBarrierState=IDLE//InitializebarrierstatetoIDLETimeCount=0//Initializetimercounterto0InterruptState=False//Initializeinterruptasdisabled//CalculatethepulserangeforbothservosonceatstartuptooptimizeperformanceMinPulse=LOWER1//StartwithLOWER1asminimumIfLOWER2<MinPulseThenMinPulse=LOWER2//UpdatetoLOWER2ifit's smallerMaxPulse=UPPER1//StartwithUPPER1asmaximumIfUPPER2>MaxPulseThenMaxPulse=UPPER2//UpdatetoUPPER2ifit's largerDirINDICATOR_LEDOut//ConfigureINDICATOR_LEDasoutputfortheindicatorLEDRepeat10//BlinkINDICATOR_LED10timestosignalprogramstartINDICATOR_LED=!INDICATOR_LED//ToggleINDICATOR_LEDstateWait50ms//Wait50msbetweentogglesEndRepeatINDICATOR_LED=False//EnsureLEDisoffafterstartup//CheckinitialreedswitchstatetosetbarrierpositionIfREEDSWITCH1=1Then//Ifreedswitchishigh(barrierclosed)LowerBarrier//LowerthebarrierElse//Ifreedswitchislow(barrieropen)RaiseBarrier//RaisethebarrierEndIf//MainlooptomonitorandcontrolthebarrierDoIfInterruptState=FalseThenOnInterruptExtInt0CallISRBarrier//EnableinterruptonREEDSWITCH1risingedgeInterruptState=True//MarkinterruptasenabledEndIfINDICATOR_LED=REEDSWITCH1//MirrorreedswitchstatetoINDICATOR_LEDHandleBarrierState//Processthebarrierstatemachine//EnteridlemodeinIDLEorWAITINGstatestosavepowerIfBarrierState=IDLEOrBarrierState=WAITINGThenSleep//Enteridlemode,wakeonREEDSWITCH1interrupt(ExtInt0)EndIfLoop//SubroutinetohandlethebarrierstatemachineSubHandleBarrierState//StatemachinetohandlebarrieroperationSelectCaseBarrierStateCaseTRIGGERED//TRIGGERED:Reedswitchtriggered,lowerbarrierLowerBarrier//CallsubroutinetolowerthebarrierTimeCount=0//ResettimercounterWaitWhileREEDSWITCH1=1//WaituntilreedswitchgoeslowBarrierState=WAITING//TransitiontoWAITINGstateCaseWAITING//WAITING:WaitfortimeoutwhileswitchislowWait100us//ShortdelaytoavoidexcessiveCPUuseIfREEDSWITCH1=0Then//IfreedswitchislowTimeCount++//IncrementtimercounterElse//Ifreedswitchgoeshigh(newsignaldetected)TimeCount=0//ResettimertorestarttimeoutEndIfIfTimeCount=TIMEOUT_COUNTThen//After~3seconds(TIMEOUT_COUNT×100µs)BarrierState=RAISING//TransitiontoRAISINGstateEndIfCaseRAISING//RAISING:RaisebarrierifswitchremainslowIfREEDSWITCH1=0Then//ConfirmswitchisstilllowRaiseBarrier//CallsubroutinetoraisethebarrierBarrierState=IDLE//ResettoIDLEstateInterruptState=False//DisableinterruptEndIfEndSelectEndSub//InterruptserviceroutineforreedswitchSubISRBarrierIfREEDSWITCH1=1Then//Ifreedswitchishigh(barrierclosed)BarrierState=TRIGGERED//SetstatetoTRIGGEREDtolowerbarrierOnInterruptExtInt0Ignore//Disablefurtherinterruptstopreventre-triggeringEndIfEndSub//SubroutinetoraisebothservossimultaneouslySubRaiseBarrier//MoveservosfromminimumtomaximumpulsewidthForPulseTime=MinPulseToMaxPulseStep1//Sendpulsetoservo1ifwithinitsrangeIfPulseTime>=LOWER1AndPulseTime<=UPPER1ThenPulseOutSERVOOUTCHANNEL1,PulseTime,10us//Sendpulsetoservo1EndIf//Sendpulsetoservo2ifwithinitsrangeIfPulseTime>=LOWER2AndPulseTime<=UPPER2ThenPulseOutSERVOOUTCHANNEL2,PulseTime,10us//Sendpulsetoservo2EndIfWait1ms//DelaybetweenpulsesforsmoothservomovementNextEndSub//SubroutinetolowerbothservossimultaneouslySubLowerBarrier//MoveservosfrommaximumtominimumpulsewidthForPulseTime=MaxPulseToMinPulseStep-1//Sendpulsetoservo1ifwithinitsrangeIfPulseTime>=LOWER1AndPulseTime<=UPPER1ThenPulseOutSERVOOUTCHANNEL1,PulseTime,10us//Sendpulsetoservo1EndIf//Sendpulsetoservo2ifwithinitsrangeIfPulseTime>=LOWER2AndPulseTime<=UPPER2ThenPulseOutSERVOOUTCHANNEL2,PulseTime,10us//Sendpulsetoservo2EndIfWait1ms//DelaybetweenpulsesforsmoothservomovementNextEndSubEnd//Endofprogram//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 road crossing 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 road crossing with the two servos.
The mounting of the servo uses two new Lego parts. The servos are very cheap GeekServos.
Train Barrier Servo Controller
Summary
This program controls two servo motors connected to an LGT8F328P microcontroller to operate a barrier system, such as a gate or crossing arm. It uses a reed switch under the track to detect the barrier's state (open/closed) and controls the servos to sweep back and forth. The servos move sequentially (one after the other) using pulse width modulation via an adapted
PulseOut
macro handling WORD time slices. An indicator LED reflects the switch state, and an interrupt handles switch events.The choice of the LGT8F328P is not important. Just change the chip and ports to suit you confiugration.
Code
This program uses the new features of GCBASIC ENUMs. The code is fully documented. I will add to the demos shortly.
Enjoy
Last edit: Anobium 24 hours ago
This is part of an implementation of a STEM project inspired and based on Hugh's Australian work.
The road crossing 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 road crossing with the two servos.
The mounting of the servo uses two new Lego parts. The servos are very cheap GeekServos.
Last edit: Anobium 23 hours ago