Svenska ElektronikForumet
https://elektronikforumet.com/forum/

Mätapplikation med Arduino och Java
https://elektronikforumet.com/forum/viewtopic.php?f=3&t=93773
Sida 2 av 4

Författare:  4kTRB [ 19.11 2019-02-01 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

En pdf om RTD:er https://www.omega.com/temperature/pdf/rtd_gen_specs_ref.pdf

Författare:  4kTRB [ 19.42 2019-02-17 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Håller ju på med att lära mig C++ för att lättare komma igång med Arduino i detta projekt men
tjuvstartade lite med Eclipse och ett av de plug-in som finns.
Efter en del huvudbry så verkar det faktiskt fungera nu.

En lite fundering, när koden laddas upp till Arduino fås en översikt av minnesanvändning med mera
i konsolen på Eclipse. Där finns att läsa att 1000 byte har skrivits till flash. Så jag letade upp
en (den enda jag hittade) hex-fil som genereras och laddade upp den i en HEX-analysator online.

Hex-analysator säger att filen består av 2832 byte.

De extra byte som ingår, kommer de från formatet?
Motorola har ju S-format till exempel.
Analysatorn fixade inte att tala om vilket format det var om det nu finns något vill säga.

Författare:  4kTRB [ 07.55 2019-02-18 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Liten följdfråga är .... har jag någon direkt nytta av den hex-filen som Eclips genererat?

Författare:  4kTRB [ 17.53 2019-02-22 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Leker en del med Arduino nu. Testat en timer-klass som kan vara användbar
om fler pinnar ska jobba med olika saker. Lite luddigt tycker jag dock att
beskrivningen av funktionerna är såsom stop() till exempel.
Sedan verkar det som man måste deklarera funktioner som man kodar,
som doSomething i koden nedan. Tycker mig ha sett åtskilliga exempel-koder
där man inte gjort så men det kanske är för att korta ned koden.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
#include <Arduino.h>
#include "Timer/Timer.h"

Timer t1;
Timer t2;
int tickEvent;
int LEDEvent;
int LEDEvent2;
void doSomething(void* context);
char w[] = {'A','B','C','D','E'};
void* ch = w;
int index = 0;

void setup() {
   Serial.begin(9600);
   pinMode(13, OUTPUT);
   tickEvent = t1.every(1000, doSomething, ch);
   LEDEvent = t1.oscillate(13, 75, HIGH);
   LEDEvent2 = t2.oscillate(13, 150, HIGH);
}

void loop() {
   while(index <=40){
      t1.update();
      if(index == 15){
         t1.stop(LEDEvent);
      }
      if(index >= 15){
         t2.update();
      }
   }
   t1.stop(tickEvent);
   t1.stop(LEDEvent);
   t2.stop(LEDEvent2);
   digitalWrite(13,LOW);
   Serial.end();
}

void doSomething(void* ch)
{
   char* p = (ch + index % 4);
   Serial.write(*p);
   Serial.print(" Index = ");
   Serial.print(index);
   Serial.print("  millisekunder = ");
   Serial.println(millis());
   index++;
}

Författare:  Klas-Kenny [ 18.52 2019-02-22 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Du måste inte skriva funktionsprototyper, men om du inte gör det måste funktionen skrivas ovanför där du anropar den. Koden läses ovanifrån, och om man då anropar en funktion som deklareras senare i koden känns den inte igen.

Författare:  4kTRB [ 15.23 2019-03-30 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Har testat en hel del nu med att samla in data via två ADC-pinnar (A0 och A1, A och B i schemat) från en bryggkoppling.
Jag sätter ett intervall på 10mV som det får diffa på för att anse att bryggan är i balans.
När den är det så blir skylten "Vid Balans Tryck Ok-->" grön. Jag testar med en trimpot och
ser att det fungerar. Men sedan har jag två så kallade progressbars (de 2 gråa fälten under kalibrerings-sekvensen)
som ska agera som indikator på när det blir ännu bättre intrimmat.
När väl det är utfört ansluter jag två kända resistorer i bryggan för att få kurvans ekvation varifrån sedan
NTC-motståndets värde beräknas. Det blir en rät linje y = kx + m.
När väl bryggan är intrimmad så kan jag påbörja uppvärmning av ett aluminiumblock där temperaturen mäts
och spänningen från bryggan som via formeln ger NTC-motståndets värde.

Författare:  4kTRB [ 15.37 2019-03-30 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Arrduinokoden består av ett menyvalssystem som kör en loop.
När olika kommandon skickas från Java-gui så utförs de olika
rutinerna. Mer funktioner kommer läggas till senare.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
#include <Arduino.h>

//Koden efterliknar en datainsamling av temperatur och NTC-motstånd
//Javaprogrammet har testats och utvecklats mot denna programkörning

// ****************************************************
//   variabler och konstanter för kalibrering av brygga
// ****************************************************
bool alertFlag;
int analogPinA = A0;                           // bryggans anslutning A
int analogPinB = A1;                           // bryggans anslutning B
int ohm = 500;
const int NUMBER_OF_SAMPLES = 100;               // medelvärdesbilda AD-omvandla många gånger
const double DIFF_MAX = 0.01;                    // tolerans 10 mV för att anse att bryggan är i balans
const double BIT_VOLTAGE_FACTOR = 0.004888;     // volt per bit för ad-omvandlare (5.0/1023)

void zeroAdjustAlert(double);
void averageData(double&, double&, double&);
void bridgeZeroAdjust(void);
// ****************************************************
// 0 är startsignal för datainsamling i Arduinos meny
// 1 är startsignal för nollkalibrering av brygga i Arduinos meny
// 2 är startsignal för datainsamling i Arduinos meny
// 3 är startsignal för datainsamling i Arduinos meny
// 4 är Exit i Arduinos meny Serial().end;
// 100 abryter while-loop i ntcMeasurement()
// 200 abryter while-loop i bridgeZeroAdjust()
// Z indikerar att bryggan är i balans i zeroAdjustAlert-funktionen
// X indikerar att bryggan är i obalans i zeroAdjustAlert-funktionen

// the setup function runs once when you press reset or power the board

int celcius;
int inByte = -1;                             // incoming serial byte

void ntcMeasurement();
void bridgeZeroAdjust();
void setCelcius(int);
int getCelcius();

void setup() {
   Serial.begin(19200);
   setCelcius(0);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);           // används för att testa programmet
   while (!Serial) {
      ;                               // wait for serial port to connect. Needed for native USB
   }
}

// En loop med meny. Data skickas från JAVA-datorn och olika saker utförs.
// Inga av de funktioner som väljs att exekveras körs som trådar på Arduino
// så för att menysystems-loopen ska kunna hantera nästa kommando måste
// den funktion som pågår först avslutas, innan dess case-break; tillåter
// fler menyval. I GUI så kan inte fler menyval utföras förrens det pågående
// avslutats, undantag gäller EXIT för programavslut.
void loop()
{
   if (Serial.available() > 0)
   {
      inByte = Serial.read();
      switch (inByte){
      case 0:                              // en NTC-mätning är begärd
         ntcMeasurement();                   // funktion med while-loop, tar en stund
         digitalWrite(LED_BUILTIN, LOW);       // visuell indikering på att NTC-mätning är utförd
         break;                            // först nu kan nya menyval utvärderas
      case 1:
         bridgeZeroAdjust();                  // en loop som hela tiden indikerar om bryggan är nolltrimmad eller ej
         digitalWrite(13, LOW);
         break;                             // fortsätt i meny-loop när bridgeZeroAdjust() har avslutats
      case 2:

         break;
      case 3:

         break;
      case 4:
         digitalWrite(LED_BUILTIN, HIGH);
         delay(3000);
         Serial.end();                      // nedkoppling av seriekommunikation/com-port
         break;
      default:
         digitalWrite(LED_BUILTIN, LOW);
      }
   }
   delay(100);
   digitalWrite(LED_BUILTIN, HIGH);              // visuell indikering att Arduino är aktiv i menyloopen
   delay(100);
   digitalWrite(LED_BUILTIN, LOW);
}

/*
 * En loop som mäter obalansen i NTC-mätbryggan.
 * Två spänningar från två ADC-ingångar mäts och medelvärdesbildas.
 * Sedan tas differensen av dessa spänningar och utifrån denna differens
 * avgörs om bryggan anses vara i balans / nolltrimmad. Arduino skickar
 * signal till Java-datorn som i sin tur indikerar balans eller obalans i GUI.
 * Loopen avbryts manuellt från GUI med tryck på en knapp.
 */
void bridgeZeroAdjust(){
   alertFlag = true;
   bool breakFlag = true;
   double averageVoltA = 0.0;
   double averageVoltB = 0.0;
   double vDiff = 0.0;
   while(breakFlag){
      averageData(averageVoltA, averageVoltB, vDiff);  // mät obalansen medeelvärdesbilda en aning
      zeroAdjustAlert(vDiff);                          // indikera om en nolljustering utförts
      delay(50);                                       // dra ned tempot
      if (Serial.available() > 0){                     // kommando sänt? Avbryt balanstrimmning av brygga?
         if(Serial.read() == 200){                    // 200 avbryter while-loop
            breakFlag = false;
         }
      }
   }
}

/*
 * Argumenten voltA, voltB och voltDiff är call by reference
 */
void averageData(double& voltA, double& voltB, double& voltDiff){
   double sumA = 0;
   double sumB = 0;
   for(int i = 0; i < NUMBER_OF_SAMPLES; i++){
      sumA += (analogRead(analogPinA)* BIT_VOLTAGE_FACTOR);
      sumB += (analogRead(analogPinB)* BIT_VOLTAGE_FACTOR);
   }
   voltA = sumA/NUMBER_OF_SAMPLES;
   voltB = sumB/NUMBER_OF_SAMPLES;
   voltDiff = voltA-voltB;
}

/*
 * Om bryggan är i balans inom given tolerans så skicka info till Java-datorn
 * att balansvillkor är uppfyllt. I GUI indikeras att bryggan är balanstrimmad.
 */
void zeroAdjustAlert(double voltageDiff){
   if(fabs(voltageDiff) <= DIFF_MAX){                   // om spänningar är lika inom tolerans så
      digitalWrite(13, HIGH);                         // ALERT!
      Serial.write("Z");                            // Meddela Java-datorn att bryggan är i balans
      Serial.write('\n');
   }
   else{
      digitalWrite(13, LOW);                          // annars så håll lysdioden släckt
      Serial.write("X");                            // Meddela Java-datorn att bryggan är i obalans
      Serial.write('\n');
   }
}

void ntcMeasurement(){
   setCelcius(24);
   int temp = getCelcius();
   digitalWrite(LED_BUILTIN, HIGH);                     // visuell indikering
   Serial.write("START");
   Serial.write("\n");
   while (getCelcius() < 101) {
      Serial.print(getCelcius());
      Serial.write("  ");
      Serial.print(ohm);
      Serial.write('\n');
      delay(800);
      setCelcius(temp++);
      ohm = -5.9 * getCelcius() + 635;
      if (Serial.available() > 0){                     // kommando sänt?
         if(Serial.read() == 100){                    // 100 avbryter while-loop
            setCelcius(101);
         }
      }
   }
}

void setCelcius(int temp){
   celcius = temp;
}

int getCelcius(){
   return celcius;
}



Författare:  4kTRB [ 15.49 2019-03-30 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Lärde mig eller ja återupptäckte kanske är mer rätt ord då jag någon gång i forntiden hade koll på detta att det går använda sig av inre klasser på ett smidigt sätt för att dela upp javakoden i fler filer/klasser och undvika att ha för mycket kod i main. Jag utnyttjar det till händelsehanterarna för de olika knapparna i GUI.

När en knapp skapats såsom t.ex. startknappen för att nolltrimma bryggan så behöver jag inte lägga till koden för hela mouseUp händelsen i main-koden utan då använder jag en separat klass i en annan fil där alla mouseUp händelser finns för varje knapp i GUI.

Ex.
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
START_A = new Button(composite_3, SWT.CENTER);
      START_A.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
      START_A.setFont(SWTResourceManager.getFont("Segoe UI", 9, SWT.BOLD));


      START_A.addMouseListener(new ButtonMouseListener().new START_A_Listener());


      START_A.setBounds(199, 0, 52, 45);
      START_A.setText("START");


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.DataOutputStream;
import java.io.IOException;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.wb.swt.SWTResourceManager;
/*
 * Samtliga knappar i GUI reagerar på ett MouseUpEvent i händelsehanteraren.
 * Kapparna identifieras i metoden mouseUp nedan och respektive knapps kod exekveras.
 */
public class ButtonMouseListener extends MouseAdapter {
   private TextFile textFile;   
   public ButtonMouseListener() {
      this.textFile = NTC.getTextFile();
   }
   /*
    *
    */
   public class START_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.getArduinoConnectedFlag()) {                              // se till att Arduino finns uppkopplad
            NTC.resetTimer();
            textFile.setTextFileName(NTC.txtDatatxt.getText());             // hämta text från textfält med önskat filnamn            
            NTC.resetLedDisplay();
            NTC.buttonStart.setEnabled(false);
            if(NTC.threadControllerThread[4].isAlive()) {
               NTC.threadControllerThread[4] = new Thread (NTC.threadController[4]);
            }
            try {            
               NTC.threadControllerThread[4].start();                     // starta trådkontrollern
               System.out.println(NTC.threadControllerThread[4].getName() + " är startad");
            }
            catch(IllegalThreadStateException itse) {
               System.out.println("IllegalThreadStateException");
            }   
         }
      }
   }
   /*
    *
    */
   public class STOPP_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if (NTC.threadControllerThread[4].isAlive()) {      // signalera Stopp till Arduino-inläsningen
            try {                                 // avbryt trådkontrollern som i sin tur avbryter
               NTC.threadControllerThread[4].interrupt();   // inäsning av data från Arduinon
               System.out.println(NTC.threadControllerThread[4].getName() + " är avbruten");
            }
            catch(SecurityException se) {
               System.out.println("SecurityException");                  
            }
         }         
      }
   }
   /*
    *
    */
   public class EXIT_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         System.out.println("EXIT-EXIT-EXIT-EXIT-EXIT");
         if(NTC.getArduinoConnectedFlag()) {
            (new Thread () {                                 // en tråd skriver ett EXIT-kommando till Arduino
               DataOutputStream javaToArduinoOut = null;
               public void run() {
                  javaToArduinoOut = new DataOutputStream(Test.getSerialPort().getOutputStream());
                  try {
                     javaToArduinoOut.writeByte(NTC.EXITZEROADJUST);   // avbryt eventuell nolltrim-loop
                     javaToArduinoOut.writeByte(NTC.EXITNTCMEASURE);   // avbryt eventuell ntc-mät-loop
                     javaToArduinoOut.writeByte(NTC.EXIT);         // menyval för Exit i Arduinos meny
                  } catch (IOException e1) {
                     e1.printStackTrace();
                  }            
                  try {
                     javaToArduinoOut.close();
                  } catch (IOException e) {
                     e.printStackTrace();
                  }
                  try {
                     NTC.threadControllerThread[0].interrupt();
                     NTC.threadControllerThread[1].interrupt();
                     NTC.threadControllerThread[2].interrupt();
                     NTC.threadControllerThread[3].interrupt();
                     NTC.threadControllerThread[4].interrupt();
                     NTC.threadControllerThread[5].interrupt();
                  }
                  catch (SecurityException se){
                     System.out.println("SecurityException");   
                  }
               }
            }).start();
         }                        
         try {
            Thread.sleep(500);
         } catch (InterruptedException e1) {
            e1.printStackTrace();
         }
         System.out.println("EXIT");            
         NTC.shlNtc.close();
         //   display.close();
         SWTResourceManager.dispose();
         System.exit(0);         
      }
   }
   /*
    *
    */
   public class OK_ABC_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {      
         NTC.threadControllerThread[1].interrupt();                  // avbryt samtliga kalibreringstrådar
         NTC.threadControllerThread[2].interrupt();
         NTC.threadControllerThread[3].interrupt();
         NTC.threadControllerThread[5].interrupt();
         if(NTC.getArduinoConnectedFlag()) {                        // se till att Arduino finns uppkopplad   
            NTC.threadStack.clearStack();                        // lägg upp ordning för kalibreringsprocedur            
            NTC.threadStack.push("F");                           // RrefB trim klart/OK
            NTC.threadStack.push("E");                           // trimma med RrefB
            NTC.threadStack.push("D");                           // RrefA trim klart/OK
            NTC.threadStack.push("C");                           // trimma med RrefA
            NTC.threadStack.push("B");                           // nolltrim klart/OK
            NTC.threadStack.push("A");                           // start nolltrim            
         }
         NTC.OK_ABC.setForeground(SWTResourceManager.getColor(255, 255, 204));
         NTC.OK_ABC.setBackground(SWTResourceManager.getColor(204, 51, 51));
         System.out.println("NTC.OK_ABC");         
      }      
   }
   /*
    *
    */
   public class START_A_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent arg0) {}
      public void mouseDown(MouseEvent arg0) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.getArduinoConnectedFlag()) {                        // se till att Arduino finns uppkopplad            
            if(NTC.threadStack.lookAtTheTopOfStack() == "A") {
               NTC.progressBarA.setSelection(0);
               NTC.progressBarB.setSelection(0);
               NTC.threadStack.pop();
               if(NTC.threadControllerThread[1].isAlive())
                  NTC.threadControllerThread[1].interrupt();
                  NTC.threadControllerThread[5].interrupt();
                  NTC.threadControllerThread[1] = new Thread (NTC.threadController[1]);
                  NTC.threadControllerThread[5] = new Thread (NTC.threadController[5]);
               try {                           
                  NTC.threadControllerThread[1].start();            // starta trådkontrollern
                  NTC.threadControllerThread[5].start();
                  NTC.OK_ABC.setForeground(SWTResourceManager.getColor(0, 0, 0));
                  NTC.OK_ABC.setBackground(SWTResourceManager.getColor(250, 250, 250));
               }
               catch(IllegalThreadStateException itse) {
                  System.out.println("IllegalThreadStateException");
               }
            }
         }
         System.out.println("NTC.START_A");         
      }
   }
   /*
    *
    */
   public class OK_A_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.threadStack.lookAtTheTopOfStack() == "B") {
            NTC.threadStack.pop();
            try {                                                         // avbryt trådkontrollern
               NTC.threadControllerThread[1].interrupt();   
               NTC.threadControllerThread[5].interrupt();
            }
            catch(SecurityException se) {
               System.out.println("SecurityException");                  
            }
            NTC.progressBarA.setSelection(0);
            NTC.progressBarB.setSelection(0);
         }
         System.out.println("NTC.OK_A");
      }
   }
   /*
    *
    */
   public class START_B_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.getArduinoConnectedFlag()) {                                       // se till att Arduino finns uppkopplad
            if(NTC.threadStack.lookAtTheTopOfStack() == "C") {
               NTC.threadStack.pop();
               if(NTC.threadControllerThread[2].isAlive())
                  NTC.threadControllerThread[2].interrupt();
                  NTC.threadControllerThread[2] = new Thread (NTC.threadController[2]);
               try {                                                      // och att trådstart sker i rätt ordning
                  NTC.threadControllerThread[2].start();                           // innan trådkontrollern startas                     
               }
               catch(IllegalThreadStateException itse) {
                  System.out.println("IllegalThreadStateException");
               }
            }
         }
         System.out.println("NTC.START_B");
      }
   }
   /*
    *
    */
   public class OK_B_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.threadStack.lookAtTheTopOfStack() == "D"){
            NTC.threadStack.pop();
            try {                                                         // avbryt trådkontrollern
               NTC.threadControllerThread[2].interrupt();   
            }
            catch(SecurityException se) {
               System.out.println("SecurityException");                  
            }               
         }
         System.out.println("NTC.OK_B");
      }
   }
   /*
    *
    */
   public class START_C_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.getArduinoConnectedFlag()) {                                       // se till att Arduino finns uppkopplad
            if(NTC.threadStack.lookAtTheTopOfStack() == "E") {
               NTC.threadStack.pop();                     
               if(NTC.threadControllerThread[3].isAlive())
                  NTC.threadControllerThread[3].interrupt();
                  NTC.threadControllerThread[3] = new Thread (NTC.threadController[3]);
               try {                                                      // och att trådstart sker i rätt ordning
                  NTC.threadControllerThread[3].start();                           // innan trådkontrollern startas                  
               }
               catch(IllegalThreadStateException itse) {
                  System.out.println("IllegalThreadStateException");
               }
            }
         }
         System.out.println("NTC.START_C");
      }
   }
   /*
    *
    */
   public class OK_C_Listener implements MouseListener{
      public void mouseDoubleClick(MouseEvent e) {}
      public void mouseDown(MouseEvent e) {}
      public void mouseUp(MouseEvent e) {
         if(NTC.threadStack.lookAtTheTopOfStack() == "F") {
            NTC.threadStack.pop();
            try {                                          // avbryt trådkontrollern
               NTC.threadControllerThread[3].interrupt();   
            }
            catch(SecurityException se) {
               System.out.println("SecurityException");                  
            }
         }
         System.out.println("NTC.OK_C");
      }
   }
}


Författare:  4kTRB [ 16.06 2019-03-30 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Trådkontrollern tar emot det objekt som ska köras som tråd och blir väldigt enkel.

De fungerar så här...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
   private Object tc0 = null;                  // objekt som ska köras av trådkontrollern
   private Object tc1 = null;                  // objekten implementerar interfacet Runnable
   private Object tc2 = null;
   private Object tc3 = null;
   private Object tc4 = null;
   private Object tc5 = null;

   public static ThreadController[] threadController;   // varje tråd har en trådkontroller
   public static Thread[] threadControllerThread;      // varje trådkontroller körs som en tråd

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
   /*
    * Skapar det antal trådkontrollörer som behövs och förbereder dem för start.
    * Till varje trådkontrollör kopplas ett objekt som trådkontrollören sedan ska starta
    * i sin run-metod. Klasserna/objekten som ska köras som tråd implementerar interfacet Runnable.
    * Även trådkontrollern implementerar interfacet Runnable då den också körs som tråd.
    * För att stoppa en tråd skickas ett interrupt till trådkotrollern som då kastar ett
    * InterruptedException vari i sin tur ett interrupt utförs på tråden som trådkontrollören
    * tidigare startat. Tråden avslutas och även trådkontrollören(dess tråd). Trådkontrollören kan
    * inte startas på nytt utan då måste en ny trådkontrollör skapas om en objekt-tråd ska startas och köras på nytt.
    */
   private void setUpThreadControllers() {
      tc0 = new Test(window,display);                           // skapa de objekt som ska köras som tråd
      Test.setBaudRate(NTC.DEFAULTBAUDRATE);                     // tc0 Anslut Arduino via comport
      tc1 = new Test_1(display);                              // tc1 Nolltrimma NTC-brygga
      tc2 = new Test_2();                                    // tc2 Ta fram ekvation R som funktion av bryggspänning RrefA
      tc3 = new Test_3();                                    // tc3 Ta fram ekvation R som funktion av bryggspänning RrefB
      tc4 = new CollectArduinoData(window,display);               // tc4 NTC-mätning
      CollectArduinoData.setBreakTemp(NTC.DEFAULTBREAKTEMP);         // default temperatur då mätning ska avbrytas
      tc5 = new MinusZeroPlusMeter(display);

      threadController = new ThreadController[NTC.NUMBEROFTHREADS];
      threadControllerThread = new Thread[NTC.NUMBEROFTHREADS];      
      threadController[0] = new ThreadController(tc0);            // en klass som körs som tråd
      threadController[1] = new ThreadController(tc1);
      threadController[2] = new ThreadController(tc2);
      threadController[3] = new ThreadController(tc3);
      threadController[4] = new ThreadController(tc4);
      threadController[5] = new ThreadController(tc5);

      threadControllerThread[0] = new Thread (threadController[0]);    // trådkontrollern threadController körs som tråd
      threadControllerThread[1] = new Thread (threadController[1]);
      threadControllerThread[2] = new Thread (threadController[2]);
      threadControllerThread[3] = new Thread (threadController[3]);
      threadControllerThread[4] = new Thread (threadController[4]);
      threadControllerThread[5] = new Thread (threadController[5]);
   }



Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)

public class ThreadController implements Runnable {   
   private Object obj;
   private Thread objectThread;
   private static final int   TIMER_INTERVAL = 2000;      // The timer interval in milliseconds
   /*
    * Konstruktor för en trådkontroller som startar
    * ett valbart Runnable-objekt/klass i form av en tråd.
    * Trådkontrollern ligger periodvis i viloläge tills
    * den blir avbruten. Vid avbrott avbryts den startade
    * tråden och sedan avslutar trådkontrollern sin while-loop.
    * Objekttypen som skickas med, när en instans av trådkontrollern skapas,
    * är en klass som implementerar interfacet Runnable och som alltså är avsedd
    * att exekveras som en tråd. Varje trådkontroller är bunden till detta objekt.
    * Ingen startad trå kan startas på nytt utan då måste en ny trådkontroller
    * för Runnable-objektet skapas på nytt.
    */
   public ThreadController(Object object) {
      this.obj = object;
   }

   /**
    * Startar vald klass som en tråd. Vid interrupt() görs avbrott
    * i klassobjekten som därefter avslutar sin aktivitet
    * som tråd. while-loopen nedan avslutas och även run().
    */
   public void run() {   
      objectThread = new Thread( (Runnable) obj);         // skapar en ny tråd
      objectThread.start();
      while(true) {
         try {
            Thread.sleep(TIMER_INTERVAL);
         }
         catch(InterruptedException ie) {   
            objectThread.interrupt();
            System.out.println("Avbrott i tråden till " + this.obj.toString());
         }      
      }
   }
}



Författare:  4kTRB [ 22.58 2019-04-01 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Medelvärdesbildningen av spänningen från AD-omvandlingen gjorde jag om då
det blev lite väl ostabilt, det blev någon typ av interpolation på det sättet
jag valt. Upplösningen per bit är ca: 5mV så jag skickar över obalansen i form
av antalet bitar och presenterar resultatet i GUI i 5mV steg, samma gäller för
de två progress-staplarna. Det fungerar riktigt bra, lätt att se när det är bra trimmat,
ligger man på gränsen av +/-5mV fladdrar staplarna medan närmare noll så blir det stabilt.

För de 2 återstående stegen i kalibreringsproceduren hade det varit fint med digitala potentiometrar
men jag tror jag ska ha någon typ av vridomkopplare eller bara ha byglar på ett pcb och koppla in
monterade fasta motstånd. Det finns ganska många värden på NTC-motstånd och de kommer
kräva olika motståndsvärden i bryggan samt för kalibrering.

Jag testade manuellt att nolltrimma bryggan med 560 ohms-motstånd och sedan ett 470ohms
och ett 68 ohms. Tog fram ekvationen och pluggade in ett 270 ohms motstånd och utifrån
spänningen beräknades 270ohms motståndet. Det blev ett fel på 6 ohm. Felet blir störst på
mitten av kurvan. Sedan kan ju multimetern visa fel också men även enligt en simulering
i LT-spice så ser man att bryggan inte ger en perfekt rak linje, den aviker mest på mitten.


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
#include <Arduino.h>

//Koden efterliknar en datainsamling av temperatur och NTC-motstånd
//Javaprogrammet har testats och utvecklats mot denna programkörning

// ****************************************************
//   variabler och konstanter för kalibrering av brygga
// ****************************************************
bool alertFlag;
int analogPinA = A0;                           // bryggans anslutning A
int analogPinB = A1;                           // bryggans anslutning B
int ohm;
const int NUMBER_OF_SAMPLES = 250;               // medelvärdesbilda AD-omvandla många gånger

void zeroAdjustAlert(int);
void averageData(int&, int&, int&);
void bridgeZeroAdjust(void);
// ****************************************************
// 0 är startsignal för datainsamling i Arduinos meny
// 1 är startsignal för nollkalibrering av brygga i Arduinos meny
// 2 är startsignal för datainsamling i Arduinos meny
// 3 är startsignal för datainsamling i Arduinos meny
// 4 är Exit i Arduinos meny Serial().end;
// 100 abryter while-loop i ntcMeasurement()
// 200 abryter while-loop i bridgeZeroAdjust()
// Z indikerar att bryggan är i balans i zeroAdjustAlert-funktionen
// X indikerar att bryggan är i obalans i zeroAdjustAlert-funktionen

// the setup function runs once when you press reset or power the board

int celcius;
int inByte = -1;                             // incoming serial byte

void ntcMeasurement();
void bridgeZeroAdjust();
void setCelcius(int);
int getCelcius();

void setup() {
   Serial.begin(19200);
   setCelcius(0);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);           // används för att testa programmet
   while (!Serial) {
      ;                               // wait for serial port to connect. Needed for native USB
   }
}

// En loop med meny. Data skickas från JAVA-datorn och olika saker utförs.
// Inga av de funktioner som väljs att exekveras körs som trådar på Arduino
// så för att menysystems-loopen ska kunna hantera nästa kommando måste
// den funktion som pågår först avslutas, innan dess case-break; tillåter
// fler menyval. I GUI så kan inte fler menyval utföras förrens det pågående
// avslutats, undantag gäller EXIT för programavslut.
void loop()
{
   if (Serial.available() > 0)
   {
      inByte = Serial.read();
      switch (inByte){
      case 0:                              // en NTC-mätning är begärd
         ntcMeasurement();                   // funktion med while-loop, tar en stund
         digitalWrite(LED_BUILTIN, LOW);       // visuell indikering på att NTC-mätning är utförd
         break;                            // först nu kan nya menyval utvärderas
      case 1:
         bridgeZeroAdjust();                  // en loop som hela tiden indikerar om bryggan är nolltrimmad eller ej
         break;                             // fortsätt i meny-loop när bridgeZeroAdjust() har avslutats
      case 2:

         break;
      case 3:

         break;
      case 4:
         digitalWrite(LED_BUILTIN, HIGH);
         delay(3000);
         Serial.end();                      // nedkoppling av seriekommunikation/com-port
         break;
      default:
         digitalWrite(LED_BUILTIN, LOW);
      }
   }
   delay(100);
   digitalWrite(LED_BUILTIN, HIGH);              // visuell indikering att Arduino är aktiv i menyloopen
   delay(100);
   digitalWrite(LED_BUILTIN, LOW);
}

/*
 * En loop som mäter obalansen i NTC-mätbryggan.
 * Två spänningar från två ADC-ingångar mäts och medelvärdesbildas.
 * Sedan tas differensen av dessa spänningar och utifrån denna differens
 * avgörs om bryggan anses vara i balans / nolltrimmad. Arduino skickar
 * signal till Java-datorn som i sin tur indikerar balans eller obalans i GUI.
 * Loopen avbryts manuellt från GUI med tryck på en knapp.
 */
void bridgeZeroAdjust(){
   alertFlag = true;
   bool breakFlag = true;
   int averageVoltA;
   int averageVoltB;
   int vDiff;
   Serial.write("ZERO");
   Serial.write("\n");
   while(breakFlag){
      averageVoltA = 0;
      averageVoltB = 0;
      vDiff = 0;
      averageData(averageVoltA, averageVoltB, vDiff);  // mät obalansen medeelvärdesbilda en aning
      zeroAdjustAlert(vDiff);                         // indikera om en nolljustering utförts
      delay(100);
      if (Serial.available() > 0){                     // kommando sänt? Avbryt balanstrimmning av brygga?
         if(Serial.read() == 200){                    // 200 avbryter while-loop
            breakFlag = false;
         }
      }
   }
}

/*
 * Argumenten voltA, voltB och voltDiff är call by reference
 * Upplösningen är 5/1023 = 4.8888 mV per bit
 * Beräkning av spänning sker hos Java-datorn
 */
void averageData(int& voltA, int& voltB, int& voltDiff){
   int sumA = 0;
   int sumB = 0;
   for(int i = 0; i < NUMBER_OF_SAMPLES; i++){
      sumA += analogRead(analogPinA);
      sumB += analogRead(analogPinB);
   }
   voltA = (sumA/NUMBER_OF_SAMPLES);
   voltB = (sumB/NUMBER_OF_SAMPLES);
   voltDiff = voltA - voltB;
}

/*
 * Skicka obalansvärdet från A/D-omvandlarna i form av antal bitar obalans.
 * Varje bit motsvarar 5/1023 = 0.004888 V
 * I GUI indikeras att bryggan är balanstrimmad.
 */
void zeroAdjustAlert(int voltageDiff){
   Serial.println(voltageDiff);
}

void ntcMeasurement(){
   ohm = 500;
   setCelcius(24);
   int temp = getCelcius();
   digitalWrite(LED_BUILTIN, HIGH);                     // visuell indikering
   Serial.write("START");
   Serial.write("\n");
   while (getCelcius() < 101) {
      Serial.print(getCelcius());
      Serial.write("  ");
      Serial.print(ohm);
      Serial.write('\n');
      delay(800);
      setCelcius(++temp);
      ohm = -5.9 * getCelcius() + 635;
      if (Serial.available() > 0){                     // kommando sänt?
         if(Serial.read() == 100){                    // 100 avbryter while-loop
            setCelcius(101);
         }
      }
   }
}

void setCelcius(int temp){
   celcius = temp;
}

int getCelcius(){
   return celcius;
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Scanner;
import org.eclipse.swt.widgets.Display;

public class Test_1 implements Runnable {

   private DataOutputStream javaToArduinoOut = null;         //write primitive Java datatypes to an output stream
   private Scanner arduinoScanIn = null;                  // produces values scanned from the specified input stream
   private String data = null;
   private Display display = null;
   private MinusZeroPlusMeter minusZeroPlusMeter = null;
   private double vMilliVolt;

   public Test_1(Display display, MinusZeroPlusMeter minusZeroPlusMeter) {
      this.display = display;
      this.minusZeroPlusMeter = minusZeroPlusMeter;
   }

   @Override
   public void run() {
      ntcBridgeZeroAdjust();
   }
   /*
    *    
    */
   private void ntcBridgeZeroAdjust() {
      javaToArduinoOut = new DataOutputStream(Test.getSerialPort().getOutputStream());
      arduinoScanIn = new Scanner(Test.getSerialPort().getInputStream());
      try {
         javaToArduinoOut.writeByte(NTC.STARTZEROADJUST);   // startsignal för nolltrimma brygga i Arduinos meny
      } catch (IOException e1) {
         e1.printStackTrace();
      }
      try {
         Thread.sleep(1000);
      } catch (InterruptedException e1) {
         e1.printStackTrace();
      }
      
      System.out.println(arduinoScanIn.findInLine("ZERO"));   // Efter texten ZERO skickas ADC-data
      arduinoScanIn.nextLine();
      
      while(true) {                                 // stanna kvar i nolltrim-läge tills avbrott kommer   
         try {
            Thread.sleep(20);                        // måste anpassas till delay i loopen till bridgeZeroAdjust() i Arduinokoden
         } catch (InterruptedException e) {               // fånga ett trådavbrott
            try {
               javaToArduinoOut.writeByte(200);           // 200 är avsluta-signal för Arduinos nolltrim-funktion
               while(arduinoScanIn.hasNextLine()) {      // om arduino skickar extra
                  arduinoScanIn.nextLine();            // strängar så ta inte med dessa
               }
               break;
            } catch (IOException e1) {
               e1.printStackTrace();
            }         
         }
         data = arduinoScanIn.nextLine();               // läs in data som zeroAdjustAlert-funktionen hos
         vMilliVolt = (double) Math.round(4.8888 * Double.parseDouble(data));            
         //   0 + 244 = 244 , 50*4.8888 + 244 = 488, -50*4.8888 + 244 = 0
         // progress bars är 488 steg långa vilket ger indikation mellan +/-50 mV
         display.asyncExec (new Runnable () {         
            public void run () {
               NTC.setVdiffLabelText(vMilliVolt + " mV");
               minusZeroPlusMeter.setSelectionValue((int) Math.round(vMilliVolt*4.889+244));
            }
         });

      }
      arduinoScanIn.close();                           // avsluta skannern
      try {
         javaToArduinoOut.close();                     //avsluta data output stream
      } catch (IOException e) {
         e.printStackTrace();
      }                  
      System.out.println("End from ntcBridgeZeroAdjust " + this.toString() + "!");
   }

   public String toString() {
      return "Test 1";
   }
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;

public class MinusZeroPlusMeter implements Runnable {
   private final int PROGRESSBARMAXIMUM = 488;
   private ProgressBar pgA;
   private ProgressBar pgB;
   private Display display = null;
   private int selection;
   
   public MinusZeroPlusMeter(Display display) {
      this.display = display;
      pgA = NTC.getProgressBarA();
      pgB = NTC.getProgressBarB();
      pgA.setMaximum(PROGRESSBARMAXIMUM);
      pgB.setMaximum(PROGRESSBARMAXIMUM);
      pgA.setSelection(0);
      pgB.setSelection(0);
      this.selection = 0;
      this.setSelectionValue(244);
   }

   @Override
   public void run() {
      work();
      display.asyncExec (new Runnable () {         
         public void run () {
            pgA.setSelection(getSelectionValue());
            pgB.setSelection(PROGRESSBARMAXIMUM-getSelectionValue());
         }
      });
   }

   private void work() {      
      while(true) {
         display.asyncExec (new Runnable () {         
            public void run () {
               pgA.setSelection(getSelectionValue());
               pgB.setSelection(PROGRESSBARMAXIMUM-getSelectionValue());
            }
         });            
         try {
            Thread.sleep(100);
         } catch (InterruptedException e) {
            break;
         }
      }
      System.out.println("End from Utskrift "+ this.toString() + "!");
   }
   public void setSelectionValue(int v) {
      this.selection = v;
   }
   private int getSelectionValue() {
      return this.selection;
   }
   public String toString() {
      return "MinusZeroPlusMeter";
   }
}

Författare:  4kTRB [ 09.53 2019-04-12 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Lärde mig lite ny teknik i C, inga stora saker men ändå.

När jag ska kalibrera bryggans kurva efter att ha nolltrimmat den så ska jag ansluta
2 stycken kända motstånd och funktionen som mäter spänningen ser likadan ut för
dessa två steg så alltså kan samma funktion nyttjas.

Enda skillnaden är att jag skickar kvittens till Java-programmet om att mätningen ska börja
och det utförs med en textsträng som id. Därför ska jag skicka med "RA" resp. "RB" som argument.
Jag använder pekare som dessutom kan göras tydligare med hjälp av typedef.

Att använda sig av kvittens från Arduino på skickade menyval visar sig fungera väldigt bra då
jag lägger Java-programmet i en liten loop som inväntar att rätt kvittens fås och först därefter
går vidare med övriga uppgifter.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
#include <Arduino.h>

//Koden efterliknar en datainsamling av temperatur och NTC-motstånd
//Javaprogrammet har testats och utvecklats mot denna programkörning

// ****************************************************
//  Variabler och konstanter för kalibrering av brygga
// ****************************************************
int analogPinA = A0;                           // bryggans anslutning A
int analogPinB = A1;                           // bryggans anslutning B
int celcius;
int inByte = 0;
const int NUMBER_OF_SAMPLES = 100;               // medelvärdesbilda AD-omvandla många gånger
const unsigned long BAUDRATE = 19200;

typedef char* CharPointer;
CharPointer Ra = "RA";                     // samma funktion används för att kalibrera med
CharPointer Rb = "RB";                     // RA och RB, bara olika id-för java-datorn

// ****************************************************
// 0 är startsignal för datainsamling i Arduinos meny
// 1 är startsignal för nollkalibrering av brygga i Arduinos meny
// 2 är startsignal för datainsamling i Arduinos meny
// 3 är startsignal för datainsamling i Arduinos meny
// 4 är Exit i Arduinos meny Serial().end;
// WHILE_LOOP_BREAK abryter while-loop i respektive mätloop

const int COLLECT_DATA = 0;
const int ZERO_ADJUST = 1;
const int CALIBRATE_RA = 2;
const int CALIBRATE_RB = 3;
const int EXIT = 4;
const int WHILE_LOOP_BREAK = 255;


// Funktionsdeklarationer
// ****************************************************
void rRefAdjust(CharPointer);
void bridgeZeroAdjust();
void averageData(double&, double&, double&);
void adjustAlert(double);
void ntcMeasurement();
int avrunda(double);
void setCelcius(int);
int getCelcius();

void setup() {
   Serial.begin(BAUDRATE);
   setCelcius(0);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);           // används för att testa programmet
   while (!Serial) {
      ;                               // wait for serial port to connect. Needed for native USB
   }
}

// En loop med meny. Data skickas från JAVA-datorn och olika saker utförs.
// Inga av de funktioner som väljs att exekveras körs som trådar på Arduino
// så för att menysystems-loopen ska kunna hantera nästa kommando måste
// den funktion som pågår först avslutas, innan dess case-break; tillåter
// fler menyval. I GUI så kan inte fler menyval utföras förrens det pågående
// avslutats, undantag gäller EXIT för programavslut.
void loop()
{
   if (Serial.available() > 0)
   {
      inByte = Serial.read();
      switch (inByte){
      case COLLECT_DATA:                        // en NTC-mätning är begärd
         digitalWrite(LED_BUILTIN, HIGH);
         ntcMeasurement();                   // funktion med while-loop, tar en stund
         break;                            // först nu kan nya menyval utvärderas
      case ZERO_ADJUST:
         digitalWrite(LED_BUILTIN, HIGH);
         bridgeZeroAdjust();                  // en loop som hela tiden indikerar om bryggan är nolltrimmad eller ej
         break;                             // fortsätt i meny-loop när bridgeZeroAdjust() har avslutats
      case CALIBRATE_RA:
         digitalWrite(LED_BUILTIN, HIGH);
         rRefAdjust(Ra);                   // en loop som hela tiden indikerar spänningen från bryggan
         break;                         // med kalibreringsmotståndet Ra anslutet
      case CALIBRATE_RB:
         digitalWrite(LED_BUILTIN, HIGH);
         rRefAdjust(Rb);
         break;
      case EXIT:                          // Avsluta. Kvittera till Java-datorn och Stäng serieporten
         digitalWrite(LED_BUILTIN, HIGH);
         Serial.write("EXIT FROM ARDUINO");     // Java-datorn skannar data från Arduino mha
         Serial.write("\n");                 // java.util.Scanner.Scanner(InputStream source)
         Serial.end();                      // nedkoppling av seriekommunikation/com-port
         break;
      default:
         digitalWrite(LED_BUILTIN, LOW);
      }
   }
   delay(100);
   digitalWrite(LED_BUILTIN, HIGH);              // visuell indikering att Arduino är aktiv utanför menyloopen
   delay(100);
   digitalWrite(LED_BUILTIN, LOW);
}
/*
 * Tar hand om  A/D-omvandlingar från två ingångar.
 * De insamlade värdena från respektive ingång är medelvärdesbildade
 * och de två ingångarnas differens-spänning skickas till Java-datorn.
 * Upplösningen är 5/1023 = 4.888 mV per bit. Differensspänningen
 * levereras som ett avrundat heltal motsvarandes antal bitar (0 till 1023).
 * Funktionen används för att ta fram ekvationen för en noll-
 * trimmad brygga mha två fasta och kända resistanser, RA och RB.
 * Loopen avbryts manuellt från GUI med tryck på en knapp.
 */
void rRefAdjust(CharPointer c){
   bool breakFlag = true;
   double averageVoltA;
   double averageVoltB;
   double vDiff;
   Serial.write(c);                           // Java-datorn skannar data från Arduino mha
   Serial.write("\n");                           // java.util.Scanner.Scanner(InputStream source)
   while(breakFlag){                           // Den inväntar texten RA eller RB innan data börjar
      averageVoltA = 0;                        // samlas in
      averageVoltB = 0;
      vDiff = 0;
      averageData(averageVoltA, averageVoltB, vDiff);  // mät obalansen medelvärdesbilda en aning
      adjustAlert(vDiff);                             // skicka obalansspänning till Java-dator
      if (Serial.available() > 0){                     // kommando sänt? Avbryt balanstrimmning av brygga?
         if(Serial.read() == WHILE_LOOP_BREAK){       // 200 avbryter while-loop
            breakFlag = false;
         }
      }
   }
}
/*
 * En loop som mäter obalansen i NTC-mätbryggan.
 * Upplösningen är 5/1024 = 4.883 mV per bit
 * Två spänningar från två ADC-ingångar mäts och medelvärdesbildas.
 * Sedan tas differensen av dessa spänningar och utifrån denna differens
 * avgörs om bryggan anses vara i balans/nolltrimmad. Arduino skickar
 * differensen till Java-datorn i form av antalet bitar (0 till 1023)
 * Ex. 2 bitar ger 2*4.8876 = 9.78mV
 *
 * Loopen avbryts manuellt från GUI med tryck på en knapp.
 */
void bridgeZeroAdjust(){
   bool breakFlag = true;
   double averageVoltA;
   double averageVoltB;
   double vDiff;                              // Java-datorn skannar data från Arduino mha
   Serial.write("ZERO");                        // java.util.Scanner.Scanner(InputStream source)
   Serial.write("\n");                           // Den inväntar texten ZERO innan data börjar
   while(breakFlag){                           // samlas in
      averageVoltA = 0;
      averageVoltB = 0;
      vDiff = 0;
      averageData(averageVoltA, averageVoltB, vDiff);  // mät obalansen medelvärdesbilda en aning
      adjustAlert(vDiff);                             // skicka obalansspänning till Java-dator
      if (Serial.available() > 0){                     // kommando sänt? Avbryt balanstrimmning av brygga?
         if(Serial.read() == WHILE_LOOP_BREAK){       // avbryter while-loop ( < 256 pga byte)
            breakFlag = false;
         }
      }
   }
}

/*
 * Argumenten voltA, voltB och voltDiff är call by reference
 * Två spänningar från två ADC-ingångar mäts och medelvärdesbildas.
 * Skillnaden mellan dessa spänningar är obalansspänningen i bryggan.
 * Upplösningen är 5/1023 = 4.89 mV per bit
 * Beräkning av spänning sker i Java-datorn
 */
void averageData(double& voltA, double& voltB, double& voltDiff){
   double sumA = 0;
   double sumB = 0;
   for(int i = 0; i < NUMBER_OF_SAMPLES; i++){
      sumA += analogRead(analogPinA);               // A/D-omv. tar 100us
      delayMicroseconds(25);
      sumB += analogRead(analogPinB);
      delayMicroseconds(25);
   }
   voltA = (sumA/NUMBER_OF_SAMPLES);
   voltB = (sumB/NUMBER_OF_SAMPLES);
   voltDiff = voltA - voltB;
}

/*
 * Skicka obalansvärdet från A/D-omvandlarna i form av antal bitar obalans.
 * Varje bit motsvarar 5/1023 = 0.004888 V
 * I GUI indikeras att bryggan är balanstrimmad.
 */
void adjustAlert(double voltageDiff){
   Serial.println(avrunda(voltageDiff));
}

void ntcMeasurement(){
   int ohm = 500;
   setCelcius(24);
   int temp = getCelcius();
   Serial.write("START");
   Serial.write("\n");
   while (getCelcius() < 101) {
      Serial.print(getCelcius());
      Serial.write(" ");
      Serial.print(ohm);
      Serial.write("\n");
      delay(800);
      setCelcius(++temp);
      ohm = -5.9 * getCelcius() + 635;
      if (Serial.available() > 0){                     // kommando sänt?
         if(Serial.read() == WHILE_LOOP_BREAK){           // avbryter while-loop
            setCelcius(101);
         }
      }
   }
}
/*
 * Avrunda en double till ett heltal
 */
int avrunda(double number){
   return static_cast<int>(floor(number + 0.5));
}
void setCelcius(int temp){
   celcius = temp;
}

int getCelcius(){
   return celcius;
}


Exempelvis när jag vill mäta med RA ansluten så körs koden nedan.
För det mesta visar det sig att loopen som väntar på kvittens inte
är nödvändig. Jag tror den eventuellt kan uteslutas men ibland har
utströmmen andra tecken kvar så jag får testa detta lite mer.

Sedan har jag gjort så att Scanner och DataOutputStream öppnas
när serieporten öppnats och sedan får de vara öppna tills hela programmet
avslutas. Det verka fungera betydligt bättre än att hålla på att stänga och öppna för varje
nytt uppdrag.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.IOException;
import java.util.NoSuchElementException;

public class Test_2 implements Runnable {
   private String data;
   private int vMilliVolt;
   private int value;
   
   public Test_2() {

   }

   @Override
   public void run() {
      NTC.getThreadControllerThread()[5] = new Thread (NTC.getThredController()[5]);            
      try {
         NTC.getThreadControllerThread()[5].start();                // MinusZeroPlusMeter
      } catch (IllegalThreadStateException itse) {
         System.out.println("IllegalThreadStateException");
      }
      ntcBridgeAdjustRA();
      try {
         NTC.getThreadControllerThread()[5].interrupt();
      } catch (SecurityException e) {
         e.printStackTrace();
      }
      System.out.println("End from  " + this.toString() + "!");
   }
   
   private void ntcBridgeAdjustRA() {               
      try {
         NTC.getJavaToArduinoOut().writeByte(NTC.STARTREFA);   // startsignal för kalibrera brygga med referens RA
      } catch (IOException e1) {                        // i Arduinos meny
         e1.printStackTrace();
      }
      int i = 0;
      try {
         data = NTC.getArduinoScanIn().nextLine();
      } catch(NoSuchElementException e) { }
      while(!data.equals(NTC.ARDUINOCALIBRATE_RA)) {         // Efter texten skickas ADC-data
         try {
            data = NTC.getArduinoScanIn().nextLine();
         } catch(NoSuchElementException e) { }
         i++;
      }         
      System.out.println("data = " + data + " i = " + i);                     
         
      while(true) {                                 // stanna kvar i kalibrerings-läge                        
         try {
            Thread.sleep(2);                        
         } catch (InterruptedException e) {               // fånga ett trådavbrott
            try {
               NTC.getJavaToArduinoOut().writeByte(NTC.WHILELOOPEXIT);  // avsluta-signal för Arduinos mätloop
            } catch (IOException e1) {
               e1.printStackTrace();
            }
            break;                                 // hoppa ur while-loop och avsluta
         }
         try {
            data = NTC.getArduinoScanIn().nextLine();      // läs in data motsvarande bryggans
         } catch(NoSuchElementException e) { }
      
         try {                                    // obalansspänning för RrefA
            value = Integer.parseInt(data);               // data är a/d-omvandlarens bitvärde som ett heltal
         } catch(java.lang.NumberFormatException nfe) {      // levererat som en textsträng
            System.out.println("NumberFormatException in Test 2");
         }
                     
         vMilliVolt = (int) Math.round(4.8828 * value);    // 5V/1023 = 4.888 mV/bit
         //   0 + 244 = 244 , 50*4.888 + 244 = 488, -50*4.888 + 244 = 0
         // progress bars är 488 steg långa vilket ger indikation mellan +/-50 mV
         NTC.getDisplay().asyncExec (new Runnable () {         
            public void run () {
               NTC.getLabelVdiff().setText(vMilliVolt + " mV" + " data (0-1023) = " + data);
               NTC.getMinusZeroPlusMeter().setSelectionValue((int) Math.round(vMilliVolt*4.8828+244));
            }
         });
      };      
   }
   public String toString() {
      return "Kalibrera med RrefA";
   }
}

Författare:  4kTRB [ 18.36 2019-04-12 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

När bryggan är nolltrimmad och de två spänningarna VA och VB är uppmätta med
två kända resistanser RA och RB så ska den räta linjen beräknas för att få fram
formeln på formen y = kx + m

Jag får se senare om jag lägger till en tredje mätpunkt mitt på kurvan. Då får
jag approximera linjen med ett polynom. Det beror på om jag vill ha bättre resultat eller ej.

När jag väl har ekvationen så kan jag låta Arduino starta uppvärmning av blocket och läsa in
spänningen y och beräkna NTC-motståndet.

Jag har inte riktigt bestämt ännu hur jag ska mäta temperaturen. Jag hade ju tänkt att mäta
till minst 150 grader och då finns några fler alternativ än RTD-sensorer att välja på men RTD
verkar ju vara något som ger noggrannast värde.

Författare:  Mindmapper [ 19.03 2019-04-12 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Definitivt ska du använda en RTD.
En thermistor typ NTC har en väldigt olinjär kurva. Definitivt ingen räta linjen.

En RTD däremot har en bra linjäritet.
Bra teori om tempmätning.
https://pentronic.se/start/temperaturgi ... ivare.aspx
Även om PT100 är industristandard, så kan PT1000 vara ett alternativ.
Du kan använda tabellerna för PT100 och multiplicera resistansvärdet med 10.

Författare:  4kTRB [ 19.09 2019-04-12 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

NTC går ju använda bara man mätt upp den noga, precis vad jag ska
använda bygget till. Men det är ju svårt innan man vet NTC-kurvan.
PTC går ju också bra att använda men samma visa där.

Författare:  4kTRB [ 21.12 2019-04-12 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Testade med att ansluta ett 553 ohms motstånd och nolltrimmade.
Sedan ett 389 ohms för att få spänningen VA.
Och sist ett 47 ohms för spänningen VB.
Resultatet blir si så där.

VA = 0.472972
VB = 1.7602360000000001
RA = 389.0
RB = 47.0
k = -0.003763929824561404
m = 1.937140701754386

Räknade på vilka värden det skulle mäta vid 0V och 1.54 (vilket var det jag fick med ett 100 ohms)
NTC 0V = 514.7
NTC 1.54V = 105.5

515 är en bit ifrån 553 medans det stämmer bättre för 100 ohm.
Avgörande för felet är nog trots allt upplösningen på 4.9mV per steg.
10-bitars A/D är nog inte tillräckligt för att få bättre resultat än så här.

Koden som körs för att ta fram ekvationen...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)

public class LinearEquation {
   
   private double va;
   private double vb;
   private double ra;
   private double rb;
   private double k;
   private double m;

   public LinearEquation() {
      va = vb = ra = rb = k = m = 0;
   }
   
   public void setVa(double value) {
      this.va = value;
   }
   public double getVa() {
      return this.va;
   }
   public void setVb(double value) {
      this.vb = value;
   }
   public double getVb() {
      return this.vb;
   }
   public void setRa(int value) {
      this.ra = (double) value;
   }
   public double getRa() {
      return this.ra;
   }
   public void setRb(int value) {
      this.rb = (double) value;
   }
   public double getRb() {
      return this.rb;
   }
   public void calculate_k() {      
      this.k = (this.vb-this.va)/(this.rb-this.ra);            
   }
   public double get_k() {
      return this.k;
   }
   public void calculate_m() {
      this.m = this.vb-this.k*this.rb;
   }
   public double get_m() {
      return this.m;
   }
   public double calculateNTCresistance(double voltage){      
      return (voltage - this.m) / this.k;
   }   
}

Sida 2 av 4 Alla tidsangivelser är UTC + 1 timme
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/