Regnator
23.04.2013, 10:33
Hallo Leute,
ich habe ein kleines Problem:
Ich habe ein Gehäuse mit Motoren des CC-RP5, AT89C5131 & einen PCF8591 welchen ich über I²C an den µC angebunden habe(zum auslesen von Analogsensoren). Das wird ein kleiner autonomer Roboter / ist es schon.
Mein derzeitiges Programm :
/*------------------------------------------------------------------+
| File: Roboterfahrzeug |
| Autor: |
| Klasse: E3GS1 |
| Controller: at89c5131 |
| Datum: 27.03.13 |
| Version: 2 |
+--------------------------------------------------------------------+
| Beschreibung: |
| |
+-----------------------------------------------------------------------------*/
#include <at89c5131.h> // fuer Atmel AT89C5131
/* adda_kniel.c ************************************************** *******************************
* Hilfsprogramme für den AD- und DA- Umsetzer mit I2C-Bus ********************************
* An DA-Umsetzer wert ausgeben: void aout (unsigned char wert)
* AD-Umsetzer einlesen, Kanal = 0,1,2,3: unsigned char ain (unsigned char kanal)
************************************************** ****************************************/
// geänderte Version 11/2007: Start und Stop-Bedingungen, funktioniert mit US-Sensoren
// geänderte Version 12/2006: funktioniert endlich aus als Library: adda.obj mit
// Tool -> Library-Manager in die Bibliothek RC51atms.lib einfügen
#include <reg51.h> // Registerdefinitionen
//#include <intrins.h> // für Rotationsfunktion
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
//****** verwendete I2C-Leitungen ************************************************** *******
sbit SDA = P4^1; // SDA-Leitung: ED2-Boards P3_5, (USB-Boards P4_1)
sbit SCL = P4^0; // SCL-Leitung: ED2-Boards P3_4, (USB-Boards P4_0)
//************************************************** **************************************
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
//***** verwendete Adressen und Kontrollbyte für den AD- und DA-Umsetzter ****************
#define Motor1 P1
#define Motor2 P2
#define vor 0x50
#define zurueck 0x44
#define stopp 0x40
#define adr_lies 0x91 // 10010001 -> 1001 fest, 000 durch Platine, 1 Wert lesen
#define adr_schreib 0x90 // 10010000 -> 1001 fest, 000 durch Platine, 0 Wert lesen
#define contr_ain 0x40 // 01000000 -> Kontrollbyte 4 einzelne ADU, Kanal= Offset dazu
sbit acc7 = 0xE7; // für Aus- und Eingabe eines Bits des Akkus
//void warte(int z);
// ************************************************** ***************************************
// I2C- Routinen zur Ansteuerung eins I2C-Slaves
// I2C-Bus-Funktionen i2c_init, i2c_start, i2c_stop, i2c_schreiben, i2c_lesen auch für andere
// I2C-Bus-ICs verwendbar
// ************************************************** ***************************************
// **** Zeitverzögerung zur Verlangsamung der Datenübertragungsrate ***********************
// **** i=2 bis i=100 wählen je nach I2C-IC und Pull-Up-Widerstand
void zeit (void) {unsigned char i; for (i=5;i!=0;i--) ;}
void vorwaerts (void);
void rueckwaerts (void);
void drehen (void);
void speaker(void);
void warte(int z);
void stop(void);
// ************************************************** **************************************
// ****** Initialiserung I2C-Bus ************************************************** ********
void i2c_init (void)
{
SDA = 1; // Leitungen in den Grundzustand High
zeit ();
SCL = 1;
zeit ();
}
// ****** Startbedingung I2C-Bus ************************************************** ********
void i2c_start (void)
{
SDA = 1; // Grundzustand
SCL = 1; // neu eingefügt 11/07
zeit();
SDA = 0; // Wechsel SDA von 1 -> 0 während SCL = 1
zeit ();
SCL = 0;
zeit ();
}
//****** Stoppbedingung I2C-Bus ************************************************** *********
void i2c_stop (void)
{
SDA = 0; // neu eingefügt 11/07
SCL = 1;
zeit ();
SDA = 1; // Wechsel von SDA 0 -> 1 während SCL =1
zeit ();
}
//************************************************** ***************************************
// * Byte ausgeben an I2C-Bus , Rückgabewert = Acknoledgebit = 0 wenn erfolgreich
// ************************************************** **************************************
bit i2c_schreiben (unsigned char byte)
{
unsigned char z; // Zähler
bit ack; // Acknoledge-Bit
ACC = byte; // Rotationsregister Akku
for (z = 8; z != 0; z --) // Zähler: serielle Ausgabe von 8 Bit
{
SDA = acc7; // Bit7 des Akku ausgeben
zeit ();
SCL = 1; // Daten sind gültig
asm {0x23}; // Akku links schieben
//ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
zeit ();
SCL = 0; // Datenausabe beendet
zeit ();
}
SDA = 1; // Leitung freigeben für Acknoledge-Bit
zeit ();
SCL = 1; // Slave kann bestätigen
zeit (); // warten
ack = SDA; // Acknoledge-Bit lesen
zeit ();
SCL = 0; // Slave soll Ackn-Ausgabe beenden
zeit();
return (ack); // Acknoledge-Bit ist Rückgabewert der Funktion
// ack = 0 bedeutet "verstanden" !!!!!!
}
//************************************************** ***************************************
// * Byte einlesen vom I2C-Bus. Bei Ack=1 wird Acknoledgebit gesendet, sonst nicht
// ************************************************** ***************************************
unsigned char i2c_lesen (bit ack)
{
unsigned char z,byte;
SDA = 1; // Leitung freigeben (high) für Daten
for (z = 8; z != 0; z --) // Zähler: serielles Einlesen von 8 Bit
{
SCL = 1; // Daten sind gültig
zeit ();
acc7 = SDA; // Datenbit in den Akku
asm {0x23}; // Akku links schieben
// ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
//P2_7 = SDA;
zeit();
SCL = 0; // Daten lesen beendet
zeit();
}
byte = ACC; // Eingelesenes Byte
if (ack == 1) {SDA = 0;} // Acknowledge-Bit senden
else {SDA = 1;} // kein Acknowledge-Bit
zeit ();
SCL = 1; // Ackn. gültig
zeit ();
SCL = 0; // Ackn. beendet
zeit ();
SDA = 0; // Leitung SDA vorbereiten für Stoppbed.
zeit ();
return (byte); // eingelesenes Byte = Rückgabewert
}
//************************** ADU und DAU- Funktionen *************************************
//************************************************** ***************************************
// * AD-Umsetzter einlesen, Kanal = Nr des ADU: 0,1,2,3
// ************************************************** ***************************************
unsigned char ain (unsigned char kanal)
{
unsigned char wert;
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse des IC und Schreibwunsch (zur Kanalwahl)
i2c_schreiben ( (kanal&0x03) | contr_ain); // Controll-Byte mit Kanalnummer
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_lies); // Adresse des IC und Lesewunsch
i2c_lesen (1); // neue AD-Wandlung Acknoledge = 1
wert = i2c_lesen (0); // Wert abholen Acknoledge =0
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
return (wert);
}
//************************************************** ***************************************
// * An DA-Umsetzer wert ausgeben
// ************************************************** ***************************************
void aout (unsigned char wert)
{
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse ADU
i2c_schreiben (contr_ain); // Control-Byte acu für Analogwert einlesen
i2c_schreiben (wert); // Wert ausgeben
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
}
void main (void) // Hauptprogramm
{
unsigned char wert; //Definition Variable wert
unsigned char swert; //Definition Variable swert zum abfragen
P0=0x00; // Port0 - Port3 als Ausgang deklarieren
P1=0x00;
P2=0x00;
P3=0x00;
while(1) //While Schleife
{
P3_1=1; //linke weiße LED ausschalten
P3_3=1; //linke rote LED ausschalten
P3_5=1; //rechte rote LED ausschalten
P3_7=1; //rechte linke LED ausschalten
wert = ain(0); //Kanal 0 einlesen und auf wert schreiben
P0 = ~wert; //wert auf P0 schreiben
swert=wert&0x80; //swert = wert mit 80 Hex "und"-Verknüpft
switch(swert) // abfrage von swert
{
case 0x80: rueckwaerts(); //Wenn swert = 80 Hex dann führe das Programm rückwärtsfahren aus
break; // Break um die Abfragen von einander zu trennen
default: vorwaerts(); break; // Wenn swert ungleich 80 Hex dann führe das Programm vorwärtsfahren aus
}
wert = ain(1);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
wert = ain(2);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
}
}
void vorwaerts (void) //Unterprogramm Vorwärtsfahren
{
Motor1 = vor; // die höherwertige 1 ist der Enable Pin
Motor2 = vor; // die niederwertige 1 ist die Richtung des Motors
}
void rueckwaerts (void) //Unterprogramm Rückwärtsfahren
{
unsigned char hinten_abfrage;
hinten_abfrage = ain(3);
if(hinten_abfrage>=0x40)
{
drehen();
}
else
{
stop(); // Sprung ins Unterprogramm stop
P3_1=0; // LED links weiß an
P3_3=1; // LED links rot aus
P3_5=1; // LED rechts rot aus
P3_7=0; // LED rechts weiß an
Motor1 = zurueck; // Motoren nach hinten fahren lassen
Motor2 = zurueck;
speaker(); // Unterprogramm für den Piepser
drehen(); // Verzweigungs ins Unterprogramm drehen
}
}
void drehen (void) // Unterprogramm drehen
{
double long x; // Variable x mit einem großen Datenbereich adressieren
Motor1 = zurueck; // Motor 1 rückwärts fahren lassen
Motor2 = vor; // Motor 2 vorwärts fahren lassen
for(x=0;x<2100;x++); // Warteschleife in der x hochgezählt wird
}
void stop(void) // Unterprogramm stop & rote LEDS an
{
Motor1=stopp; // Enable pin & Drehrichtungsangabe aus
Motor2=stopp;
P3_3=0; // LED links rot an
P3_5=0; // LED rechts rot an
warte(50); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
}
void speaker (void) // Unterprogamm für die Lautsprecher
{
P3_0=1; // Lautsprecher an
warte(25); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=0; // Lautsprecher aus
warte(10); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=1;
warte(25);
P3_0=0;
}
void warte(int z) // Unterprogramm fürs Warten
{
int s, x; // definieren von Variablen
for(s=z;s>0;s--) // s nimmt den Wert von z an welche vorher übergeben wurde. s wird runtergezählt
{
for(x=2000;x>0;x--); // for schleife in welcher x runtergezählt wird
}
}
Nun meine Frage : wie bekomme ich eine PWM zur Steuerung der Motoren möglichst einfach hin ? Die Motoren werden über einen L298 geschalten.
ich habe ein kleines Problem:
Ich habe ein Gehäuse mit Motoren des CC-RP5, AT89C5131 & einen PCF8591 welchen ich über I²C an den µC angebunden habe(zum auslesen von Analogsensoren). Das wird ein kleiner autonomer Roboter / ist es schon.
Mein derzeitiges Programm :
/*------------------------------------------------------------------+
| File: Roboterfahrzeug |
| Autor: |
| Klasse: E3GS1 |
| Controller: at89c5131 |
| Datum: 27.03.13 |
| Version: 2 |
+--------------------------------------------------------------------+
| Beschreibung: |
| |
+-----------------------------------------------------------------------------*/
#include <at89c5131.h> // fuer Atmel AT89C5131
/* adda_kniel.c ************************************************** *******************************
* Hilfsprogramme für den AD- und DA- Umsetzer mit I2C-Bus ********************************
* An DA-Umsetzer wert ausgeben: void aout (unsigned char wert)
* AD-Umsetzer einlesen, Kanal = 0,1,2,3: unsigned char ain (unsigned char kanal)
************************************************** ****************************************/
// geänderte Version 11/2007: Start und Stop-Bedingungen, funktioniert mit US-Sensoren
// geänderte Version 12/2006: funktioniert endlich aus als Library: adda.obj mit
// Tool -> Library-Manager in die Bibliothek RC51atms.lib einfügen
#include <reg51.h> // Registerdefinitionen
//#include <intrins.h> // für Rotationsfunktion
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
//****** verwendete I2C-Leitungen ************************************************** *******
sbit SDA = P4^1; // SDA-Leitung: ED2-Boards P3_5, (USB-Boards P4_1)
sbit SCL = P4^0; // SCL-Leitung: ED2-Boards P3_4, (USB-Boards P4_0)
//************************************************** **************************************
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
//***** verwendete Adressen und Kontrollbyte für den AD- und DA-Umsetzter ****************
#define Motor1 P1
#define Motor2 P2
#define vor 0x50
#define zurueck 0x44
#define stopp 0x40
#define adr_lies 0x91 // 10010001 -> 1001 fest, 000 durch Platine, 1 Wert lesen
#define adr_schreib 0x90 // 10010000 -> 1001 fest, 000 durch Platine, 0 Wert lesen
#define contr_ain 0x40 // 01000000 -> Kontrollbyte 4 einzelne ADU, Kanal= Offset dazu
sbit acc7 = 0xE7; // für Aus- und Eingabe eines Bits des Akkus
//void warte(int z);
// ************************************************** ***************************************
// I2C- Routinen zur Ansteuerung eins I2C-Slaves
// I2C-Bus-Funktionen i2c_init, i2c_start, i2c_stop, i2c_schreiben, i2c_lesen auch für andere
// I2C-Bus-ICs verwendbar
// ************************************************** ***************************************
// **** Zeitverzögerung zur Verlangsamung der Datenübertragungsrate ***********************
// **** i=2 bis i=100 wählen je nach I2C-IC und Pull-Up-Widerstand
void zeit (void) {unsigned char i; for (i=5;i!=0;i--) ;}
void vorwaerts (void);
void rueckwaerts (void);
void drehen (void);
void speaker(void);
void warte(int z);
void stop(void);
// ************************************************** **************************************
// ****** Initialiserung I2C-Bus ************************************************** ********
void i2c_init (void)
{
SDA = 1; // Leitungen in den Grundzustand High
zeit ();
SCL = 1;
zeit ();
}
// ****** Startbedingung I2C-Bus ************************************************** ********
void i2c_start (void)
{
SDA = 1; // Grundzustand
SCL = 1; // neu eingefügt 11/07
zeit();
SDA = 0; // Wechsel SDA von 1 -> 0 während SCL = 1
zeit ();
SCL = 0;
zeit ();
}
//****** Stoppbedingung I2C-Bus ************************************************** *********
void i2c_stop (void)
{
SDA = 0; // neu eingefügt 11/07
SCL = 1;
zeit ();
SDA = 1; // Wechsel von SDA 0 -> 1 während SCL =1
zeit ();
}
//************************************************** ***************************************
// * Byte ausgeben an I2C-Bus , Rückgabewert = Acknoledgebit = 0 wenn erfolgreich
// ************************************************** **************************************
bit i2c_schreiben (unsigned char byte)
{
unsigned char z; // Zähler
bit ack; // Acknoledge-Bit
ACC = byte; // Rotationsregister Akku
for (z = 8; z != 0; z --) // Zähler: serielle Ausgabe von 8 Bit
{
SDA = acc7; // Bit7 des Akku ausgeben
zeit ();
SCL = 1; // Daten sind gültig
asm {0x23}; // Akku links schieben
//ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
zeit ();
SCL = 0; // Datenausabe beendet
zeit ();
}
SDA = 1; // Leitung freigeben für Acknoledge-Bit
zeit ();
SCL = 1; // Slave kann bestätigen
zeit (); // warten
ack = SDA; // Acknoledge-Bit lesen
zeit ();
SCL = 0; // Slave soll Ackn-Ausgabe beenden
zeit();
return (ack); // Acknoledge-Bit ist Rückgabewert der Funktion
// ack = 0 bedeutet "verstanden" !!!!!!
}
//************************************************** ***************************************
// * Byte einlesen vom I2C-Bus. Bei Ack=1 wird Acknoledgebit gesendet, sonst nicht
// ************************************************** ***************************************
unsigned char i2c_lesen (bit ack)
{
unsigned char z,byte;
SDA = 1; // Leitung freigeben (high) für Daten
for (z = 8; z != 0; z --) // Zähler: serielles Einlesen von 8 Bit
{
SCL = 1; // Daten sind gültig
zeit ();
acc7 = SDA; // Datenbit in den Akku
asm {0x23}; // Akku links schieben
// ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
//P2_7 = SDA;
zeit();
SCL = 0; // Daten lesen beendet
zeit();
}
byte = ACC; // Eingelesenes Byte
if (ack == 1) {SDA = 0;} // Acknowledge-Bit senden
else {SDA = 1;} // kein Acknowledge-Bit
zeit ();
SCL = 1; // Ackn. gültig
zeit ();
SCL = 0; // Ackn. beendet
zeit ();
SDA = 0; // Leitung SDA vorbereiten für Stoppbed.
zeit ();
return (byte); // eingelesenes Byte = Rückgabewert
}
//************************** ADU und DAU- Funktionen *************************************
//************************************************** ***************************************
// * AD-Umsetzter einlesen, Kanal = Nr des ADU: 0,1,2,3
// ************************************************** ***************************************
unsigned char ain (unsigned char kanal)
{
unsigned char wert;
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse des IC und Schreibwunsch (zur Kanalwahl)
i2c_schreiben ( (kanal&0x03) | contr_ain); // Controll-Byte mit Kanalnummer
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_lies); // Adresse des IC und Lesewunsch
i2c_lesen (1); // neue AD-Wandlung Acknoledge = 1
wert = i2c_lesen (0); // Wert abholen Acknoledge =0
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
return (wert);
}
//************************************************** ***************************************
// * An DA-Umsetzer wert ausgeben
// ************************************************** ***************************************
void aout (unsigned char wert)
{
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse ADU
i2c_schreiben (contr_ain); // Control-Byte acu für Analogwert einlesen
i2c_schreiben (wert); // Wert ausgeben
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
}
void main (void) // Hauptprogramm
{
unsigned char wert; //Definition Variable wert
unsigned char swert; //Definition Variable swert zum abfragen
P0=0x00; // Port0 - Port3 als Ausgang deklarieren
P1=0x00;
P2=0x00;
P3=0x00;
while(1) //While Schleife
{
P3_1=1; //linke weiße LED ausschalten
P3_3=1; //linke rote LED ausschalten
P3_5=1; //rechte rote LED ausschalten
P3_7=1; //rechte linke LED ausschalten
wert = ain(0); //Kanal 0 einlesen und auf wert schreiben
P0 = ~wert; //wert auf P0 schreiben
swert=wert&0x80; //swert = wert mit 80 Hex "und"-Verknüpft
switch(swert) // abfrage von swert
{
case 0x80: rueckwaerts(); //Wenn swert = 80 Hex dann führe das Programm rückwärtsfahren aus
break; // Break um die Abfragen von einander zu trennen
default: vorwaerts(); break; // Wenn swert ungleich 80 Hex dann führe das Programm vorwärtsfahren aus
}
wert = ain(1);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
wert = ain(2);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
}
}
void vorwaerts (void) //Unterprogramm Vorwärtsfahren
{
Motor1 = vor; // die höherwertige 1 ist der Enable Pin
Motor2 = vor; // die niederwertige 1 ist die Richtung des Motors
}
void rueckwaerts (void) //Unterprogramm Rückwärtsfahren
{
unsigned char hinten_abfrage;
hinten_abfrage = ain(3);
if(hinten_abfrage>=0x40)
{
drehen();
}
else
{
stop(); // Sprung ins Unterprogramm stop
P3_1=0; // LED links weiß an
P3_3=1; // LED links rot aus
P3_5=1; // LED rechts rot aus
P3_7=0; // LED rechts weiß an
Motor1 = zurueck; // Motoren nach hinten fahren lassen
Motor2 = zurueck;
speaker(); // Unterprogramm für den Piepser
drehen(); // Verzweigungs ins Unterprogramm drehen
}
}
void drehen (void) // Unterprogramm drehen
{
double long x; // Variable x mit einem großen Datenbereich adressieren
Motor1 = zurueck; // Motor 1 rückwärts fahren lassen
Motor2 = vor; // Motor 2 vorwärts fahren lassen
for(x=0;x<2100;x++); // Warteschleife in der x hochgezählt wird
}
void stop(void) // Unterprogramm stop & rote LEDS an
{
Motor1=stopp; // Enable pin & Drehrichtungsangabe aus
Motor2=stopp;
P3_3=0; // LED links rot an
P3_5=0; // LED rechts rot an
warte(50); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
}
void speaker (void) // Unterprogamm für die Lautsprecher
{
P3_0=1; // Lautsprecher an
warte(25); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=0; // Lautsprecher aus
warte(10); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=1;
warte(25);
P3_0=0;
}
void warte(int z) // Unterprogramm fürs Warten
{
int s, x; // definieren von Variablen
for(s=z;s>0;s--) // s nimmt den Wert von z an welche vorher übergeben wurde. s wird runtergezählt
{
for(x=2000;x>0;x--); // for schleife in welcher x runtergezählt wird
}
}
Nun meine Frage : wie bekomme ich eine PWM zur Steuerung der Motoren möglichst einfach hin ? Die Motoren werden über einen L298 geschalten.