mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Frequenzmessung mit Timer0 ohne ICP


Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich beschäftige mich seit so nen halben Jahr mit MC, d.h. ich bin net 
ganz so fit drin.

Ich möchte mit einem atmega16 die Frequenz messen. Jedoch ist der Timer1 
schon mit der Steuerung eines Reglers beschäftigt somit kann ich den 
ICP-Mode nicht nutzen. Das es damit funktioniert hab ich schon probiert.

Jetzt wollte ich mein Signal an einen externen Interrupt anhängen.
Durch eine steigende Flanke wird der Timer gestartet. Eine zweite Flanke 
soll die Messung stoppen und das ergebnis auf einem Display ausgeben.

Anbei mein Code:

#include <mega16.h>
#include <delay.h>
#include <lcd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


#asm
.equ __lcd_port=0x15 ;PORTC
#endasm


unsigned char buffer[16];
float Frequenz;
unsigned int Zeit=0, i=0,Messzeit,takt=62500,Ueberlaeufe=0;

void Ausgabe ()
{

        lcd_gotoxy(0,0);
        ftoa(Frequenz,3,buffer);
        lcd_puts(buffer);


}


interrupt [EXT_INT0] void ext_int0_isr(void)
{

  Zeit=TCNT0;
  TCNT0=0;
  TIMSK=0x01;



   i++;

  if(i==2)
  { TIMSK=0x00;
    Messzeit=(Zeit+(256*Ueberlaeufe));
    Frequenz=takt/Messzeit;     //31250Takte/ICR1(z.B. 1500)= 20,83Hz
    Ueberlaeufe=0;
    i=0;
     Ausgabe();
    }

}


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
  Ueberlaeufe++;
}



void main(void)
{


DDRC=0xff;
lcd_init(16);
lcd_clear ();
DDRB=0xff;
DDRD=0x00;

TCCR0=0x04;     //Prescaler 256
TIMSK=0x00;      //Timer0 Interrupt bei Überlauf


  TCNT0=0;
MCUCR=0x03; //externer Interrupt durch steigende Flanke
//GIFR=0x40;
GICR|=0x40;        // Freigabe Int0



#asm("sei")

while (1)
      {
            }
}


Es kommt einfach nix gescheites raus.
Ständig ist da schon ein wert obwohl keine Flanke kommt.

Ich würde mich über jederlei Hilfe freuen.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wäre echt lieb wenn mir jemand helfen könnte.
Ich brauch des für ne Abschlussarbeit und komm irgendwie net weiter.

Würde es überhaupt so funktionieren wie ichs mir vorstelle und der Code 
ist einfach schlecht?

Ich bin für jede Hilfe dankbar!!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:

> Ich möchte mit einem atmega16 die Frequenz messen. Jedoch ist der Timer1
> schon mit der Steuerung eines Reglers beschäftigt

Was ist das für eine Steuerung?

Wenn dafür der Timer im immer gleichen Zählumfang zählt und das auch 
noch unterbrechungsfrei tut, gibt es keinen Grund warum du den nicht für 
ICP hernehmen kannst (ausser du kommst mit dem Vorteiler nicht hin).

Ein Timer kann durchaus 2 oder mehr Dinge tun.

Autor: NutEinGast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn's Dir nicht sofort und drekt bei Deinem Problem hilft, 
trotzdem

Bitte - nimm mal die LCD Ausgabe aus der Interruptroutine raus.
Ansonsten kann doch kein Mensch mehr voraussehen was da wirklich 
passiert ?

> Ständig ist da schon ein wert obwohl keine Flanke kommt.

Darf ich das so verstehen ?
Dein LCD zeigt einen Wert, obwohl noch keine Flanke gekommen ist ?

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für deine Antwort.

Ich steuer einen Modellflug-Regler, also nen Brushless Regler.
Ich erzeuge mit den Timer 1 alle 20ms einen Impuls von 0,9ms bis 2 ms.
Je nachdem wie lang der Impuls andauert so schnell dreht sich mein 
motor(Festplattenmotor). Das heißt, ich hab 2 Compare Werte.

Ich poste am besten mal meinen Code.

/* SERVO SCHRITTMOTOR ANSTEUERUNG
mit Wana Modell Regler Festplattenmotor ansteuern
-------------------------------------------------------
Autor: Agnes Poks
*/

#include <mega16.h>
#include <delay.h>
#include <stdio.h>


#define Signal_ein PORTB.0
#define Signal_warten PORTB.1
#define Signal_aus PORTB.2



unsigned char freigabe=0;
unsigned int Stufe[12],i=0,x=0,j=0,z;

void init()
{
    Stufe[0]=1900;
    Stufe[1]=1900;
    Stufe[2]=2100;
    Stufe[3]=2300;
    Stufe[4]=2500;
    Stufe[5]=2700;
    Stufe[6]=3000;
    Stufe[7]=3200;
    Stufe[8]=3400;
    Stufe[9]=3600;
    Stufe[10]=3800;
    Stufe[11]=4000;

}



interrupt [TIM1_COMPA]
void timer1_compa_isr(void)
{
PORTD=0;

}

interrupt [TIM1_COMPB]
void timer1_compb_isr(void)
{
PORTD|=(1<<7);
TCNT1=0;
}



void main ()
{
init();

DDRD=(1<<7);
PORTD&=~(1<<7);

DDRA=0x00;
PORTA=0xff;

DDRB=(1<<0) | (1<<1)| (1<<2);


TCCR1A=0x00;
TCCR1B=0b00000010;
OCR1B=40000;
x=0;

Signal_aus=1;

#asm("sei")

while (1)
 {

     OCR1A=Stufe[x];

     if(!(PINA & (1<<0)))       //STOPP  if(!(PINBD & (1<<0)))
      {
      x=0;              // Motor in Leerlauf
      Signal_warten=1;
      Signal_ein=0;
      z++;
      if(x==0 && z==2)
      {
      delay_ms(4000);
      TIMSK=0b00000000;
      PORTD=0;
      Signal_aus=1;
      Signal_warten=0;
      z=0;
      freigabe=0;
      }
       }

       if(!(PINA & (1<<1)))        //START
      {
        TIMSK=0b00011000;
        x=0;
        Signal_aus=0;
        Signal_warten=1;
        delay_ms(8000);
        Signal_ein=1;
        Signal_warten=0;
        freigabe=1;
        }

      if(freigabe==1)
      {
      if(!(PINA & (1<<2)))//if(PINA.0==0) // Geschwindigkeit erhöhen
      {
        delay_us(40);
        i++;
        if(i==40000 && x<=10)
        {x++;
        i=0;}
        if(PINA & (1<<2))
        i=0;
      }

      if(!(PINA & (1<<3)))//if(PINA.0==0) // Geschwindigkeit verringern
      {
        delay_us(40);
        j++;
        if(j==40000 && x>=1)
        {x--;
        j=0;}
        if(PINA & (1<<3))
        j=0;


      }
      }
     }
}


Mir fehlt da nicht ein wie ich des machen soll wennn der nach 20ms 
zurückgesetzt wird.
Hab mal gelesen das man den Compare und ICP nicht gleichzeitig benutzen 
kann geht das doch? Wäre gut zu wissen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:

> Ständig ist da schon ein wert obwohl keine Flanke kommt.

Da wird dann wohl schon ein Interrupt aufgelaufen sein, ehe mittels sei 
die Interrupts dann freigegeben werden.

Lösch das entsprechende Interrupt Flag Bit im GIFR Register
   Frequenz=takt/Messzeit;

wozu hast du hier Frequenz als float definiert.
Die Division wird sowieso als Ganzzahldivision gemacht und damit wirst 
du nie Kommastellen haben. Der float verbrutzelt nur Zeit bei der 
Ausgabe.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:

> Ich steuer einen Modellflug-Regler, also nen Brushless Regler.
> Ich erzeuge mit den Timer 1 alle 20ms einen Impuls von 0,9ms bis 2 ms.
> Je nachdem wie lang der Impuls andauert so schnell dreht sich mein
> motor(Festplattenmotor). Das heißt, ich hab 2 Compare Werte.

Ja, und?

So wie ich das sehe


> TCCR1A=0x00;
> TCCR1B=0b00000010;

läuft der Timer ganz normal einfach nur durch.
D.h. er zählt seinen Zählbereich vor sich hin.

Es gibt keinen Grund warum du da nicht auch noch einen ICP Interrupt 
drauflegen kannst.

Hinweis: Man muss nicht unbedingt zur Zeitmessung den Timer immer wieder 
auf 0 stellen. Du kannst ja auch mit einer normalen Uhr stoppen und 
braucht keine Stoppuhr dafür. Einfach von der Endzeit die Startzeit 
abziehen und schon hat man die Differenz, vulgo die Zeit die inzwischen 
vergangen ist. Bei einem Timer ist das nicht anders.


furchtbares Programm. Darf ich fragen was das für ein Abschluss ist?

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

>
> interrupt [TIM1_COMPB]
>void timer1_compb_isr(void)
>{
>PORTD|=(1<<7);
>TCNT1=0;
>}

Bei diesem Interrupt stell ich den Timer auf 0.


Doch ich hab nen mal nen Frequenzzähler programmiert.
Im Anhang hab ich den Code.
Da kommt ziemlich genau das raus was ich mit den Frequenzgenerator 
vorgeben. Sogar auf 2 Stellen nach dem Komma.
Den hab ich übrigens mit der Differenz berechnet und den Timer 
durchlaufen lassen. Ich weiß nur net wie ich des bei diesen Code mit der 
Steuerung reinfrimmeln soll.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> @Karl heinz Buchegger
>
>>
>> interrupt [TIM1_COMPB]
>>void timer1_compb_isr(void)
>>{
>>PORTD|=(1<<7);
>>TCNT1=0;
>>}
>
> Bei diesem Interrupt stell ich den Timer auf 0.

Ah, hab ich bei der Codedurchsicht übersehen.

Wer macht denn aber auch sowas.

Oh, Mann. Da fehlt es aber hinten und vorne in deinem Code.
Das Servo-Signal kann der Timer völlig ohne dein Zutun ganz alleine 
erzeugen. Das kann man als stink normale PWM aufsetzen, bei der der 
Timer selber seinen OCxx Pin ansteuert.

Du schmeisst dir in deinem Code absichtlich Prügel zwischen die Beine 
und wunderst dich dass du stolperst.

> durchlaufen lassen. Ich weiß nur net wie ich des bei diesen Code mit der
> Steuerung reinfrimmeln soll.

Mach erst mal deine Servo-Ansteuerung richtig(er). Das ist doch Unsinn, 
da selber mit den Interrupts rumzuhantieren, wenn du nur 1 Servo 
ansteuern musst.

Das ist das eine.
Das andere ist, dass es aber im Grunde nicht wirklich die große Rolle 
spielt. Die Obergrende des Timers ist ja trotzdem nach wie vor fix, d.h. 
der Timer zählt immer im gleichen Bereich. Von 0 bis 39999. Ob der jetzt 
immer von 0 bis 39999 oder von 0 bis 65535 zählt, ist doch nur ein 
Zahlenwert in der Berechnung. Deswegen kann man immer noch ICP benutzen.

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@ NutEinGast
Also ich hab den Code mit den Timer0 geändert.
Also die ausgabe Raus und die Flag gelöscht.
Es kommt schon mal eine Frequenz raus die aber immer etwas am Ziel 
vorbeischießt. Bei den geringeren Frequenzen sind des 4-10 Hz bei 
höheren z.B 200 Hz so ca. 20-30 Hz.

@Karl heinz Buchegger
Bin leider Anfängerin :(
Hab mir vor nen halben Jahr C und MC selbsr beigebracht und für des 
Projekt dachte ich das ich des schon hinkriege.
Naja hoffe meine Codes ist net ganz so schlimmere anblicke ;)

Was ist den so das schlimmste im Code? Damit ich weiß was ich ändern 
soll bzw. kann.
Ich hab nur mal nen Lüfter über PWM angesteuert aber da war die 
Impuls-Pausenzeit gleich lang.
Meinst du ich kann in den Code nicht die Frequenzmessung unterbringen?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups des war mal wieder ein tolles deutsch im letzten Post von mir.
Sorry. Programmier nebenbei da klingen meine Sätze manchmal etwas ... :)

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mal was neues geschrieben mit FastPWM.
Muss dran noch arbeiten damit man die impulsdauer ändern kann.
Ich habe auch meine Servosteuerung geändert um die Frequenz zu messen.
Leider hängt das Programm sobald die Ausgabe drin ist.
Wenn ich sie auskomentiere dann funktioniert die Steuerung aber anzeigen 
kann ich nix.
Ich weiß du findest es net so gut aber könntest du mir trotzdem helfen. 
Ich würde gern wissen warum es sich bei der ausgabe aufhängt.
Das aufhängen ist unabhängig von der Frequenzmessung. Als ich einfach 
den x-Wert aufm display ausgeben wollte hatte es sich auch aufgehängt.

Über etwas hilfe wäre ich echt dankbar.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dreh hier mal die Reihenfolge um
#include <mega16.h>
#include <delay.h>
#include <stdio.h>

#asm
.equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>

#include <stdlib.h>

Ich kenn zwar die LCD Routinen nicht, ich fände es aber logisch, dass 
man den LCD Port definieren muss, ehe dann lcd.h irgendetwas mit dieser 
Information macht. Bei dir ist nicht ganz klar, was denn eventuelle 
inline-Funktionen in lcd.h für einen Port annehmen, bzw. wie da 
nachträglich ein LCD Port einfliessen kann.


PORTC:  JTAG hast du mit einer Fuse abgeschaltet?

> Ich weiß du findest es net so gut
In deinem Code kommen mir zb. viel zu viele magische Zahlenwerte vor.

zb
   lcd_init(16);

Was will uns der Meister hier sagen? Warum 16? Warum nicht 14 oder 15? 
Was hat es mit diesen 16 auf sich?


Bis hier her

#define Signal_ein PORTB.0
#define Signal_warten PORTB.1
#define Signal_aus PORTB.2


ist das alles wunderbar.
Du abstrahierst die tatsächliche Belegung weg, sodass im Code steht

  Signal_aus=1;

Die Bezeichnung ist vielleicht nicht so glücklich gewählt, denn "Signal 
Aus" kann alles und nichts bedeuten, aber zumindest ist es schon mal 
besser als nichts. ZUmindest wird hier eine gewisse Absicht deutlich.

Aber ... das ist nicht durchgezogen. Nur stellvertretend für viele 
andere Stellen
   PORTD&=~(1<<7);

Wie, was, wer? Da wird Bit 7 vom Port D auf 0 gesetzt. Soweit ist das 
klar. Aber was hängt an diesem Pin? Was ist wenn ich den Pin im Programm 
ändern will, muss ich dann wirklich durch das komplette Programm 
durchgehen und mir alle 7-er suchen und überlegen, ob die damit was zu 
tun haben? Warum kann da nicht stehen

   Servo_Signal = 0;

und weiter oben, machst du wieder ein

#define Servo_Signal  PORTD.7


Dein Code ist nach ... eigentlich gar keinem Schema eingerückt. Da eine 
logische Struktur zu finden ist Detektivarbeit. Was ist leichter zu 
lesen und zu verstehen, welche Anweisungen von welchen anderen 
Anweisungen abhängen. Das Original
    if(!(PINA & (1<<0)))       //STOPP  if(!(PINBD & (1<<0)))
      {
      x=0;              // Motor in Leerlauf
      Signal_warten=1;
      Signal_ein=0;
      z++;
      if(x==0 && z==2)
      {
      delay_ms(4000);
      TIMSK=0b00000000;
      PORTD=0; 
      Signal_aus=1;
      Signal_warten=0;
      z=0;
      freigabe=0;
      }
       }

oder die überarbeitete Version
    if(!(PINA & (1<<0)))       //STOPP  if(!(PINBD & (1<<0)))
    {
      x=0;              // Motor in Leerlauf
      Signal_warten=1;
      Signal_ein=0;
      z++;

      if(x==0 && z==2)
      {
        delay_ms(4000);
        TIMSK=0b00000000;
        PORTD=0; 
        Signal_aus=1;
        Signal_warten=0;
        z=0;
        freigabe=0;
      }
    }

sowas
        if(j==40000 && x>=1)
        {x--; 
        j=0;} 
geht schon mal überhaupt nicht!
Entscheide dich für ein Schema, wie du { } anordnen willst und halte 
dich daran.
Ein übliches Schema ist:
nach einem { kommt die Fortsetzung auf jeden Fall in die nächste Zeile 
und wird dort um 2 Zeichen eingerückt, damit optisch ersichtlich ist, 
dass hier eine neue Hierarchieebene anfängt. Die schliessende } kommt 
auch auf eine neue Zeile und wird wieder um 2 Leerzeichen ausgerückt. 
Auf die Art stehen immer die öffnende { und die schliessende } in 
derselben Spalte untereinander. Will ich wissen wo das jeweilige 
Gegenstück ist (und welche Anweisungen daher von { } eingeschlossen 
sind) brauch ich nur mit dem Cursor in derselben Spalte nach oben bzw. 
unten fahren, bis ich das jeweilige Gegenstück in dieser Spalte habe.

Variablennamen wie x und z für Werte die eine spezielle Bedeutung haben. 
x ... das sagtmir nicht viel. Warum kann das nicht 'MotorStufe' oder 
'ActStufe' (für aktuelle Stufe) oder (denk dir eine sinnvolle 
Bezeichnung aus) heißen.

Dann würde da zb auch auf einmal stehen

     OCR1A = Stufe[ ActStufe ];

und das erzählt mir schon ein wenig mehr als dieses ominöse x unter dem 
man sich nichts vorstellen kann.

Faustregel: Variablennamen und Funktionsnamen sind dann gut gewählt, 
wenn sich aus den meisten Anweisungen durch Hinzudenken von Füllwörtern 
schon fast sinnvolle Sätze ergeben.
Ein
    ActStufe = 0;
ist dann schon fast selbsterklärend und braucht
      x=0;              // Motor in Leerlauf
den Komentar gar nicht mehr.

und sowas
  TCCR1B=0b00000010;
geht schon mal gar nicht.
Ich will doch nicht Bitpositionen abzählen müssen, nur damit ich dann im 
Datenblatt raussuchen kann, was du da eigentlich einstellst.
  TCCR1B = (1<<CS11);   // Vorteiler 8
ist zwar auch noch nicht optimal, aber es ist schon mal auf jeden Fall 
besser als die Bitschreibweise. Denn nach CS11 kann ich im Datenblatt 
PDF suchen! Und falls mal eine Portierung auf einen anderen Prozessor 
ansteht, bei dem CS11 zwar immer noch im TCCR1B Register ist, aber an 
einer anderen Stelle, dann erledigt der Compiler die Anpassung und ich 
muss nicht erst mühsam Bits aus den Datenblättern zusammenklauben.

Auch wenn es dem C COmpiler egal ist: Nur weil man in C alles Knirsch an 
Knirsch schreiben kann, muss man das nicht tun. Seit Kindesbeinen an 
bist du darauf trainiert worden, dass beim Lesen zwischen Wörtern ein 
Leerraum steht. Dein Gehirn findet die mitlerweile von alleine, du musst 
nicht mehrBuchstabenanylisierenundnachWortzusammenhängensuchen um die 
Wörter zu finden, oder war dieses Monster etwa für dich einfach zu 
lesen? Warum machst du es dann in deinem Code? Warum schreibst du deinen 
Code so, dass du erst mal langwierig mit den Augen die Einzelteile 
suchen musst:
   PORTD|=(1<<6);

   PORTD |= (1<<6);

dann übersieht man auch nicht so leicht, dass da ein |= steht und kein =


Und nein. Das alles macht man nicht im Nachhinein, sondern während man 
den Code schreibt. Eine saubere optische Codestruktur ist nämlich auch 
ein Hilfsmittel um Fehler zu vermeiden. Nicht umsonst sind die 
Programmierer mit der grauslichsten Codestruktur meistens auch die 
Programmierer mit den meisten Fehlern im Programm.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
:) Okay muss dir recht geben ne Auszeichnung bekomm ich dafür bestimmt 
net. Ich schiebe das darauf das ich mir C selbst beigebracht hab und 
deswegen nen üblen Dialekt habe ;) Okay verdammt übel.
Gelobe Besserung!

Das 16 bedeutet das man 16 Zeichen ins Display zeigen kann. Ist die 
Routine von CodeVision.

Habs vertauscht aber funktioniert trotzdem nicht. Es zeigt ne 0 also 
liegt es am JTAG net. Die Funktion um zu Starten und Stoppen 
funktioniert nur die anderen beiden nicht. Auch bleibt er ganze Zeit bei 
Null d.h. messen tut der auch net bzw. zeigt er es nicht an.
Ich glaub er hängt sich irgendwo bei der Anzeige auf. Weil die 
Servosteuerung ja funktioniert sobald man die Anzeige raus macht.

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mal mein Code geändert.
Also Hardware PWM, um die ganzen Interrupts weg zu kriegen.

Funktioniert ganz gut.
Er zeigt die Geschwindigkeitsstufe an aber mit der Frequenz da bleibt er 
bei Null.

Ich hab den Code gepostet und hoffe sehr das mir jemand helfen kann!!

Vielen Dank im voraus!!

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat keiner ne Idee woran es liegen könnte?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann des überhaupt funktionieren mit FastPWM und Input Capture? Ich 
schreibe ja ins ICR1 Register einen Wert rein. Und der Input Capture 
holt sich ja aus diesem Register den aktuellen Wert des Timers. Gibts ne 
andere Möglichkeit wie FastPWM um HardwarePWM hinzubekommen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Kann des überhaupt funktionieren mit FastPWM und Input Capture? Ich
> schreibe ja ins ICR1 Register einen Wert rein. Und der Input Capture
> holt sich ja aus diesem Register den aktuellen Wert des Timers.

Das wird wohl nicht gehen

> Gibts ne
> andere Möglichkeit wie FastPWM um HardwarePWM hinzubekommen?

Es gibt ja auch noch andere PWM Modi, die das ICR1 Register nicht 
brauchen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TCCR1A = (1<<7);     //Com1A1=1
TCCR1B = (1<<1)| (1<<4) | (1<<3);  // Prescaler8 , WGM13=1 , WGM12=1


Das kannst du auch so schreiben
TCCR1A = (1<<COM1A1);
TCCR1B = (1<<1)| (1<<WGM13) | (1<<WGM12);  // Prescaler8

dann brauchst du den Großteil der Kommentare nicht mehr und dann können 
auch die Kommentare nicht falsch sein.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit welchen würde des gehen?
CTC=OCR1B Top oder FastPWM=OCR1B Top oder ganz mit nen anderen?
Bin ganze zeit auf der suche nach ner möglichkeit finde nur grand nix.
Hast du vielleicht ein Codebeispiel?

Ich arbeite mit CodeVision der akzeptiert nur die Variante TCCR1A = 
(1<<7);
Deswegen schreib ich auch die Komentare damit jemand der des ließst net 
soviel suchen muss, um's zu verstehen.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Ich arbeite mit CodeVision der akzeptiert nur die Variante TCCR1A =
> (1<<7);

Könnte es sein dass dein <mega16.h> kaputt ist?

> interrupt [TIM1_CAPT] void timer1_capt_isr(void)
> {
>   T2=T1;
>   T1=ICR1;
>   Timer=T1-T2;

Da steckt noch ein Fehler drin. Falls T1 kleiner als T2 ist bekommst du 
für Timer einen falschen Wert. Wenn T1 gleich T2 ist Null, und 
anschliessend machst du dann eine Division durch Null. (Mit einer 
if-Abfrage kannst du dieses Problem leicht korrigieren.)
Brauchst du wirklich den Modus 12, dann müsstest du statt ICR1 halt 
TCNT1 einlesen. Sonst vielleicht mit Modus 4, TOP mit OCR1A gesetzt, 
dann sollte ICR1 benutzbar sein (wenn ich das richtig aus dem Datenblatt 
gelesen habe).

Rolf

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:

>> interrupt [TIM1_CAPT] void timer1_capt_isr(void)
>> {
>>   T2=T1;
>>   T1=ICR1;
>>   Timer=T1-T2;
>
> Da steckt noch ein Fehler drin. Falls T1 kleiner als T2 ist bekommst du
> für Timer einen falschen Wert.

Das passt schon. Durch die unsigned Rechnung kommt auch in diesem Fall 
das richtige raus.

> Wenn T1 gleich T2 ist Null, und
> anschliessend machst du dann eine Division durch Null.

das ist ein Problem das tatsächlich auftreten könnte, wenn zwischen T1 
und T2 tatsächlich exakt 65536 Timerticks liegen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Mit welchen würde des gehen?

Datenblatt studieren.
Da gibt es bei den PWM Modi eine schöne Tabelle, in der alle 
Möglichkeiten aufgeführt sind, zusammen mit dem Register welches als Top 
Wert genommen wird.

> Bin ganze zeit auf der suche nach ner möglichkeit finde nur grand nix.

Schau ins Datenblatt.
Noch übersichtlicher als die Modi Tabelle dort geht kaum noch.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Das passt schon. Durch die unsigned Rechnung kommt auch in diesem Fall
> das richtige raus.

Beispiel: T2=39990 T1=10 (mit TOP=40000)
T1-T2 = -39980 = -0x9C2C = 0x63D4 = 25556
Richtiger Wert wäre aber: 10 + 40001-39990 = 21
Automatisch richtig raus kommt es nur wenn TOP=65535 ist.

Rolf

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:

> Beispiel: T2=39990 T1=10 (mit TOP=40000)
> T1-T2 = -39980 = -0x9C2C = 0x63D4 = 25556
> Richtiger Wert wäre aber: 10 + 40001-39990 = 21
> Automatisch richtig raus kommt es nur wenn TOP=65535 ist.

MIst.
Ich hab mit einem TOP Wert von 65535 gerechnet, dort passts.
Ja natürlich. Du hast recht.

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@Rolf Pfister
Bin mir net sicher ob die Header kaputt ist.
Bei AVRStudio gehts so aber bei CodeVision irgendwie net.

Ich hab des jetzt mit FastPWM hinbekommen. Läuft super ab 156Hz. Naja so 
schnell wird mein Motor aber nicht laufen :) Alles darunter ist Unsinn 
und ist gerade des was ich sehen will. Mensch das immer was net 
geht*heul*

Liegt wahrscheinlich daran was du versucht hast zu erklären aber ich 
kenn mich da noch net so aus und verstehe des net so wirklich. Wieso 
kommt da 25556 raus und net 10-39980=-39970 ? Warum hat des bei 65535 
geklappt?
Wie kann ich diesen Fehler vermeiden?

Danke für deine Hilfe!

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mir grad noch überlegt das es doch sein kann das ich mehrere 
Überläufe hatte und der MC aber nur den ersten Wert rechnet das er schon 
komplett mehrfach durch gelaufen ist merkt der ja net. Oder lieg ich da 
falsch?
Wie kann ich überläufe am besten zählen?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab noch ne if anweisung mit if(T1>T2)ausgabe_arcleistung();

Er zeigt jetzt bis ca 50Hz. Dann kommt nur mist.
Liegt des an den OCR1B Wert das der auf 50Hz eingestellt ist??
Wie kann ich des umgehen?

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt was anderes probiert aber da geht der nur bis 35-37Hz und dann 
kommt wieder mist.
Was treibt das ding da? HILFE!
Was muss ich machen damit der damit aufhört?

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Liegt wahrscheinlich daran was du versucht hast zu erklären aber ich
> kenn mich da noch net so aus und verstehe des net so wirklich. Wieso
> kommt da 25556 raus und net 10-39980=-39970 ? Warum hat des bei 65535
> geklappt?
> Wie kann ich diesen Fehler vermeiden?

Wegen dem "unsigned int". Da macht der Compiler immer positive Zahlen. 
(In obiger Rechnung habe ich versucht zu zeigen wie man aus der 
negativen Zahl unter Bildung des Zweiercomplements eine positive Zahl 
erhält.)
Im Prinzip muss man wenn T1<=T2 ist, einfach noch TOP+1 dazuzählen damit 
das Ergebnis positiv wird. (Wenn TOP+1=65536 ist sind die untersten 16 
Bit alle 0, dies zu addieren ändert somit nichts.)

Wenn du mehr als einen Ueberlauf haben kannst, dann brauchst du, wie 
schon richtig erkannt, einen Ueberlaufzähler. Ich würde fuer T1, T2 und 
Timer statt int "unsigned long" nehmen. Dann den Ueberlaufzähler gleich 
mit einrechnen. Das würde dann in etwa so aussehen (nicht getestet, nur 
eben mal schnell getippt):
static unsigned char ueberlauf=0;
#define TOPPLUS1 40000L

void ISR(TIMER1_CAPT_vekt)
 {
   T2=T1;
   T1=ICR1+ueberlauf*TOPPLUS1;
   if(T1>T2) 
      Timer = T1-T2;
   else
      Timer = T1 + TOPPLUS1*256 - T2;
   ...

Den uberlauf musst du natürlich noch im Timer1_Overflow-Interrupt 
jeweils erhöhen.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geht der CompareB überhaupt wenn FastPWM eingeschaltet ist? Ist komisch 
das die Frequenz nur bis 35Hz geht, liegt des am Überlauf?

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Geht der CompareB überhaupt wenn FastPWM eingeschaltet ist? Ist komisch

Ja, ich glaub schon. Im Zweifelsfall musst du halt nochmals die 
Dokumentation lesen. Welchen Controllertyp genau hast du eigentlich, und 
welche Dokumentation hast du runtergeladen? Es gibt nämlich mehrere 
unterschiedliche Atmega16. (Weiss jetzt nicht ob da die Timer bei allen 
gleich sind)

> das die Frequenz nur bis 35Hz geht, liegt des am Überlauf?

Deine timer1_capt_isr ist immer noch kreuzfalsch. Du kannst nicht 
einfach immer 40000 dazuzählen. Sondern nur wenn ein Ueberlauf 
stattgefunden hat, also wenn T1<=T2 ist dann soll 40000 dazugezählt 
werden.
Woher kommt eigentlich dieses 40000?
Was ist takt=2000000, das war in vorherigen Versionen doch was anderes. 
Ist das F_CPU, ein 2MHz Quarz, wird der auch wirklich benutzt?
Da ist auch was komisch
#define Periodendauer OCR1A
...
Periodendauer=40000;
Vermutlich wolltest du sowas machen:
#define PERIODENDAUER 40000
...
OCR1A = PERIODENDAUER-1;
OCR1A muss jeweils 1 weniger sein als die Periodendauer, weil jeweils 
von Null bis und mit OCR1A gezählt wird.

Du wolltest doch eigentlich einen FastPWM-Modus haben, hast aber einen 
CTC-Modus eingestellt.
Ich hatte mal eine Zusammenfassung vom ATmega8 gemacht:
http://www.rolfp.ch/elektronik/atmega8.html
Da ist auch eine Zusammenfassung vom Timer1 mit drin, allerdings ohne 
die PWM-Moden. Vielleicht machst du mal selber eine ähnliche 
Zusammenfassung vom Timer1 im ATmega16 inklusive der PWM-Moden die du 
brauchst. Mir jedenfalls hilft es jeweils so eine Zusammenfassung zu 
schreiben um besser durchzublicken.

Rolf

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:
> Welchen Controllertyp genau hast du eigentlich, und
> welche Dokumentation hast du runtergeladen?

Hab den Atmega16-16 DIP bei reichelt bestellt siehe Link: 
http://www.reichelt.de/?;ACTION=3;LA=444;GROUP=A36...

ATMega AVR 16-16 PDIP
Gehäuse: DIL-40
MHz: 16
Flash: 16
EEProm: 512
RAM: 1K
I/O: 32

Rolf Pfister schrieb:
> du kannst nicht
> einfach immer 40000 dazuzählen.

Ja stimmt es war schon spät und ich hab offensichtlich etwas mühl 
geschrieben :) Werd ich ändern sobald ich daheim bin. Was ich immer noch 
net versteh ist warum es bei 65536 funktioniert ohne was machen muss 
aber bei anderen Top Werten nicht. Ich weiß ich bin etwas schwer von 
Begriff aber wäre total nett wenn des nochmal erklären könntest.


Rolf Pfister schrieb:
> Du wolltest doch eigentlich einen FastPWM-Modus haben, hast aber einen
> CTC-Modus eingestellt.

Ich hab des so verstanden das dies als FastPWM Mode15 mit Top wert OCR1A 
bezeichnet wird. Was müsste ich den machen um Mode15 zu bekommen?
Gedacht wars so Der MC zählt bis zu den in OCR1A Register eingetragenen 
Wert, wird dann Null und fängt dann wieder bis (in meinen Fall) 40000 zu 
zählen. Dadurch erhalte ich die Periodendauer hast aber recht normal 
muss ich noch 1 abziehen. Was laut Oszi auch so funktioniert.
Das OCR1B Register enthält die Impulsdauer, die ich für meine 
Motorreglersteurerung brauch.

Rolf Pfister schrieb:
> Woher kommt eigentlich dieses 40000?
> Was ist takt=2000000, das war in vorherigen Versionen doch was anderes.
> Ist das F_CPU, ein 2MHz Quarz, wird der auch wirklich benutzt?

Die Werte ergeben sich da ich ein 16Mhz Quarz und den Prescaler 8 habe. 
Das heißt Timertakt 2MHz. Den Prescaler habe ich deshalb genommen weil 
des Umrechnen so ziemlich leicht war.
Jedenfalls brauch ich alle 20ms für den Regler ein Impuls der ja je 
nachdem wie schnell der Motor laufen soll 0,9 bis 2ms lang sein kann.

Rolf Pfister schrieb:
> Da ist auch was komisch#define Periodendauer OCR1A
> ...
> Periodendauer=40000;
> Vermutlich wolltest du sowas machen:#define PERIODENDAUER 40000
> ...
> OCR1A = PERIODENDAUER-1;
> OCR1A muss jeweils 1 weniger sein als die Periodendauer, weil jeweils
> von Null bis und mit OCR1A gezählt wird.

Ich dachte ich mach des damit die leute die den Text lesen es besser 
verstehen aber du hast recht anders rum ist es besser.


Wenn der Compare nicht funktioniert hättest du vielleicht ne Idee wie 
ich es sonst machen könnte? Wie hast du Überläufe gezählt?

Vielen Dank für deine Hilfe.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Hab den Atmega16-16 DIP bei reichelt bestellt siehe Link:

Ok, ich nehm jetzt mal an du hast auch das Datenblatt von dort.
Auf Seite 106 findest du da die Tabelle der Timer1-Moden.

> geschrieben :) Werd ich ändern sobald ich daheim bin. Was ich immer noch
> net versteh ist warum es bei 65536 funktioniert ohne was machen muss
> aber bei anderen Top Werten nicht. Ich weiß ich bin etwas schwer von
> Begriff aber wäre total nett wenn des nochmal erklären könntest.
>
Also nochmal ganz langsam: Der Zähler im Timer1 ist 16 Bit breit. Die 
grösste Zahl die darin gespeichert werden kann ist 65535, dann sind alle 
16 Bits gesetzt. Wenn jetzt TOP auf 65535 eingestellt ist, dann wechselt 
der Zähler von 65535 im nächsten Takt nach 0. Der richtige Zählerwert, 
(wenn er beliebig grosse Zahlen enthalten könnte) wäre dann aber 65536. 
Binär geschrieben ist das eine 1 mit 16 Nullen hinten dran. Wenn du das 
zu einem 16-Bitwert dazuaddierst dann passiert da also gar nichts. Ist 
TOP hingegen was anderes z.B. 40000 dann springt der Zähler von 40000 
her wieder nach 0. Dann sind wir um 40000 falsch und müssen das also 
addieren. Bei 40000 sind aber die unteren 16 Bit nicht alle gleich Null, 
also ist die Addition wirklich nötig.

> Ich hab des so verstanden das dies als FastPWM Mode15 mit Top wert OCR1A
> bezeichnet wird. Was müsste ich den machen um Mode15 zu bekommen?

Siehe Seite 106: Für Modus 15 müssen alle WGMXY gesetzt sein. Du hast 
vergessen WGM11 und WGM10 zu setzen. (Aufgepasst die sind dann in 
TCCR1A, nicht wie 12 und 13 die in TCCR1B sind.)

> Die Werte ergeben sich da ich ein 16Mhz Quarz und den Prescaler 8 habe.
> Das heißt Timertakt 2MHz. Den Prescaler habe ich deshalb genommen weil
> des Umrechnen so ziemlich leicht war.
> Jedenfalls brauch ich alle 20ms für den Regler ein Impuls der ja je
> nachdem wie schnell der Motor laufen soll 0,9 bis 2ms lang sein kann.
>
Ok, Modellbau-Servos steuert man auch so an. Dort ist dann die Pulslänge 
gerade die Position auf die der Servo gehen soll.

> Wenn der Compare nicht funktioniert hättest du vielleicht ne Idee wie
> ich es sonst machen könnte? Wie hast du Überläufe gezählt?

Der Compare müsste auch im PWM-Modus funktionieren. Aber brauchst du 
doch gar nicht, der PWM setzt ja schon automatisch den entsprechenden 
Ausgang.

Zum Überläufe zählen habe ich doch schon im Beitrag vom 21.10.2010 15:56 
ein Beispiel gegeben. Einfach der Overflow-Interrupt müsste noch 
angefügt werden:
ISR(TIMER1_OVF_vekt)
{
  ueberlauf++;
}

Muss aber nicht unbedingt genau so sein wie in meinen Beispielen. Für 
die Variable "ueberlauf" würde ich auch noch einen sinnvolleren Namen 
suchen.
Ach ja, TOIE1 in TIMSK muss auch noch gesetzt werden. (siehe Seite 109)

Rolf

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:
> Siehe Seite 106: Für Modus 15 müssen alle WGMXY gesetzt sein. Du hast
> vergessen WGM11 und WGM10 zu setzen. (Aufgepasst die sind dann in
> TCCR1A, nicht wie 12 und 13 die in TCCR1B sind.)

Des hab ich in den Zeilen gemacht damit das PWM Signal solange aus ist 
bist ich die Beiden Bits setze.

       if(!(PINA & (1<<1)))        //START
        {
>           TCCR1A|=(1<<1); //9Bit-PWM Ein WGM10,WGM11
>           TCCR1A|=(1<<0);
            arcstufe=0;
            LED_Signal_aus=0;
            LED_Signal_warten=1;
            delay_ms(8000);
            LED_Signal_ein=1;
            LED_Signal_warten=0;
            freigabe=1;
        }

Wieso hast du eigentlich den Topplus1 * 256 gemacht? Ist das der 
Prescaler?

Rolf Pfister schrieb:
> if(T1>T2)
>       Timer = T1-T2;
>    else
>       Timer = T1 + TOPPLUS1*256 - T2;
>    ...

Ich werd des ganze mal am montag versuchen. Hab nämlich noch kein 
Frequenzgenerator (arme Studentin*g*).

Hoffe es klappt dann. Vielen vielen dank für deine Hilfe hoffe wenn 
ich's net hinkrieg, das mir noch helfen kannst.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine kurze Frage bevor ich dich für's Wochenend in Ruhe lasse :) 
Auf der Seite 106 beim FastPWM steht TOV1 Flag set on TOP meinen die den 
Top Wert den ich eingestellt hab oder 65535?

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Wieso hast du eigentlich den Topplus1 * 256 gemacht? Ist das der
> Prescaler?

Nein, das ist wegen dem Ueberlauf vom ueberlauf. Die Variable ueberlauf 
hatte ich als unsigned char definiert.


Agi schrieb:
> Auf der Seite 106 beim FastPWM steht TOV1 Flag set on TOP meinen die den
> Top Wert den ich eingestellt hab oder 65535?
>
Das ist immer der TOP Wert den du eingestellt hast.

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hab's heut nochmal mit den änderungen versucht.
Das Display zeigt nur ganz schnell ändernde Zahlen.
Man kann nicht genau sagen ob der richtige Wert dabei ist oder nicht.
Wobei es aussieht als ob oberhalb 50 noch irgendwie der richtige dabei 
wäre und unterhalb spinnt der dann total.

Bin langsam echt verzweifelt.
Weiß nicht wie ich des lösen soll.
Bestimmt hat doch jemand schon das gleiche wie ich gemacht und musste 
doch irgendwie das Problem lösen oder?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat keiner ne Idee was ich falsch mach?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rolf Pfister
Ist das jetzt mit den Input Capture Interrupt richtig?

Autor: Rolf Pfister (rolfp)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Hab's heut nochmal mit den änderungen versucht.

Ich hatte noch keine Zeit mir deine neue Version genauer anzuschauen.

> Das Display zeigt nur ganz schnell ändernde Zahlen.
> Man kann nicht genau sagen ob der richtige Wert dabei ist oder nicht.
> Wobei es aussieht als ob oberhalb 50 noch irgendwie der richtige dabei
> wäre und unterhalb spinnt der dann total.
>
Könnte es sein dass du noch irgendwelche Störsignale hast? Hast du ein 
Schaltschema?
Um die Anzeige besser zu sehen könntest du noch in der Hauptschlaufe 
probehalber nur bei jedem n-ten Durchlauf ausgabe_frequenz() aufrufen.

> Bestimmt hat doch jemand schon das gleiche wie ich gemacht und musste
> doch irgendwie das Problem lösen oder?

Ich habe letzten Sonntag mal eine kleine Testschaltung am MyAvrBoard 
gemacht. Ein LCD angeschlossen, einen Modellbauservo und einen Eingang 
auf den ich vom Tongenerator die Freqeunz eingegeben habe. Ich stelle 
das entsprechende Testprogramm mal hier rein. Das mit dem Ueberlauf habe 
ich etwas eleganter mit einer ulong Variablen gelöst.
Gestern habe ich dann noch Mittelwert-Berechnungen eingebaut. (Unter 
backup/ sind noch die einfacheren Versionen zu finden.)

Mal schauen vielleicht habe ich bald mal Zeit deine neue Version auf 
meiner Testschaltung auszuprobieren.

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow jetzt weiß ich wie ne gute Programmierung aussieht. Ganz schön 
kompliziert :) Wie lang machst du des schon?

Werd die mal in Ruhe anschauen und vergleichen vielleicht finde ich ja 
meine Fehler.

Rolf Pfister schrieb:
> Könnte es sein dass du noch irgendwelche Störsignale hast? Hast du ein
> Schaltschema?

Meinst du wo ich was angeschlossen habe?
Der Frequenzgenerator ist leicht defekt. Der Offset funktioniert nicht 
mehr, deswegen geht der in den negativen Bereich so ca 1V. Kann des 
Störungen verursachen?

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Wow jetzt weiß ich wie ne gute Programmierung aussieht. Ganz schön
> kompliziert :) Wie lang machst du des schon?
>
Mikrokontroller seit etwa 2 Jahren. C-Programmierung schon einiges 
länger.

> Meinst du wo ich was angeschlossen habe?

Ja genau. Inklusive aller Leitungen, Widerstände, Condensatoren, Motoren 
und was du sonst noch so dran hängen hast. Mein Verdacht wegen Störungen 
geht so in Richtung des Motors den du mit dem PWM steuerst. (Wobei du ja 
das Schema nicht unbedingt schicken musst, mach dir einfach Gedanken was 
daran Störungen verursachen könnte)

> Der Frequenzgenerator ist leicht defekt. Der Offset funktioniert nicht
> mehr, deswegen geht der in den negativen Bereich so ca 1V. Kann des
> Störungen verursachen?

Negative Spannung gegenüber dem GND des Mikrocontrollers? Das ist aber 
ganz schlecht, könnte vielleicht sogar den Controller zerstören. 
Hoffentlich hast du wenigstens einen Schutzwiderstand dazwischen 
geschaltet. Ich würde hinter dem Schutzwiderstand (vielleicht 10k Ohm) 
noch eine Diode gegen GND schalten um negative Spannungen zu vermeiden.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab grad mal deine neue Version versucht zu compilieren. Bei mir gibt 
das immer noch diverse Fehler. Hast du vielleicht auch noch Fehler oder 
Warnungen beim Compilieren die du einfach ignoriert hast? Oder -Wall 
vergessen einzustellen?

Möglicherweise hast du noch einen grundsätzlichen Fehler in deiner 
Toolchain. Was verwendest du denn eigentlich?
Dieses  #include <mega16.h>  ist das in deiner Toolchain wirklich 
richtig?

Meine Toolchain besteht aus Linux-Kubuntu, avr-gcc, avr-libc und make 
zum Compilieren, und avrdude um auf den Controller zu brennen.
Ich muss folgende includes machen damit es funktioniert:
#include <avr/io.h>
#include <avr/interrupt.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define F_CPU 16000000
#include <util/delay.h>
Ein  #include <mega16.h>  brauche ich nicht, sondern mache im Makefile:
# Processortyp M fuer Compiler, N fuer avrdude:
M=atmega16
N=m16
# Compileraufrufe:
C=avr-gcc -mmcu=$M -Wall -Os -c
L=avr-gcc -mmcu=$M -Wall -Os

Das fehlende F_CPU in deinem Programm könnte auch noch ein Problem sein. 
Dann stimmen die delay_Funktionen vielleicht nicht.
(Heute abend reicht die Zeit jetzt nicht mehr um noch Anpassungen an den 
ATmega8 zu machen, dass ich es mit meiner Hardware testen könnte)

Autor: Agi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:
> Oder -Wall
> vergessen einzustellen?
Habe grad in CV geguckt sowas wie Wall find ich net.Was ist des?

Ich arbeite mit CodeVision und übertragen tue ich meine Programme mit 
AVRStudio dazu musste ich WinAVR20100110 installieren.

avr-gcc, avr-libc gehören doch zu avrstudio oder ? Wenn du mit AVRstudio 
arbeitest funktionieren meine programme überhaupt bei dir?die funktionen 
heißen doch anders wie funktioniert des dann?
also wenn ich nämlich den code in avrstudio kopiert und die includes von 
dir mit rein tue dann kommen bei mir viele fehler. Kommt des bei dir 
auch?
Danke übrigens nochmal für deine hilfe.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Habe grad in CV geguckt sowas wie Wall find ich net.Was ist des?
>
"avr-gcc -Wall" sagt dem Compiler dass er alle Fehler und Warnungen 
anzeigen soll. Wird jeweils im Makefile mit angegeben.

> Ich arbeite mit CodeVision und übertragen tue ich meine Programme mit
> AVRStudio dazu musste ich WinAVR20100110 installieren.
>
Wenn du schon AVRStudio hast warum willst du dann noch CodeVision 
benutzen?

> avr-gcc, avr-libc gehören doch zu avrstudio oder ? Wenn du mit AVRstudio
> arbeitest funktionieren meine programme überhaupt bei dir?die funktionen
> heißen doch anders wie funktioniert des dann?

Ich arbeite nicht mit AVRStudio. Aber da AVRStudio auch avr-gcc und 
avr-libc benutzt, sollten meine Programme auch mit AVRStudio übersetzbar 
sein.
Um dein Programm mit avr-gcc zu übersetzen musste ich nur wenige 
Funktionen anpassen.

> also wenn ich nämlich den code in avrstudio kopiert und die includes von
> dir mit rein tue dann kommen bei mir viele fehler. Kommt des bei dir
> auch?

Ja, ebend! Ausser den Fehlermeldungen wegen unterschiedlicher Funktionen 
von CodeVision, gibt es auch noch einige Fehlermeldungen die auch mit 
CodeVision kommen müssten. Die gilt es dann im Programm zu korrigieren. 
Falls CodeVision keine Fehlermeldungen bringt, dann ist da etwas falsch. 
Das muss unbedingt geflickt werden, denn die Fehlermeldungen sind 
wirklich wichtig.
Ausserdem musst du CodeVision auch dazu bringen sowas zu verstehen:
TCCR1A = (1<<COM1A1);
Das muss auf alle Fälle gehen, egal welchen Compiler du verwendest.

Dann, wenn dein Compiler also alle Fehler und Warnungen anzeigt, musst 
du die entsprechenden Stellen in deinem Programm flicken. Solltest du 
eine Fehlermeldung mal nicht verstehen, dann ist es eine gute Idee diese 
mit Copy-Paste in Google zu kopieren. Oder sonst frägst du halt wieder.

Rolf

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> @Rolf Pfister
> Ist das jetzt mit den Input Capture Interrupt richtig?

Nein, ist mir auch eben erst jetzt aufgefallen. uberlauf=0 ist falsch. 
Damit stimmt dann beim nächsten Durchlauf T1 nicht mehr.

Ich hab dein Programm inzwischen auf meinem Aufbau zum laufen gebracht. 
Ich musste aber von Anfang an den PWM-Modus einschalten. Bei der 
Fliesszahlberechung noch
  Frequenz = (float)takt/Timer;
sonst rundet er immer auf eine ganze Zahl ab.
Nach ausgabe_frequenz() habe ich noch delay_ms(500) gemacht um die 
Anzeige besser zu sehen. Bei 100 Hz läufts recht gut, bei 1 Hz gibt er 
zwischendurch ganz falsche Werte.

Rolf

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Pfister schrieb:
> Wenn du schon AVRStudio hast warum willst du dann noch CodeVision
> benutzen?

Ich benutzte gern die funktion von CodeVision das ich nen Port PORTB.2 
so angeben kann. So kann ich dann des define so #define LED_Signal_aus 
PORTB.2 machen und um den Port zu aktivieren mach ich dann nur 
LED_Signal_aus=1; SWie ich sowas in AVRStudio nachstellen kann weiß ich 
net. Wenn ich des wüsste würde ich mein nächstes Programm in studio 
schreiben. Denn ich will mehrere Ports als LED1 LED2 usw definieren und 
in ein Array speichern. ich muss dann das entsprechende Array nur =1 
setzten und alle LEDS leuchten die im Array gespeichert sind egal an 
welchen Port sie sind.

Rolf Pfister schrieb:
> Ausser den Fehlermeldungen wegen unterschiedlicher Funktionen
> von CodeVision, gibt es auch noch einige Fehlermeldungen die auch mit
> CodeVision kommen müssten. Die gilt es dann im Programm zu korrigieren.
> Falls CodeVision keine Fehlermeldungen bringt, dann ist da etwas falsch.
> Das muss unbedingt geflickt werden, denn die Fehlermeldungen sind
> wirklich wichtig.

Das klingt so als ob mein Compiler nen Knacks hat. Der zeigt mir 
wirklich keinen Fehler an. Mir hat des mal ein Kumpel installiert weil 
er etwas  neueres hat. Kann mir des also nimmer neu installieren. Anders 
kann ich des auch net korrigieren oder?

Rolf Pfister schrieb:
> Nein, ist mir auch eben erst jetzt aufgefallen. uberlauf=0 ist falsch.
> Damit stimmt dann beim nächsten Durchlauf T1 nicht mehr.

Aber wenn ich überlauf nicht auf 0 setze zählt er immer weiter dann 
stimmt das Ergebnis doch nimmer oder?

Rolf Pfister schrieb:
> Ich hab dein Programm inzwischen auf meinem Aufbau zum laufen gebracht.

ECHT!? Wahnsinn, könntest du es mir des schicken vielleicht tue ich mir 
dann bei der fehlersuche etwas leichter. Versuche es grad in Studio zumm 
laufen zu bekommen.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Ich benutzte gern die funktion von CodeVision das ich nen Port PORTB.2
> so angeben kann. So kann ich dann des define so #define LED_Signal_aus
> PORTB.2 machen und um den Port zu aktivieren mach ich dann nur
> LED_Signal_aus=1; SWie ich sowas in AVRStudio nachstellen kann weiß ich
> net. Wenn ich des wüsste würde ich mein nächstes Programm in studio

Genau diese Syntax geht mit avr-gcc soweit ich weiss nicht. Aber mit 
entsprechend einfachen Maktros kann man eine ähnliche Syntax verwenden:
//Maktros definieren:
#define LED_Signal_aus_ON   PORTB |= (1<<2)
#define LED_Signal_aus_OFF  PORTB &= ~(1<<2)

//dann so verwenden:
 LED_Signal_aus_ON;  //LED einschalten
 LED_Signal_aus_OFF; //LED ausschalten
Oder unter Verwendung einer inline-Funktion:
//Funktion definieren:
inline void LED_Signal_aus(char n)
{
 if(n==0) PORTB &= ~(1<<2);
 else     PORTB |= (1<<2);
}

//dann so verwenden:
 LED_Signal_aus(1); //LED einschalten
 LED_Signal_aus(0); //LED ausschalten
(Das hab ich auch verwendet um dein Beispiel bei mir laufen zu lassen)

> schreiben. Denn ich will mehrere Ports als LED1 LED2 usw definieren und
> in ein Array speichern. ich muss dann das entsprechende Array nur =1
> setzten und alle LEDS leuchten die im Array gespeichert sind egal an
> welchen Port sie sind.
>
Ich glaube nicht, dass das so geht. Aber mit einer kleinen Funktion kann 
man das auch elegant machen:
void alle_LEDs_setzen(char n)  //einschalten n=1, ausschalten n=0
{
//LEDs an PB2, PD0 und PC5 ein- oder aus-schalten
 if(n==0) {PORTB &= ~(1<<2); PORTD &= ~(1<<0); PORTC &= ~(1<<5);}
 else     {PORTB |=  (1<<2); PORTD |=  (1<<0); PORTC |=  (1<<2);}
}

//dann so verwenden:
 alle_LEDS_setzen(1); //alle LEDs ein
 alle_LEDS_setzen(0); //alle LEDs aus

> Das klingt so als ob mein Compiler nen Knacks hat. Der zeigt mir
> wirklich keinen Fehler an. Mir hat des mal ein Kumpel installiert weil
> er etwas  neueres hat. Kann mir des also nimmer neu installieren. Anders
> kann ich des auch net korrigieren oder?
>
Ich glaube nicht dass der Compiler nen Knacks hat. Es ist wahrscheinlich 
nur eine Kleinigkeit die du anders einstellen musst. Suche doch mal im 
Handbuch nach "Compiler Configuration" und schau dann nach ob bei dir 
"Enable Warnings" (oder wie immer das heisst) gesetzt sind. Wenn nicht 
dann setze die mal.

> Aber wenn ich überlauf nicht auf 0 setze zählt er immer weiter dann
> stimmt das Ergebnis doch nimmer oder?
>
Doch, der muss immer weiter zählen. ("uberlauf" ist vielleicht nicht 
grad die beste Wahl für diesen Variablennamen, "erweiterter_zaehler" 
würde die Sache vielleicht besser beschreiben.) Beim Berechnen von T1 
wird ja der Inhalt von "ueberlauf" berücksichtigt. Beim nächsten 
Durchlauf dann das auf T2 umkopierte enthält dann den alten Zählerstand 
von "ueberlauf". Bei der Differenzbildung wird dann also der alte vom 
neuen Zählerstand abgezogen, so dass wir wirklich den Zeit-Unterschied 
zu vorher haben.

> Rolf Pfister schrieb:
>> Ich hab dein Programm inzwischen auf meinem Aufbau zum laufen gebracht.
>
> ECHT!? Wahnsinn, könntest du es mir des schicken vielleicht tue ich mir
> dann bei der fehlersuche etwas leichter. Versuche es grad in Studio zumm
> laufen zu bekommen.

Ich glaube das macht wenig Sinn. Ich habe ja da noch die Änderungen mit 
drin um es an meinen Aufbau anzupassen. Aber ich habe mal "diff" laufen 
gelassen um die relevanten Unterschiede aufzulisten:
> #include <delay.h>
< #define F_CPU 16000000
< #include <delay.h>
---
>   ueberlauf=0;
<   //ueberlauf=0;
---
>   Frequenz=takt/Timer;            
<   Frequenz = (float)takt/Timer;            
---
> TCCR1B|=(1<<1) | (1<<3) | (1<<4); //PWM Mode14 WGM13,WGM12, Prescaler8    0x1A;
< TCCR1B|=(1<<1) | (1<<3) | (1<<4); //PWM Mode14 WGM13,WGM12, Prescaler8    0x1A;
< TCCR1A|=(1<<1); //9Bit-PWM Ein WGM10,WGM11
< TCCR1A|=(1<<0);
---
>       ausgabe_frequenz (); 
<      ausgabe_frequenz (); 
<      delay_ms(500);
Ich denke wenn du diese Änderungen machst, funktionierts auch bei dir. 
Ich habe allerdings erst mit 100Hz und 1Hz getestet und nur auf die 
Frequenzmessung geachtet. Schalter, LEDs und die PWM-Ausgabe habe ich 
noch nicht überprüft.
Dass es bei mir mit der 1Hz Messung Fehler gab, liegt warscheinlich am 
DCF-Modul das ich für diesen Takt benutzt habe (Das Modul schaltet nicht 
so sauber.)

Rolf

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Funktioniert dann bei dir das PWM auch gleichzeitig?

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Agi schrieb:
> Funktioniert dann bei dir das PWM auch gleichzeitig?

Ich verstehe die Frage nicht. Was meinst du mit gleichzeitig?

Autor: Agi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mein, ob du den Regler ansteueren, also ein verstellbares PWM Signal 
erzeugst, und gleichzeitig eine frequenz messen kannst? Weil bei mir 
grad nur immer eins funktioniert deswegen wollt ich wissen ob bei dir 
beides geht und bei mir nur irgendeine einstellung net stimmt.

Autor: Rolf Pfister (rolfp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Selbstverständlich geht PWM und Frequenzmessung unabhängig voneinander. 
In deinem Programm hast du ja absichtlich den PWM-Modus manchmal 
ausgeschaltet. Wenn du das nicht machst, sollte es keine Probleme geben. 
Wenn du willst dass dein Motor keine PWM-Signale bekommt, dann schalte 
doch einfach den entsprechenden Port-Pin aus. Oder vielleicht die 
COM1B1:0 Bits in TCCR1A.

Das Konzept mit den Tastern funktioniert nicht. Vergiss doch einfach mal 
das mit den entprell_Taster. Bei Taste1 und Taste2 hast du ja eh schon 
Pausen eingefügt, so dass sich die Entprellung erübrigt. Füg doch 
einfach bei den andern beiden Tasten auch noch Pausen ein. Wobei so etwa 
100 oder 200 Millisekunden reichen. Die 4 und 8 Sekunden bei den ersten 
beiden Tastern sind wohl etwas übertrieben.

Das Hauptprogramm musst du ja sowieso noch überarbeiten. Da kannst du 
dann gleich noch schön formatieren und einige Kommentare einfügen. Wie 
war das doch gleich noch mit den 4 Tastern und den 3 LEDs, wie sollte 
das alles zusammenspielen? Ist ziemlich mühsam das aus dem Programm 
rauszulesen.

Die Frequenzmessung funktioniert bei mir bis etwa 1200 Hz einwandfrei. 
(Die Fehler bei 1Hz lagen bei meinem DCF-Modul.) Und das PWM-Signal kann 
ich am Oszilloskop auch mitverfolgen.
(Bei dir sollte es etwa bis 5200 Hz gehen, wegen dem höheren Takt. Für 
höhere Frequenzen müsste man die Fliesskomma-Berechnung aus der 
Interruptroutine rausnehmen.)

Rolf

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.