www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADXL213 mit C167CR auswerten


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

Bewertung
0 lesenswert
nicht lesenswert
Hey,

ich habe es jetzt geschafft den ADXL213 Neigungssensor (ähnliche 
Funktionsweise wie ADXL202) mit meinem uC, einem C167CR auszuwerten.
Der Sensor liefert ein seinem Neigungswinkel proportionales 
Tastverhältniss eines Rechtecksignals.
Dieses Tastverhältniss schwankt zwischen minimal 20% (Winkel=-90°) und 
maximal 80% (Winkel=+90°).

Ich verwende für jede Achse einen Timer in Gated Timer Mode zum 
auswerten.
Der Timer zählt also solange das Ausgangssignal des Sensors HIGH ist. 
Somit erhalte ich einen dem Tastverhältniss proportionalen Timerwert.
Mit absteigender Flanke wird der Timer in einem Interrupt ausgelesen und 
wieder 0 gesetzt.
Mein C167CR liefert mir nun Werte zwischen 480(20%) und 2000(80%).
Diese Verteilung ist zwar nicht ganz linear, aber man kann damit 
rechnen. Ich habe nähmlich eine Bandbreite von 1520 Werten.
Im Dateianhang befindet sich ein Datenblatt des Sensors, wo auf Seite 8 
der Verlauf des Tastverhältnis dargestellt ist. Für die errechnung des 
Winkels wird nur die X-Achse betrachtet, die Y-Achse könnt ihr euch also 
wegdenken.
Ich habe 30%Tastverhältnis pro g und einen Offset von 50%.
Ich ziehe nun von dem erhaltenen Timerwert die 50% Offset ab und 
dividiere diesen Wert durch 30%.
Meine Formel zur Winkelberechnung:
winkel= (aktueller_timerwert-wert50%)/(wert50%-wert20%);
Damit erhalte ich Werte zwischen +1 und -1, die ich mithilfe von 
ArcusSinus in einen Winkel umwandeln kann.
Das funktioniert und der Winkel passt auch.

Mein Problem ist nun folgendes:
Der errechnete Winkel erstreckt sich nicht stufenlos von +90° bis -90°.
Bei einem Wert von 2000 erhalte ich folgenden Winkel:
winkel = (2000-1240)/(1240-480)=1 =>asin(1)=90°
das passt.
Der nächstkleinere Wert ist allerdings 1999.
Wenn ich nun 1999 in die Formel einsetze erhalte ich
winkel=759/760=099868 =>asin(0.99868)=87°
Ich brauche allerdings einen Winkel von zumindest 89°.

Habt ihr eine Idee, wie ich meine Formel ändern könnte, oder was ich 
falsch gemacht habe.

MfG. Peter

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst die Timerauflösung erhöhen!
Wenn Du sehr genaue Winkelauflösungen willst, dann fahr die Bandbreite 
runter (ist bei mir bei ca. 0.5Hz) und dann kommst Du auch in 1/100° 
Regionen (relativ).
Ich hab das Ganze auch schon mal durchexerziert und hier der Code (nicht 
dokumentiert und optimiert und zudem noch für nen AVR):
#include <avr/io.h>
#include <avr/interrupt.h>


#include <math.h>
#include "m_usart.h"
#include "fcts.h"
#include "main.h"


// Globals
volatile uint32_t  value, pw;
volatile uint16_t  endpw, endvalue;
volatile uint8_t    MState = 0;



// ISR's ******************************************************************************
ISR (SIG_UART_RECV)
{
  uint8_t ch;
  ch = UDR;
}

ISR (TIMER1_OVF_vect)
{
  if (MState < 2)
    value += 65535;
  if (MState < 3)
    pw     += 65535;
}

ISR (INT0_vect)
{
  if (MState == 0)
  {
    Enable16bitTimer ();
    EnableEInt0Falling ();
    MState++;
  }
  else if (MState == 1)
  {
    endvalue = TCNT1;
    EnableEInt0Rising ();
    MState++;
  }
  else if (MState == 2)
  {
    endpw = TCNT1;
    Disable16bitTimer ();
    DisableEInt0 ();
    MState++;
  }
}

double MeasureAngle ()
{
  value   = 0;
  pw     = 0;
  MState   = 0;
  TCNT1    = 0;
  EnableEInt0Rising ();

  while (MState < 3);

  pw += endpw;
  value += endvalue;

  // 0.49 = ZeroGBias (normalerweise 0.5)
  // 0.3  = Sensitivity pro g
  double ratio = (((double)value / (double) pw) - 0.49) / 0.3;

  double angle = asin (ratio) * RAD2DEG;

  return angle;
}

/*******************************************************************************************/
int main ()
{
  // Locals

  DDRD   = 0x00;
  PORTD  |= (1 << PD2) | (1 << PD3);        // Enable pullups

  DDRC = 0xFF;
  PORTC = 0xFF;

  // Value init
  pw = 0;

  Init_UART ();

  sei ();

  for (;;)
  {
    uint8_t  i;
    uint8_t count = 250;
    double mangle = 0.0;
    double rangle = 0.0;

    for (i = 0; i < count; i++)
    {
      mangle = MeasureAngle ();
      rangle += mangle / (double)count;
    }
    
    long   rvalue = (int)(rangle * 100.0);
    
    if (rvalue < 0)
    {
      uart_putc (' ');
      uart_putc ('-');
      rvalue = -rvalue;
    }
    uart_putc (0x30 + (rvalue % 10000) / 1000);
    uart_putc (0x30 + (rvalue % 1000) / 100);
    uart_putc ('.');
    uart_putc (0x30 + (rvalue % 100) / 10);
    uart_putc (0x30 + (rvalue % 10));
    uart_putc ('\n');
  }
  
  return 1;
}

Hoffe es hilft!

Grüße,
Michael

Autor: Michael K. (mmike)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier noch meine math. Herleitung ....

Grüße,
Michael

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

meine Timerauflösung ist bereits auf dem maximal möglichen, nämlich bei 
einer Abtastubngsperiodedauer von 0.4us.
Allerdings ist unser Sensorausgangssignal relativ 'hochfrequent', 
nämlich 1kHz.
Ich nehme an du meinst mit Bandbreite die Frequenz des Sensors?
Es gibt aber auch im Datenblatt eine Bandbreite zu bestimmen, mit den 
beiden Kondensatoren, wobei ich die auf ca 25Hz (Cx=0.22uF) habe. Wozu 
diese Bandbreite genau dient habe ich nie verstanden, ich weiß nur ich 
würde gerne 25 Mal pro sekunde einen Winkel bekommen.

Mit dem Code fang ich leider nichts an, weil ich die Programmiersprache 
nicht kenne und somit auch den Code nicht verstehe.
Und die mathematische Herleitung ist eh ungefähr so wie bei mir.

Danke trotzdem Mal für die Hilfe.

MfG. peter

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sofern ich es verstanden habe bestimmt die Bandbreite die 
"Schnelligkeit" des Sensors. D.h. bis zu welcher Frequenz können 
Bewegungen des Sensors bei eingestellter Bandbreite noch detektiert 
werden. Bei meiner Beschaltung hat der Sensor noch eine Bandbreite von 
0.5Hz um das Rauschen maximal zu unterdrücken(Siehe Tabelle 6 RMS 
noise[mg]). Wird jetzt der Sensor schlagartig geneigt, so läuft der 
gemessene und ausgegeben Wert dem aktuellen Wert nach ....

> Allerdings ist unser Sensorausgangssignal relativ 'hochfrequent',
> nämlich 1kHz.
Die Ausgabe des Sensorsignals T2 (in Deinem Fall rund 1ms) wird über R2 
bestimmt.
T2(s) = Rset / 125MOhm
Datenblatt Seite 1 unter dem functional block diagram ....
für eine Ausgabe von 25 Hz brauchst Du:

T2 (25Hz) = 40ms

40ms = Rset / 125MOhm

RSet = 125e6 * 40e-3 = 5e6 Ohm = 5 MOhm

> Mit dem Code fang ich leider nichts an, weil ich die Programmiersprache
> nicht kenne und somit auch den Code nicht verstehe.

C !!??

Grüße,
Michael

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.