LV #8, 23.05.2024 Grundlagen der Mikrocontrollertechnik im Sommersemester 2024
(EN google-translate)
(PL google-translate)
Themen
|
Servos mit OOP
//Mode 8 //Phasen- und Frequenz-korrekt //WGM1 3 2 1 0 // 1 0 0 0 //ICR1=..... TOP //fpwm = fclk/(2*N*TOP) //Vorteilung //N=8 //80Hz = 16000000/(2*8*TOP) //TOP = 16000000/(2*8*80Hz)=12500 //dt==1000ms*(1/80Hz)/12500 == 0,001ms (1 Schritt == 0,001ms) //=> //1ms == 1000 Schritte //1,5ms == 1500 Schritte //2ms == 2000 Schritte class MeinServo { public: void start() { TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<COM1C1) | (0<<COM1C0) | (0<<WGM11) | (0<<WGM10); TCCR1B = (0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10); //Vort. 8, s.S. 135 ICR1=12500; DDRB |= (1<<PB5); //OCR1A DDRB |= (1<<PB6); //OCR1B OCR1A = 1500; //PWM-Breite auf Mitte setzen. OCR1B = 1500; //PWM-Breite auf Mitte setzen. } int getPWMminus90() { return 500; } int getPWMplus90() { return 2500; } int getPWMmitte() { return 1500; } void setPWMA(int value) { OCR1A = value; } void setPWMB(int value) { OCR1B = value; } /* Übergebener Winkel in Grad für Servo an Digital Pin 9 Bereich: -90.0 bis +90.0 */ void setzeWinkelA(double winkel) { if(winkel<-90.0) winkel=-90.0; if(winkel>90.0) winkel=90.0; double pwm = 500.0 + 2000.0*(winkel+90.0)/180.0 +0.5; setPWMA((int)pwm); } void setzeWinkelB(double winkel) { if(winkel<-90.0) winkel=-90.0; if(winkel>90.0) winkel=90.0; double pwm = 500.0 + 2000.0*(winkel+90.0)/180.0 +0.5; setPWMB((int)pwm); } };
Code 0-1: Klasse MeinServo.
#include "MeinServo.h" MeinServo servo; void setup() { servo.start(); } void loop() { //servo.setPWMA(servo.getPWMminus90()); //servo.setPWMB(servo.getPWMminus90()); servo.setzeWinkelA(-90.0); servo.setzeWinkelB(-90.0); delay(3000); servo.setPWMA(servo.getPWMmitte()); servo.setPWMB(servo.getPWMmitte()); delay(3000); servo.setPWMA(servo.getPWMplus90()); servo.setPWMB(servo.getPWMplus90()); delay(3000); }
Code 0-2: Hauptprogramm.
Ausgangspunkt ist das bereits besprochene Register basierte Programm:

#define WMIN 1000 #define WMITTE 1500 #define WMAX 2000 #define SCHRITTE 1000 //Mode 8 //Phasen- und Frequenz-korrekt //WGM1 3 2 1 0 // 1 0 0 0 //ICR1=..... TOP //fpwm = fclk/(2*N*TOP) //Vorteilung //N=8 //80Hz = 16000000/(2*8*TOP) //TOP = 16000000/(2*8*80Hz)=12500 //dt==1000ms*(1/80Hz)/12500 == 0,001ms (1 Schritt == 0,001ms) //=> //1ms == 1000 Schritte //1,5ms == 1500 Schritte //2ms == 2000 Schritte void setup() { TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<COM1C1) | (0<<COM1C0) | (0<<WGM11) | (0<<WGM10); TCCR1B = (0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10); //Vort. 8, s.S. 135 ICR1=12500; DDRB |= (1<<PB5); //OCR1A DDRB |= (1<<PB6); //OCR1B OCR1A = WMITTE; //PWM-Breite auf Mitte setzen. OCR1B = WMITTE; //PWM-Breite auf Mitte setzen. } void loop() { OCR1A = WMAX; //PWM-Breite auf Null setzen. OCR1B = WMAX; //PWM-Breite auf Null setzen. delay(3000); OCR1A = WMITTE; //PWM-Breite auf Null setzen. OCR1B = WMITTE; //PWM-Breite auf Null setzen. delay(3000); OCR1A = WMIN; //PWM-Breite auf Null setzen. OCR1B = WMIN; //PWM-Breite auf Null setzen. delay(3000); }
Code 0-3: Modellbau-Servos auf OC1A und OC1B mittels Timer 1 mit hoher Genauigkeit ansteuern.
TWI / I2C Schnittstelle und Anschluss eines dreiachsigen Beschleunigungssensors MPU6050

Anschluss des Sensors, siehe "6. Auslesen eines MPU6050 über die I2C-Schnittstelle mittels Library " in dem vorangehenden "day by day" Dokument.
Objektorientierte Kapselung des Beschleunigungssensors
Umsetzung in Vorlesung.
Übung
Als Vorstufe für eine elektronische Wasserwaage, soll eine rote LED aufleuchten, sobald die Laborplatine um einen größeren Winkel als 10 Grad aus der Waagerechten gebracht wird.
|
#include <math.h> #include <Wire.h> #include "Level.h" Level level; void setup() { pinMode (4, OUTPUT); Serial.begin(9600); level.begin(); delay(500); } void loop() { level.aquire(); if (level.angle > 10.0){ digitalWrite(4, HIGH); } else{ digitalWrite(4, LOW); } Serial.print(level.angle);Serial.print("Grad "); delay(50); }
Code 0-4: Hauptprogramm studentische Lösung.
class Level { private: const int MPU = 0x68; // I2C address of the MPU-6050 double calculateAngleDEG(int AcX, int AcY, int AcZ) { // a = gemessener Vektor (x,y,z) // b = (0,0,1) // a*b = AcX*0 + AcY*0 + AcZ*1 = AcZ // || a || = sqrt(AcX^2 + AcY^2 + AcZ^2) // || b || = sqrt(0^2 + 0^2 + 1^2) = 1 // || a || * || b || = 1*sqrt(AcX^2 + AcY^2 + AcZ^2) double rawValue = AcZ / (sqrt(AcX*AcX + AcY*AcY + AcZ*AcZ)); double angleDEG = acos(rawValue) * (180 / M_PI); return angleDEG; } public: int16_t AcX = 0, AcY = 0, AcZ = 0; double angle = 0.0; void begin() { Wire.begin(); Wire.beginTransmission(MPU); Wire.write(0x6B); // PWR_MGMT_1 register Wire.write(0); // set to zero (wakes up the MPU-6050) Wire.endTransmission(true); } void aquire() { Wire.beginTransmission(MPU); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); // request a total of 14 registers AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) angle = calculateAngleDEG(AcX, AcY, AcZ); } };
Code 0-5: Klasse Level studentische Lösung.