Forum: Mikrocontroller und Digitale Elektronik DC-Motorsteuerung über Taster mit ATtiny


von Horst H. (marvinlorenz)


Lesenswert?

Ich habe bereits in anderen Forenbeiträge gesucht, jedoch nichts 
passendes gefunden.

Um einen kleinen DC-Motor 3V 200mA über einen Taster zu steuern würde 
ich gerne einen ATtiny 45 gebrauchen.

Mit dem Taster sollen drei verschiedene Geschwindigkeiten eingestellt 
werden können. Quasi: tasten--> Stufe 1; nochmal tasten---> Stufe 2; 
nochmal tasten-->Stufe 3

Ich bin auf dem Gebiet noch recht neu. Einen Atmega 32 hab ich schon 
geflasht und in C hab ich Grundkenntnisse. Ein STK500 hab ich auch.

Die Drehzahlregelung kann man über PWM und Mosfet machen oder?

Wichtig wäre mir auch, dass der Attiny sehr wenig Stom verbraucht im 
Leerlauf. Da die Schaltung über längere Zeit nicht benutzt wird und nur 
gelegentlich gebraucht wird. Gibt es eine Art Sleepmodus beim ATiny?
Kann man das so programmieren, dass sich der Atiny nach einer gewissen 
Zeit nachdem es keinen Tasterschluss gab sich in den Sleepmodus schickt.
Die Steuerung soll im Gesamten über einen Taster funktionieren also auch 
das Aufwecken des ATiny.

Ich wäre sehr froh wenn mir jemand helfen könnte.


Viele Grüsse
Horst

von Cyblord -. (cyblord)


Lesenswert?

Horst H. schrieb:
> Ich habe bereits in anderen Forenbeiträge gesucht, jedoch nichts
> passendes gefunden.
Klar...

> Die Drehzahlregelung kann man über PWM und Mosfet machen oder?
Ja. Falls der Motor nur in eine Richtung laufen soll, reicht ein Mosfet. 
Ansonsten würde ich einen Motortreiber (L293D oder neuere Generationen) 
nehmen.

> Wichtig wäre mir auch, dass der Attiny sehr wenig Stom verbraucht im
> Leerlauf. Da die Schaltung über längere Zeit nicht benutzt wird und nur
> gelegentlich gebraucht wird. Gibt es eine Art Sleepmodus beim ATiny?

Ja, bitte schau ins Datenblatt. Steht da alles drin. Es gibt 
verschiedene Stromsparmodi, jeder hat andere Eigenschaften und andere 
Aufweckquellen.

> Kann man das so programmieren, dass sich der Atiny nach einer gewissen
> Zeit nachdem es keinen Tasterschluss gab sich in den Sleepmodus schickt.
> Die Steuerung soll im Gesamten über einen Taster funktionieren also auch
> das Aufwecken des ATiny.
Ja klar.


> Ich wäre sehr froh wenn mir jemand helfen könnte.

Was für eine Art Hilfe stellst du dir hier vor?

gruß cyblord

von m.n. (Gast)


Lesenswert?

Das Ein-Ausschalten mit Tiny45 kannst Du hier sehen. 
Beitrag "EIN-AUS mit Taster per Interrupt, ATtiny25 o.ä."

Es wird auch schon ein PWM-Signal an PB0 erzeugt. Die Ladungspumpe wird 
nicht benötigt, sondern ein passender N-Kanal MOSFET, der den Motor 
gegen GND einschaltet.
Aber das Programm muß so modifiziert werden, dass das PWM-Signal bei 
jedem Tastendruck erhöht wird (OCR0A) und am Ende auf 0 gesetzt wird.
Ist PWM auf 0, kann der Tiny wieder 'eingeschläfert' werden.

Am einfachsten kann das in main() in der Schleife while1() erledigt 
werden, denn jeder erneute Tastendruck setzt die Variable 'abschalten' 
auf '1'.

von Karl H. (kbuchegg)


Lesenswert?

Schrittweise vorgehen!

Die Sache mit dem Sleep legst du erst mal auf Eis. Die brauchst du nicht 
sofort.
Wenn du mit Motoren noch nicht so fit bist, dann nimm als erstes 
Ausgabeelement erst mal eine LED. Die ist einfach anzusteuern und auch 
vom Programm her kein Problem. PWM brauchst du da erst mal auch noch 
nicht.

Denn: Du brauchst ein einfaches Ausgabeelement um dir erst mal eine 
'Anzeigemöglichkeit' für dein erstes Teilziel zu schaffen:

Tasten einlesen, entprellen und auswerten.

Das ist dein erstes Teilziel, das du angehst: Die Tastendrücke erkennen. 
Und zwar nicht einfach irgendwie erkennen, sondern
* als Tastendruck
* und auch noch entprellt.

Entprellung

und mit dieser Tastenentprellung schaltest du erst mal nur die LED 
ein/aus.

Hast du dieses Teilziel erreicht, dann kommt der nächste Schritt. 
Anstatt die popelige LED einfach nur ein/aus zu schalten, möchtest du 
sie dimmen (was im Prinzip den unterschiedlichen Drehzahlen deines 
Motors entspricht). Zum Dimmen nimmst du eine PWM her. Die probierst du 
erst mal ohne Tasten aus. D.h. du nimmst die PWM in Betrieb und mit der 
LED kontrollierst du, ob das so funktioniert, wie es sein soll. Durch 
Verändern der PWM (Konstante im Programm durch eine anderen Zahlenwert 
austauschen) siehst du nach, ob du tatsächlich unterschiedliche 
Helligkeiten der LED erreichen kannst.

FAQ: Timer

Ist das dann soweit erledigt, kannst du die Helligkeit durch Verändern 
der LED verstellen, dann werden die bisherigen beiden Teilziele 
zusammengeführt. Du möchtest mittels Tastendruck die LED durch eine 
Abfolge von Helligkeiten durchschalten. (Jetzt näherst du dich bereits 
deinem endgültigen Programm-Ziel). D.h. jetzt ist die Logik gefragt, wie 
Tastendrücke ausgewertet werden und so in Veränderungen der PWM 
umgesetzt werden, so dass die LED bei Tastendruck die jeweils nächste 
Helligekeit annnimmt.

Jetzt ist es dann auch an der Zeit, die LED durch einen Motor zu 
ersetzen. Dazu brauchst du einen Motortreiber, denn der µC kann ja den 
Motorstrom/Spannung nicht liefern. D.h. es wird langsam Zeit diese 
Hardware aufzubauen und in Betrieb zu nehmen. In deinem Programm werden 
sich die konkreten Zahlenwerte für die PWM ein wenig verändern aber das 
ist das kleinere Problem. Dank guter Vorbereitung mit der LED hast du ja 
ein Programm, welches im Prinzip schon das gewünschte leistet. Wenn da 
jetzt also noch Probleme auftauchen, dann können die nur noch im Bereich 
Motortreiber bzw. dessen Ansteuerung liegen.

Und dann, ganz zum Schluss kümmerst du dich um den Sleep-Modus und wie 
man den µC aus diesem rauskriegt bzw. um die Logik, wann sich der µC 
wieder schlafen legt. Eventuell musst du dazu deinen Taster nochmal an 
einen anderen µC-Pin legen, mit dem es dir gelingt den Sleep zu beenden.

Tja, und so wie ich das sehe, bist du dann auch 'schon' fertig.
Das wichtige: Arbeite in Schritten! Setz dir Teilziele! Teilziele, die 
du erreichen kannst ohne allzuviel Neues im System zu haben. Nach 
Möglichkeit willst du im nächsten Teilziel immer nur eine neue 
Komponente haben um die du dich kümmern musst. Also nicht alles auf 
einmal und keine AHnung haben, wo man anfängt, sondern bei den einfachen 
Dingen anfangen und dann sukzessive in kleinen Schritten in Richtung 
Ziel gehen, wobei durchaus auch mal ein kleiner Umweg (wie hier die LED) 
erlaubt bzw. sinnvoll ist, wenn sich dadurch das zu testende System 
zwischendurch extrem vereinfacht. Eine LED kann man einfach (mit 
Vorwiderstand) anhängen - ein Motor bringt schon wieder seine eigenen 
Probleme (wie zb Ströme) mit. Also sucht man für den Motor erst mal 
einen Ersatz, so dass man die programmiertechnische Seite trotzdem in 
Angriff nehmen kann OHNE dass einem die Hardware da sofort in die Suppe 
spuckt.

von Karl H. (kbuchegg)


Lesenswert?

m.n. schrieb:
> Das Ein-Ausschalten mit Tiny45 kannst Du hier sehen.
> Beitrag "EIN-AUS mit Taster per Interrupt, ATtiny25 o.ä."

Kein guter Artikel.
Tasten mittels RC zu entprellen ist unnötig kompliziert.
Aber auch das wurde im Artikel schon angesprochen.

von Eumel (Gast)


Lesenswert?

An dieser Stelle mal ein dickes Lob an Karl Heinz! Finde es immer wieder 
schön zu sehen wie viel Mühe du dir gibst und wie gut verständlich und 
hilfreich deine oft ausführlichen Antworten sind. :)

von m.n. (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Tasten mittels RC zu entprellen ist unnötig kompliziert.
> Aber auch das wurde im Artikel schon angesprochen.

Na gut, dann hast Du es auch nicht verstanden :-)

@Horst
Einen Abschnitt weiter beim obigen Link findest Du das Programm 
'toggle_25.c'. Da ist die Ein-Ausschaltfunktion übersichtlicher.
Diese könntest Du als Basis nehmen und die PWM-Stufen hinzufügen.

von MaWin (Gast)


Lesenswert?

> dass sich der Atiny nach einer gewissen Zeit nachdem es keinen
> Tasterschluss gab sich in den Sleepmodus schickt.

Du weisst also schon, daß er schlafen muss, allerdings nicht wenn
kein Tatendruck kam, sondern wenn der Motor nicht läuft.

Aus dem sleep-Beispiel 
http://www.mikrocontroller.net/articles/Sleep_Mode zusammengestrichen, 
Fuses und Erklärungen siehe dort
1
#define F_CPU 1000000
2
#include <avr/io.h>
3
#include <avr/sleep.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
ISR(INT0_vect) { }
7
void long_delay(uint16_t ms) { while(ms-->0) _delay_ms(1); }
8
uint8_t mode; // 0=Motor aus, sleep, 1..3=Motor PWM
9
uint8_t taste,gedrueckt;
10
int main(void) 
11
{
12
    DDRD=0x01;   // PD0 = Motor, PD2 = INT0 = Eingang
13
    PORTD=0x04;  // Pull Up aktivieren, Motor aus
14
    ACSR=0x80;   MCUCR&=~0x3;
15
    sei();
16
    while(1) 
17
    {
18
        GICR|=(1<<INT0);
19
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
20
        sleep_mode();
21
        // hier wachen wir wieder auf wenn Taste gedrückt
22
        gedrueckt=0; // auf jeden Fall Tastendruck
23
        GICR&=~(1<<INT0);
24
        do // 30ms Schleife, Motor-PWM und Tastenentprellung
25
        {
26
            taste=!(PORTB&1); // aktuellen Tastenzustand
27
            if(taste&&!gedrueckt) mode=(mode+1)&3;
28
            gedrueckt=taste; // entprellen
29
            PORTB|=1;   // MOTOR PWM an
30
            long_delay(30-10*(3-mode));
31
            PORTB&=0xFE; // Motor PWM aus
32
            long_delay(10*mode);
33
        }
34
        while(mode||gedrueckt);
35
        // fall asleep again
36
    }
37
}
Es ist also nicht so schwer, ein Transistor an PD0 schaltet den Motor

5V -+--(M)--+ Motor
    |       |
    +--|<|--+ BA157
            |
PD0--220R--|< BC337
            |E
           GND

von m.n. (Gast)


Lesenswert?

Meinen obigen Vorschlag habe ich spaßhalber umgesetzt und an den 
betreffenden Artikel angehängt. 
Beitrag "Re: EIN-AUS mit Taster per Interrupt, ATtiny25 o.ä."

von Horst H. (marvinlorenz)


Lesenswert?

Vielen Vielen Dank, das hat mir sehr geholfen. Ich setze mich diese 
Wochenende mal dran und geb mein bestes. Bis Später

von Horst H. (marvinlorenz)


Lesenswert?

Mercie Leute,

es läuft, ein Traum.
Vielen Dank.
Besonderen Dank an m.n.

Bei jedem Tastendruck wird der nächste Wert aus der tabelle genommen:


uint8_t pwm_tabelle[] = {100, 160, 255}0;

Jetzt würde ich gern einen einen Modus erzeugen indem ein PWM-Signal 
fadenkann.

also quasi:

uint8_t pwm_tabelle[] = {100,160,255, faden}0;

Sprich die LED soll heller werden, dann wieder dunkler und das in einer 
Schleife.


  int a = 255; //höchster Wert

    while(1){

        while(a>100){
            OCR1A = a;
            _delay_ms(10);
            a--;
        }

        while(a<255){
            OCR1A = a;
            _delay_ms(10);
            a++;
  }

Wie kann ich das jetzt in eine Methode packen, die ich in die Tabelle 
schreiben kann?

Vielen Dank

Mein Code ist der von m.n.
1
/*
2
Dieses Programm erzeugt mit einem ATtiny25/45/85 ein PWM-Signal an PB0.
3
Ein einziger Taster schaltet den Prozessor ein und nimmt den 1. Wert aus der
4
PWM-Tabelle für das Tastverhältnis. Weitere Tastendrücke nehmen den nächsten Wert aus
5
der Tabelle, bis das Ende erreicht ist. Abschließend wird der Prozessor wieder in den 
6
Power-Don-Modus gelegt.
7
8
zur Funktion:
9
Nach dem Anlegen der Versorgungsspannung geht der µC nach ein
10
paar Befehlen zur Initialisierung in den Power-Down-Modus mit einer Stromaufnahme
11
von <1µA und wartet auf einen Interrupt, der ihn aufweckt.
12
13
Wird beim Drücken des Tasters die Schaltschwelle von PB4 zum Erkennen eines '0'-Pegels überschritten, 
14
wird der PinChange-Interrupt ausgelöst. Der Kondensator wird in der PCINT-Routine 
15
beschleunigt entladen, bis er GND Potential erreicht hat. Dadurch wird die Eingangshysterese auf 
16
nahezu Vcc erhöht. 'taste_gedrueckt' wird zur Auswertung in main() auf 1 gesetzt.
17
18
Das Loslassen des Tasters wird nicht ausgewertet. Lediglich der Kondensator am Eingang
19
wird aktiv auf '1' Pegel gebracht.
20
21
http://www.mino-elektronik.de
22
23
Alle Angaben ohne Gewaehr !
24
2013-10-01
25
*/
26
27
#include <avr/io.h>
28
#include <avr/interrupt.h>
29
#include <avr/sleep.h>
30
31
#define BIT(x)  (1<<x)
32
#define EIN_AUS_TASTER  4           // PortB 4
33
#define EIN_AUS_SIGNAL  3           // PortB 3 (ggf. mit LED)
34
#define PWM_OUT         0           // PortB 0
35
36
uint8_t pwm_tabelle[] = {100, 160, 255}0; // beliebige PWM-Werte
37
#define MAX_PWM_INDEX (sizeof(pwm_tabelle)/sizeof(pwm_tabelle[0]))
38
39
volatile uint8_t    taste_gedrueckt;
40
uint8_t pwm_index, abschalten;
41
42
// Interrupt vom Ein-Aus-Taster. Beim Schliessen des Tasters wird 'taste_gedrueckt' gesetzt.
43
ISR (PCINT0_vect)
44
{
45
volatile uint8_t n = 0xff;          // darf nicht wegoptimiert werden
46
  PCMSK &= ~BIT(EIN_AUS_TASTER);    // sperren
47
  if(PINB & BIT(EIN_AUS_TASTER)) {  // steigende flanke
48
    PORTB |= BIT(EIN_AUS_TASTER);
49
    DDRB  |= BIT(EIN_AUS_TASTER);   // und Ausgang aktiv auf 1
50
  } else {
51
    taste_gedrueckt = 1;            // bei jedem Tastendruck setzen
52
    PORTB &= ~BIT(EIN_AUS_TASTER);
53
    DDRB  |= BIT(EIN_AUS_TASTER);   // und Ausgang aktiv auf 0
54
  }
55
  while(n--);                       // kurz warten bis kondensator aufge- oder entladen
56
  PORTB |= BIT(EIN_AUS_TASTER);     // pullup immer aktiv
57
  DDRB  &= ~BIT(EIN_AUS_TASTER);    // und auf Eingangschalten
58
  GIFR = 0x20;                      // ggf. Störungen ausfiltern, flag löschen
59
  PCMSK |= BIT(EIN_AUS_TASTER);     // zulassen
60
}
61
62
void schreibe_pwm_wert(uint8_t wert)
63
{
64
  OCR0A = wert;                     // aktuellen Wert setzen
65
  if(wert) {                        // PWM aktivieren, wenn wert != 0
66
    TCCR0B = 0x02;                  // 8 Vorteiler
67
    TCCR0A = BIT(COM0A1) + BIT(WGM01) + BIT(WGM00);         // Fast PWM einschalten
68
    PORTB &= ~BIT(EIN_AUS_SIGNAL);  // Ausgang (LED) auf '0' = aktiv !
69
  } else {                          // sonst PWM abschalten
70
    TCCR0B = 0x00;                  // Timer0 abschalten
71
    TCCR0A &= ~(BIT(COM0A1) + BIT(WGM01) + BIT(WGM00));     // Fast PWM abschalten
72
    PORTB &= ~BIT(PWM_OUT);         // Ausgang auf '0'
73
    PORTB |= BIT(EIN_AUS_SIGNAL);   // Ausgang (LED) auf '1' = passiv !
74
  }
75
}
76
77
78
int16_t main(void)                  // typ. RC-Osz. 8MHz mit Teiler/8 
79
{
80
  DDRB  |= BIT(EIN_AUS_SIGNAL);     // Schaltausgang (PB3) aktivieren
81
  DDRB  |= BIT(PWM_OUT);            // immer als Ausgang
82
  PORTB |= BIT(EIN_AUS_SIGNAL);     // Schaltausgang (LED) passiv
83
  PORTB |= BIT(EIN_AUS_TASTER);     // interner Pullup für Taster
84
  PCMSK |= BIT(EIN_AUS_TASTER);     // PCINT für PB4 freigeben
85
  GIFR = BIT(PCIF);                 // flag löschen
86
  GIMSK |= BIT(PCIE);               // PCINT PORTB zulassen
87
  abschalten = 1;                   // nach Reset in den Schlafmodus gehen
88
  sei();
89
  while(1) {
90
    if(abschalten) {
91
      schreibe_pwm_wert(0);         // PWM-Signal abschalten
92
      abschalten = 0;
93
      pwm_index = 0;                // beim Einschalten wieder mit 1.Stufe beginnen
94
      while(!(PINB & BIT(EIN_AUS_TASTER))); // warten, solange Taste gedrueckt
95
      MCUCR = BIT(SE) + BIT(SM1);   // Power-Down wählen
96
      sleep_cpu();                  // und immer wieder schlafen legen
97
    }
98
    if(taste_gedrueckt) {
99
      taste_gedrueckt = 0;
100
      if(pwm_index >= MAX_PWM_INDEX) {
101
        abschalten = 1;
102
      } else {
103
        schreibe_pwm_wert(pwm_tabelle[pwm_index]);    // neuen Wert schreiben
104
        pwm_index++;
105
      }
106
    }
107
  } // endlos Schleife
108
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.