diff --git a/Button.py b/Button.py new file mode 100644 index 0000000..dc1c7c8 --- /dev/null +++ b/Button.py @@ -0,0 +1,30 @@ +import machine +import time + +class Button(): + def __init__(self,pin,onPushDown = None, onPushUp = None,debounceTimeMs = 50,inputMode = machine.Pin.IN,inverted = False): + self.pin = machine.Pin(pin,inputMode) + self.pressedTime = -debounceTimeMs + self.debounceTimeMs = int(debounceTimeMs) + self.onPushDown = onPushDown + self.onPushUp = onPushUp + self.pin.irq(trigger=machine.Pin.IRQ_RISING|machine.Pin.IRQ_FALLING , handler=self._IRQ) + self.value = self.pin.value() + self.inverted = inverted + + def _IRQ(self,p): + new_value = self.pin.value() + if (self.value != new_value): + self.value = new_value + time_ms = time.ticks_ms() + if ((self.pressedTime+self.debounceTimeMs) < time_ms): + self.pressedTime = time_ms + if (new_value ^ self.inverted): + if (self.onPushUp != None): + self.onPushUp() + else: + if (self.onPushDown != None): + self.onPushDown() + else: + pass + \ No newline at end of file diff --git a/README.md b/README.md index 7669757..f7b7003 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Pin (ESP32)| Function ## Reference [L298M H-Bridge](https://www.instructables.com/id/Control-DC-and-stepper-motors-with-L298N-Dual-Moto/) + [DS3231 RTC](https://github.com/micropython-Chinese-Community/mpy-lib/tree/master/misc/DS3231) + [NodeMCU-32S Pinout](https://www.shenzhen2u.com/NodeMCU-32S) [ESP32 Usable Pins](https://randomnerdtutorials.com/esp32-pinout-reference-gpios/) diff --git a/StepperClock.py b/StepperClock.py index a761336..215325b 100644 --- a/StepperClock.py +++ b/StepperClock.py @@ -1,23 +1,31 @@ import StepperL298M import time +import uasyncio as asyncio + class StepperClock: def __init__(self,stepperHour,stepperMin): self._stepperMinute = stepperMin self._stepperHour = stepperHour + self.started_async = False + def start(self): + if not self.started_async: + self.started_async = True + self._stepperMinute.start() + self._stepperHour.start() + loop = asyncio.get_event_loop() + loop.create_task(self._update_async()) + + async def _update_async(self): + while(True): + await asyncio.sleep(1) + self.update() + def update(self): hour = time.localtime()[3] minute = time.localtime()[4] - self._stepperHour.rotateTo(hour/60) - self._stepperMinute.rotateTo(minute/60) - self._stepperHour.update() - self._stepperMinute.update() - - def waitForStillstand(self): - while not (self._stepperHour.isAtTarget() or self._stepperMinute.isAtTarget()): - self._stepperHour.update() - self._stepperMinute.update() - time.sleep(0.1) + self._stepperHour.rotateTo(1-((hour%12)/12+minute/(12*60))) + self._stepperMinute.rotateTo(1-minute/60) def disablePower(self): self._stepperHour.disablePower() diff --git a/StepperL298M.py b/StepperL298M.py index 294c785..4f807e7 100644 --- a/StepperL298M.py +++ b/StepperL298M.py @@ -1,16 +1,27 @@ from machine import Pin import time +import uasyncio as asyncio + stepping = [[1,0,1,0],[1,0,0,0],[1,0,0,1],[0,0,0,1],[0,1,0,1],[0,1,0,0],[0,1,1,0],[0,0,1,0]] class Stepper: - def __init__(self,pins,stepsPerRev=400): + def __init__(self,pins,stepsPerRev=400,stepDurationMs=50,inverted=False): self._pins = [Pin(p, Pin.OUT) for p in pins] self.stepnum = 0 self.rotDirection = 1 - self.rotTarget = 0 - self.stepDuration = 0.05 + self._rotTarget = 0 + self.stepDurationMs = stepDurationMs + self._speedMs = 0 self._lastStepTime = time.time() self.stepsPerRev=stepsPerRev + self.started_async = False + self.inverted = inverted + + def start(self): + if not self.started_async: + self.started_async = True + loop = asyncio.get_event_loop() + loop.create_task(self._update_async()) def _setPins(self,level): self._pins[0].value(level[0]) @@ -18,37 +29,41 @@ class Stepper: self._pins[2].value(level[2]) self._pins[3].value(level[3]) - def doSteppsBlock(self,num,speed=0.05): - for i in range(num): - self.stepnum = (self.stepnum + 1) - self._setPins(stepping[self.stepnum%8]) - time.sleep(speed) - self.disablePower() + def getStepsToTarget(self): + return ((self._rotTarget - self.stepnum)*self.rotDirection)%self.stepsPerRev - def rotateTo(self, target,direction=0): + def rotateTo(self, target,duration=0,direction=0): """sets the rotation target and (if direction == 0) calculates if it should rotate left or right""" - self.rotTarget = int(target*self.stepsPerRev) % self.stepsPerRev - if (direction == 0): - self.rotDirection = 1 if (self.stepnum- self.rotTarget)%self.stepsPerRev \ - > self.stepsPerRev/2 else 0 - else: - self.rotDirection = direction + self._rotTarget = int(target*self.stepsPerRev) % self.stepsPerRev + if not self.isAtTarget(): + if (direction == 0): + self.rotDirection = 1 if (self._rotTarget - self.stepnum)%self.stepsPerRev \ + < self.stepsPerRev/2 else -1 + else: + self.rotDirection = direction + self._speedMs = max(int(self.stepDurationMs),duration*1000/self.getStepsToTarget()) - def update(self): - if (self.rotTarget%self.stepsPerRev != self.stepnum%self.stepsPerRev) \ - and not self.isMoving(): - self._lastStepTime = time.ticks_ms() - self.stepnum = (self.stepnum + self.rotDirection) % self.stepsPerRev - self._setPins(stepping[self.stepnum%8]) - #time.sleep(speed) + async def _update_async(self): + while(True): + await asyncio.sleep_ms(self.stepDurationMs) + if not self.isAtTarget(): + self._update() + else: + self.disablePower() + + def _update(self): + self.stepnum = (self.stepnum + self.rotDirection) % self.stepsPerRev + self._setPins(stepping[(self.stepnum%8) if not self.inverted else ((8-self.stepnum)%8)]) def disablePower(self): self._setPins([0,0,0,0]) - def isMoving(self): - return time.ticks_diff(time.ticks_ms(), self._lastStepTime) <= self.stepDuration + def getOrientation(self): + return self.stepnum / self.stepsPerRev + + def getTarget(self): + return (self._rotTarget / self.stepsPerRev) def isAtTarget(self): - return (not self.isMoving()) \ - and (self.rotTarget%self.stepsPerRev == self.stepnum%self.stepsPerRev) + return (self._rotTarget%self.stepsPerRev == self.stepnum%self.stepsPerRev) diff --git a/main.py b/main.py index c4db509..c90f8fe 100644 --- a/main.py +++ b/main.py @@ -1,24 +1,41 @@ import time import machine import DS3231 +import Button +import uasyncio as asyncio +import StepperL298M +import StepperClock +#Async +loop = asyncio.get_event_loop() + +#Initialise the time module with the RTC dsRtc = DS3231.DS3231(machine.I2C(sda = machine.Pin(17), scl=machine.Pin(18))) - rtc = machine.RTC() rtc.init(dsRtc.DateTime()+[0]) -#while(True): -# print(rtc.DateTime()) -# time.sleep(0.1) -# pass -#import StepperL298M -#import StepperClock -#stepperminu = StepperL298M.Stepper([12,27,26,25],stepsPerRev=408) -#stepperhour = StepperL298M.Stepper([19,21,22,23]) -#clock = StepperClock.StepperClock(stepperhour,stepperminu) +#Initalise the Motors +stepperminu = StepperL298M.Stepper([19,21,22,23],inverted=False) +stepperhour = StepperL298M.Stepper([12,27,26,25],inverted=True) +clock = StepperClock.StepperClock(stepperhour,stepperminu) -#while(True): -# clock.update() -# clock.waitForStillstand() -# clock.disablePower() -# time.sleep(0.1) + +LED = machine.Pin(32,machine.Pin.OUT) + +def leftButtonClick(): + global i + print("Down",LED.value()) + LED.value(not LED.value()) + stepperhour.rotateTo(stepperhour.getTarget()+0.1) +Button.Button(36,leftButtonClick,None,inverted=True) + +def rightButtonClick(): + global i + print("Down",LED.value()) + LED.value(not LED.value()) + stepperhour.rotateTo(stepperhour.getTarget()-0.2) +Button.Button(34,rightButtonClick,None,inverted=True) + +clock.start() + +loop.run_forever()