Hallo, ich möchte eine Maschine zur Rotationsentwicklung von analogen Filmen bauen.
Dazu habe ich einen Nema 17 bipolaren Motor den ich mit einem Treiber Board DRVB8825 ansteuere. Mit der AccelStepper Library klappt das soweit gut.
Nun wollte ich noch einen Buzzer dazu nehmen, der jede Minute kurz piept. Sowie die im
Ein-Schalter befindliche LED, welche nach dem Einschalten leuchtet, jede Minute kurz blinken lassen. Das alles auf einem AtTiny85 (passt drauf)
Dazu habe ich folgenden Code genutzt:
/* Sketch für eine Rotationsentwicklungs-Maschine für Jobo Dosen
15xx und 25xx/28xx mit Nema 17 Stepper-Motor und DRV8825
8 Umdrechungen im Uhrzeigersinn und zurück. Ca. 70 U/min */
#include <Arduino.h>
#include "AccelStepper.h"
const int BUZZER = 3;
const int ledPin = 4;
unsigned long ledTimer;
unsigned long BuzzerTimer;
int LedStatus = HIGH;
// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 0
#define stepPin 1
#define motorInterfaceType 1
// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);
void setup() {
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin, HIGH);
// Set the maximum speed and acceleration:
stepper.setMaxSpeed(470); //Half-Step
stepper.setAcceleration(400); //Half-Step
}
void loop() {
if(millis() - BuzzerTimer >=60000 ){
tone(BUZZER, 500,1000);//tone of 500Hz for 1 second/1000 milliseconds
BuzzerTimer = millis();
}
if (LedStatus == HIGH) {
if (millis() - ledTimer >= 60000 ) {
digitalWrite(ledPin, LOW);
ledTimer = millis();
LedStatus = LOW;
}
} else {
if (millis() - ledTimer >= 250) {
digitalWrite(ledPin, HIGH);
LedStatus = HIGH;
}
{// Set the target position:
stepper.moveTo(3200); // Half-Step
// Run to target position with set speed and acceleration/deceleration:
stepper.runToPosition();
delay(300);
// Move back to zero:
stepper.moveTo(0);
stepper.runToPosition();
delay(300);
}
}
}
Beide Code Abschnitte für sich laufen richtig:
Buzzer und LED (ohne den Stepper Anteil in der Loop) oder Motor alleine.
Zusammen läuft der Motor und der Buzzer piept jede Minute. Jedoch die Led geht jede Minute aus und bleibt dann länger als eingestellt (250 ms) aus. Scheinbar un die Zeit länger, die ein kompletter Zyklus Stepper Motor dauert.
Moves the motor (with acceleration/deceleration) to the target position and blocks until it is at position. Dont use this in event loops, since it blocks.
Es gibt andere functions in AccelStepper die nicht blockierend sind.
Die müssen aber mit ganz hoher Frequenz immer wieder neu aufgerfufen werden.
Das geht gar nicht mit delay() zusammen.
Dann müssen die delay auf jeden Fall durch nicht blockierendes timing basierend auf millis() verwendet werden.
Die andere Variante ist die library mobaTools zu verwenden.
Da werden die Step-Impulse per Timer-interrupt erzeugt.
Hat der Tiny85 Timer 1? dann geht das.
Frage: muss es unbedingt so ein Winzling wie Tiny85 sein?
hier ein Sketch, der Deine Anforderungen (hoffentlich) erfüllen sollte:
/*
Forum: https://forum.arduino.cc/t/timer-problem-accelstepper-library/1341227
Wokwi: https://wokwi.com/projects/419796124630104065
Originalsketch aus Post 1 Wokwi: https://wokwi.com/projects/419795832434931713
2025/01/11
Angepasst durch ec2021
*/
/* Sketch für eine Rotationsentwicklungs-Maschine für Jobo Dosen
15xx und 25xx/28xx mit Nema 17 Stepper-Motor und DRV8825
8 Umdrechungen im Uhrzeigersinn und zurück. Ca. 70 U/min */
#include <Arduino.h>
#include "AccelStepper.h"
const int BUZZER = 3;
const int ledPin = 4;
const unsigned long stepperDelay = 300;
const unsigned long ledIntervall = 5000; // 60000;
const unsigned long blinkDuration = 300;
const unsigned long buzzerIntervall = 5000; //60000;
const int stepperRechts = 3200;
const int stepperLinks = 0;
enum StatusTyp {WARTERECHTS, RECHTS, WARTELINKS, LINKS};
StatusTyp status = WARTERECHTS;
unsigned long ledTimer = 0;
unsigned long buzzerTimer = 0;
unsigned long stepperTimer = 0;
int LedStatus = HIGH;
// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 0
#define stepPin 1
#define motorInterfaceType 1
// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);
void setup() {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
// Set the maximum speed and acceleration:
stepper.setMaxSpeed(470); //Half-Step
stepper.setAcceleration(400); //Half-Step
ledTimer = millis();
buzzerTimer = millis();
}
void loop() {
stateMachine();
beep();
blink();
}
void stateMachine() {
switch (status) {
case WARTERECHTS:
if (millis() - stepperTimer > stepperDelay) {
status = RECHTS;
stepper.moveTo(stepperRechts);
}
break;
case RECHTS:
stepper.run();
if (stepper.currentPosition() >= stepperRechts) {
status = WARTELINKS;
stepperTimer = millis();
}
break;
case WARTELINKS:
if (millis() - stepperTimer > stepperDelay) {
status = LINKS;
stepper.moveTo(stepperLinks);
}
break;
case LINKS:
stepper.run();
if (stepper.currentPosition() <= stepperLinks) {
status = WARTERECHTS;
stepperTimer = millis();
}
break;
}
}
void beep() {
if (millis() - buzzerTimer >= buzzerIntervall ) {
buzzerTimer = millis();
tone(BUZZER, 500, 1000); //tone of 500Hz for 1 second/1000 milliseconds
}
}
void blink() {
static byte ledStatus = HIGH;
if (millis() - ledTimer >= ledIntervall && ledStatus == HIGH) {
ledTimer = millis();
ledStatus = LOW;
digitalWrite(ledPin, ledStatus);
}
if (millis() - ledTimer >= blinkDuration && ledStatus == LOW) {
ledStatus = HIGH;
digitalWrite(ledPin, ledStatus);
}
}
// ACHTUNG:
// Hilfslösung, da der Attiny85 bei Wokwi tone() auf Pin PB3 nicht unterstützt
//
void tone(byte Pin, int f, int d) {
pinMode(Pin, OUTPUT);
for (int i = 0; i < 5; i++) {
digitalWrite(Pin, HIGH);
delay(1);
digitalWrite(Pin, LOW);
}
}
Der Sketch wurde auf Wokwi geschrieben und getestet, wo tone() am Pin PB3 nicht unterstützt wird. Daher habe ich tone() hilfsweise mit einer eigenen Funktion überschrieben. Diesen Teil (ganz unten im Sketch!) kannst Du löschen, wenn die Funktion an Deinem Attiny85 gegeben ist.
Die Konstanten für die Intervalle zum Blinken und die Tonausgabe habe ich zum Testen auf 5 s gesetzt; hier kannst Du wieder die 60 s eintragen:
const unsigned long ledIntervall = 5000; // 60000;
const unsigned long blinkDuration = 300;
const unsigned long buzzerIntervall = 5000; //60000;
Hallo,
habe mich mit der mobaTools Library befasst. Dabei habe ich fo0lgendes gebaut:
/* Example for MobaTools
Moving a stepper back and forth
*/
#include <MobaTools.h>
// Adjust pins, steps and time as needed
const byte stepPin = 9;
const byte dirPin = 8;
const int stepsPerRev = 800; // Steps per Revolution ( example with 1/4 microsteps )
const long targetPos = 6400; // stepper moves between 0 and targetpos
long nextPos;
const int Buzzer = 10;
MoToTimer Buzzerzeit;
const int Led = 11;
MoToTimer Ledzeit;
MoToStepper myStepper ( stepsPerRev, STEPDIR );
MoToTimer stepperPause; // Pause between stepper moves
bool stepperRunning;
void setup() {
myStepper.attach( stepPin, dirPin );
myStepper.setSpeed( 700 ); // 70 Rev/Min ( if stepsPerRev is set correctly )
myStepper.setRampLen( 1200 );
stepperRunning = true;
//pinMode(Buzzer, OUTPUT);
pinMode(Led, OUTPUT);
digitalWrite(Led, HIGH);
}
void loop() {
if ( stepperRunning ) {
// Wait till stepper has reached target, then set pause time
if ( !myStepper.moving() ) {
// stepper has reached target, start pause
stepperPause.setTime( 1000 );
stepperRunning = false;
}
} else {
// stepper doesn't move, wait till stepperPause time expires
if ( stepperPause.expired() ) {
// stepperPause time expired. Start stepper in opposite direction
if ( nextPos == 0 ) {
nextPos = targetPos;
} else {
nextPos = 0;
}
myStepper.moveTo( nextPos );
stepperRunning = true;
}
}
// The sketch is not blocked while the stepper is moving nor while it is stopped.
// Other nonblocking tasks can be added here
// diese Led blinkt mit unsymetrischem Taktverhältnis
if ( Ledzeit.running()== false ) {
// Blinkzeit abgelaufen, Ausgang toggeln und
// Zeit neu aufziehen
if ( digitalRead( Led ) == LOW ) {
digitalWrite( Led, HIGH );
Ledzeit.setTime( 30000 );
} else {
digitalWrite( Led, LOW );
Ledzeit.setTime( 500 );
}
}
if ( Buzzerzeit.running() == false ) { // Buzzerzeit abgelaufen
tone(Buzzer, 440, 500);
Buzzerzeit.setTime( 30000 ); // Zeit neu aufziehen
}
}
Dabei sollte doch der Buzzer und die led gleichzeitig blinken. Jedoch läuft nach kurzer Zeit die LED dem Buzzer immer weiter hinterher?
für regelmäßiges Auslösen gibt es das Objekt MotoTimebase
MoToTimebase myBase;
myBase.setBasetime( 5000 );
Wie ist das wenn man jetzt
myBase.tick();
abfragt.
Muss das genau nach 5000 Millisekunden sein ud nur wenn man exakt in der 5000sten Millisekunde abfragt, dann liefert das ein einziges mal true weil dann wird ja das nächste intervall gestartet ?
Oder bleibt das true bis man es einmal abgefragt hat ?
Was bedeuten würde auch wenn ich nach 6000 Millisekunden das erste man tick() aufrufe liefert es true?
Nein. Wenn in dem Fall die 5000ms abgelaufen sind, wird tick() einmal true zurückliefern, egal wann Du abfragst.
Ja, beim nächsten Mal dann aber schon wenn Du nach 4000ms ein weiters Mal abfragst. Solange Du öfter abfragst als es dem Intervall entspricht, bleibt das Raster gleich. Wenn Du allerdings immer zu spät abfragst, funktioniert das nicht mehr. Dann macht die Funktion aber eigentlich keinen Sinn mehr. [EDIT] Das Raster bleibt auch in dem Fall gleich, aber Du verlierst 'ticks'[/EDIT]
D.h. Du solltest tick() auf jeden Fall öfter abfragen als es dem Intervall entspricht, aber Du musst nicht immer genau den Intervallzeitpunkt treffen ( dann würde es ja auch keinen Sinn machen)