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
72_COACH2/05_I2C -- Infos zu I2C
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.