Go Down

Topic: Arduino PWM-Generator (Read 4550 times) previous topic - next topic

Holzwurm56

Hallo Doc_Arduino,
nochmals vielen Dank für deine Hilfe, aber Du bist im übertragenem Sinne ein Lehrer in der 13. Klasse und ich bin ein Grundschüler.

MfG

Hans

ArduFE

Einfach ist halt nicht überall einfach.

Das eigene Erarbeiten der entsprechenden Einstellungen aus dem Datenblatt mag lehrreich sein, aber spätestens beim Wechsel auf einen Arduino mit anderem Prozessor (z.B. Zero, 101, Due, ...) geht der Zirkus dann wieder von vorne los.

Der schon erwähnte Paul Stoffregen macht es bei seinem Teensy anders, wie schon verlinkt
Code: [Select]

void setup() {
  analogWriteFrequency(4, 50000);  // Pin Nummer und Frequenz
}


Man hat also die Wahl zwischen einfach oder einfach.


Doc_Arduino

#32
Oct 26, 2016, 04:57 pm Last Edit: Oct 26, 2016, 05:14 pm by Doc_Arduino
Hallo Doc_Arduino,
nochmals vielen Dank für deine Hilfe, aber Du bist im übertragenem Sinne ein Lehrer in der 13. Klasse und ich bin ein Grundschüler.

MfG
Hans
:)  lustig formuliert. Irgendwann schaffst du die 13. Klasse auch und landest wieder bei mir.  :)
Wobei ich aber, muß ich dazu sagen, woanders noch Schwächen habe. Nur beim Timer kenne ich mich schon ziemlich gut aus.  ;)   Die Anzahl der Postings darfste nicht gleichsetzen mit "der hat den kompletten Durchblick". Hier hat jeder sein Spezialgebiet. Bei manchen ist das Gebiet allerdings wirklich sehr hoch und weit gefasst. Die machen scheinbar den ganzen Tag wirklich nichts anderes.

@ ArduFE:
genau das sehe ich komplett anders. Ich hatte bewußt versucht und werde es weiterhin versuchen mit einzubauen, den Bezug zum Datenblatt herzustellen. Hat man einmal intensiv mit dem Datenblatt gearbeitet und die prinzipielle Funktionalität eines Timers verstanden, dann und genau dann, kann man jeden µC hernehmen, greift sich das Datenblatt, sucht die Register und Bits raus und kann den Timer einstellen. Vollkommen egal wie die Register und Bits heißen. Ein Kinderspiel. Das ist mein Anspruch. Das ist mein Ziel.

Man könnte die Funktion
Code: [Select]
analogWriteFrequency(4, 50000);

auch beim Arduino nachrüsten. Eine Funktion hätte ich dafür sogar schon. Ist allerdings für feste Einstellung in setup gedacht. Müßte man noch weiter anpassen. Daraus eine universelle Lib zumachen ist aber im Moment nichts für mich. Bin nicht der große Lib Schreiber.

@Hans:
wir machen einen Deal. Ich lasse dich quälen bis du mir einen funktionierenden Code zeigst mit deinen 2 Potiabfragen und deren Einlesewertdarstellung auf dem Display. Dann schreibe ich dir, wenn du noch beim Arduino bleiben möchtest, die benötigten Timerfunktionen. Eigentlich wollte ich an Hand eines "Grundschülers" :)  eine Anleitung testen. Aber das ist doch schwieriger zu formulieren wie ich dachte. Hab schon angefangen. Die Bilder anfertigen halten auf.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

agmue

Hallo Hans,
was hälst Du von Hilfe aus der Mittelstufe, um bei Deinem Bild zu bleiben? Aufgrund der Hilfe aus der 13. habe ich einen Sketch gebastelt, der irgendwie Frequenzen bis 50 kHz bei variablem Tastverhältnis ausgibt. Bitte melde Dich, wenn Du noch Interesse hast.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Holzwurm56

Hallo Doc_Arduino,
ich habe im www einen Code gefunden, der funktioniert von ca 7kHz bis 160kHz und habe den mit meinem LCD-Code kombiniert, es funktioniert mit kleinen Berichtigungen am LCD-Code, auch die Einstellung von Frequenz und Taktlänge. Warum es funktioniert weiß ich nicht würde es mit deiner Hilfe gerne lernen.
Wenn die Frequenz mit Null anfangen würde wäre es für mich besser.
Code: [Select]

// portions extracted from Timer1
// http://www.arduino.cc/playground/Code/Timer1

/* The wiper of a potentiometer should be hooked up to A0
    and controls the frequency of the function generator. The
    other connections of the potentiometer should be hooked up
    to +5 and GND.

    Possible frequencies are between about 7 khz and 300 khz.

    Another potentiometer hooked up to A1 controls the duty
    cycle, from very low to very high.
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //initialisieren Bibliothek
                                       //LCD-Pins
word freq; // Frequenz des PWM-Signals
int tast; // Tastverhältnis
int user_cycles;
int user_duty;

void set(int cycles, float duty) {
  char oldSREG;
  int dutyCycle = cycles * duty;
  if (dutyCycle < 6) {
    dutyCycle = 6; // Prevent duty cycle from being too short
  }
  if (dutyCycle > 1015) {
    dutyCycle = 1015; // Prevent duty cycle from being 100%
  }
  if (cycles < 50) {
    cycles = 50; // Prevent frequency from being too high
  }

  oldSREG = SREG;             // Save the registers
  cli();       // Disable interrupts for 16 bit register access
  ICR1 = cycles;              // ICR1 is TOP in p & f correct pwm mode
  OCR1A = dutyCycle;          // OCR1A is BOTTOM
  SREG = oldSREG;             // Restore the registers
}

void setup()
{
  lcd.begin(16, 2); //Konfigurieren LCD-Display 2 Reihen
                    //mit je 16 Zeichen
  lcd.setCursor(0, 0);
  lcd.print("Freq: ");
  lcd.setCursor(14, 0);
  lcd.print("Hz");
  lcd.setCursor(0, 1);
  lcd.print("Takt: ");
  lcd.setCursor(14, 1);
  lcd.print("%");
  pinMode(9, OUTPUT); //PWM-Pin als Output
  TCCR1A = 0;                 // clear control register A
  TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer

  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // Clear all prescaler bits
  TCCR1B |= _BV(CS10);        // choose prescaler 1, no prescaling, and start the clock

  DDRB |= _BV(PORTB1);        // sets data direction register for pwm output pin
  TCCR1A |= _BV(COM1A1);      // activates the output pin

  pinMode(A0, INPUT);
  pinMode(A1, INPUT);

  //pinMode(13, OUTPUT);
}

void loop()
{
  int temp_cycles = analogRead(A0);
  int temp_duty = analogRead(A1);
  if (temp_duty > 1000) temp_duty = 1000;
  lcd.setCursor(6, 0);
  freq = temp_cycles * 50;
  lcd.print(".......");
  lcd.setCursor(6, 0);
  lcd.print(freq);
  lcd.setCursor(6, 1);
  tast = temp_duty / 10;
  lcd.print(".......");
  lcd.setCursor(6, 1);
  lcd.print(tast);

  if (temp_cycles != user_cycles || temp_duty != user_duty) {
    user_cycles = temp_cycles;
    user_duty = temp_duty;
    set(user_cycles, user_duty / 1024.0);
  }
}


Hallo agmue,
ich habe  selbstverständlich Interesse am deinem Code, dann hätte ich was bis ich den Lehrgang bei Doc_Arduino abgeschlossen habe.

Wie wäre es in diesem Zuge mit einem Messgerät für Frequenz und Tastverhältnis bis ca 50kHz?

Vielen Dank für eure Hilfe

Hans

Holzwurm56

Ev. Verletzung von Urheberrechten sind unbeabsichtigt und würden bei Nachricht umgehend abgestellt.

MfG
Hans

agmue

#36
Oct 28, 2016, 05:57 pm Last Edit: Oct 28, 2016, 09:31 pm by agmue
Was macht der aus der Mittelstufe, schreibt bei dem aus der 13. ab, sieht dann so aus:

Code: [Select]
const int PWMpin = 10, potiPinPWM = A1, potiPinFreq = A2;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(10, OUTPUT);
}
void loop() {
  FreqTastver();
}

void FreqTastver() {
  static bool init = true;
  uint16_t potiWertFreq = analogRead(potiPinFreq);
  uint16_t freq = map(potiWertFreq, 0, 1023, 0, 50000);
  uint16_t potiWertPWM = analogRead(potiPinPWM);
  uint16_t PWMwert = map(potiWertPWM, 0, 1023, 0, 255);
  set_Timer1(freq, PWMwert, init);
  init = false;
  Serial.print("\tFreq: ");
  Serial.print(potiWertFreq);
  Serial.print("\t");
  Serial.print(freq);
  Serial.print("\tPWM: ");
  Serial.print(potiWertPWM);
  Serial.print("\t");
  Serial.println(PWMwert);
  delay(200);
}

void set_Timer1(uint16_t frequenz, uint16_t pulsWeite, bool initialisierung)  //  Phase Correct PWM, Mode 11
{
  if (frequenz > 50000) {
    frequenz = 50000;
  }
  uint16_t top = 8000000UL / frequenz;  // 16 MHz / 2
  pulsWeite = 1UL * pulsWeite * top / 255;
  cli();         // Interrupts ausschalten
  if (initialisierung) {
    TCCR1A = 0;    // Reset TCCR1A Register
    TCCR1B = 0;    // Reset TCCR1B Register
    TIMSK1 = 0;    // Reset TIMSK1 Register (disable Timer Compare Interrupts)
    TCNT1  = 0;    // Start 0
  }
  OCR1A = top;   // TOP Wert bestimmt Auflösung und mit Prescaler den PWM Takt 50kHz
  OCR1B = pulsWeite;    // 40 = 25% Pulsweite, OCR1B <= OCR1A
  if (initialisierung) {
    TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10); // nicht invertiert
    TCCR1B = (1 << WGM13) | (1 << CS10); // Prescaler 1
  }
  sei();         // Interrupts einschalten
}  // Ende Funktion set_Timer1

Das funktioniert zwischen 1 und 50 kHz ganz gut, wegen des schwankenden Analogwertes aber nicht hinreichend konstant.

Alle Serial.print sind nur zum Debuggen. Die Funktion set_Timer1 kannst Du übernehmen, ohne sie im Detail zu verstehen. Das mache ich ja auch nicht anders. Ob dies notwendig ist, sagt uns dann hoffentlich jemand:
Code: [Select]
oldSREG = SREG;             // Save the registers

Unklar ist mir, wann Du einen neuen Wert für Frequenz und Tastverhältnis aktivieren möchtest:
  • Neuen Wert einstellen und per Tastendruck aktivieren
  • Potis kontinuierlich abfragen und Werte direkt übernehmen
  • Noch was anderes

Meine hier im Forum veröffentlichten Programme dienen der Lehre und können frei verwendet werden. Sie basieren immer auf dem Wissen anderer Personen, wobei ich nur im Einzelfall in der Lage wäre, meine Quellen zu benennen.

EDIT: 16000000UL/2 geändert in 8000000UL (siehe #39)
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Holzwurm56

Hallo agmue,
beim Programm in meinem Beitrag kann man die Frequenz und Tastverhältnis mit den Potis kontinuierlich regeln,
das sieht man gut auf dem Oszi. Die Werte und die Anzeige sind einigermaßen stabil. Wenn es über die Potis eine Analogdrift gibt, würde ich die Einstellung in Kombination mit einem Taster in eine while-Schleife einbinden.

MfG

Hans

agmue

Code: [Select]
freq = map(potiWertFreq, 0, 1023, 0, 50000);
Eine Frequenz kann nur in 50 Hz-Schritten verändert werden. Außerdem liefert der AD-Wandler +- ein Digit Abweichung. Im günstigen Fall springt der Sollwert nur um 100 Hz. Die Temperaturdrift ist dabei noch nicht berücksichtigt. Daher ist das Poti für die Sollfrequenz nur mit Einschränkungen zu gebrauchen.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Doc_Arduino

#39
Oct 28, 2016, 08:35 pm Last Edit: Oct 29, 2016, 01:56 am by Doc_Arduino
Hallo,

Hans, bin wie schon erwähnt am kompletten neu schreiben einer dann hoffentlich verständlichen Anleitung in deutsch. Dauert länger wie ich dachte.   :)

Wenn ich zwischen durch Tipps geben darf.
Das mit dem Poti kann nur ein Anfang sein. Für den gesamten Bereich zu grob. Glätten könnte man es noch mit Gunthers Mittelwert-Filterfunktion. Dann ist es stabiler. Oder man übernimmt eben erst mit Tastendruck. Die ganze Frequenzeinstellerei würde ich persönlich im Endausbau mit Tastern machen. Ob für jede Stelle +/- oder Gruppenweise oder gar mit Drehencoder ist jedem selbst überlassen. Das erlernt sich Hans bestimmt noch Schritt für Schritt.

SREG Sicherung braucht man hier nicht. Da wir
a) keine Variablenwerte nutzen die aus einer ISR stammen und
b) weil wir die Interrupts allgemein sowieso erlauben müssen
SREG sichern müssen wir erst, wenn das Programm irgendwo die allgemeine Interruptsteuerung gezielt abschalten muß und wir den vorherigen Zustand nicht wissen und noch beibehalten müssen.

Durch das Double Buffer Feature der OCRnx Register in den PWM Modi wird der neue Wert erst bei Compare Match richtig übernommen. Man kann die OCRnx Register jederzeit live ändern. Nur das Pulsweiten-Register darf nie größer dem Frequenz bestimmenden Register werden. OCR1B <= OCR1A.

Mehr wie 80kHz sind nicht drin. Weil dann OCR1A bei einem Wert von 100 steht. Was bedeutet, man hat für das Pulsweiten bestimmente Register OCR1B auch nur noch 100 Möglichkeiten. Was letztlich 1% Duty Cycle Abstufungen bedeuten. Jetzt habe ich doch schon vorgegriffen mit den Erklärungen.  ;)

Im weiteren Ausbau muß man dann geeignete Umschaltbereiche definieren um den Prescaler zu ändern, damit man wieder zu einer vernünftigen Auflösung kommt in niedrigeren Frequenzbereichen. Oder man läßt ihn immer wieder neu berechnen, den passenden Prescaler. Hatte mal vor langer Zeit eine Funktion geschrieben. Allerdings für den CTC Modus. Müßte ich für den PWM Mode anpassen. Interesse oder selber coden?

Einen klitze kleinen Tipp noch, weil hier alles schnell gehen muß. Bei der Registerwertberechnung in der Formel aus dem Datenblatt kann man kürzen. Statt 16MHz durch 2 usw. zu teilen, kann man die /2 weglassen und 8MHz einsetzen. Der 8 Bitter wird es einem danken.  :)    

Soll nicht belehrend wirken. Auf keinen Fall.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Holzwurm56

Hallo,
Ich will den Generator benutzen um zu sehen wie sich Servoumrichter und Endstufen bei welcher Frequenz und Taktlänge verhalten, da ist eine Auflösung von 50Hz ausreichend. Die Einstellung über Drehgeber mit einem Taster als Multiplikator wäre dann die 2. Stufe.

MfG

Hans

Doc_Arduino

#41
Oct 29, 2016, 11:08 am Last Edit: Oct 29, 2016, 11:12 am by Doc_Arduino
Hallo Hans,

wie versprochen, auch wenn der fleißige agmue schon Code geliefert hat :) , gebe ich dir mal was von mir womit du alles von 0Hz an einstellen kannst inkl. Pulsweite. Den setup Code für dein Display kannste bestimmt selbst abändern. Wenn du für den Frequenzfaktor ein drittes Poti oder Tasten nimmst, haste schon einen universellen PWM Generator.

Der Unterschied zu deinem Code ist, dass für die Frequenz (TOP Wert) nicht das ICR1 Register verwendet wird, sondern das OCR1A Register und für die Pulsweite das OCR1B. Hat den Vorteil das bei Frequenzänderungen und gleichbleibenden Prescaler nicht jedesmal der Timer gestoppt werden muß. Nur wenn sich der benötigte Prescaler ändert muß der Timer kurz gestoppt werden. In einem weiten Bereich bleibt der Prescaler auf 1. Erst unter 2Hz wird der Prescaler 256 benötigt und unter 0,5Hz der 1024er. Zur Poti Beruhigung ist Gunthers Filterfunktion enthalten. Ich hoffe der Code überfordert dich nicht zu sehr. Kommentare habe ich eingefügt.

Wenn du den Code von uns verstehen lernst was der macht, dann habe ich mein Ziel schon erreicht. Danach kannste dir den Frequenzmesser selbst bauen.

Wegen dem SREG nochmal. Wie gesagt, da wir die Interrupts sowieso benötigen bleibt das SREG Bit sowieso eingeschalten. Müßte man eigentlich nicht sichern. Ich habe dennoch zur Vollständigkeit die avr-gcc konforme atomic Funktion eingefügt. Hatte ich vor nicht all zu langer Zeit selbst erst gelernt im Forum.  ;)

Und so ganz nebenbei haben wir die Teensy Funktion schon fast nachgebaut, auch wenn noch nicht so Pin universell wie dort.

Wegen der Codebenutzung. Wie agmue schon sagt, kannste alles frei verwenden. Wenn jemand Code ins Forum stellt, dann gibt er das damit der Öffentlichkeit preis. Man hat sowieso keine Kontrolle mehr darüber. Wenn ich etwas nicht veröffentlichen möchte, dann behalte ich es für mich.

Mit der Länge des Codes sprengt es die 9000 Zeichen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

#42
Oct 29, 2016, 11:10 am Last Edit: Oct 29, 2016, 11:21 am by Doc_Arduino
Änderung des Pins für den UNO und Display nicht vergessen!

Code: [Select]

/*
 *  Doc_Arduino - german Arduino Forum
 *  IDE 1.6.12
 *  Arduino Mega2560
 *  29.10.2016
 *  
 *  Timer Mode 11 - Phase Correct
 *  
 *  PWM Generator mit live Frequenz- und Pulsweiteneinstellung
 *  voller Frequenz-Einstellbereich was der Timer Mode möglich macht
 *  automatische Prescaler Berechnung
 *  
 */

#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung
#include <SPI.h>
#include <DogLcdSPI.h>   // für Hardware SPI angepaßte DogLcd.h

DogLcdSPI lcd (38, 39);  // EA DOGM 163 Display

float Filt_Poti_Takt;     // gefilteter gleitender Mittelwert
float Filt_Poti_PWM;    

const byte PWM_Takt_Pin = 10; // OC1B Pin (beim UNO ist das Pin 10)
long new_TOP;                 // passender errechneter Compare Match Register Wert für Frequenz

float _real_Frequency;        // für Displayausgabe, Frequenz in Hz
unsigned int _real_DutyCycle; // für Displayausgabe, Tastgrad in Prozent

void setup() {
  
  //Serial.begin(250000);
  pinMode(53, OUTPUT);
  pinMode(PWM_Takt_Pin, OUTPUT);
  SPI.begin();
  lcd.begin(DOG_LCD_M163);       // EA-DOGM Display 3 zeilig
    
  set_Timer1();   // Timer 1 Grundeinstellung Phase Correct Mode 11

}  // Ende Setup

 
void loop() {

  unsigned int Takt = analogRead(A0) * 1 + 1;  // Faktor für höhere Frequenzbereiche wegen Poti
  Filtern(Filt_Poti_Takt, Takt, 30);            // Eingangswert filtern/beruhigen
  Takt = (unsigned int) (Filt_Poti_Takt + 0.5); // richtig runden
  calc_Timer1_Frequenz(Filt_Poti_Takt);   // gewünschte Taktfrequenz in Hz, bei Bedarf mit einer Kommastelle
                                          // bis ca. 80kHz, mehr ist nicht sinnvoll
    
  unsigned int PWM = analogRead(A2) / 11;     // Limitierung wegen Poti    
  Filtern(Filt_Poti_PWM, PWM, 30);            // Eingangswert filtern/beruhigen              
  PWM = (unsigned int) (Filt_Poti_PWM + 0.5); // richtig runden
  calc_Timer1_Pulsweite(Filt_Poti_PWM);       // PWM Duty Cycle in Prozent

  LCD_Monitor();
}


// *** Funktionen *** ----------------------------------------------

void calc_Timer1_Pulsweite (unsigned int DutyCycle)  // Timer 1 Tastgrad Berechnung
{  
  unsigned int Reg_DutyCycle = new_TOP * DutyCycle / 100;  // berechneter OCR1B Registerwert für Pulsweite
  OCR1B = Reg_DutyCycle;   // OCR1B Register aktualisieren
  _real_DutyCycle = (unsigned int) (100UL * Reg_DutyCycle / new_TOP);  // [%] Rechnung rückwärts mit eingestellten Werten  
}


void calc_Timer1_Frequenz(float Frequency)
{  
  // berechnet den best möglichen TOP Wert und setzt die Register entsprechend
  const float CPU_Takt = 8000000.0;  // echten Takt halbiert, dann hats der 8 Bitter einfacher mit rechnen
  const int usedPrescaler[] = {1,8,64,256,1024};  // mögliche Prescaler
  int new_Prescaler = 0;
  static int old_Prescaler = 0;
  const long max_TOP = 65535;    // max. Compare Match Register Wert

  /* Gültigkeitskontrolle, ansonsten Timer stoppen */  
  if (Frequency < 0.2 || Frequency > 8000000)  {  
    new_Prescaler = 0;
    new_TOP = 0;
  }
  else {
    for ( byte i = 0; i<5; i++)  {                    // kleinsten passenden Prescaler raussuchen
      new_TOP = (long) ((CPU_Takt/usedPrescaler[i]/Frequency)+0.5);  // TOP Berechnung und runden
      if (new_TOP <= max_TOP && new_TOP >= 0)  {
        new_Prescaler = usedPrescaler[i];
        break;
      }  
    }
    /* Ergebnis Gültigkeitskontrolle, ansonsten Timer stoppen */
    if (new_TOP < 0 || new_TOP > max_TOP)  {  
      //Serial.print(F("ungueltiger TOP: ")); Serial.println(new_TOP);  // Debug
      new_Prescaler = 0;
      new_TOP = 0;
    }
  }  // end else

  /* durch Ganzzahlrundungen Rechnung rückwärts */
  _real_Frequency = (float) (CPU_Takt/new_Prescaler/new_TOP);  // Hz
  //lcd.setCursor(0,0); lcd.print("new_Prescaler: "); lcd.print(new_Prescaler); lcd.print("   ");  // Debug
  //lcd.setCursor(0,1); lcd.print("TOP "); lcd.print(new_TOP); lcd.print("   ");                 // Debug

  /* wenn sich Prescaler ändert, dann Timer stoppen und Register neu setzen */
  if (new_Prescaler != old_Prescaler) {
    //Serial.print(F("new Prescaler: ")); Serial.println(new_Prescaler);  // Debug
    ATOMIC_BLOCK (ATOMIC_RESTORESTATE)    // cli()+sei() mit SREG Sicherung
    {
      TCCR1B &= ~( (1<<CS12)|(1<<CS11)|(1<<CS10) );  // Timer stoppen
      TCNT1  = 0;      // initialize counter value to 0
      OCR1A = new_TOP;      // Compare Match Register <= 65535  
      switch (new_Prescaler)  {    // set Prescaler Clock Select Bits
        case    1 : TCCR1B |= (1<<CS10);  
                 break;
        case    8 : TCCR1B |= (1<<CS11);
                break;
        case   64 : TCCR1B |= (1<<CS11)|(1<<CS10);
                break;
        case  256 : TCCR1B |= (1<<CS12);
                break;
        case 1024 : TCCR1B |= (1<<CS12)|(1<<CS10);
                break;
        default :   ;     // sollte nicht passieren
      }  // Ende switch
    }
    old_Prescaler = new_Prescaler;
  }
  /* wenn Prescaler gleich bleibt, wird nur TOP live geändert */
  else {
    OCR1A = new_TOP;      // Compare Match Register <= 65535  
  }
}  // end Funktion


void set_Timer1()  // Phase Correct Mode 11 Voreinstellungen
{
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)    // cli()+sei() mit SREG Sicherung
  {
    // set Timer-1 Register
    TCCR1A = 0;      // Reset TCCR1A Register
    TCCR1B = 0;      // Reset TCCR1B Register
    TIMSK1 = 0;      // Reset TIMSK1 Register (disable Timer Compare Interrupts)
    TCNT1  = 0;      // initialize counter value to 0
    OCR1A = 65535;   // Compare Match Register MAX <= 65535
    OCR1B = 32767;   // Duty Cycle 50%
    TCCR1A = (1<<COM1B1)|(1<<WGM11)|(1<<WGM10);   // OC1B Pin nicht invertiert
    TCCR1B = (1<<WGM13);                          // Mode 11, Phase Correct    
  }
}


/****************************************************************************************
** Funktion Filtern()  by GuntherB                                                     **
*****************************************************************************************
** Bildet einen Tiefpassfilter (RC-Glied) nach.                                        **
** FF = Filterfaktor;  Tau = FF / Aufruffrequenz                                       **
** Input: FiltVal der gefilterte Wert, NewVal der neue gelesene Wert; FF Filterfaktor  **
** Output:  FiltValPoti ...                                                            **
** genutzte Globale Variablen: FiltValPoti ...  (call by Reference)                    **
*****************************************************************************************/
void Filtern(float &FiltVal, unsigned int NewVal, int FF) {
  FiltVal = ((FiltVal * FF) + NewVal) / (FF + 1);
}


void LCD_Monitor()
{  
  static unsigned int intervall = 500;    // Anzeige Intervall [ms]
  static unsigned long last_millis = 0;

  if (millis()-last_millis<intervall) return; // Zeit noch nicht erreicht, Funktion abbrechen
  
  lcd.setCursor(0,0); lcd.print("Hz "); lcd.print(_real_Frequency); lcd.print("   ");   // Hz
  lcd.setCursor(0,1); lcd.print("% "); lcd.print(_real_DutyCycle); lcd.print("  ");
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Holzwurm56

Hallo Doc_Arduino und Agmue,
im Code sind auch ein paar Assemblerbefehle (sei, cli) kann man die einfach benutzen? Ihr benutzt beide die Timerlibrary nicht? Ich habe da ein Manual vom AtMega328 mit 444 Seiten gefunden. Ist das was man durcharbeiten muß? Kapitel 16 ging nur bis 16.2.2 dann kam Kapitel 17.
Ich versuche erstmal den Code von agmue zu verstehen weil er kürzer ist.
Ich werde mal bei dem Code versuchen bei jeder Zeile dahinter zu schreiben was ich denke das es bedeutet, ev. könntet ihr da mal nachsehen ob ich richtig liege.
Hat dieses Dogm-Display eine serielle Ansteuerung? Müsste man das an den TX-Pin anschließen?

Im voraus besten Dank

Hans

Doc_Arduino

#44
Oct 29, 2016, 09:25 pm Last Edit: Oct 29, 2016, 09:42 pm by Doc_Arduino
Hallo,

mein 328er Manual hat 555 Seiten, 21,1MB.
... gleich mal selbst geschaut ...
http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf
Oh ah. Atmel hat in 06/2016 ein neues Manual rausgebracht und die Kapitelnummern geändert.
Die Säcke, kann ich meine schönen Bilder nochmal ändern.  :smiley-confuse:
Timer 1 liegt demnach jetzt im Kapitel 20.
Die zerpflückte Tabelle Seite 171-172 blieb erhalten. :smiley-confuse:


Ich steuere mein DOGM per SPI an.

cli / sei, grundsätzlich kann man alle Befehle benutzen, wenn man weiß warum und wofür.

Die Timer Lib gefällt mir persönlich nicht. Zwei Gründe hatte ich schon geschrieben. Zudem so ein Timer schnell konfiguriert ist.  :smiley-twist:
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up