PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM vom ADXL im Atmega8 auswerten über ICP1 (PB0)



Grave80
17.09.2005, 17:29
Hi,
probier hier jetzt schon seit einer Weile mit einem Atmega8 auf einem STK500 und einem ADXl202 Beschleunigungssensor rum.
die Analogen Signale die aus dem ADXl kommen konnte ich shcon auswerten, jetzt woltl ich mal probieren die PWM Signale die der ADXL ausgibt mir gilfe des Atmega8 auszuwerten, aber irgendwie klappt das alles nicht.
Wahrscheinlich habe ich nur irgendwelche Register falsch gesetzt.
so wie ich es der Beschreibung entnhemen konnte habe ich folgende Register gesetzt:

DDRB = 0xff;
PORTB = 0xff;
DDRD = 0xff; //für die Ausgabe über LEDs
PORTD = 0xff;

ACSR = (1<<ACIC);


TCCR1B |= (1<<WGM13); // fallende Flanke
//TCCR1B = (1<<ICES1); // steigende Flanke

while(TIFR & (1<<ICF1)); //warten bis das ICF1 Flag gesetzt
wurde
result= ICR1L; //lesen der Werte
result1= ICR1H;

if(result>>0 & 0x01) //ausgabe der WErte über
LEDs
PORTD &= ~(1<<PD0);
if(result>>1 & 0x01)
PORTD &= ~(1<<PD1);
if(result>>2 & 0x01)
PORTD &= ~(1<<PD2);
if(result>>3 & 0x01)
PORTD &= ~(1<<PD3);
if(result>>4 & 0x01)
PORTD &= ~(1<<PD4);
if(result>>5 & 0x01)
PORTD &= ~(1<<PD5);
if(result>>6 & 0x01)
PORTD &= ~(1<<PD6);
if(result>>7 & 0x01)
PORTD &= ~(1<<PD7);

bin über jede hilfe dankbar

recycle
17.09.2005, 17:55
In Bascom Basic reicht zum Auslesen des digitalen Signals eines ADX eigentlich eine einzige Zeile.
Z.B:
Pulsein Adxlwert , Pinc , 4 , 0

Ich weiss allerdings nicht so genau welche Sprache dein Codeschnipsel ist - sieht mir mehr nach C aus und dann hilft der Bascom Befehl leider nicht soviel.

SprinterSB
23.09.2005, 10:27
[...] die PWM Signale die der ADXL ausgibt mir gilfe des Atmega8 auszuwerten, aber irgendwie klappt das alles nicht.
Wahrscheinlich habe ich nur irgendwelche Register falsch gesetzt.

So ist es.


ACSR = (1<<ACIC);

ACIC: Analog Comparator Input Capture Enable
When written logic one, this bit enables the Input Capture function in Timer/Counter1 to be triggered by the Analog Comparator. The comparator output is in this case directly connected to the Input Capture front-end logic, making the comparator utilize the noise canceler and edge select features of the Timer/Counter1 Input Capture interrupt. When written logic zero, no connection between the Analog Comparator and the Input Capture function exists. To make the comparator trigger the Timer/Counter1 Input Capture interrupt, the TICIE1 bit in the Timer Interrupt Mask Register (TIMSK) must be set.
Das ist nicht was du willst. Ich vermute mal, du willst dem ICP1 (PB0) als Eingang verwenden, und nicht den AIN0/AIN1 (PD6/PD7), den du zudem als Ausgang geschaltet hast.

ACSR &= ~_BV(ACIC);

Der ICP1 (PB0) muss als Eingang geschaltet werden, nicht als Ausgang. Sonst schmort's im Mega8 oder im ADXL -- oder in beiden.

// ICP1 ist Eingang ...
DDRB &= ~_BV(0);
// ... mit Pullup
PORTB &= ~_BV(0);
// ... oder ohne Pullup
PORTB |= _BV(0);

Vor du den InputCapture musst du noch

// Timer1 stoppen, InCapt-Flanke wählen und Timer1 Reset
TCCR1B = _BV(ICES1); // oder = 0;
TCNT1 = 0;


// ICF1-Flag Reset
TIFR |= _BV(ICF1);


// Timer1 starten
//Timer 1 in Mode 0, prescale = 1
TCCR1B |= _BV(CS10);

Das alleine reicht für eine PWM-Auswertung aber noch nicht, es sind nur ein paar Bausteine, die du brauchen wirst. Am besten geht so was in einer ISR:

#include <avr/signal.h>
#include <avr/interrupt.h>
...
volatile uint8_t icr1_update = 0;

uint16_t _icr1_hi, _icr1_low;
uint16_t icr1_hi, icr1_low;
...

{
...
TIMSK = _BV (TICIE1);
sei();

while (1)
{
while (0 == icr1_update)
;
cli();
icr1_hi = _icr1_hi;
icr1_low = _icr1_low;
icr1_update = 0;
sei();
PORTD = icr1_low & 0x00ff;
}
}

SIGNAL (SIG_INPUT_CAPTURE1)
{
TCNT1 = 0;
uint8_t tccr1b = TCCR1B;

if (tccr1b & _BV(ICES1))
_icr1_low = ICR1;
else
_icr1_hi = ICR1;

TCCR1B = tccr1b ^ _BV(ICES1);

TIFR |= _BV(ICF1);
icr1_update = 1;
}


Das nur als Vorschlag. Das ist ein ad-hoc-Code und nicht getestet.

Grave80
13.10.2005, 20:21
Hi Sprinter,

danke für deine Antwort, eine Antwort kommt so spät weil ich etwas arg im stress war die letzten Tage, doch jetzt hab ich mich damit mal wieder beschäftigt.
Habs jetzt erstmal soweit geschafft das überhaupt schon mal was flakert, kann ja den Code hier mal posten, auf das ihr mir vielleicht noch etwas unter die arme greifen könn/würdet wie auch immer.

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



int main(void)
{

int T1,T2;


DDRB &= ~(1<<PB0);
PORTB &= ~(1<<PB0);
DDRD = 0xff; //für die Ausgabe über LEDs
PORTD = 0xff;

while(1)
{
//ACSR &= ~(1<<ACIC);
//Zähler starten ohne vorteiler
TCCR1B = 0;
TCCR1B |= (1<<CS10);
TCCR1B |= (1<<ICES1);

TCCR1B |= (1<<ICNC1);
sei();
TIMSK = (1<<TICIE1); //Interrupt für ICP
sei(); //einschalten für erste messung
//nach der ersten flanke wird der timer gestartet
//nach der zweiten Flanke ist die Periodendauer
//ermittelt
//es wird der gespeicherte wert aus dem ICR1
//register zur berechnung verwendet

while(TIFR & (1<<ICF1));
TCCR1B = 0; //Zähler stoppen
TCNT1= 0;


T1=T2=0;
T1 = ICR1;
T2 = ICR1H;

TIFR &= ~(1<<ICF1);// oder das hier beides
TIMSK = 0; // nach unten


if(T1>>0 & 0x01)
PORTD &= ~(1<<PD0);
if(T1>>1 & 0x01)
PORTD &= ~(1<<PD1);
if(T1>>2 & 0x01)
PORTD &= ~(1<<PD2);
if(T1>>3 & 0x01)
PORTD &= ~(1<<PD3);
if(T1>>4 & 0x01)
PORTD &= ~(1<<PD4);
if(T1>>5 & 0x01)
PORTD &= ~(1<<PD5);
if(T1>>6 & 0x01)
PORTD &= ~(1<<PD6);
if(T1>>7 & 0x01)
PORTD &= ~(1<<PD7);

}
}


mfG der Grave

SprinterSB
13.10.2005, 21:12
Wenn du ohne ISR arbeitest, dann wird irgendwann eine IRQ ausgelöst und du landest im Nirvana, genauer bei __bad_interrupt, was auf einen Soft-Reset angebildet wird.
Wenn du sei() benutzt, musst du ISRs für alle IRQs zur Verfügung stellen, die auftreten können (hier: SIG_INPUT_CAPTURE1).

Offenbar willst du aber erst mal ohne Interrupts arbeiten.
Dann wirf das sei() raus und lass erst mal die Finger von TIMSK ;-)

Bevor du auf das ICF1-Flag wartest, musst du es erst mal rücksetzen auf 0. Des geht, indem man eine 1 hinschreibt wie oben gesagt. Die anderen Flags werden nicht angefasst durch das 0-Schreiben.

TIFR = _BV(ICF1);

Danach wartest du:

while (!(TIFR & _BV(ICF1))) // Flag==0 --> *schnarch*
...

Dann wirst du die Flanke umschalten wollen, falls du nicht auf beide Flanken konfiguriert hast.
Nach dem Flanken-Umschalt und vor dem nächsten Warten: wieder ICF1 resetten.

Grave80
23.10.2005, 20:59
so habs das wochenden endlich mal alles zum laufen gebracht und funktioniert jetzt prima, danke für deine Hilfe

mfg der Grave

jeybo
01.08.2006, 21:16
Hat das Auswerten von PMW-Signalen einen Vorteil gegenüber den Werten der Analogausgänge?