PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Weis nicht mehr weiter :-(



Nigthlord
19.11.2007, 14:29
Hallo Leute,

Sorry dass ich euch wiedermal auf die Nerwen falle aber ich brauche "mal wieder" eure Hilfe.

Ich habe folgendes Programm:


// Timer_Interrupt_TEST_2.c Programm //

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>


int A;
int Delai;

// Routine d'interruption
//-----------------------

ISR (TIMER1_COMPB_vect) {
if(A==0x00){
PORTB=0x05;
}

if(A==0x01){
PORTB=0x00;
}

if(A==0x0A){
PORTB=0x0A;
}

if(A==0x0B){
PORTB=0x00;
}

A=A++;
OCR1B=TCNT1+Delai;

if(A==0x14){
A=0;
}
}

// Programme principal:
//---------------------

int main () {

A=0;

DDRB=0xFF; // PORTB mis en sortie
DDRC=0xFF;

Delai=3686000/20/20/165;


TCCR1B=(3<<CS10); // timer1 source: ck/64


OCR1B=TCNT1+Delai; // initialisation du registre de comparaison


TIMSK|=(1<<OCIE1B); // autorisation de l'interruption

sei (); // autorisation de toutes les interruptions


while (1){
}

}


Dieses Program funktioniert auch prima nur ich muss es noch soweit ergänzen , dass die ISR Routine durchlaufen wird wenn PORTA == 0x01 ist.

d.h. erst wenn Pin 0 am portA betätigt wird, soll die unterrupt routine durchlaufen werden und dann erst beim nachsten betätigen von Pin 0 wieder von vorn durchlaufen werden.



Dieses Programm soll für eine B2 Schaltung mit Thyristoren sein.
Am Pin0 vom port A soll ein Rechtecksignal anliegen der immer dann 1 wird, wenn der Nulldurchgang der Positiven halbwelle erfolgt und während 2-5ms anliegt.

Da der Nulldurchgang aber immer nur 1x pro Periode kommt , soll nach ablaufren der ISR der Programm in der While(1) schleifr "nix tuhn" bis wieder der Pin0 am portA betätigt wird.


hab es schon mit sei (); in einer If schleife probiert und mit einer cli(); im "if(A==0x14){
A=0;
}" probiert, ist aber nix draus geworden :-(

Ich habe mir überlegt , wenn man eine if schleife schreiben würde, wo man den Timer1 startet und am ende der ISR routine :
" if(A==0x14){
A=0;
}"
den Timer1 wieder Stoppen würde, dann müsste es gehen, da bei dem nachsten betätigen von Pin0 am PortA der Timer ja wieder gestartet werden würde. Das Problem ist ich weiss nicht wie ich den timer Stoppen und Starten kann.


Wass kann ich denn jetzt tun


Ein Newbie fragt den Forengötter um rat.




Euer Nightlord

robocat
19.11.2007, 15:59
eigentlich müsste es ja mit cli(); und sei(); funktionieren. "eigentlich" weil ich das grade nicht testen kann.

geht sicher geschickter, aber wie wäre das hier:

ISR (TIMER1_COMPB_vect)
{
if(PINA==1&&A==0x14)
{
A=0;
}

if(A<0x14)
{
if(A==0x00)
{
PORTB=0x05; // könnte man dort einfügen, wo A auf 0 gesetzt wird
}

if(A==0x01)
{
PORTB=0x00;
}

if(A==0x0A)
{
PORTB=0x0A;
}

if(A==0x0B)
{
PORTB=0x00;
}
A=A++;
OCR1B=TCNT1+Delai;
}
}
der zähler bleibt bei 0x14 stehen, und beginnt erst wieder von 0 aufwärts zu zählen, wenn PINA=1 ist.

Hubert.G
19.11.2007, 16:16
In die while-Schleife:
if((PINA(1<<PA0)){
TCCR1B|=(1<<CS10)|(1<<CS11); //timer start
}

Und am Anfang der ISR schreibst du:
TCCR1B&=(~(1<<CS10)|(1<<CS11)); // timer stopp

Das ist eine der vielen Möglichkeiten.

Nigthlord
20.11.2007, 11:42
Jepp es klappt:

Habe soeben das Program ergänzt und es funktioniert genau so wie ich es möchte.



// Timer_Interrupt_TEST_3.c Programm //

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>


int A;
int Delai;

// Routine d'interruption
//-----------------------

ISR (TIMER1_COMPB_vect) {


if(A==0x00){
PORTB=0x05;
}

if(A==0x01){
PORTB=0x00;
}

if(A==0x0A){
PORTB=0x0A;
}

if(A==0x0B){
PORTB=0x00;
}

A=A++;
OCR1B=TCNT1+Delai;

if(A==0x0C){ //0x14
A=0;
TCCR1B=(0<<CS10); // timer stopp
}
}

// Programme principal:
//---------------------

int main () {

A=0;

DDRB=0xFF; // PORTB mis en sortie
DDRC=0xFF;

Delai=3686000/20/20/165;

OCR1B=TCNT1+Delai; // initialisation du registre de comparaison

TIMSK|=(1<<OCIE1B); // autorisation de l'interruption

sei (); // autorisation de toutes les interruptions


while (1){

if(PINA == 0xFE){
TCCR1B=(3<<CS10); //timer1 start, timer1 source: ck/64
}
}
}


Natürlich währe es ohne eure Hilfe nix geworden.

Danke normals.

Dass mit dem

CS12, CS11, CS10 (Clock Select Bits)
Diese 3 Bits bestimmen die Quelle für den Timer/Counter:
CS12 CS11 CS10 Resultat
0 0 0 Stopp, Der Timer/Counter wird angehalten.
0 0 1 CPU-Takt
0 1 0 CPU-Takt / 8
0 1 1 CPU-Takt / 64
1 0 0 CPU-Takt / 256
1 0 1 CPU-Takt / 1024
1 1 0 Externer Pin T1, fallende Flanke
1 1 1 Externer Pin T1, steigende Flanke


hatte ich aus einer anderen Website aber bin gestern einfach nicht darauf gekommen, obwohl es gross draufstand... 0<<CS10 = timer Stopp eieiei


Naja jetzt gehts ja lol


Ciao

Euer Nightlord

Nigthlord
22.11.2007, 14:25
Hallo leute, ich bin ess schon wieder.

Unser nächstes Problem besteht darin, dass ich den inhalt vom TCNT1 auf die schnittstelle heraus geben will. Dies geht aber irgendwie nicht so richtig, wie ich mir dass so vorstelle.

Ein Freund hat diesen Testprogram entwickelt damit der Atmel den eingegebenen text im VBTREM (Sonderprogram) liest und wieder zurückschickt.

Ich habe lediglich die Rot markierten zeilen eingefügt, um zu testen, ob der Atmel mir dass herrausgibt, wass ich will.

Das Program funktioniert so:

Der Atmel fragt immer dien Sendeport ab nach neuen informationen. Wird ein Zeichen zum Atmel gesendet, so speichert er dieser den Wert in den buffer und dann sendet er das Zeichen zur schnittstelle zurück.

Die rot markierten Zeilen habe ich eingefügt, damit mit der Atmel, bei jedem gesendeten Zeichen diesen durch den Wert von TEST ersetzt und diesen dann zurückschickt anstatt des von mir gesendeten Zeichens.

kurz:
Egal welches Zeichen ich in den VBTERM eingebe, soll mir der Atmel den vert von TEST, also 576 zurücksenden.

VBTERM ist ein program in dem ich die Zeichen (Ziffern oder auch ganze sätze)eingeben kann , die ich dem Atmel senden will.





#include <avr/io.h>
#include <inttypes.h>


// Sollte schon im Makefile definiert sein.
// In dem Fall hier einfach löschen.
#define F_CPU 3686000UL

#define BAUD 9600UL
#define UBRR_BAUD ((F_CPU/(16L*BAUD))-1)

int TEST;

TEST = 576;

// USART initialisieren
void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
UBRRH = (uint8_t) (UBRR_BAUD>>8 );
UBRRL = (uint8_t)UBRR_BAUD;

// Aktivieren von receiver und transmitter
UCSRB = (1<<TXEN) | (1<<RXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
//UCSRC |= (1<<URSEL)|(3<<UCSZ0);
}

int main(void)
{



uint8_t buffer;

// USART initialisieren
uart_init();

while (1)
{
// Warten bis Daten empfangen wurden
while ( !(UCSRA & (1<<RXC)) );

// Empfangsregister auslesen */
buffer = UDR;

buffer = TEST;

// Warten bis der Sendepuffer frei ist
while ( !( UCSRA & (1<<UDRE)) );

// Daten in den Puffer schreiben und damit senden
UDR = buffer;
}
return 0;

}


Nur leider sendet mir der Atmel nicht den Wert von TEST (576) sondern er wandelt diesen Wert in ein ASCII-Zeichen um und sendet mir diesen.


Beide Programme (also der Sendeprogramm und den Ersten programm für die B2) muss ich anschliesend miteinander verbinden damit der Atmel den erstmals ermittelten wert von TCNT1 schickt.

Diesen benötige ich, um die Interrupts so genau wie möglich an der Netzfrequez anzupassen.




Mein Kollege und ich sind schon am verzweiffeln.
Wenn wir schreiben
TEST = '576';
Sendet uns der Atmel , bei jeder eingabe im VBTERM, immer nur die letzte Ziffer, also 6.


Wass können wir da tun damit der Atmel uns "576" Sendet anstatt irgendwass anderes???






Euer Nightlord

fluchtpunkt
23.11.2007, 21:08
Die Integervariable in einen String umwandeln, und dann diese 3 Zeichen senden.

Die passende Funktion dazu:
char* ltoa(long int __val, char *__s, int __radix) klick (http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g1d4c7b84110553544081a69a0 fc49c52)

Nigthlord
27.11.2007, 14:09
Hm... ich bekomme dass irgendwie nicht hin, weiss echt nicht weiter.

Solte echt nicht so schwer sein den Wert von TCNT1 zu lesen und abzuschicken.

P.S. dass mit dem char* ltoa(long int __val, char *__s, int __radix) bekomme ich ebensowenig hin.




Euer Nightlord