MrMiffy08
10.09.2013, 19:24
Hallo zusammen,
ich möchte eine Motorsteuerung aufbauen, mit einem Arduino Uno R3 und einem LCD-Shield von Sainsmart (http://www.sainsmart.com/arduino-compatibles-1/lcd-module/sainsmart-1602-lcd-keypad-shield-for-arduino-duemilanove-uno-mega2560-mega1280.html), die PWM geht auf ein Motorshield vom robotikhardware.de (http://www.shop.robotikhardware.de/shop/catalog/product_info.php?cPath=65&products_id=90) . Der Motor ist einer dieser Scheibenwischermotore vom Pollin (http://www.pollin.de/shop/dt/MjM1OTg2OTk-/Motoren/DC_Getriebemotoren/DC_Getriebemotor_mit_Spindel_200680_12_V_rechts.ht ml), 12Volt, 3,5A, unter Last max. 22A.
Ich will mit einem Drehencoder ansteuern, der zusätzlich einen Taster hat (für Start/Stop), R/L wird über Taster auf dem LCD-Shield geschaltet, die über eine Widerstandsleiter an einem Analogeingang abgefragt werden. Würde ich alle drei Taster an einen eigenen Port hängen, hätte ich genau einen zu wenig.
Also, das ganze ist aus mehreren Tuts zusammen gewürfelt, und da ich Programmieranfänger bin, stecken da sicher einige Fehler drin. Die Testhardware ist auch noch nicht ganz fertig, die Teile sind aber im Zulauf.
Nun meine Bitte: Könntet Ihr mal bitte auf meinen "zusammengewürfelten" Code schauen, ob da "dicke Hunde" drin stecken oder auch mehrere kleinere Fehlerchen, ich lerne noch...
Besonders unsicher bin ich, ob die Übergabe der Variablen encoderPos (ganz weit unten, bei Motor Steuerung) als PWM Wert überhaupt so funktioniert. Muss die nicht oben erst deklariert werden? Kann man das so machen?
/*
Interrupt Routine für Drehencoder von rafbuff, LCD vom SainSmart LCDShield, Motor Routine aus Tutorial
Das Dingens soll:
einen DC Motor rechts und links herum steuern, dabei die Geschwindigkeit per PWM
über den Drehencoder erhöhen/verringern, die Encoder-Werte auf dem LCD ausgeben.
Am LCD Shield sind einige Taster angebracht, die über eine Widerstandsleiter an
einem Analogeingang dekodiert werden. Stammt aus dem Example zum LCD-Shield. Das ist pfiffig, denn die digitalen Inputs
würden bei normaler Beschaltung jedes Tasters an einem digitalen In nicht
ausreichen...
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
char LCDChar[2]="";
// Drehencoder-Deklaration: A & B, Gnd in der Mitte, Achtung 100nF und 10k als Debouncer-Glied...
int motor1_A=5;
int motor1_B=4;
int motor1_PWM=13;
enum PinAssignments {
encoderPinA = 2, // rigth , Speed up
encoderPinB = 3, // left , Speed down
clearButton = ? // Stop-Button, Taster am Drehencoder
LinksButton = ? // Laufrichtung Links Taster
RechtsButton ? // Laufrichtung Rechts Taster
};
volatile unsigned int encoderPos = 0; // a counter for the dial
unsigned int lastReportedPos = 1; // change management
static boolean rotating=false; // debounce management
// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;
//ab hier die Tasterabfrage:
************************************************** ******/
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int backLight = 10; // LCD Panel Backlight LED connected to digital pin 10
int lightLevel = 255; // Initialise light full on
int lcd_key = 0;
int adc_key_in = 0;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the resistor-ladder
// my [Mark Bramwell's] buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this...
}
//************************************************** ******
void setup() {
//Motor Pins deklarieren:
pinMode(motor1_A,OUTPUT);
pinMode(motor1_B,OUTPUT);
//Encoder Pins decl.
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
//LCD starten
lcd.begin(16, 2); // 16x2 LCD panel
lcd.setCursor(0,0);
lcd.print("LCD KeyPadShield");
lcd.setCursor(0,1);
lcd.print("<Character Set>");
delay(2000);
// Pullups setzen
digitalWrite(encoderPinA, HIGH);
digitalWrite(encoderPinB, HIGH);
// Encoder pin on interrupt 0 (pin 2)
attachInterrupt(0, doEncoderA, CHANGE);
// Encoder pin on interrupt 1 (pin 3)
attachInterrupt(1, doEncoderB, CHANGE);
}
//************************************************** ******
// main loop, work is done by interrupt service routines; set motor
void loop() {
lcd.clear();
for(int i=0; i<=255; i++){
lcd.setCursor(0,0);
lcd.print("Drehzahl= ");
sprintf(LCDChar, "0x%02X", i);
lcd.print(LCDChar);
lcd.setCursor(5,1);
lcd.print(encoderPos, DEC);
delay(500);
//************************************************** ******
//ab hier geht's um den Drehencoder:
rotating = true; // reset the debouncer
if (lastReportedPos != encoderPos) {
lcd.print("Geschwind.: ");
lcd.print( encoderPos, DEC);
lastReportedPos = encoderPos;
}
if (digitalRead(clearButton) == LOW ) {
encoderPos = 0;
}
}
// Interrupt on A changing state
void doEncoderA(){
// debounce
if ( rotating ) delay (1); // wait a little - 1 ms - until the bouncing is
done
// Test transition, did things really change?
if( digitalRead(encoderPinA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set )
encoderPos += 10;
rotating = false; // no more debouncing until loop() hits again
}
}
// Interrupt on B changing state, same as A above
void doEncoderB(){
if ( rotating ) delay (1);
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if( B_set && !A_set )
encoderPos -= 10;
rotating = false; // no more debouncing until loop() hits again
}
// ab hier - die Motor Ansteuerung
//************************************************** ******
// Rechts drehen
digitalWrite(motor1_A,HIGH); // A = HIGH and B = LOW means the motor will turn right
digitalWrite(motor1_B,LOW);
digitalRead(motor1_Speed, encoderPos); // speed is taken over from encoder
Position
}
//Links drehen
digitalWrite(motor1_A,LOW); // A = LOW and B = HIGH means the motor will turn left
digitalWrite(motor1_B,HIGH);
digitalRead(motor1_Speed, encoderPos); // speed is taken over from encoder
Position
}
//Ab hier die Tastenabfrage und Ausgabe auf LCD:
{
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btnRIGHT:
{
lcd.print("LED On ");
lightLevel = 255;
break;
}
case btnLEFT:
{
lcd.print("LED Off ");
lightLevel = 1;
break;
}
case btnUP:
{
lcd.print("LED Fade Up ");
if (lightLevel < 255) lightLevel += 1;
break;
}
case btnDOWN:
{
lcd.print("LED Fade Down ");
if (lightLevel > 1) lightLevel -= 1;
break;
}
case btnSELECT:
{
lcd.print("Select ");
break;
}
case btnNONE:
{
lcd.print(" ");
break;
}
}
}
}
PS: den Code für die Taster am Analogeingang habe ich grade noch hinzugefügt.
Ist es besser, den ganzen Sermon mal mehr in Einzelteile zu zerlegen?
Vielen Dank auf jeden Fall schon mal im Voraus für Eure Hilfe!
Schöne Grüße, MrMiffy08
ich möchte eine Motorsteuerung aufbauen, mit einem Arduino Uno R3 und einem LCD-Shield von Sainsmart (http://www.sainsmart.com/arduino-compatibles-1/lcd-module/sainsmart-1602-lcd-keypad-shield-for-arduino-duemilanove-uno-mega2560-mega1280.html), die PWM geht auf ein Motorshield vom robotikhardware.de (http://www.shop.robotikhardware.de/shop/catalog/product_info.php?cPath=65&products_id=90) . Der Motor ist einer dieser Scheibenwischermotore vom Pollin (http://www.pollin.de/shop/dt/MjM1OTg2OTk-/Motoren/DC_Getriebemotoren/DC_Getriebemotor_mit_Spindel_200680_12_V_rechts.ht ml), 12Volt, 3,5A, unter Last max. 22A.
Ich will mit einem Drehencoder ansteuern, der zusätzlich einen Taster hat (für Start/Stop), R/L wird über Taster auf dem LCD-Shield geschaltet, die über eine Widerstandsleiter an einem Analogeingang abgefragt werden. Würde ich alle drei Taster an einen eigenen Port hängen, hätte ich genau einen zu wenig.
Also, das ganze ist aus mehreren Tuts zusammen gewürfelt, und da ich Programmieranfänger bin, stecken da sicher einige Fehler drin. Die Testhardware ist auch noch nicht ganz fertig, die Teile sind aber im Zulauf.
Nun meine Bitte: Könntet Ihr mal bitte auf meinen "zusammengewürfelten" Code schauen, ob da "dicke Hunde" drin stecken oder auch mehrere kleinere Fehlerchen, ich lerne noch...
Besonders unsicher bin ich, ob die Übergabe der Variablen encoderPos (ganz weit unten, bei Motor Steuerung) als PWM Wert überhaupt so funktioniert. Muss die nicht oben erst deklariert werden? Kann man das so machen?
/*
Interrupt Routine für Drehencoder von rafbuff, LCD vom SainSmart LCDShield, Motor Routine aus Tutorial
Das Dingens soll:
einen DC Motor rechts und links herum steuern, dabei die Geschwindigkeit per PWM
über den Drehencoder erhöhen/verringern, die Encoder-Werte auf dem LCD ausgeben.
Am LCD Shield sind einige Taster angebracht, die über eine Widerstandsleiter an
einem Analogeingang dekodiert werden. Stammt aus dem Example zum LCD-Shield. Das ist pfiffig, denn die digitalen Inputs
würden bei normaler Beschaltung jedes Tasters an einem digitalen In nicht
ausreichen...
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
char LCDChar[2]="";
// Drehencoder-Deklaration: A & B, Gnd in der Mitte, Achtung 100nF und 10k als Debouncer-Glied...
int motor1_A=5;
int motor1_B=4;
int motor1_PWM=13;
enum PinAssignments {
encoderPinA = 2, // rigth , Speed up
encoderPinB = 3, // left , Speed down
clearButton = ? // Stop-Button, Taster am Drehencoder
LinksButton = ? // Laufrichtung Links Taster
RechtsButton ? // Laufrichtung Rechts Taster
};
volatile unsigned int encoderPos = 0; // a counter for the dial
unsigned int lastReportedPos = 1; // change management
static boolean rotating=false; // debounce management
// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;
//ab hier die Tasterabfrage:
************************************************** ******/
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int backLight = 10; // LCD Panel Backlight LED connected to digital pin 10
int lightLevel = 255; // Initialise light full on
int lcd_key = 0;
int adc_key_in = 0;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the resistor-ladder
// my [Mark Bramwell's] buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this...
}
//************************************************** ******
void setup() {
//Motor Pins deklarieren:
pinMode(motor1_A,OUTPUT);
pinMode(motor1_B,OUTPUT);
//Encoder Pins decl.
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
//LCD starten
lcd.begin(16, 2); // 16x2 LCD panel
lcd.setCursor(0,0);
lcd.print("LCD KeyPadShield");
lcd.setCursor(0,1);
lcd.print("<Character Set>");
delay(2000);
// Pullups setzen
digitalWrite(encoderPinA, HIGH);
digitalWrite(encoderPinB, HIGH);
// Encoder pin on interrupt 0 (pin 2)
attachInterrupt(0, doEncoderA, CHANGE);
// Encoder pin on interrupt 1 (pin 3)
attachInterrupt(1, doEncoderB, CHANGE);
}
//************************************************** ******
// main loop, work is done by interrupt service routines; set motor
void loop() {
lcd.clear();
for(int i=0; i<=255; i++){
lcd.setCursor(0,0);
lcd.print("Drehzahl= ");
sprintf(LCDChar, "0x%02X", i);
lcd.print(LCDChar);
lcd.setCursor(5,1);
lcd.print(encoderPos, DEC);
delay(500);
//************************************************** ******
//ab hier geht's um den Drehencoder:
rotating = true; // reset the debouncer
if (lastReportedPos != encoderPos) {
lcd.print("Geschwind.: ");
lcd.print( encoderPos, DEC);
lastReportedPos = encoderPos;
}
if (digitalRead(clearButton) == LOW ) {
encoderPos = 0;
}
}
// Interrupt on A changing state
void doEncoderA(){
// debounce
if ( rotating ) delay (1); // wait a little - 1 ms - until the bouncing is
done
// Test transition, did things really change?
if( digitalRead(encoderPinA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set )
encoderPos += 10;
rotating = false; // no more debouncing until loop() hits again
}
}
// Interrupt on B changing state, same as A above
void doEncoderB(){
if ( rotating ) delay (1);
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if( B_set && !A_set )
encoderPos -= 10;
rotating = false; // no more debouncing until loop() hits again
}
// ab hier - die Motor Ansteuerung
//************************************************** ******
// Rechts drehen
digitalWrite(motor1_A,HIGH); // A = HIGH and B = LOW means the motor will turn right
digitalWrite(motor1_B,LOW);
digitalRead(motor1_Speed, encoderPos); // speed is taken over from encoder
Position
}
//Links drehen
digitalWrite(motor1_A,LOW); // A = LOW and B = HIGH means the motor will turn left
digitalWrite(motor1_B,HIGH);
digitalRead(motor1_Speed, encoderPos); // speed is taken over from encoder
Position
}
//Ab hier die Tastenabfrage und Ausgabe auf LCD:
{
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btnRIGHT:
{
lcd.print("LED On ");
lightLevel = 255;
break;
}
case btnLEFT:
{
lcd.print("LED Off ");
lightLevel = 1;
break;
}
case btnUP:
{
lcd.print("LED Fade Up ");
if (lightLevel < 255) lightLevel += 1;
break;
}
case btnDOWN:
{
lcd.print("LED Fade Down ");
if (lightLevel > 1) lightLevel -= 1;
break;
}
case btnSELECT:
{
lcd.print("Select ");
break;
}
case btnNONE:
{
lcd.print(" ");
break;
}
}
}
}
PS: den Code für die Taster am Analogeingang habe ich grade noch hinzugefügt.
Ist es besser, den ganzen Sermon mal mehr in Einzelteile zu zerlegen?
Vielen Dank auf jeden Fall schon mal im Voraus für Eure Hilfe!
Schöne Grüße, MrMiffy08