Tutorial Arduino programmieren,

Antworten
pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Ich versuche gerade ein am2320 Sensor zum "laufen" zu bekommen. Bin schon recht weit gekommen, aber nun hänge ich leider fest, weil ich bei C++ einige Probleme habe. Ich habe mich erst mal an die adafruit Lib gehalten...
Hier ist ein Code Auszug:

Code: Alles auswählen

 
 
/**************************************************************************/
/*!
    @brief  read 2 bytes from a hardware register
    @param reg the register to read
    @return the read value as a 2 byte unsigned integer
*/

/**************************************************************************/
uint16_t Adafruit_AM2320::readRegister16(uint8_t reg) {
  // wake up
  Wire.beginTransmission(_i2caddr);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(10); // wait 10 ms
 
  // send a command to read register
  Wire.beginTransmission(_i2caddr);
  Wire.write(AM2320_CMD_READREG);
  Wire.write(reg);
  Wire.write(2);  // 2 bytes
  Wire.endTransmission();
 
  delay(2);  // wait 2 ms
 
  // 2 bytes preamble, 2 bytes data, 2 bytes CRC
  Wire.requestFrom(_i2caddr, (uint8_t)6);
  if (Wire.available() != 6)
    return 0xFFFF;
 
  uint8_t buffer[6];
  for (int i=0; i<6; i++) {
    buffer[i] = Wire.read();
    //Serial.print("byte #"); Serial.print(i); Serial.print(" = 0x"); Serial.println(buffer[i], HEX);
  }
 
  if (buffer[0] != 0x03)   return 0xFFFF; // must be 0x03 modbus reply
  if (buffer[1] != 2)      return 0xFFFF; // must be 2 bytes reply
 
  uint16_t the_crc = buffer[5];
  the_crc <<= 8;
  the_crc |= buffer[4];
  uint16_t calc_crc = crc16(buffer, 4); // preamble + data
  //Serial.print("CRC: 0x"); Serial.println(calc_crc, HEX);
  if (the_crc != calc_crc)
    return 0xFFFF;
 
  // All good!
  uint16_t ret = buffer[2];
  ret <<= 8;
  ret |= buffer[3];
 
  return ret;
}
 
/**************************************************************************/
/*!
    @brief  perfor a CRC check to verify data
    @param buffer the pointer to the data to check
    @param nbytes the number of bytes to calculate the CRC over
    @return the calculated CRC
*/

/**************************************************************************/
uint16_t Adafruit_AM2320::crc16(uint8_t *buffer, uint8_t nbytes) {
  uint16_t crc = 0xffff;
  for (int i=0; i<nbytes; i++) {
    uint8_t b = buffer[i];
    crc ^= b;
    for (int x=0; x<8; x++) {
      if (crc & 0x0001) {
   crc >>= 1;
   crc ^= 0xA001;
      } else {
   crc >>= 1;
      }
    }
  }
  return crc;
}
 

Nun habe ich Probleme einiges davon umzusetzen. Soweit ich verstanden habe ist die Methode "crc16" nicht unbedingt notwendig erst mal ist das richtig?

Code: Alles auswählen

  uint16_t ret = buffer[2];
  ret <<= 8;
  ret |= buffer[3];
 

Damit habe ich meine Probleme:

Code: Alles auswählen

 
  ret:=buffer[2];
  ret:=ret shl 8;
  ret:=ret or buffer[3];
 


So sieht meine Funktion komplett aus

Code: Alles auswählen

 
function readRegister16(reg: UInt8): UInt16;
var
  Buffer: PUInt8Array;
  i:Integer;
  ret:UInt16;
begin
  TWIStart((ADSaddr0 shl 1) or TWI_Write);
  TWIWrite($0);
  TWIStop;
 
  UARTSendString('TestA'#13#10);
  TWIStart((ADSaddr0 shl 1) or TWI_Write);
  TWIWrite(00);
  TWIStop;
 
  mysleep(1000*9);
  UARTSendString('TestB'#13#10);
 
  TWIStart((ADSaddr0 shl 1) or TWI_Write);
  TWIWrite(AM2320_CMD_READREG);
  TWIWrite(reg);
  TWIWrite($02);
  TWIStop;
  // 250000 = 500
  //            2
 
  mysleep(4);
 
  UARTSendString('TestC'#13#10);
 
  TWIStart((ADSaddr0 shl 1) or TWI_Read);
  for i:=0 to 6 do begin
    buffer[i]:=TWIReadACK;
  end;
  TWIStop;
 
  ret:=buffer[2];
  ret:=ret shl 8;
  ret:=ret or buffer[3];
 
//   UARTSendByte();
  UARTSendString('Test1:'+Char(ret)+#13#10);
//  UARTSendIntArray(Buffer);
  result:=0;
end;
 

Kann mir jemand ein paar Tipps geben? Danke!
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Ich weiß nicht was Sinnvoller ist, mein letzten Beitrag zu bearbeiten oder eine neue Antwort, ich habe mich jetzt für eine neue Antwort entschieden.

Also: Ich habe es fast hinbekommen, ich bekomme werte vom Sensor....

Code: Alles auswählen

 
function readRegister16(reg: UInt8): UInt16;
var
  Buffer: uInt8Array;
  i:Integer;
  ret:UInt16;
  s:string;
begin
  UARTSendString('TestA'#13#10);
  s:='';
 
  // Aufwecken
  TWIStart((ADSaddr0 shl 1) or TWI_Write);
  TWIWrite($00);
  TWIStop;
  delay_ms(10);
 
  UARTSendString('TestB'#13#10);
 
  // Ein Kommando Senden zum "Lese Register"
  TWIStart((ADSaddr0 shl 1) or TWI_Write);
  TWIWrite(AM2320_CMD_READREG);
  TWIWrite(reg);
  TWIWrite(2);
  TWIStop;
  delay_ms(2);
 
  UARTSendString('TestC'#13#10);
 
//  Hier müsste noch eine Überprüfung vorher hin:
//  2 bytes preamble, 2 bytes data, 2 bytes CRC
//  Wire.requestFrom(_i2caddr, (uint8_t)6);
//  if (Wire.available() != 6)
//  return 0xFFFF;
 
  TWIStart((ADSaddr0 shl 1) or TWI_Read);
  for i:=0 to 5 do begin
    buffer[i]:=TWIReadACK;
  end;
  TWIStop;
 
// Bishierher kommt der Code ohne irgendwo "hängen" zu bleiben
 
  ret:=buffer[2];
  ret:=ret shl 8;
  ret:=ret or buffer[3];
 
 
 
  Str((ret) div 10,s);
  UARTSendString(s+#13#10);
 
 
  result:=0;
end;       
 

Jedoch müssen die noch "umrechnet" werden und ich weiß nicht, ob es so "richtig" ist...

Die Adafruit Lib macht es so:

Code: Alles auswählen

 
float Adafruit_AM2320::readTemperature() {
  uint16_t t = readRegister16(AM2320_REG_TEMP_H);
  float ft;
  if (t == 0xFFFF) return NAN;
  // check sign bit - the temperature MSB is signed , bit 0-15 are magnitude
  if(t & 0x8000){
    ft = -(int16_t)(t&0x7fff);
  }
  else {
    ft = (int16_t)t;
  }
  return ft / 10.0;
}
 

ich weiß noch nicht wie ich das nach Pascal konvertieren kann...
5657
So sehen die Werte im Moment aus, die verändert sich auch, wenn ich auf den Sensor drücke....
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Hier ist das ganze Projekt.….

Wäre schön, wenn sich das jemand anschauen könnte und mir vielleicht den eine oder anderen "Tipp" geben könnte.... gerade zum Beispiel zu "crc16" oder aber auch:

Code: Alles auswählen

  Wire.requestFrom(_i2caddr, (uint8_t)6);
  if (Wire.available() != 6)
    return 0xFFFF;
 


Aber im Prinzip läuft es:

Code: Alles auswählen

Temperatur: 225
Luftfeuchtigkeit: 587
Temperatur: 225
Luftfeuchtigkeit: 588
Temperatur: 225
Luftfeuchtigkeit: 588
Temperatur: 225
Luftfeuchtigkeit: 588
Temperatur: 225
Luftfeuchtigkeit: 588
Temperatur: 224
Luftfeuchtigkeit: 589

Schade das noch keine Fließkommazahlen unterstütz werden.
Dateianhänge
am2320_Test.zip
(129.64 KiB) 14-mal heruntergeladen
MFG
Michael Springwald

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

ich weiß noch nicht wie ich das nach Pascal konvertieren kann...
5657
So sehen die Werte im Moment aus, die verändert sich auch, wenn ich auf den Sensor drücke....
Wen am anderen Ende der Seriellen-Schnittstelle ein Program von dir ist, dann würde ich die Umwandlung von Integer auf Float dort machen.

Die andere Variante.
So wie ich es sehe, kommt aus deinem Sensor 1/10°

Code: Alles auswählen

  return ft / 10.0;

Du könntest deinen String folgendermassen aus einem Integer erzeugen.
http://wiki.freepascal.org/AVR_Embedded ... _digits/de
Digit sind dann bei dir die Zeichen im String.
Digit[3] wäre dann fest der Dezimalpunkt.
Und Digit[4] dann die 1/10°.

Ich hoffe du verstehst, was ich meine.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Zur Zeit mache ich es so, da Float werte ja noch nicht gehen.

Code: Alles auswählen

 repeat
    Temp:=readRegister16(AM2320_REG_TEMP_H);
    Hum:=readRegister16(AM2320_REG_HUM_H);
 
    Str(Temp div 10, s);
    UARTSendString('Temperatur: '+s+#13#10);
 
    Str(Hum div 10,s);
    UARTSendString('Luftfeuchtigkeit: '+s+#13#10);
    mysleep(dl);
  until 1 = 2;


Deine Idee ist aber auch nicht schlecht, ich werde es mir mal anschauen.

Ich finde es aber schon Interessant.

Die Delay Funktion von "Timm Thaler" kann leider nur bis 255 ms, ich bräuchte aber eine, die auch Sekunden kann. Z.B. 2 oder 4 Sekunden. Gerade bei Sensor Abfragen wäre es Hilfreich....
MFG
Michael Springwald

Timm Thaler
Beiträge: 1107
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Tutorial Arduino programmieren,

Beitrag von Timm Thaler »

pluto hat geschrieben:Ich weiß nicht was Sinnvoller ist, mein letzten Beitrag zu bearbeiten oder eine neue Antwort...


Auf jeden Fall sinnvoll wäre es, für Deine Fragen einen eigenen Thread aufzumachen. Da erhöhst Du auch die Chancen, dass Dir Leute antworten, weil sie da einen aussagekräftigen Titel vorfinden.

pluto hat geschrieben:Die Delay Funktion von "Timm Thaler" kann leider nur bis 255 ms, ich bräuchte aber eine, die auch Sekunden kann. Z.B. 2 oder 4 Sekunden. Gerade bei Sensor Abfragen wäre es Hilfreich....


Du kannst natürlich einfach mehr nops in die Delayfunktion einbauen.

ABER: Es ist eine ganz schlimme Unsitte, derart lange Delays in einem Programm zu verbauen, und den µC während dieser Zeit lahmzulegen. Dafür gibt es weitaus elegantere Möglichkeiten. Zum Beispiel läßt man einen Timer im msec-Bereich laufen, der einen Zähler hochzählt. Anhand des Zählerstandes kann man dann seine Sekunden abzählen. Und der µC kann in der Zwischenzeit noch auf Tasten reagieren, eine serielle Schnittstelle bedienen, Werte auf einem Display anzeigen.

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

Du könntest deinen String folgendermassen aus einem Integer erzeugen.
http://wiki.freepascal.org/AVR_Embedded ... _digits/de
Digit sind dann bei dir die Zeichen im String.
Digit[3] wäre dann fest der Dezimalpunkt.
Und Digit[4] dann die 1/10°.


Ich habe das Tutorial ein wenig ergänzt: http://wiki.freepascal.org/AVR_Programm ... em_umgehen

ABER: Es ist eine ganz schlimme Unsitte, derart lange Delays in einem Programm zu verbauen, und den µC während dieser Zeit lahmzulegen. Dafür gibt es weitaus elegantere Möglichkeiten. Zum Beispiel läßt man einen Timer im msec-Bereich laufen, der einen Zähler hochzählt. Anhand des Zählerstandes kann man dann seine Sekunden abzählen. Und der µC kann in der Zwischenzeit noch auf Tasten reagieren, eine serielle Schnittstelle bedienen, Werte auf einem Display anzeigen.
Es kommt immer auf den Anwendungsfall an.
Wen ich alles Sekunden ein Messwert auslese und ihn dann ausgebe, würde ich auch ein Sekunden-Delay verwenden. Aber wen der AVR noch andere Aufgaben erledigen soll, sieht es natürlich anders aus.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Auf jeden Fall sinnvoll wäre es, für Deine Fragen einen eigenen Thread aufzumachen. Da erhöhst Du auch die Chancen, dass Dir Leute antworten, weil sie da einen aussagekräftigen Titel vorfinden.

Vielleicht kann ja ein Mod die Beiträge hier abtrennen und in einem neuen Thread hinzufügen?

ABER: Es ist eine ganz schlimme Unsitte, derart lange Delays in einem Programm zu verbauen, und den µC während dieser Zeit lahmzulegen. Dafür gibt es weitaus elegantere Möglichkeiten. Zum Beispiel läßt man einen Timer im msec-Bereich laufen, der einen Zähler hochzählt. Anhand des Zählerstandes kann man dann seine Sekunden abzählen. Und der µC kann in der Zwischenzeit noch auf Tasten reagieren, eine serielle Schnittstelle bedienen, Werte auf einem Display anzeigen.

Da hast du natürlich recht, aber es gibt fälle wo es durchaus sinn macht. Ich gewöhne mir aber immer an "Zeitschleifen".... So eine Art state Maschine....


So klappt es nun ganz gut.... danke für den Tipp

Code: Alles auswählen

  repeat
    Temp:=readRegister16(AM2320_REG_TEMP_H);
    Hum:=readRegister16(AM2320_REG_HUM_H);
 
    ClearDigit;
    IntToDigit(Temp);
    s1:=#0; s2:=#0; s3:=#0;
    str(Digit[1], s1);
    str(Digit[2], s2);
    str(Digit[3], s3);
    UARTSendString('Temperatur: ' + s1 + s2 + '.' + s3+' °C'+#13#10);
 
    ClearDigit;
    IntToDigit(Hum);
    s1:=#0; s2:=#0; s3:=#0;
    str(Digit[1], s1);
    str(Digit[2], s2);
    str(Digit[3], s3);
 
    UARTSendString('Luftfeuchtigkeit: '+s1+s2+'.'+s3+' %'+#13#10);
 
    mysleep(dl);
 

Erst mal klappte es ganz gut, es ist noch nicht alles schön, aber es Funktioniert.
MFG
Michael Springwald

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

Die vielen str sind unschön. Ein einzelnes Zeichen kannst du sehr einfach mit Byte('x') un Char(2) umwandeln. Hast du mein neues Tutorila zu den Float schon angeguckt, dort ist Digit schon ein String.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Code: Alles auswählen

 repeat
    Temp:=readRegister16(AM2320_REG_TEMP_H);
    Hum:=readRegister16(AM2320_REG_HUM_H);
 
//    ClearDigit;
    IntToDigit(Temp);
    UARTSendString('Temperatur: ' + Digit[2] + Digit[3] + '.' + Digit[4]+' °C'+#13#10);
 
//    ClearDigit;
    IntToDigit(Hum);
    UARTSendString('Luftfeuchtigkeit: '+Digit[2] + Digit[3] + '.' + Digit[4]+' %'+#13#10);
 
    mysleep(dl);
  until 1 = 2;

Da gibt nun schmierzeichen raus....
MFG
Michael Springwald

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

Ich muss das Tutorial nochmals angucken, so wie jetzt ist komnen Steuerzeichen anstellen von Zahlen. Es müsste etwa so aussehen. Ch := Char(Ziffer + ?);

Digit ist direkt ein String, die + kannst du sparen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

UARTSendString('Temperatur: ' + Digit+' °C'+#13#10);

Wenn ich es so mache kommt jedoch ein:
project1.pas(83,35) Error: Operator is not overloaded

Code: Alles auswählen

Digit  : array[0..4] of String;

Du hast hier auch ein Array von 4 Strings definiert und kein Einzelnen String....
MFG
Michael Springwald

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

Du hast hier auch ein Array von 4 Strings definiert und kein Einzelnen String....

Wo ?

Auf jeden Fall ist es so richtig:

Code: Alles auswählen

var
  Digit: string[4];
 
  procedure IntToDigit(val: UInt16);
  var
    achr: byte;
    leer: boolean;
  begin
    Digit[0] := #4; // Der String ist 4 Zeichen lang, inklusive Dezimalpunkt.
 
    // Zehner
    achr := 0;
    while (val >= 100) do begin
      Dec(val, 100);
      Inc(achr);
      leer := False;
    end;
    if leer then begin
      achr := 16;
    end;
    Digit[1] := char(achr + 48);
 
    // Einer
    achr := 0;
    while (val >= 10) do begin
      Dec(val, 10);
      Inc(achr);
      leer := False;
    end;
    if leer then begin
      achr := 16;
    end;
    Digit[2] := char(achr + 48);
 
    // Dezimalpunkt
    Digit[3] := '.';
 
    // Zehntel
    achr := 0;
    while (val >= 1) do begin
      Dec(val);
      Inc(achr);
    end;
    Digit[4] := char(achr + 48);
  end;

Ausgabe:

Code: Alles auswählen

      UARTSendString(Digit);
      // oder
      UARTSendString('Temperatur: ' + Digit+' °C'+#13#10);
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

pluto
Lazarusforum e. V.
Beiträge: 7096
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Tutorial Arduino programmieren,

Beitrag von pluto »

Du hast hier auch ein Array von 4 Strings definiert und kein Einzelnen String....

Mein Fehler, ich habe nicht gesehen, dass du aus den 4 bzw. 5 Array's ein String gemacht hattest....
Nun geht es, Danke !!!

Ich habe hier noch ein gutes Beispiel für eine RTC Modul gesehen, vielleicht könntest du das noch im Wiki erwähnen und bei github hochladen?
Mein AM2320 Projekt, ist noch nicht ganz Fertig, ich habe noch Probleme mit den crc....
MFG
Michael Springwald

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Tutorial Arduino programmieren,

Beitrag von Mathias »

Ich habe hier noch ein gutes Beispiel für eine RTC Modul gesehen, vielleicht könntest du das noch im Wiki erwähnen und bei github hochladen?
Mein AM2320 Projekt, ist noch nicht ganz Fertig, ich habe noch Probleme mit den crc....

Einen AM2320 und ein DS3231 habe ich gerade beim Chinesen bestellt.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Antworten