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

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

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

Jag påbörjade en tråd med lite frågor om mätinsamling.
Då jag nu kommit igång lägger jag in det hela som ett projekt.

Projektet går ut på att få en Arduino Uno att slå igång ett
värmeelement och mäta temperaturen på värmeelementet.

På värmeelemetet monterar jag också ett NTC-motstånd vars
resistans Arduinon ska mäta parallellt med uppvärmningen.

Tanken är att Arduinon ska leverera två mätvärden, temperatur
och NTC-resistans via serieporten till datorn. Jag tänker mig
att få ett mätvärde på NTC-resistansen vid varje hel grad upp
till en viss temperaturgräns där mätningen avslutas.

På datorn snurrar ett Java-program som tar emot varje mätvärdespar
och skriver dessa till en textfil. Textfilen får formen av två
kolumner med temperatur och ohm-värde.

Exempel...

24 500
25 497
26 492
....osv.

En annan programvara jag har kan sedan läsa den här filen
och plotta en kurva samt kurvanpassa.

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

Har skissat på ett Java-GUI och det kommer se ut ungefär så här...
eventuellt tänkte jag ta med en timer/klocka så man kan se hur lång
tid som mätningen pågått.

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

Den här koden använder jag som test mot Arduino som snurrar en loop för att
efterlikna insamlade mätvärden. Nästa steg blir att få Arduinon att utföra
riktiga mätningar och eftersom jag är helt ny på Arduino så blir det nog
en del labbande där för att få till det. Men det finns ju en uppsjö av exempel
på nätet så det borde gå bra.

Jag har lagt in en funktion som sänder till Arduinon och avbryter mätloopen som
t.ex. använd om man trycker på STOPP-knappen.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Scanner;
import com.fazecast.jSerialComm.SerialPort;

public class SerialMainScanner {

   public static void main(String[] args) throws InterruptedException {

      boolean ArduinoFlag = false;
      int AUnoIndex = -1;
      SerialPort serialPort = null;
      Scanner arduinoScanIn = null;
      DataOutputStream javaToArduinoOut = null;
      TextFile textFile = new TextFile();                              // TextFile-objekt vars metoder nu kan nås
      String data = new String();                                    // textsträng att lagra inläst data i
      String breakValue = new String("48");                            // avbryter mätning vid uppnått värde
      int breakIntValue = Integer.parseInt(breakValue);                   // konvertera till heltal
      boolean stopSignal = true;                                     // signal som skickas till Arduino
      int delimiterIndex;
      textFile.setTextFileName("data.txt");                            // namn på fil att lagra data i

      SerialPort[] sp = SerialPort.getCommPorts();

      System.out.println("Antal tillgängliga seriella portar: "+sp.length);
      for(int j=0;j<sp.length;j++) {
         System.out.println(sp[j].getDescriptivePortName()+" öppen = "+sp[j].isOpen());
         if(sp[j].getDescriptivePortName().contains("Arduino Uno")){
            ArduinoFlag = true;
            AUnoIndex = j;
         }
      }
      if(ArduinoFlag) {         
         serialPort = sp[AUnoIndex];   
         if(serialPort.isOpen()) {
            serialPort.closePort();                               // Close connection
         }
         if(!serialPort.isOpen()) {
            serialPort.openPort();                                  // Open connection
         }         
         Thread.sleep(500);
         serialPort.clearDTR();                                    // Arduino Reset - Starta en mätinsamling

         serialPort.setBaudRate(19200);                              // Ställ in baudrate
         serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 2500, 0);   // Vänta antal ms på att data ska anlända                   
         System.out.println(serialPort.getDescriptivePortName()+ " öppnad = "+serialPort.isOpen());
         System.out.println();
         System.out.println("==== NTC Measurement Application Januari 2019 ====");
         if((serialPort.bytesAvailable()>0)) {
            try
            {   
               javaToArduinoOut = new DataOutputStream(serialPort.getOutputStream()); // se till att det går skicka data till Arduino
               arduinoScanIn = new Scanner(serialPort.getInputStream());   // se till att det går ta emot data från Arduino
               arduinoScanIn.useDelimiter(" ");                        // två datavärden levereras med blanksteg emellan                
               System.out.println(arduinoScanIn.findInLine("START"));       // startmeddelande från Arduino
               arduinoScanIn.nextLine();                              // hoppa över nyrads-tecken /n
            }
            catch(IllegalStateException  e)
            {
               e.printStackTrace();
            }
            textFile.createTextFile();                              // skapa en textfil
            while(arduinoScanIn.hasNextLine())                        // loopa så länge det finns data i skannern
            {         
               try
               {
                  data = arduinoScanIn.nextLine();                        
                  System.out.println(data);
                  textFile.writeToFile(data);
                  delimiterIndex = data.indexOf(" ");                      // ta reda på vart blanktecknet befinner sig
                  try {                                           // innan blanktecknet finns temperaturvärdet
                     if(Integer.parseInt(data.substring(0, delimiterIndex)) % breakIntValue == 0){
                        System.out.println("===========================");    // stämmer det med temeraturbrytvärdet så....
                        try {
                           javaToArduinoOut.writeBoolean(stopSignal);       // avbryt mätning
                           while(arduinoScanIn.hasNextLine()) {          // om arduino skickar extra
                              System.out.println(arduinoScanIn.nextLine());// strängar (fyllt på skannern) så
                           }                                     // ta inte med dessa, Integer.parseInt
                        }                                        // får problem med sånt
                        catch(IOException e) {                           
                        }                        
                     }
                  }
                  catch(NumberFormatException e) {
                     e.printStackTrace();                     
                  }
               }
               catch(IllegalStateException e)
               {
                  e.printStackTrace();
               }
            }
            arduinoScanIn.close();                                      // stäng scanner
            textFile.closeFileOutputStream();                            // stäng textfil
         }         
         if(serialPort.isOpen()) {
            serialPort.closePort();                                     // stäng serieport
            System.out.println("Java Closed The Serial Port!");
         }      
         System.out.println("End from Java!");         
      }      
   }
}



Arduinokod...

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
// the setup function runs once when you press reset or power the board
int celcius = 24;
int ohm = 500;
boolean flag = true;
int inByte = 0;         // incoming serial byte

void setup() {
  Serial.begin(19200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }
}
void loop() {
  if (flag) {
    Serial.write("START");
    Serial.write("\n");
    flag = false;
  }
  while (celcius < 101) {
    Serial.print(celcius);
    Serial.write("  ");
    Serial.print(ohm);
    Serial.write('\n');
    delay(200);
    celcius++;
    ohm = -5.9 * celcius + 635;
    if (Serial.available() > 0) {
      if(Serial.read()){          // om en boolean true skickats så avsluta
          celcius = 101;
      }
    }
  }
  Serial.write("End from Aurdino!\n");
  Serial.write("NTC measurement Terminated!\n");
  Serial.end(); 
}

Författare:  Fransson [ 19.13 2019-01-20 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Mycket intressant!

Det du gör har tydliga paralleller med ett projekt som jag har kört fast i.
Men du har börjat med kommunikationen (och verkar ha något som "fungerar"), vilket är var jag har kört fast.

Jag mäter dock bara 3-4st spänningar och "skalar" dem med hjälp av map() funktionen.

Det jag har kört fast i, är "styrningen" från PCn, till Arduinon. (Vill bland annat överföra nya kalibreringsvärden och ett "nödstopp" kommando.)

Kan jag "låna" din kod och experimentera med?

Med vänliga hälsningar Magnus Fransson.

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

Går bra.
En sak som inte fungerade bra ihop med GUI är processen att seriekommunisera med Arduino och
skyffla data till en fil. GUI fryser och kontrollknapparna blir omöjliga att klicka på.

Jag blev tvungen att placera den funktionen i en tråd.

Att sedan via en trådkontroller skicka en signal från GUI till tråden utförs genom
att interrupta trådkontrollern som i sin tur meddelar serie/arduino-objektet med
en interrupt. Fungerar bra.

Åt andra hållet var det till börja med inte lika enkelt tills jag läste om hur man
utför detta i samband med SWT-komponenter.

Jag vill ha en display i GUI som visar aktuell temperatur och NTC och de data finns
ju i tråden.

Det går att fixa med GUI och funktionalitet hos "mätinstrumentet" bra länge, tex skulle
man kunna tänka sig att först värma upp ett metallblock, slå ifrån värmeelementet vid
satt temperatur och påbörja mätning.

En sak som jag kanske ska lägga till är att skriva timervärde och metallblockets temperatur
till en annan fil parallellt, inget som har med NTC-resistansen att göra direkt men mer
som en möjlighet att mäta en kylares egenskaper. Går ju då ta fram en avsvalningskurva.

Så här ser det ut, eventuellt ska jag addera en klocka...

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

Seriekommiunikationsklassen som dessutom skriver data till en fil.

Den här koden gör att man kan skicka data från tråden till SWT-GUI.
Exempel...
display.asyncExec (new Runnable () {
public void run () {
window.btnExit.setEnabled(true);
}
});


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;
import com.fazecast.jSerialComm.SerialPort;

/*
 * Klassen representerar en seriell com-port där Arduino finns ansluten.
 */
public class Serial implements Runnable{
   private int baudRate;                        // serieportens i GUI valda överföringshastighet
   boolean stopSignal;                           // signal som skickas till Arduino så den kan avbryta mätloopen
   private int breakTempValue;                     // temperatur då mätning ska avbrytas, anges i GUI
   private int delimiterIndex;                     // använd för att söka efter temperatur då mätning ska avbrytas
   private TextFile textFile = null;               // instans skapas i metoden startSerial()
   private SerialPort serialPort = null;             // instans skapas i metoden comPortSetUp()
   private DataOutputStream javaToArduinoOut = null;   // instans skapas i metoden scanAndWriteData()
   private Scanner arduinoScanIn = null;         // produces values scanned from the specified input stream
   private NTC window;
   private Display display;
   private String data = null;

   /*
    * Konstruktor till objekt av typen Serial
    * Ett objekt av denna klass skapas i klassen som innehåller main
    * Detta objekt ger tillgång till metoden run() som anropar startSerial(TextFile textfile) som
    * påbörjar en kommunikation med Arduino och lagrar data från denna i en textfil.
    * Vid tryck på knappen START i GUI anropas startSerial(TextFile textfile)
    */
   public Serial(NTC window, Display display) {
      this.window = window;
      this.display = display;
   }

   public void run() {
      try {
         startSerial(NTC.getTextFile());

      } catch (InterruptedException e) {
         System.out.println("InterruptedException in Serial run()");
      }
   }

   /*
    * I GUI kan en temperatur väljas där mätningen ska avbrytas.
    * Default är angivet i en klassvariabel
    */
   public void setBreakTemp(int breaktemp) {
      breakTempValue = breaktemp;
   }
   /*
    * Returnerar aktuellt satt stopp/avbryt temperatur
    */
   public int getBreakTemp() {
      return breakTempValue;
   }

   /*
    * I GUI kan olika baudrate väljas. Default är 9600bps
    * Metoden sätter valt värde.
    */
   public void setBaudRate(int baudrate) {
      baudRate = baudrate;
   }

   /*
    * Returnerar aktuellt satt baudrate
    */
   public int getBaudRate() {
      return baudRate;
   }

   /*
    * Påbörjar en kontakt med den COM-port som Arduino är ansluten till och
    * när kontakt är upprättad påbörjas datainsamling från Arduino.
    * Via GUi finns alternativa val för baudrate. Denna metod anropas
    * vid tryck på knappen START i GUI.
    */
   private void startSerial(TextFile textfile) throws InterruptedException {
      textFile = textfile;                     // referens till ett objekt av typen TextFile som skapats i GUI
      boolean flag = this.comPortSetUp();            // konfigurerar porten

      if(flag) {
         this.scanAndWriteData();               // läs indata och skriv till textfil
      }         
   }

   /*
    * Metod. Scannar av vilka COM-portar som finns tillgängliga och om Arduino är ansluten
    * till någon av dessa. Port med Arduino öppnas och porten konfigureras. Baudrate väljs i GUI.
    *
    * @return Ett SerialPort objekt som håller porten till Arduino annars null.
    * @throws InterruptedException
    */
   public boolean comPortSetUp() throws InterruptedException {

      boolean AUnoFlag = false;
      int AUnoIndex = -1;   
      SerialPort[] sp = SerialPort.getCommPorts();      
      System.out.println("Antal tillgängliga seriella portar: "+sp.length);            
      for(int j=0;j<sp.length;j++) {
         System.out.println(sp[j].getDescriptivePortName()+" öppen = "+sp[j].isOpen());
         if(sp[j].getDescriptivePortName().contains("Arduino Uno")){
            AUnoFlag = true;
            AUnoIndex = j;
         }
      }
      if(AUnoFlag) {
         serialPort = sp[AUnoIndex];   
         if(serialPort.isOpen()) {
            serialPort.closePort();                      // Close connection
         }
         if(!serialPort.isOpen()) {
            serialPort.openPort();                         // Open connection
         }         
         Thread.sleep(500);
         serialPort.clearDTR();                           // Arduino Reset         
         serialPort.setBaudRate(this.getBaudRate());
         serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 2500, 0);
         
         System.out.println(serialPort.getDescriptivePortName()+ " öppnad = "+serialPort.isOpen());         
      }      
      return AUnoFlag;
   }

   /*
    * Metod. Läser in data från Arduino som skickas på serieporten och skriver ut data
    * till en display i GUI samt till en textfil. Data skrivs i textfilen i två kolumner,
    * temperatur och NTC-ohm-värde. Inläsning avslutas antingen då en default-temperatur
    * uppnåtts eller då en valbar temperatur som angivits i GUI uppnås. Sedan stängs
    * skannern, textfilen och serieporten.
    */
   public void scanAndWriteData() {
      textFile.createTextFile();            // skapa en namngiven textfil att lagra inskannad data i      
      

      System.out.println("Temperatur där mätning ska avbrytas: "+this.getBreakTemp());
      System.out.println("====== NTC Measurement Application Januari 2019 =======");
      if((serialPort.bytesAvailable()>0)) {
         try
         {   
            javaToArduinoOut = new DataOutputStream(serialPort.getOutputStream());            
            arduinoScanIn = new Scanner(serialPort.getInputStream());
            arduinoScanIn.useDelimiter(" ");               
            System.out.println(arduinoScanIn.findInLine("START"));
            arduinoScanIn.nextLine();
         }
         catch(IllegalStateException  e)
         {
            e.printStackTrace();
         }
         while(arduinoScanIn.hasNextLine())
         {            
            try
            {
               if(Thread.interrupted()) {
                  try {                                       // så dess mätloop avslutas
                     javaToArduinoOut.writeBoolean(true);             // avbryt mätning skicka signal
                     while(arduinoScanIn.hasNextLine()) {            // om arduino skickar extra
                        arduinoScanIn.nextLine();                  // strängar så ta inte med dessa                     
                     }
                     break;                                    // hoppa ur loopen vid "nödstopp"
                  }                                        
                  catch(IOException e) {                     
                  }                           
               }
               data = arduinoScanIn.nextLine();               
               System.out.println(data);
               textFile.writeToFile(data);                           // skriv data till textfil
               
               display.asyncExec (new Runnable () {                  // uppdatera temp- och ntc-display i GUI
                  public void run () {
                     window.changeLedDisplay(data);
                  }
               });
                              
               delimiterIndex = data.indexOf(" ");                     // avbryt mätning om användardefinierad
               try {                                          // stopptemperatur uppnåtts
                  if(Integer.parseInt(data.substring(0, delimiterIndex)) % this.getBreakTemp() == 0){                   
                                                            // stoppsignal ska skickas till Arduino
                     try {                                    // så dess mätloop avslutas
                        javaToArduinoOut.writeBoolean(true);          // avbryt mätning
                        while(arduinoScanIn.hasNextLine()) {         // om arduino skickar extra
                           arduinoScanIn.nextLine();               // strängar så ta inte med dessa
                        }
                        break;                                             
                     }                                        
                     catch(IOException e) {                           
                     }
                     System.out.println();
                  }
               }
               catch(NumberFormatException e) {
                  e.printStackTrace();                     
               }
            }
            catch(IllegalStateException e)
            {
               e.printStackTrace();
            }
         }
         arduinoScanIn.close();                  // avsluta skannern
         textFile.closeFileOutputStream();         // stäng textfilen
      }         
      if(serialPort.isOpen()) {
         serialPort.closePort();                  // koppla ned com-porten
      }
      display.asyncExec (new Runnable () {         // EXIT-knapp i GUI
         public void run () {
            window.btnExit.setEnabled(true);
         }
      });         
      System.out.println("End from Java!");
   }
}


Trådkontrollern....

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
public class ThreadController implements Runnable {
   private Thread   arduinoSerialThread;
   private Serial arduinoSerial;
   // The timer interval in milliseconds
   private static final int   TIMER_INTERVAL = 1000;
   public ThreadController() {

   }
   public void run() {
      arduinoSerial = NTC.getArduinoSerial();
      arduinoSerialThread = new Thread(arduinoSerial);
      Thread.currentThread().setName("ControllerThread");
      arduinoSerialThread.start();
      while(true) {
         try {
            Thread.sleep(TIMER_INTERVAL);
         }
         catch(InterruptedException ie) {            
            Thread.currentThread().interrupt();
         }
         if(Thread.interrupted()) {
            arduinoSerialThread.interrupt();
            break;
         }
      }
   }
}



GUI och main......

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Button;
import org.eclipse.wb.swt.SWTResourceManager;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Spinner;

public class NTC {

   protected static Shell shlNtc;
   private Text txtDatatxt;
   private static final int DEFAULTBREAKTEMP = 100;
   private static final String DEFAULTTEXTFILENAME = "data.txt";
   private static final int DEFAULTBAUDRATE = 19200;
   private static Serial arduinoSerial;
   private ThreadController threadController;
   private Thread threadControllerThread;
   private Button btnStopp;
   public Button btnExit;
   private static TextFile textFile;
   private TempDisplay tempDisplay;
   private NTCDisplay ntcDisplay;
   private String[] ImgLink = new String[12];
   private CLabel LED_0;   
   private CLabel LED_1;
   private CLabel LED_2;
   private CLabel LED_3;
   private CLabel LED_4;
   private CLabel LED_5;
   private CLabel LED_6;
   private CLabel LED_7;
   private CLabel LED_8;
   private static NTC window;
   private Display display;
   private static final String LED0 = "/LED/LED_GREEN_0.jpg";
   private static final String LED1 = "/LED/LED_GREEN_1.jpg";
   private static final String LED2 = "/LED/LED_GREEN_2.jpg";
   private static final String LED3 = "/LED/LED_GREEN_3.jpg";
   private static final String LED4 = "/LED/LED_GREEN_4.jpg";
   private static final String LED5 = "/LED/LED_GREEN_5.jpg";
   private static final String LED6 = "/LED/LED_GREEN_6.jpg";
   private static final String LED7 = "/LED/LED_GREEN_7.jpg";
   private static final String LED8 = "/LED/LED_GREEN_8.jpg";
   private static final String LED9 = "/LED/LED_GREEN_9.jpg";
   private static final String LEDBLANK = "/LED/LED_GREEN_BLANK.jpg";
   private static final String LEDMINUS = "/LED/LED_GREEN_MINUS.jpg";
   private Composite composite;
   private CLabel lblNewLabel_2;
   private Spinner spinner;


   /**
    * Launch the application.
    * @param args
    */
   public static void main(String[] args) {   
      try {
         window = new NTC();
         window.open();
      } catch (Exception e) {
         e.printStackTrace();
      }      
   }

   /**
    * Open the window.
    */
   public void open() {      
      display = Display.getDefault();
      createContents();
      shlNtc.open();
      shlNtc.layout();
      while (!shlNtc.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
   }

   /*
    * Diverse Metoder. Vid tryck på knappen START i GUI så påbörjas en NTC-mätning.
    * Den port Arduino är ansluten till öppnas och konfigureras. En fil
    * med valbart namn skapas och data från Arduino läses in och lagras
    * i filen. När mätningen är klar eller har stoppats stängs porten och
    * filen med data.
    */
   private void setUpLEDDisplay() {
      ImgLink[0] = LED0;
      ImgLink[1] = LED1;
      ImgLink[2] = LED2;
      ImgLink[3] = LED3;
      ImgLink[4] = LED4;
      ImgLink[5] = LED5;
      ImgLink[6] = LED6;
      ImgLink[7] = LED7;
      ImgLink[8] = LED8;
      ImgLink[9] = LED9;
      ImgLink[10] = LEDBLANK;
      ImgLink[11] = LEDMINUS;

      LED_0 = new CLabel(shlNtc, SWT.NONE);      // temperatur-display 3st LED
      LED_1 = new CLabel(shlNtc, SWT.NONE);
      LED_2 = new CLabel(shlNtc, SWT.NONE);
      LED_3 = new CLabel(shlNtc, SWT.NONE);      // NTC-display 6st LED
      LED_4 = new CLabel(shlNtc, SWT.NONE);      
      LED_5 = new CLabel(shlNtc, SWT.NONE);
      LED_6 = new CLabel(shlNtc, SWT.NONE);
      LED_7 = new CLabel(shlNtc, SWT.NONE);
      LED_8 = new CLabel(shlNtc, SWT.NONE);
      LED_0.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK)); // bakgrundsbilder i form av 7-seg. LED
      LED_1.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_2.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_3.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_4.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_5.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_6.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_7.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      LED_8.setImage(SWTResourceManager.getImage(NTC.class, LEDBLANK));
      tempDisplay = new TempDisplay();
      ntcDisplay = new NTCDisplay();
   }
   
   private void setTempGUIdisplayValue() {   
      int digit100 = tempDisplay.getLED100Value();
      int digit10 = tempDisplay.getLED10Value();
      int digit1 = tempDisplay.getLED1Value();
      LED_0.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit100]));
      LED_1.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit10]));
      LED_2.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit1]));
   }
   
   private void setNTCGUIdisplayValue() {   
      int digit100000 = ntcDisplay.getLED100000Value();
      int digit10000 = ntcDisplay.getLED10000Value();
      int digit1000 = ntcDisplay.getLED1000Value();
      int digit100 = ntcDisplay.getLED100Value();
      int digit10 = ntcDisplay.getLED10Value();
      int digit1 = ntcDisplay.getLED1Value();      
      LED_3.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit100000]));
      LED_4.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit10000]));
      LED_5.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit1000]));
      LED_6.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit100]));
      LED_7.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit10]));
      LED_8.setImage(SWTResourceManager.getImage(NTC.class, ImgLink[digit1]));
   }
   private void setUpTextFile() {
      textFile = new TextFile();
      textFile.setTextFileName(NTC.DEFAULTTEXTFILENAME);   // default textfilsnamn där insamlad data lagras
   }
   public static TextFile getTextFile() {
      return textFile;
   }
   private void setUpSerial() {
      arduinoSerial = new Serial(window,display);
      arduinoSerial.setBaudRate(NTC.DEFAULTBAUDRATE);      // default baudrate för kommunikation med Arduino
      arduinoSerial.setBreakTemp(NTC.DEFAULTBREAKTEMP);   // default temperatur då mätning ska avbrytas
   }
   public static Serial getArduinoSerial() {
      return arduinoSerial;
   }
   /**
    * Skapar de objekt som måste ha referenser klara innan createContents()
    * exekveras fullt ut
    */
   private void setUpSomeOfTheGUI() {
      btnExit = new Button(shlNtc, SWT.BORDER | SWT.FLAT | SWT.CENTER);
      btnExit.setEnabled(true);
      btnStopp = new Button(shlNtc, SWT.BORDER | SWT.FLAT | SWT.CENTER);
      btnStopp.setEnabled(false);
   }

   /**
    * Uppdaterar de två 7seg-LED-displayerna i GUI
    *
    * @param data en textsträng på formen "temperatur ntcmotstånd"
    */
   public void changeLedDisplay(String data) {
      String temp = data.substring(0, data.indexOf(" "));
      String ntc = data.substring(data.indexOf(" ")).trim();
      tempDisplay.setTempValue(Integer.parseInt(temp));
      ntcDisplay.setOhmValue(Integer.parseInt(ntc));
      setTempGUIdisplayValue();            
      setNTCGUIdisplayValue();
   }

   /**
    * Create contents of the window.
    */
   protected void createContents() {
      shlNtc = new Shell();
      shlNtc.setImage(null);
      shlNtc.setForeground(SWTResourceManager.getColor(0, 0, 0));
      shlNtc.setBackground(SWTResourceManager.getColor(0, 102, 102));
      shlNtc.setSize(465, 467);
      shlNtc.setText("Arduino Serial Control Software");
      shlNtc.setLayout(null);

      setUpLEDDisplay();
      setUpTextFile();
      setUpSerial();
      setUpSomeOfTheGUI();

      //----------------------------------------------------------------------------EXIT-knapp
      btnExit.addMouseListener(new MouseAdapter() {
         @Override
         public void mouseUp(MouseEvent e) {            
            System.exit(0);
         }
      });

      btnExit.setText("EXIT");
      btnExit.setForeground(SWTResourceManager.getColor(255, 255, 0));
      btnExit.setFont(SWTResourceManager.getFont("Sitka Display", 15, SWT.BOLD));
      btnExit.setBackground(SWTResourceManager.getColor(0, 0, 0));
      btnExit.setBounds(355, 60, 88, 44);


      //----------------------------------------------------------------------------Info om Baudrate
      Group grpBaudrate = new Group(shlNtc, SWT.NONE);
      grpBaudrate.setEnabled(false);
      grpBaudrate.setBounds(355, 10, 88, 44);
      grpBaudrate.setBackground(SWTResourceManager.getColor(SWT.COLOR_TITLE_BACKGROUND));
      grpBaudrate.setFont(SWTResourceManager.getFont("Sitka Display", 12, SWT.BOLD | SWT.ITALIC));
      grpBaudrate.setText("Baudrate");
      grpBaudrate.setLayout(null);

      CLabel lblNewLabel_1 = new CLabel(grpBaudrate, SWT.NONE);
      lblNewLabel_1.setFont(SWTResourceManager.getFont("Segoe UI", 9, SWT.BOLD));
      lblNewLabel_1.setBackground(SWTResourceManager.getColor(SWT.COLOR_TITLE_BACKGROUND));
      lblNewLabel_1.setAlignment(SWT.CENTER);
      lblNewLabel_1.setBounds(13, 23, 65, 21);
      lblNewLabel_1.setText("9600bps");


      //----------------------------------------------------------------------------Info. Rubriktext Banner
      CLabel lblNtcMeasurementSoftware = new CLabel(shlNtc, SWT.NONE);
      lblNtcMeasurementSoftware.setForeground(SWTResourceManager.getColor(255, 248, 220));
      lblNtcMeasurementSoftware.setBackground(SWTResourceManager.getColor(0, 0, 139));
      lblNtcMeasurementSoftware.setFont(SWTResourceManager.getFont("Sitka Display", 15, SWT.BOLD));
      lblNtcMeasurementSoftware.setAlignment(SWT.CENTER);
      lblNtcMeasurementSoftware.setBounds(10, 10, 339, 44);
      lblNtcMeasurementSoftware.setText("NTC Measurement  Software");

      CLabel lblAngeTextfilnamnAtt = new CLabel(shlNtc, SWT.NONE);
      lblAngeTextfilnamnAtt.setAlignment(SWT.CENTER);
      lblAngeTextfilnamnAtt.setFont(SWTResourceManager.getFont("Segoe UI", 12, SWT.BOLD));
      lblAngeTextfilnamnAtt.setBounds(10, 60, 339, 21);
      lblAngeTextfilnamnAtt.setText("Ange textfilnamn att spara data till:");

      //----------------------------------------------------------------------------Textfält för filnamn
      txtDatatxt = new Text(shlNtc, SWT.BORDER);
      txtDatatxt.setText("data.txt");
      txtDatatxt.setFont(SWTResourceManager.getFont("Arial", 9, SWT.NORMAL));
      txtDatatxt.setBounds(10, 87, 339, 21);

      //----------------------------------------------------------------------------Info.skylt startknapp
      CLabel lblAvbrytsVid = new CLabel(shlNtc, SWT.NONE);
      lblAvbrytsVid.setText("Avbryts vid 100 grader Celcius som default");
      lblAvbrytsVid.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.BOLD));
      lblAvbrytsVid.setBackground(SWTResourceManager.getColor(255, 255, 153));
      lblAvbrytsVid.setAlignment(SWT.CENTER);
      lblAvbrytsVid.setBounds(10, 114, 339, 22);

      //----------------------------------------------------------------------------Info.skylt startknapp
      CLabel lblNewLabel = new CLabel(shlNtc, SWT.NONE);
      lblNewLabel.setBackground(SWTResourceManager.getColor(255, 255, 153));
      lblNewLabel.setAlignment(SWT.CENTER);
      lblNewLabel.setFont(SWTResourceManager.getFont("Segoe UI", 12, SWT.BOLD));
      lblNewLabel.setBounds(10, 136, 339, 22);
      lblNewLabel.setText("Starta Arduino NTC-m\u00E4tning ---->");

      //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> STARTKNAPP
      Button btnStartaArduinoNtcmtning = new Button(shlNtc, SWT.BORDER | SWT.FLAT | SWT.CENTER);
      btnStartaArduinoNtcmtning.addMouseListener(new MouseAdapter() {         
         public void mouseUp(MouseEvent e) {            
            textFile.setTextFileName(txtDatatxt.getText());          // hämta text från textfält med filnamn
            threadController = new ThreadController();
            threadControllerThread = new Thread(threadController);      // en tråd får bara startas en gång                                                      
            try {            
               threadControllerThread.start();                     // starta upp NTC-mätning
            }
            catch(IllegalThreadStateException itse) {
               System.out.println("IllegalThreadStateException");
            }
            btnStopp.setEnabled(true);
            btnStartaArduinoNtcmtning.setEnabled(false);
            btnExit.setEnabled(false);
         }});
      btnStartaArduinoNtcmtning.setFont(SWTResourceManager.getFont("Sitka Display", 15, SWT.BOLD));
      btnStartaArduinoNtcmtning.setBackground(SWTResourceManager.getColor(0, 139, 139));
      btnStartaArduinoNtcmtning.setForeground(SWTResourceManager.getColor(255, 255, 0));      
      btnStartaArduinoNtcmtning.setBounds(355, 114, 88, 44);
      btnStartaArduinoNtcmtning.setText("START");

      //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> STOPPKNAPP      
      btnStopp.addMouseListener(new MouseAdapter() {
         public void mouseUp(MouseEvent e) {               // signalera Stopp till Arduino-inläsningen
            try {                                 // avbryt trådkontrollern som i sin tur avbryter
               threadControllerThread.interrupt();         // inäsning av data från Arduinon
            }
            catch(SecurityException se) {
               se.printStackTrace();
            }
            btnStartaArduinoNtcmtning.setEnabled(true);
            btnExit.setEnabled(true);
         }
      });

      btnStopp.setText("STOPP");
      btnStopp.setForeground(SWTResourceManager.getColor(255, 255, 240));
      btnStopp.setFont(SWTResourceManager.getFont("Sitka Display", 15, SWT.BOLD));
      btnStopp.setBackground(SWTResourceManager.getColor(204, 0, 0));
      btnStopp.setBounds(10, 164, 88, 44);

      //----------------------------------------------------------------------------Info.skylt stoppknapp
      CLabel label = new CLabel(shlNtc, SWT.NONE);
      label.setBackground(SWTResourceManager.getColor(255, 255, 153));
      label.setText("<---- Stoppa Arduino NTC-m\u00E4tning");
      label.setFont(SWTResourceManager.getFont("Segoe UI", 12, SWT.BOLD));
      label.setAlignment(SWT.CENTER);
      label.setBounds(104, 164, 339, 44);

      //----------------------------------------------------------------------------Info.skylt Ange avbryt-temperatur      
      CLabel lblAngeEnTemperatur = new CLabel(shlNtc, SWT.NONE);
      lblAngeEnTemperatur.setLeftMargin(5);
      lblAngeEnTemperatur.setText("Ange en temperatur\r\nf\u00F6r Automatiskt Stopp -->");
      lblAngeEnTemperatur.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.BOLD));
      lblAngeEnTemperatur.setBackground(SWTResourceManager.getColor(255, 255, 153));
      lblAngeEnTemperatur.setBounds(10, 214, 203, 44);

      //----------------------------------------------------------------------------Info.skylt avbryt-temperatur range
      CLabel lblGrader = new CLabel(shlNtc, SWT.NONE);
      lblGrader.setAlignment(SWT.CENTER);
      lblGrader.setText("50 grader till 150 grader");
      lblGrader.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.BOLD));
      lblGrader.setBackground(SWTResourceManager.getColor(255, 255, 153));
      lblGrader.setBounds(219, 214, 187, 21);
      spinner = new Spinner(shlNtc, SWT.BORDER);
      spinner.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.NORMAL));
      spinner.setMaximum(150);
      spinner.setMinimum(50);
      spinner.setSelection(100);
      
      
      spinner.addSelectionListener(new SelectionAdapter() {
         @Override
         public void widgetSelected(SelectionEvent e) {
            spinner.getSelection();
         }
      });
      
      
      //-----------------------------------------------------------------------------Spinner
      spinner.setBounds(219, 237, 62, 21);

      CLabel lblgraderCelsius = new CLabel(shlNtc, SWT.NONE);
      lblgraderCelsius.setText(" [grader Celsius]");
      lblgraderCelsius.setForeground(SWTResourceManager.getColor(240, 230, 140));
      lblgraderCelsius.setFont(SWTResourceManager.getFont("Segoe UI", 9, SWT.BOLD));
      lblgraderCelsius.setBackground(SWTResourceManager.getColor(0, 0, 0));
      lblgraderCelsius.setAlignment(SWT.CENTER);
      lblgraderCelsius.setBounds(277, 237, 129, 21);

      CLabel lblKryssaIOm = new CLabel(shlNtc, SWT.NONE);
      lblKryssaIOm.setLeftMargin(5);
      lblKryssaIOm.setText("Bekr\u00E4fta Automatiskt Stopp ->");
      lblKryssaIOm.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.BOLD));
      lblKryssaIOm.setBackground(SWTResourceManager.getColor(255, 255, 153));
      lblKryssaIOm.setBounds(10, 264, 203, 27);
      composite = new Composite(shlNtc, SWT.NONE);
      lblNewLabel_2 = new CLabel(composite, SWT.CENTER);
      
            //---------------------------------------------------------------------------------------- Checkruta
            composite.setBackground(SWTResourceManager.getColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT));
            composite.setBounds(219, 264, 224, 27);
            
                  Button btnCheckButton = new Button(composite, SWT.CHECK);
                  btnCheckButton.setSelection(false);
                  btnCheckButton.addSelectionListener(new SelectionAdapter() {
                     @Override
                     public void widgetSelected(SelectionEvent e) {
                        Button source =  (Button) e.getSource();
                        if(source.getSelection())  {                                  // inmatad temperaturgräns konverteras till int   
                           try {
                              btnCheckButton.setSelection(true);
                              spinner.setEnabled(false);
                           //   int intValue = (int) Math.round(Double.parseDouble(text_1.getText()));
                              int intValue = spinner.getSelection();
                              if(intValue<50) {
                                 lblNewLabel_2.setText(""+50);
                                 spinner.setSelection(50);
                                 arduinoSerial.setBreakTemp(50);
                              }
                              else if(intValue>150) {
                                 lblNewLabel_2.setText(""+150);
                                 spinner.setSelection(150);
                                 arduinoSerial.setBreakTemp(150);
                              }
                              else {
                                 lblNewLabel_2.setText(""+intValue);
                                 arduinoSerial.setBreakTemp(intValue);            // användardefinierat mätstopp tillämpas
                              }
                           }
                           catch(NumberFormatException nfe) {                     // om annat än ett tal knappas in så återställ textfältet
                              btnCheckButton.setSelection(false);
                              spinner.setSelection(DEFAULTBREAKTEMP);
                              lblNewLabel_2.setText(""+DEFAULTBREAKTEMP);
                           }
                        }
                        else if(!source.getSelection())  {
                           btnCheckButton.setSelection(false);
                           spinner.setEnabled(true);
                           spinner.setSelection(DEFAULTBREAKTEMP);
                           lblNewLabel_2.setText(""+DEFAULTBREAKTEMP);
                           arduinoSerial.setBreakTemp(DEFAULTBREAKTEMP);
                        }

                     }
                  });
                  btnCheckButton.setLocation(5, 0);
                  btnCheckButton.setSize(68, 27);
                  btnCheckButton.setFont(SWTResourceManager.getFont("Segoe UI", 9, SWT.BOLD));
                  btnCheckButton.setBackground(SWTResourceManager.getColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT));
                  btnCheckButton.setText("Markera");
                  
                        lblNewLabel_2.setBackground(SWTResourceManager.getColor(0, 0, 0));
                        lblNewLabel_2.setForeground(SWTResourceManager.getColor(240, 230, 140));
                        lblNewLabel_2.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.BOLD));
                        lblNewLabel_2.setBounds(75, 0, 49, 27);
                        lblNewLabel_2.setText("100");
                        
                              CLabel label_1 = new CLabel(composite, SWT.NONE);
                              label_1.setText(" [grader Celsius]");
                              label_1.setForeground(SWTResourceManager.getColor(240, 230, 140));
                              label_1.setFont(SWTResourceManager.getFont("Segoe UI", 9, SWT.BOLD));
                              label_1.setBackground(SWTResourceManager.getColor(0, 0, 0));
                              label_1.setAlignment(SWT.CENTER);
                              label_1.setBounds(123, 0, 101, 27);

      //----------------------------------------------------------------------------Info.skylt Rubrik Aktuell Mätdata
      CLabel lblAktuellMtdata = new CLabel(shlNtc, SWT.BORDER | SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.CENTER);
      lblAktuellMtdata.setForeground(SWTResourceManager.getColor(0, 0, 128));
      lblAktuellMtdata.setBackground(SWTResourceManager.getColor(SWT.COLOR_INFO_BACKGROUND));
      lblAktuellMtdata.setFont(SWTResourceManager.getFont("Courier", 17, SWT.BOLD));
      lblAktuellMtdata.setBounds(10, 297, 433, 35);
      lblAktuellMtdata.setText("A k t u e l l  M \u00E4 t d a t a");

      //----------------------------------------------------------------------------Info.skylt Rubrik Temperatur [Celsius]
      CLabel lblTemperatur = new CLabel(shlNtc, SWT.NONE);
      lblTemperatur.setForeground(SWTResourceManager.getColor(240, 230, 140));
      lblTemperatur.setBackground(SWTResourceManager.getColor(0, 0, 0));
      lblTemperatur.setFont(SWTResourceManager.getFont("Segoe UI", 12, SWT.BOLD));
      lblTemperatur.setAlignment(SWT.CENTER);
      lblTemperatur.setBounds(10, 338, 182, 34);
      lblTemperatur.setText("Temperatur [Celsius]");

      //----------------------------------------------------------------------------Info.skylt Rubrik NTC [ohm]
      CLabel lblNtcohm = new CLabel(shlNtc, SWT.NONE);
      lblNtcohm.setText("NTC [ohm]");
      lblNtcohm.setForeground(SWTResourceManager.getColor(240, 230, 140));
      lblNtcohm.setFont(SWTResourceManager.getFont("Segoe UI", 12, SWT.BOLD));
      lblNtcohm.setBackground(SWTResourceManager.getColor(0, 0, 0));
      lblNtcohm.setAlignment(SWT.CENTER);
      lblNtcohm.setBounds(238, 338, 205, 34);

      //----------------------------------------------------------------------------LED-display Temperatur
      LED_0.setText("");
      LED_0.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_0.setBounds(96, 378, 28, 44);

      LED_1.setText("");
      LED_1.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_1.setBounds(130, 378, 28, 44);

      LED_2.setText("");
      LED_2.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_2.setBounds(164, 378, 28, 44);

      //----------------------------------------------------------------------------LED-display NTC
      LED_3.setText("");
      LED_3.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_3.setBounds(238, 378, 28, 44);

      LED_4.setText("");
      LED_4.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_4.setBounds(278, 378, 28, 44);

      LED_5.setText("");
      LED_5.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_5.setBounds(313, 378, 28, 44);

      LED_6.setText("");
      LED_6.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_6.setBounds(347, 378, 28, 44);

      LED_7.setText("");
      LED_7.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_7.setBounds(381, 378, 28, 44);

      LED_8.setText("");
      LED_8.setBackground(SWTResourceManager.getColor(0, 0, 0));
      LED_8.setBounds(415, 378, 28, 44);
   }
}



Textfils-klassen...

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
/*
 * Klassen representerar en öppnad textfil att skriva data till
 */
public class TextFile {
   private PrintWriter outputStream = null;
   private String textFileName = "data.txt";

   /*
    * Konstruktor till ett objekt av typen TextFileOutput.
    * Ett objekt av denna klass skapas i klassen som innehåller main
    */
   public TextFile() {

   }

   /*
    * En fil öppnas och namnges enligt vad som angivits i GUI eller default
    */
   public void createTextFile() {      
      try {
         outputStream = new PrintWriter(new FileOutputStream(this.getTextFileName()));
      }
      catch(FileNotFoundException e){
         System.out.println("Error opening the file");
         System.exit(0);
      }
   }

   /*
    * Metod som skriver data till en öppnad och namngiven textfil.
    */
   public void writeToFile(String data)
   {
      outputStream.println(data);
      outputStream.flush();      
   }

   /*
    * Metod som stänger ned en öppnad textfil
    */
   public void closeFileOutputStream()
   {
      outputStream.close();
   }

   /*
    * I GUI kan textfilen dit data skrivs namnges.
    * Default är data.txt
    */
   public void setTextFileName(String name) {
      textFileName = name;
   }

   /*
    * Returnerar aktuellt namn på datatextfilen där data ska lagras
    */
   public String getTextFileName() {
      return textFileName;
   }
}



Temperatur-displayen (NTC är nästan samma fast med 6 siffror)...

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
/**
 * @author 4kTRB
 *
 * Denna klass implementerar en digital temperatur-display i form av en
 * tresiffrig 7-segments LED
 */
public class TempDisplay{

   private DigitDisplay LED100;
   private DigitDisplay LED10;
   private DigitDisplay LED1;
   private String displayStringLED100;
   private String displayStringLED10;
   private String displayStringLED1;
   private static final int BLANK = 10;
   private static final int MINUS = 11;

   /*
    * Konstruktor för TempDisplay-objekt.
    * Skapar en ny temperaturdisplay som representerar tre 7-segments LED
    * Klassen har metoder för att hantera vad som ska visas i temperaturdisplayen
    * Själva displayen finns i GUI i form av bilder inlagda i CLabels.
    */
   public TempDisplay() {
      LED100 = new DigitDisplay();            // 100-tal
      LED10 = new DigitDisplay();               // 10-tal
      LED1 = new DigitDisplay();               // 1-tal
   }
   /**
    * Åtkomst av de individuella 7-segments LED
    * @return
    */
   public int getLED100Value() {
      return LED100.getValue();
   }
   public int getLED10Value() {
      return LED10.getValue();
   }
   public int getLED1Value() {
      return LED1.getValue();
   }
   /*
    * Sätter temperaturen på displayen
    * Displayen i GUI ändras ej. GUI har en egen metod
    * för detta.
    */
   public void setTempValue(int temp) {      
      int length = String.valueOf(temp).length();
      if(temp<0) {                           // minusgrader
         length = length-1;                     // räkna bort minustecken
         temp = Math.abs(temp);
         if(length==1) {
            LED100.setValue(BLANK);
            LED10.setValue(MINUS);      
            LED1.setValue(temp);
         }
         if(length==2) {
            LED100.setValue(MINUS);
            LED10.setValue(temp/10);
            LED1.setValue(temp%10);
         }         
      }
      else {
         if(length==1) {
            LED100.setValue(BLANK);
            LED10.setValue(BLANK);      
            LED1.setValue(temp);
         }
         if(length==2) {
            LED100.setValue(BLANK);
            LED10.setValue(temp/10);
            LED1.setValue(temp%10);
         }
         if(length==3) {
            LED100.setValue(temp/100);
            LED10.setValue(temp%100/10);
            LED1.setValue(temp%100%10);
         }
      }
   }

   /*
    * Returnerar aktuell temperatur som visas på displayen
    */
   public String getTempValue() {
      displayStringLED100 = ""+LED100.getDisplayValue();
      displayStringLED10 = ""+LED10.getDisplayValue();
      displayStringLED1 =  ""+LED1.getDisplayValue();
      return displayStringLED100+displayStringLED10+displayStringLED1;
   }
}



och så klassen som representerar en 7-seg LED...

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
/**
 * @author 4kTRB
 * Klassen representerar en digital nummerdisplay som kan hålla en siffra 0-9
 */
public class DigitDisplay {
   private int tempValue;
   /*
    * KOnstruktor för objekt av klassen TempDigitDisplay
    */
   public DigitDisplay() {
      tempValue = 10;
   }
   /*
    * Returnera displayens aktuella värde.
    */
   public int getValue() {
      return tempValue;
   }
   /*
    * Sätter displayen till önskat värde.
    */
   public void setValue(int replacementValue) {
      tempValue = replacementValue;
   }
   /*
    * Returnerar displayvärdet i form av en sträng.
    */
   public int getDisplayValue() {
      return tempValue;
   }
}

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

Textfilen och eclipse-konsolen.

Ska börja labba med Arduinon och en dallas-tempsensor snart.
Måste sätta mig in i lite basic C++ vad det verkar som... :cry:

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

Den där Dallas-sensorn är inte gjord för högre temperaturer
så jag får tänka om. Funderade på en PT100
https://www.energibutiken.se/sv/29-pt100
Det blir mer pyssel med elektronik runt elementet.
https://www.instructables.com/id/Reading-Temperature-From-PT100-Using-Arduino/

Edit:
Eller en sån här

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

Implementerade en timer.
Måste nog lägga till ett val där tid och temperatur finns med i en separat fil.
Sedan om jag vill ha en avsvalningskurva så måste elementet först värmas
och sedan logga tempen tills det svalnat.
:)

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

Labbade med att försöka tända och släcka den inbyggda lysdioden på Arduino UNO-kortet
och upptäckte några programvaruförbättringar att applicera på NTC-projektet.
Varje gång man klickar på switch-knappen tänds eller släcks lysdioden.
Det här är ju ganska coolt tycker jag. :)

Kör den här koden på Arduinon:
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(19200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  } 
}
void loop() {
  if (Serial.available() > 0) {
    if (Serial.read()) {                  // om en boolean true skickats så LED = High
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else {
      digitalWrite(LED_BUILTIN, LOW);
    }
  }
}


Skapade ett gui med 3 knappar...

Bilaga:
LED_controller_GUI.png


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;

public class AppWin {
   private static final int DEFAULTBAUDRATE = 19200;
   private static AppWinThreadController threadController;
   private static Thread threadControllerThread;
   private static AppWinSerial appwinSerial;

   private static void setUpSerial() {
      appwinSerial = new AppWinSerial();
      appwinSerial.setBaudRate(AppWin.DEFAULTBAUDRATE);      // default baudrate för kommunikation med Arduino
   }

   public static AppWinSerial getAppWinSerial() {
      return appwinSerial;
   }

   /**
    * Launch the application.
    * @param args
    */
   public static void main(String[] args) {
      Display display = Display.getDefault();
      Shell shell = new Shell();
      shell.setSize(239, 169);
      shell.setLocation(800, 200);
      shell.setText("SWT Application");

      AppWin.setUpSerial();

      //----------------------------------------------------------------START
      Button btnNewButton = new Button(shell, SWT.NONE);
      btnNewButton.addMouseListener(new MouseAdapter() {
         @Override
         public void mouseDown(MouseEvent e) {
            if(threadController == null) {
               threadController = new AppWinThreadController();
               threadControllerThread = new Thread(threadController);      // låt trådkontrollern bli en tråd
               try {
                  threadControllerThread.start();                     // starta upp Seriekommunikationen
               }
               catch(IllegalThreadStateException itse) {
                  System.out.println("IllegalThreadStateException");
               }
            }            
         }});
      btnNewButton.setBounds(10, 32, 75, 25);
      btnNewButton.setText("START");

      //----------------------------------------------------------------EXIT
      Button btnNewButton_1 = new Button(shell, SWT.NONE);
      btnNewButton_1.addMouseListener(new MouseAdapter() {
         @Override
         public void mouseUp(MouseEvent e) {
            if (threadControllerThread != null) {
               appwinSerial.setStopSignal();
               try {                                 
                  threadControllerThread.interrupt();         
               }
               catch(SecurityException se) {
                  se.printStackTrace();
               }            
               shell.close();
               display.close();
               try {
                  this.finalize();
               } catch (Throwable e1) {
                  e1.printStackTrace();
               }
            }
            System.out.println("Exit!");
            System.exit(0);            
         }
      });
      btnNewButton_1.setBounds(10, 82, 75, 25);
      btnNewButton_1.setText("EXIT");

      //----------------------------------------------------------------Switcha LED
      Button btnSwitchaLed = new Button(shell, SWT.NONE);
      btnSwitchaLed.addMouseListener(new MouseAdapter() {
         @Override
         public void mouseUp(MouseEvent e) {            
            if (threadControllerThread != null) {
               appwinSerial.toggleSignal();               // toggla styrvillkoret för LED
               try {                                 
                  threadControllerThread.interrupt();         
               }
               catch(SecurityException se) {
                  se.printStackTrace();
               }
            }
         }
      });
      btnSwitchaLed.setBounds(103, 32, 75, 25);
      btnSwitchaLed.setText("Switcha LED");

      shell.open();
      shell.layout();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
   }
}



Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.io.DataOutputStream;
import java.io.IOException;
import com.fazecast.jSerialComm.SerialPort;

/*
 * Klassen representerar en seriell com-port där Arduino finns ansluten.
 */
public class AppWinSerial implements Runnable{
   private int baudRate;                        // serieportens i GUI valda överföringshastighet
   private SerialPort serialPort = null;             
   private DataOutputStream javaToArduinoOut = null;
   private boolean stopSignal;   
   private boolean toggle;

   /*
    * Konstruktor till objekt av typen AppWinSerial
    */
   public AppWinSerial() {
      this.stopSignal = false;
      this.toggle = false;
   }

   public void run() {
      try {
         startSerial();
      } catch (InterruptedException e) {
         System.out.println("InterruptedException in Serial run()");
      }
   }
   /*
    * Skiftar flaggan som använd för att avgöra
    * om LED ska tändas eller släckas
    */
   public void toggleSignal() {
      if(this.toggle)
         this.toggle = false;
      else
         this.toggle = true;
   }
   
   public boolean getToggleSignal() {
      return this.toggle;
   }
   /*
    * Om denna flagga sätts true så indikeras att
    * kommunikationen med Arduino ska avslutas
    */
   public void setStopSignal() {
      this.stopSignal = true;
   }
   
   public boolean getStopSignal() {
      return this.stopSignal;
   }
   /*
    * Baudrate Default är 9600bps
    * Metoden sätter värdet
    */
   public void setBaudRate(int baudrate) {
      baudRate = baudrate;
   }
   /*
    * Returnerar aktuellt satt baudrate
    */
   public int getBaudRate() {
      return baudRate;
   }
   /*
    * Påbörjar en kontakt med den COM-port som Arduino är ansluten till och
    * Denna metod anropas vid tryck på knappen START i GUI.
    */
   private void startSerial() throws InterruptedException {
      boolean flag = this.comPortSetUp();            // konfigurerar porten
      if(flag) {
         this.LEDcontroller();
      }         
   }
   /*
    * Metod. Scannar av vilka COM-portar som finns tillgängliga och om Arduino är ansluten
    * till någon av dessa. Port med Arduino öppnas och porten konfigureras.
    */
   public boolean comPortSetUp() throws InterruptedException {
      boolean ArduinoUnoFlag = false;
      int ArduinoUnoIndex = -1;   
      SerialPort[] sp = SerialPort.getCommPorts();      
      System.out.println("Antal tillgängliga seriella portar: "+sp.length);            
      for(int j=0;j<sp.length;j++) {
         System.out.println(sp[j].getDescriptivePortName()+" öppen = "+sp[j].isOpen());
         if(sp[j].getDescriptivePortName().contains("Arduino Uno")){
            ArduinoUnoFlag = true;
            ArduinoUnoIndex = j;
         }
      }
      if(ArduinoUnoFlag) {
         serialPort = sp[ArduinoUnoIndex];   
         if(serialPort.isOpen()) {
            serialPort.closePort();                      // Close connection
         }
         if(!serialPort.isOpen()) {
            serialPort.openPort();                         // Open connection
         }         
         Thread.sleep(500);
         serialPort.clearDTR();                           // Arduino Reset         
         serialPort.setBaudRate(this.getBaudRate());
         serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 2500, 0);

         System.out.println(serialPort.getDescriptivePortName()+ " öppnad = "+serialPort.isOpen());         
      }      
      return ArduinoUnoFlag;
   }

   /*
    *
    */
   public void LEDcontroller() {   
      try
      {   
         javaToArduinoOut = new DataOutputStream(serialPort.getOutputStream());            
      }
      catch(IllegalStateException  e)
      {
         e.printStackTrace();
      }
      while(true)
      {
         if(Thread.interrupted()) {               
            if(this.stopSignal) {                     // denna tråd har blivit avbruten
               break;                              // för att avsluta
            }
            try {                                             
               if(this.toggle) {                     // för att toggla LED
                  System.out.println("SLÄCK");
                  javaToArduinoOut.writeBoolean(false);
               }
               else {
                  System.out.println("TÄND");
                  javaToArduinoOut.writeBoolean(true);
               }
            }                                        
            catch(IOException e) {   
               e.printStackTrace();
            }
         }
      }                                          // end while         
      if(serialPort.isOpen()) {
         serialPort.closePort();                        // koppla ned com-porten
      }
      try {
         javaToArduinoOut.close();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}


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

public class AppWinThreadController implements Runnable {
   private Thread   arduinoSerialThread;
   private static final int   TIMER_INTERVAL = 500;
   private AppWinSerial appwinSerial;
   
   public AppWinThreadController() {

   }
   public void run() {
      appwinSerial = AppWin.getAppWinSerial();
      arduinoSerialThread = new Thread(appwinSerial);      // låt appwinSerial bli en tråd
      Thread.currentThread().setName("ControllerThread");
      arduinoSerialThread.start();                     
      while(true) {
         try {
            Thread.sleep(TIMER_INTERVAL);
         }
         catch(InterruptedException ie) {            
            arduinoSerialThread.interrupt();
         }
         if(Thread.interrupted() && appwinSerial.getStopSignal()) {
            arduinoSerialThread.interrupt();
            break;
         }
      }
   }
}


Författare:  kodar-holger [ 21.28 2019-01-26 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
    if (Serial.read()) {


Men Serial.read returnerar väl en char och då är den där ju true för nästan allt. Eller?

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

Bra fråga, jag blev tvungen att testa.

Fungerar ej
javaToArduinoOut.writeDouble(47);

Fungerar dåligt
javaToArduinoOut.writeInt(-15);


Det jag skickar till Arduinon är en boolean och jag skickar ju inget annat så det fungerar ändå.
Men helt klart så får jag ta och filtrera lite bättre i Arduinokoden.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
   try {                                             
               if(this.toggle) {                     // för att toggla LED
                  System.out.println("SLÄCK");
                  javaToArduinoOut.writeBoolean(false);
               }
               else {
                  System.out.println("TÄND");
                  //javaToArduinoOut.writeBoolean(true);
                  javaToArduinoOut.writeInt(-15);
               }
            }                                        
            catch(IOException e) {   
               e.printStackTrace();
            }
         }



Du kanske har förslag på hur villkoret ska se ut i iffen?

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

Bytte mot det här och det känns ju bättre faktiskt.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
try {                                             
               if(this.toggle) {                     // för att toggla LED
                  System.out.println("SLÄCK");
                  javaToArduinoOut.writeByte(0);
               }
               else {
                  System.out.println("TÄND");
                  javaToArduinoOut.writeByte(1);
               }
            }                                        
            catch(IOException e) {   
               e.printStackTrace();
            }


och

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
// the setup function runs once when you press reset or power the board
int data;
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(19200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  } 
}
void loop() {
  if (Serial.available() > 0) {
    data = Serial.read();
    if (data == 1) {                               // om en boolean true skickats så LED = High
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else {
      digitalWrite(LED_BUILTIN, LOW);
    }
  }
}

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

Bilaga:
MAX31856_Sch_000.png
Maxim har några ganska lika IC för termoelement, MAX31855, MAX31856, MAX31865
Jag caddade ett kort till en MAX31856 https://www.maximintegrated.com/en/products/sensors/MAX31856.html
Lite nytt att ge sig på ytmonterat men det verkar inte finnas något val när det gäller den IC:n.
Cadda går väl an men att montera blir nog inte lätt för en ovan.
Kapseln är en 14-Pin TSSOP. Syns ju knappt!

MAX31856 har olika tabeller för att korrigera kurvor för en mängd element,
Citera:
A lookup table (LUT) stores linearity correction data for several types of thermocouples (K, J, N, R, S, T, E, and B).

plus en del andra finesser. Kommunikationen sker över SPI.

Bilaga:
MAX31856_PCB_000.png

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

MAX31865 är gjord för RTD, alltså den ger ingen spänning ut som ett termoelement
utan det är resistansen som varierar. De har blivit väldigt poppis upp till 600 grader
läste jag. Så jag funderade på om inte det vore fint med ett sånt kort också.
4-trådsmätning stöder chippet. Lite fler pinnar och annan kapsel.

Det blev en del mixter i CAD-programmet men efter att ha studerat databladet och ritningar
på kapseln så hamnade jag nog ganska nära.

TQFN20 heter kapseln och är 5x5mm. Jag är inte helt säker på hur FORCE2-pinnen ska anslutas
men antar att det är till skärmstrumpan?

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;
   }   
}

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

Kom igång med projektet efter en tids uppehåll med blåskärm i windows 10.
Och efter att ha laddat hem Eclipse, WindowsBuilder och Arduino-pluginnet på nytt och förmodligen gjort allt mer rätt
den här gången så fungerar allt så mycket smidigare.

På något sätt tror jag Arduino ide lagt till något för info om USB-porten då den alltid dök upp med namnet Arduino inbakat.
Nu verkar den alltid koppla upp sig med COM3 men eftersom jag inte vet om det alltid är så så valde jag att ha en lista
med de portar som finns och sedan får man klicka på den port man misstänker hör till Arduino.

Man kanske skulle kunna ha kod på Arduinon och pinga men då måste man ju göra det på alla portar och dessutom öppna dom
och sätta upp scannern och DataOutputStream först.

På något sätt måste jag i alla fall ta reda på om det är Arduino som finns på den porten annars
kan det hända att allt ser bra ut och den verkar uppkopplad men när man väl kör igång med
kommunikationen så dyker programmet.

Så här ser guit ut nu i vilket fall och klickar jag på rätt port så fungerar det bra.

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

Hittade en variant som går ut på att antalet tillgängliga portar scannas av och så
kopplar man bort resp. ansluter USB-kontakten och när kodsnutten känner av
förändringen i antal portar så presenteras den nyupptäckta porten som Arduino.

Labbade med com-portsinställningar i enhetshanteraren och upptäckte att det inte
fungerar att ändra comports-nummer medans Arduino är ansluten och tro att det ska
gå att koppla upp sig sedan. Det fungerar om man drar ur USB-kontakten och sedan
ansluter igen. Vet inte om det kanske har att göra med com.fazecast.jSerialComm?

Författare:  Zhorts [ 07.52 2019-04-26 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Att byta nummer på COM-porten under löpande körning är troligen ett Windows-problem... Windows är inte överdrivet bra på att hantera CAN-portar, och mellansteget med USB gör inte saken bättre.

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

Tror mig hittat en lösning för att hitta rätt com-port att koppla upp programmet emot.

Det hela går ut på att skanna av vilka portar som är anslutna och sedan koppla ifrån, eller dra ut, Arduino-kontakten.
När skillnaden i antal portar analyserats så jämför jag 2 stackar och den port som inte fanns med är uppenbarligen
den som plockades bort, alltså den till Arduino.

Den porten presenteras i en klickbar label som COM3 i exemplet nedan. Klickar man nu på den labeln så
öppnas kommunikationen och in och utdataström konfigureras.

Programmet är startat...
Bilaga:
java_GUI_100.png

START för uppkoppling är aktiverad...
Bilaga:
java_GUI_101.png

USB-kontakten är bortkopplad och tillbakasatt...
Bilaga:
java_GUI_102.png

Labeln med COM 3 är klickad på...
Bilaga:
java_GUI_103.png


Här är den kod som kör som en tråd så länge programmet är igång.
Det finns en del kontroll i händelsehanterarna till START och den klickbara labeln
så inte tråden startas på nytt utan att det behövs plus för att undvika några andra problem
för handhavandefel.
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import com.fazecast.jSerialComm.SerialPort;

/*****************************************************************************************************
 *    Ett objekt av denna klass körs som en tråd tills hela programmet avslutas.
 *  Klassen sköter om uppkoppling och nedkoppling av seriekommunikationen med Arduino.
 *    Genom att utföra avbrott i tråden som kör trådkontrollern så kopplas porten ned
 *  Detta utför till exempel då knappen EXIT aktiveras.
 *  Skapar ett scannerobjekt för att läsa data från Arduino
 *  Skapar en DataOutputStream för att skriva till Arduino 
 * 
 *  Metoder som ingår i klassen:
 * 
 *  public static void comPortConnect()
 *  public void comPortSetUp()
 *  public static boolean getComPortSetUpFlag()
 *  private void fillStackA()
 *  private void fillStackB()
 *  private void comPortCloseDown()
 *   public static int getBaudRate()
 *   public static SerialPort getSerialPort()
 *   public String toString()
 *****************************************************************************************************/

public class Test implements Runnable {
   private static SerialPort serialPort;                   // instans skapas i metoden comPortSetUp()
   private static int baudRate;                        // serieportens i GUI valda överföringshastighet
   private static SerialPort[] sp;   
   private static StringStack stackA;
   private static StringStack stackB;
   private static String id;
   private static boolean found;
   private static boolean comPortSetUpFlag;
   public Test(int baudrate) {
      baudRate = baudrate;
      stackA = new StringStack();
      stackB = new StringStack();
      id = "";
      found = true;
   }
   /*
    * En tråd av denna klass kopplar upp Arduino via den serieport där den finns ansluten.
    * När tråden avbryts, sker vid EXIT i GUI, så kopplas porten ned.
    * @see java.lang.Runnable#run()
    */
   public void run() {
      comPortSetUp();      
      while(true) {
         if(Thread.interrupted()) {                                                                                             
            try {
               Thread.sleep(500);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }            
            comPortCloseDown();   
            System.out.println("Tråden " + toString() + " är avslutad");
            break;                     
         }
      }
   }
   /*
    * En lista med com-portar finns att välja bland där en av dessa är den identifierade i
    * Arduino-porten. Metoden comPortSetUp() i denna klass identifierar porten.
    * När identifieringen gjorts utförs ett försök att öppna den via ett musklick i GUI som
    * startar denna metod. Metoden låser den klickbara labeln med portnamnet så metoden inte
    * körs mer än en gång. Endast om USB-kontakten inte var ansluten låses labeln upp och
    * man får starta med comPortSetUp() på nytt.
    * Vidare konfigureras portens baudrate och timeouts samt att Scannern och DataOutPutStream
    * aktiveras. En mjukvarureset av Arduino utförs genom att lägga DTR-linan låg en kort stund.
    */
   public static void comPortConnect() {
      NTC.setLabelConnectArduinoPortActiveFlag(false);   // förhindra att Com-ports-label är klickbar
      sp = SerialPort.getCommPorts();
      for(int k=0;k<sp.length;k++) {                  // leta reda på Arduino-porten
         if(sp[k].getSystemPortName().equals(id)) {
            serialPort = sp[k];
            break;
         }
      }
      if(serialPort != null) {
         serialPort.openPort();
         serialPort.setBaudRate(baudRate);
         serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 2500, 0);
         // värdet 2500 [ms] måste ökas om processen som Arduino mäter på är långsam.
         NTC.newArduinoScanIn();
         NTC.newjavaToArduinoOut();
         if(!serialPort.isOpen()) {
            serialPort.openPort();                   // Open connection
            System.out.println("port is open = "+ serialPort.isOpen());
         }
         if(serialPort.isOpen()) {
            NTC.setArduinoConnectedFlag(serialPort.isOpen());
            System.out.println("port is open = "+ serialPort.isOpen());
         }               
         try {
            Thread.sleep(500);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         serialPort.clearDTR();                           // Arduino Reset
         System.out.println("Arduino är Uppkopplad");
         System.out.println("Scanner och DataOutputStream är konfigurerade");
         NTC.getDisplay().asyncExec (new Runnable () {         
            public void run () {                         // Informativ text i GUI om com-portens baudrate
               NTC.changeComPortLabel("Arduino är uppkopplad med " + Test.getBaudRate() + " bts");
               NTC.setArduinoConnectedFlag(true);
            }
         });
      }
      else {                                          // om usb-kontakten inte var ansluten
         NTC.getDisplay().syncExec (new Runnable () {            
            public void run () {
               NTC.changeComPortLabel("Anslut USB-kontakten\noch tryck START på nytt");
               NTC.getLabelConnectArduinoPort().setText("COM PORT");
            }
         });
      }         
   }
   /*
    *  Skannar av vilka com-portar som finns tillgängliga och i GUI presenteras en av dessa
    *  som den aktuella Arduino-porten. Arduino-porten identifieras genom att ta ur och sätta
    *  i den fysiska USB-kontakten.
    */
   public static void comPortSetUp() {
      comPortSetUpFlag = true;
      found = true;
      stackA.clearStack();
      stackB.clearStack();
      NTC.getDisplay().syncExec (new Runnable () {            
         public void run () {
            NTC.changeComPortLabel("Dra ur och Sätt i USB-kontakten\nVälj sedan port från fältet nedan");            
         }
      });
      fillStackA();                           // fyll stackA med anslutna portar
      while(found) {                           // invänta att Arduino kopplas bort eller läggs till
         try {
            Thread.sleep(100);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         fillStackB();                           // fyll stackB med anslutna portar
         if(stackA.stackSize() > stackB.stackSize()) {   // om antal skiljer sig så jämför innehållet i stackA och stackB
            while(found) {
               id = stackA.pop();
               found = stackB.searchForString(id);
               if(!found) {
                  System.out.println("id = " + id);
                  NTC.getDisplay().syncExec (new Runnable () {   // presentera Arduino-porten         
                     public void run () {
                        NTC.getLabelConnectArduinoPort().setText(id);
                     }
                  });
                  NTC.setLabelConnectArduinoPortActiveFlag(true);   // tillåt att presentations-label med Arduino-porten är klickbar
               }
            }
         }
         if(stackB.stackSize() > stackA.stackSize()) {      // om antal skiljer sig så jämför innehållet i stackA och stackB
            while(found) {
               id = stackB.pop();
               found = stackA.searchForString(id);
               if(!found) {
                  System.out.println("id = " + id);
                  NTC.getDisplay().syncExec (new Runnable () {   // presentera Arduino-porten            
                     public void run () {
                        NTC.getLabelConnectArduinoPort().setText(id);
                     }
                  });
                  NTC.setLabelConnectArduinoPortActiveFlag(true);   // tillåt att presentations-label med Arduino-porten är klickbar
               }
            }
         }
      }
      System.out.println("Exit Comportsetup");
      comPortSetUpFlag = false;
   }
   /*
    * En flagga som visar om metoden comPortSetUp() exekveras.
    * Den används av START-knappen till denna trådkörning så man inte försöker
    * skapa och starta en ny tråd mitt under pågående set up.
    */
   public static boolean getComPortSetUpFlag() {
      return comPortSetUpFlag;
   }
   /*
    * Lägg upp alla anslutna com-portar på stackA
    */
   private static void fillStackA() {
      stackA.clearStack();
      sp = SerialPort.getCommPorts();
      for(int j=0;j<sp.length;j++) {                     
         NTC.setComPortId(j);
         NTC.getDisplay().syncExec (new Runnable () {            
            public void run () {                     
               stackA.push(sp[NTC.getComPortId()].getSystemPortName());                                          
            }
         });                                                
      }
   }
   /*
    * Lägg upp alla anslutna com-portar på stackB   
    */
   private static void fillStackB() {                        
      stackB.clearStack();
      sp = SerialPort.getCommPorts();
      for(int j=0;j<sp.length;j++) {                        
         NTC.setComPortId(j);
         NTC.getDisplay().syncExec (new Runnable () {            
            public void run () {                     
               stackB.push(sp[NTC.getComPortId()].getSystemPortName());                                          
            }
         });                                                
      }
   }

   /*
    * Stänger porten. Sker först när knappen EXIT i GUI aktiveras som då
    * avbryter run-metoden i denna klass
    */
   private void comPortCloseDown() {
      if(serialPort != null)
         serialPort.closePort();
      NTC.setArduinoConnectedFlag(false);                     
   }

   /*
    * Returnerar aktuellt satt baudrate
    */
   public static int getBaudRate() {
      return baudRate;
   }   
   public static SerialPort getSerialPort() {
      return serialPort;
   }
   public String toString() {
      return "ComPortConnect";
   }
}


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

Hur fungerar det med t.ex. en USB-mus ansluten,
com.fazecast.jSerialComm.SerialPort listar inte att
den används?

Författare:  4kTRB [ 22.42 2019-05-06 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Försöker få bättre precision i bryggan som ska mäta NTC-motståndet.
Som det ser ut nu diffar det aningen för mycket från en rät linje.

Så jag testade att nolla bryggan med ett 680ohms motstånd och sedan anslöt jag ett antal
uppmätta motstånd ända ned till ett 47 ohms.
I plotten syns den svarta linjen med punkter motsvarande de värden jag anslutit.
Jag kan alltså inte interpolera med en rät linje så därför är jag inne på att använda ett
polynom då det finns bra stöd för detta från Apache mattebibliotek som jag också
laddade hem.

I första exemplet tas konstanterna till f(x) = a + bx fram, alltså en rät linje.
I andra exemplet en kurva på formen f(x) = a + bx + cx^2 som blir i princip den samma
som kurvan v(x) = -0.0458x^0.6188 + 2.582 vilket är den matteprogrammet kom fram till (pwrfit).
Jag kollade lite på hur den kurvan tas fram men det blir en del matte som man måste plöja igenom
så det blir bra mycket enklare att använda Apache-biblioteket org.apache.commons.math3.fitting.PolynomialCurveFitter

Jag ska också ta och testa med att se hur bra det kan bli med enbart 3 olika motståndsvärden, 47, 390 och 680 som exempel.
Det underlättar att bara behöva trimma in kurvan med 3 motstånd och jag har inte extrema krav på att kurvan ger rätt
motståndsvärde men lite bättre än en diff på 50 ohm vore kul att få till.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.text.DecimalFormat;
import java.util.Locale;
import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;

/*
 * f(x) = a + bx + cx^2
 */
public class Exempel {
   private static Exempel exempel;
   private PolynomialCurveFitter pcf;
   private double[] coeff;   
   private WeightedObservedPoints obs = new WeightedObservedPoints();
   private Locale s = Locale.getDefault();
   DecimalFormat myFormatter = new DecimalFormat("##0.##E0");
   
   public static void main(String[] args) {      
      Locale.setDefault(Locale.ENGLISH);
      exempel = new Exempel();
      exempel.data();
      exempel.show();
   }
   public void data() {
      obs.add(680, 0);
      obs.add(467, 0.513);
      obs.add(391, 0.762);
      obs.add(47.3, 2.087);      
   }

   public void show() {
      pcf = PolynomialCurveFitter.create(2);
      coeff = pcf.fit(obs.toList());
      for(int i=0;i<coeff.length;i++) {
         if(i == 0)
            System.out.printf(s,"a = " + myFormatter.format(coeff[i])+"\n");   
         if(i == 1)
            System.out.printf(s,"b = " + myFormatter.format(coeff[i])+"\n");   
         if(i == 2)
              System.out.printf(s,"c = " + myFormatter.format(coeff[i])+"\n");            
      }
   }
}

Output:
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
a = 2.3084E0
b = -4.7609E-3
c = 2.0056E-6

Författare:  4kTRB [ 00.27 2019-05-07 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Här har jag lagt in 7 punkter och använt 3 av dessa värden för att generera polynomet.
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
   public void data() {
      obs.add(680, 0);
      obs.add(391, 0.762);
      obs.add(47.3, 2.087);      
   }

Resultat:
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
a = 2.305E0
b = -4.6992E-3
c = 1.9258E-6


Som synes diffar det som mest från 450 - 560 ohm men inte så mycket, acceptabelt tycker jag.

Författare:  Zhorts [ 07.42 2019-05-07 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Ett tips: För att snabbt och enkelt utvärdera hur bra en kurva passar en annan: Ta den ena minus den andra, och plotta felet. Procentuellt eller absolut, beroende på vilken sida man vaknade på.

Ett andragradspolynom ser ju ut att duga fint - beroende på exakt vad du ska mäta, naturligtvis...

Författare:  4kTRB [ 08.17 2019-05-07 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Jag funderar på om det är något som skulle kunna förbättras i kretsen jag använder?
Kanske matcha motstånden i förstärkarna eller använda andra förstärkare?
Jag använder inte AD822 som i schemat men i övrigt stämmer värdena.
1V genererar jag från en spänningsdelare med en 7805 som regulator och den
håller spänningen bra. Om det är 1V eller 1.01V spelar ingen roll för hur olinjärt det blir.

Författare:  4kTRB [ 17.57 2019-05-09 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Så här kan det se ut efter att ha mätt upp bryggan med 3 motstånd, 680, 390 och 47 ohm.

Använder mig av klassen Polynomial för ändamålet.

Ska snart börja labba med styrning av värmeelement.
Jag adderade en funktion för att kontinuerligt mäta spänningen från bryggan,
en voltmeter helt enkelt.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
/*
 * Klassen används för att ta fram ett andragradspolynom
 * på formen A + Bx + Cx^2
 *
 */
public class Polynomial {
   private double A;
   private double B;
   private double C;
   private PolynomialCurveFitter pcf;
   private double[] constants;   
   private WeightedObservedPoints obs;
   
   public Polynomial() {
      A = B = C = 0;
      pcf = PolynomialCurveFitter.create(2);
      obs = new WeightedObservedPoints();
   }

   public void calcPolynomialConstants() {
      constants = pcf.fit(obs.toList());
      for(int i=0;i<constants.length;i++) {
         if(i==0) {
            A = constants[i];
            System.out.println(constants[i]);
         }            
         if(i==1) {
            B = constants[i];
            System.out.println(constants[i]);
         }            
         if(i==2) {
            C = constants[i];
            System.out.println(constants[i]);
         }               
      }      
   }
   public void addPoint(double ohm, double volt) {
      obs.add(ohm, volt);
   }
   public void clearDataPoints() {
      obs.clear();
      A=B=C=0;
   }
   public double getConstA() {
      return A;
   }
   public double getConstB() {      
      return B;
   }
   public double getConstC() {
      return C;
   }
}


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

Håller på att labba med ritfunktioner i Java därför att jag eventuellt ville ha med
grafen på den interpolerade kurvan och samtidigt plotta de uppmätta värdena i
realtid. Jag tänker mig en Canvas som kurvan ritas i med automatiskt satta markers
på x- och y-axel. Det är lite att lära in och en del läsning för att få det som jag vill.
Jag har inte ritat kurvan ännu men väl markers och axlar.
Jag använder i nuläget 3 klasser. Java kräver inte så hemskt mycket kod för det här.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import javax.swing.JFrame;
import java.awt.SystemColor;
import javax.swing.JButton;
import javax.swing.Box;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JSpinner;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Font;
import java.awt.Label;
import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

public class SwingWindow extends JFrame {

   private static final long serialVersionUID = 1L;
   public final int WINDOW_WIDTH = 515;
   public final int WINDOW_HEIGHT = 400;
   public final int SPINNER_X_STARTVALUE = 0;
   public final int SPINNER_Y_STARTVALUE = 0;
   private static JButton b0;
   private static JButton b1;
   private static JButton b2;
   private static JSpinner spinner_X;
   private static JSpinner spinner_Y;
   private static int spinner_X_value;
   private static int spinner_Y_value;
   private static Label label_Y;
   private static Label label_X;
   private JSpinner spinner_dX;
   private JSpinner spinner_dY;
   private static SwingWindow window;
   private static MyCanvas canvas;

   /**
    * Launch the application.
    */
   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               window = new SwingWindow();
               window.setVisible(true);
               canvas.setFocusable(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }

   /**
    * Create the application.
    */
   public SwingWindow() {
      super("Swing");      
      getContentPane().setBackground(SystemColor.window);
      getContentPane().setLayout(null);
      setForeground(SystemColor.textText);
      setBackground(SystemColor.window);
      setBounds(400, 100, WINDOW_WIDTH, WINDOW_HEIGHT);
      setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);   
      setUpGUI();
   }
   
   /**
    * Initialize the contents of the frame.
    */
   private void setUpGUI() {
      canvas = new MyCanvas();
      canvas.addFocusListener(new FocusListener() {
         @Override
         public void focusGained(FocusEvent e) {
            System.out.println("focus");         
         }
         @Override
         public void focusLost(FocusEvent e) {
            System.out.println("ur focus");   
         }   
      });
      getContentPane().add(canvas);
      JPanel panel = new JPanel();
      panel.setBackground(SystemColor.menu);
      panel.setBounds(10, 275, 474, 76);
      getContentPane().add(panel);
      panel.setLayout(null);
      
      Box horizontalBox_1 = Box.createHorizontalBox();
      horizontalBox_1.setBounds(20, 11, 438, 20);
      panel.add(horizontalBox_1);
      
      JLabel label_Ymax = new JLabel("Ymax");
      horizontalBox_1.add(label_Ymax);
      
      Component rigidArea = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea);
      
      spinner_Y = new JSpinner();
      spinner_Y.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_Y_value = (int) spinner_Y.getValue();
            label_Y.setText(String.valueOf(spinner_Y_value));
            canvas.setNewY(spinner_Y_value);
         }
      });
      horizontalBox_1.add(spinner_Y);
      
      Component rigidArea_5 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_5);
      
      JLabel label_Xmax = new JLabel("Xmax");
      horizontalBox_1.add(label_Xmax);
      
      Component rigidArea_1 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_1);
      
      spinner_X = new JSpinner();
      spinner_X.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_X_value = (int) spinner_X.getValue();
            label_X.setText(String.valueOf(spinner_X_value));
            canvas.setNewX(spinner_X_value);
         }
      });
      horizontalBox_1.add(spinner_X);
      
      Component rigidArea_8 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_8);
      
      JLabel label_dY = new JLabel("dY");
      horizontalBox_1.add(label_dY);
      
      Component rigidArea_6 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_6);
      
      spinner_dY = new JSpinner();
      horizontalBox_1.add(spinner_dY);
      
      Component rigidArea_7 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_7);
      
      JLabel label_dX = new JLabel("dX");
      horizontalBox_1.add(label_dX);
      
      Component rigidArea_9 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox_1.add(rigidArea_9);
      
      spinner_dX = new JSpinner();
      horizontalBox_1.add(spinner_dX);
      Box horizontalBox = Box.createHorizontalBox();
      horizontalBox.setBounds(20, 42, 438, 23);
      panel.add(horizontalBox);
      
      b0 = new JButton("Ny Skala");
      b0.setMaximumSize(new Dimension(120, 23));
      horizontalBox.add(b0);
      
      Component rigidArea_2 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox.add(rigidArea_2);
      
      b1 = new JButton("B");
      b1.setMaximumSize(new Dimension(120, 23));
      horizontalBox.add(b1);
      
      Component rigidArea_3 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox.add(rigidArea_3);
      
      b2 = new JButton("C");
      b2.setMaximumSize(new Dimension(120, 23));
      horizontalBox.add(b2);
      
      JButton b3 = new JButton("Avsluta");
      b3.setMaximumSize(new Dimension(120, 23));
      b3.addActionListener(new Listener().new Avbryt());
      
      Component rigidArea_4 = Box.createRigidArea(new Dimension(20, 20));
      horizontalBox.add(rigidArea_4);
      horizontalBox.add(b3);
      
      JPanel panel_1 = new JPanel();
      panel_1.setBackground(SystemColor.text);
      panel_1.setBounds(10, 252, 474, 20);
      getContentPane().add(panel_1);
      panel_1.setLayout(null);
      
      label_Y = new Label(String.valueOf(SPINNER_Y_STARTVALUE));
      label_Y.setFont(new Font("Arial Black", Font.BOLD, 15));
      label_Y.setAlignment(Label.CENTER);
      label_Y.setForeground(Color.BLACK);
      label_Y.setBackground(Color.YELLOW);
      label_Y.setBounds(10, 0, 106, 20);
      panel_1.add(label_Y);
      
      label_X = new Label(String.valueOf(SPINNER_X_STARTVALUE));
      label_X.setForeground(Color.BLACK);
      label_X.setFont(new Font("Arial Black", Font.BOLD, 15));
      label_X.setBackground(Color.YELLOW);
      label_X.setAlignment(Label.CENTER);
      label_X.setBounds(122, 0, 106, 20);
      panel_1.add(label_X);
   }
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.SystemColor;

public class MyCanvas extends Canvas{
   private static final long serialVersionUID = 1L;
   public final int CANVAS_WIDTH = 480;
   public final int CANVAS_HEIGHT = 240;
   public final int AXIS_MARGIN = 40;
   public final int SCALEX = 7;
   public final int SCALEY = 10;
   private int xAxisLength;
   private int yAxisLength;
   private int x1Axis;
   private int y1Axis;
   private int y2Axis;
   private int xAxisStartPoint;
   private int xAxisEndPoint;
   private int yAxisStartPoint;
   private int yAxisEndPoint;
   
   private int x1;
   private int y1;
   private int x2;
   private int y2;
   private Graphics2D g2;
   
   public MyCanvas() {
      x1 = 0;
      y1 = 0;
      x2 = 0;
      y2 = 0;
      setBackground(SystemColor.info);
      setBounds(10, 10, CANVAS_WIDTH, CANVAS_HEIGHT);
   }

   public MyCanvas(GraphicsConfiguration config) {
      super(config);
      // TODO Auto-generated constructor stub
   }

   public void paint(Graphics g) {            
      g2 = (Graphics2D) g;
      g2.drawLine(x1, y1, x2, y2);
      drawAxis();
      drawMarkers();
   }
   public void drawXMarker(int xpos) {
      super.getGraphics().drawLine(xpos, y2Axis-3, xpos, y2Axis+3);      
   }
   public void drawYMarker(int ypos) {
      super.getGraphics().drawLine(x1Axis-3, ypos, x1Axis+3, ypos);      
   }
   public void drawAxis() {
      
      xAxisLength = CANVAS_WIDTH - AXIS_MARGIN;            
      yAxisLength = CANVAS_HEIGHT - AXIS_MARGIN;            
      x1Axis = CANVAS_WIDTH - xAxisLength - AXIS_MARGIN/2;    
      y1Axis = CANVAS_HEIGHT - yAxisLength - AXIS_MARGIN/2;                                 
      y2Axis = CANVAS_HEIGHT - AXIS_MARGIN/2;
      xAxisStartPoint = x1Axis;
      xAxisEndPoint = xAxisLength + x1Axis;
      yAxisStartPoint = y2Axis;
      yAxisEndPoint = y1Axis;
      super.getGraphics().drawLine(xAxisStartPoint, yAxisEndPoint, xAxisStartPoint, yAxisStartPoint);   //y-axel
      super.getGraphics().drawLine(x1Axis, y2Axis, xAxisEndPoint, y2Axis);                     //x-axel
      
   }
   public int getXaxisLength() {
      return xAxisLength;
   }
   public int getYaxisLength() {
      return yAxisLength;
   }
   public int getXaxisStartPoint() {
      return xAxisStartPoint;
   }
   public int getYaxisStartPoint() {
      return yAxisStartPoint;
   }
   public int getXaxisEndPoint() {
      return xAxisEndPoint;
   }
   public int getYaxisEndPoint() {
      return yAxisEndPoint;
   }
   public void setX1(int x) {
      x1 = x;      
   }
   public void setY1(int y) {
      y1 = y;
   }
   public void setNewX(int x) {
      x1 = x2;
      x2 = x;
      super.getGraphics().drawLine(x1, y1, x2, y2);
   }
   public void setNewY(int y) {
      y1 = y2;
      y2 = y;
      super.getGraphics().drawLine(x1, y1, x2, y2);
   }
   private void drawMarkers() {
      int dx = getXaxisLength()/SCALEX;
      int dy = getYaxisLength()/SCALEY;
      int xs = getXaxisStartPoint();
      int xe = getXaxisEndPoint();
      int ys = getYaxisStartPoint();
      int ye = getYaxisEndPoint();
      System.out.println(String.valueOf(ys));
      System.out.println(String.valueOf(ye));
      System.out.println(String.valueOf(dy));
      for(int i=xs;i<=xe;i+=dx) {
         drawXMarker(i);
      }                        
      for(int i=ye;i<=ys;i+=dy) {
         drawYMarker(i);
      }
   }
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

public class Listener extends JFrame{
   private static final long serialVersionUID = 1L;
   public Listener() {
      
   }

   public class Avbryt implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         System.exit(0);         
      }      
   }
}

Författare:  4kTRB [ 19.54 2019-06-20 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Då det vore kul med en kurva på det som mäts plus den kurva som
polynomapproximerats och kunna skriva ut denna från NTC-programmet
så har jag dykt ned i kodningen av grafik i Java.

Jag har labbat med att rita axlar i en lagerbild och sedan
plotta kurvan i en annan lagerbild då jag upptäckte att om
jag ville ha en marker för x och y så måste kurvan plottas på
nytt vilket inte blir bra. Att byta en bild går betydligt snabbare
men jag har inte helt testat detta ännu.

I vilket fall så har jag lyckats rita två lager uppepå varandra
med en viss genomskinlighet och det anser jag vara en bra start.
Main...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import javax.swing.JFrame;
import java.awt.SystemColor;
import javax.swing.JButton;
import javax.swing.Box;
import java.awt.Component;
import java.awt.Dimension;
//import java.awt.EventQueue;
import javax.swing.JSpinner;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Font;
import java.awt.Label;
import java.awt.Color;
import javax.swing.SpringLayout;
import javax.swing.SpinnerNumberModel;

public class SwingWindow extends JFrame {
   
   private static final long serialVersionUID = 1L;
   public final int WINDOW_WIDTH = 800;
   public final int WINDOW_HEIGHT = 500;
   public static final int CANVAS_WIDTH = 772;
   public static final int CANVAS_HEIGHT = 365;
   public final int SPINNER_X_STARTVALUE = 0;
   public final int SPINNER_Y_STARTVALUE = 0;
   // y = 2.31 - 0.0047*x + 1.93*10^-6*x^2
   public static final double A = 2.31;
   public static final double B = -0.0047;
   public static final double C = 0.00000193;
   private static JButton b0;
   private static JButton b1;
   private static JButton b2;
   private static JSpinner spinner_X;
   private static JSpinner spinner_Y;
   private static int spinner_X_value;
   private static int spinner_Y_value;
   private static Label label_Y;
   private static Label label_X;
   private JSpinner spinner_dX;
   private JSpinner spinner_dY;
   public static SwingWindow swingwindow;
   /**
    * Launch the application.
    */
   public static void main(String[] args) {
      swingwindow = new SwingWindow();
      swingwindow.setVisible(true);
      /*EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               new SwingWindow();
               
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      }); */
   }

   /**
    * Create the application.
    */
   public SwingWindow() {
      super("Swing");   
      setMaximumSize(new Dimension(1000, 800));
      getContentPane().setBackground(new Color(240, 230, 140));
      getContentPane().setLayout(null);
      setBounds(400, 100, WINDOW_WIDTH, WINDOW_HEIGHT);
      setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);   
      setUpGUI();
   }
   /**
    * Initialize the contents of the frame.
    */
   private void setUpGUI() {      
      JPanel panel = new JPanel();
      panel.setBackground(SystemColor.menu);
      panel.setBounds(5, 376, 575, 76);
      getContentPane().add(panel);
      SpringLayout sl_panel = new SpringLayout();
      panel.setLayout(sl_panel);
      
      Box horizontalBox_1 = Box.createHorizontalBox();
      sl_panel.putConstraint(SpringLayout.WEST, horizontalBox_1, 10, SpringLayout.WEST, panel);
      sl_panel.putConstraint(SpringLayout.EAST, horizontalBox_1, -10, SpringLayout.EAST, panel);
      horizontalBox_1.setOpaque(true);
      sl_panel.putConstraint(SpringLayout.NORTH, horizontalBox_1, 11, SpringLayout.NORTH, panel);
      panel.add(horizontalBox_1);
      
      JLabel lblYMarker = new JLabel("Y1 marker");
      horizontalBox_1.add(lblYMarker);
      
      Component rigidArea = Box.createRigidArea(new Dimension(20, 20));
      rigidArea.setMinimumSize(new Dimension(15, 20));
      rigidArea.setPreferredSize(new Dimension(15, 20));
      rigidArea.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea);
      
      spinner_Y = new JSpinner();
      spinner_Y.setDoubleBuffered(true);
      spinner_Y.setMinimumSize(new Dimension(50, 20));
      spinner_Y.setPreferredSize(new Dimension(50, 20));
      spinner_Y.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_Y_value = (int) spinner_Y.getValue();
            label_Y.setText(String.valueOf(spinner_Y_value));
            //canvas.setNewY(spinner_Y_value);
         }
      });
      horizontalBox_1.add(spinner_Y);
      
      Component rigidArea_5 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_5.setMinimumSize(new Dimension(15, 20));
      rigidArea_5.setPreferredSize(new Dimension(15, 20));
      rigidArea_5.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_5);
      
      JLabel lblXMarker = new JLabel("X1 marker");
      horizontalBox_1.add(lblXMarker);
      
      Component rigidArea_1 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_1.setMinimumSize(new Dimension(15, 20));
      rigidArea_1.setPreferredSize(new Dimension(15, 20));
      rigidArea_1.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_1);
      
      spinner_X = new JSpinner();
      spinner_X.setModel(new SpinnerNumberModel(0, 0, 700, 1));
      spinner_X.setDoubleBuffered(true);
      spinner_X.setMinimumSize(new Dimension(50, 20));
      spinner_X.setPreferredSize(new Dimension(50, 20));
      spinner_X.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_X_value = (int) spinner_X.getValue();
            label_X.setText(String.valueOf(spinner_X_value));
         //   canvas.setMarkerLineX1pos(spinner_X_value);
         //   canvas.repaint();
         }
      });
      horizontalBox_1.add(spinner_X);
      
      Component rigidArea_8 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_8.setMinimumSize(new Dimension(15, 20));
      rigidArea_8.setPreferredSize(new Dimension(15, 20));
      rigidArea_8.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_8);
      
      JLabel lblXMarker_1 = new JLabel("Y2 marker");
      horizontalBox_1.add(lblXMarker_1);
      
      Component rigidArea_6 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_6.setMinimumSize(new Dimension(15, 20));
      rigidArea_6.setPreferredSize(new Dimension(15, 20));
      rigidArea_6.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_6);
      
      spinner_dY = new JSpinner();
      spinner_dY.setDoubleBuffered(true);
      spinner_dY.setMinimumSize(new Dimension(50, 20));
      spinner_dY.setPreferredSize(new Dimension(50, 20));
      horizontalBox_1.add(spinner_dY);
      
      Component rigidArea_7 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_7.setMinimumSize(new Dimension(15, 20));
      rigidArea_7.setPreferredSize(new Dimension(15, 20));
      rigidArea_7.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_7);
      
      JLabel lblXMarker_2 = new JLabel("X2 marker");
      horizontalBox_1.add(lblXMarker_2);
      
      Component rigidArea_9 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_9.setMinimumSize(new Dimension(15, 20));
      rigidArea_9.setPreferredSize(new Dimension(15, 20));
      rigidArea_9.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_9);
      
      spinner_dX = new JSpinner();
      spinner_dX.setDoubleBuffered(true);
      spinner_dX.setPreferredSize(new Dimension(50, 20));
      spinner_dX.setMinimumSize(new Dimension(40, 20));
      horizontalBox_1.add(spinner_dX);
      Box horizontalBox = Box.createHorizontalBox();
      sl_panel.putConstraint(SpringLayout.WEST, horizontalBox, 10, SpringLayout.WEST, panel);
      sl_panel.putConstraint(SpringLayout.EAST, horizontalBox, -10, SpringLayout.EAST, panel);
      horizontalBox.setAlignmentX(0.0f);
      sl_panel.putConstraint(SpringLayout.NORTH, horizontalBox, 42, SpringLayout.NORTH, panel);
      panel.add(horizontalBox);
      
      b0 = new JButton("Plotta Kurva");
      b0.setDoubleBuffered(true);
      b0.setPreferredSize(new Dimension(130, 23));
      b0.setMaximumSize(new Dimension(130, 23));
      b0.addActionListener(new Listener().new PlotFunction());
      horizontalBox.add(b0);
      
      Component rigidArea_2 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_2.setMaximumSize(new Dimension(22, 20));
      rigidArea_2.setMinimumSize(new Dimension(22, 20));
      rigidArea_2.setPreferredSize(new Dimension(22, 20));
      horizontalBox.add(rigidArea_2);
      
      b1 = new JButton("Radera Kurva");
      b1.setDoubleBuffered(true);
      b1.setPreferredSize(new Dimension(130, 23));
      b1.setMaximumSize(new Dimension(130, 23));
      b1.addActionListener(new Listener().new Repaint());
      horizontalBox.add(b1);
      
      Component rigidArea_3 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_3.setMaximumSize(new Dimension(22, 20));
      rigidArea_3.setMinimumSize(new Dimension(22, 20));
      rigidArea_3.setPreferredSize(new Dimension(22, 20));
      horizontalBox.add(rigidArea_3);
      
      b2 = new JButton("Render Canvas");
      b2.setDoubleBuffered(true);
      b2.setPreferredSize(new Dimension(130, 23));
      b2.setMaximumSize(new Dimension(130, 23));
      b2.addActionListener(new Listener().new Render());
      horizontalBox.add(b2);
      
      JButton b3 = new JButton("Avsluta");
      b3.setDoubleBuffered(true);
      b3.setMinimumSize(new Dimension(72, 23));
      b3.setPreferredSize(new Dimension(130, 23));
      b3.setMaximumSize(new Dimension(130, 23));
      b3.addActionListener(new Listener().new Avbryt());
      
      Component rigidArea_4 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_4.setMaximumSize(new Dimension(22, 20));
      rigidArea_4.setMinimumSize(new Dimension(22, 20));
      rigidArea_4.setPreferredSize(new Dimension(22, 20));
      horizontalBox.add(rigidArea_4);
      horizontalBox.add(b3);
      
      JPanel panel_1 = new JPanel();
      panel_1.setOpaque(false);
      panel_1.setForeground(new Color(0, 0, 0));
      panel_1.setBackground(new Color(255, 255, 255));
      panel_1.setBounds(612, 376, 165, 20);
      getContentPane().add(panel_1);
      panel_1.setLayout(null);
      
      label_Y = new Label(String.valueOf(SPINNER_Y_STARTVALUE));
      label_Y.setFont(new Font("Arial Black", Font.BOLD, 15));
      label_Y.setAlignment(Label.CENTER);
      label_Y.setForeground(Color.BLACK);
      label_Y.setBackground(Color.YELLOW);
      label_Y.setBounds(0, 0, 80, 20);
      panel_1.add(label_Y);
      
      label_X = new Label(String.valueOf(SPINNER_X_STARTVALUE));
      label_X.setForeground(Color.BLACK);
      label_X.setFont(new Font("Arial Black", Font.BOLD, 15));
      label_X.setBackground(Color.YELLOW);
      label_X.setAlignment(Label.CENTER);
      label_X.setBounds(85, 0, 80, 20);
      panel_1.add(label_X);   
      CanvasGraph canvas =  new CanvasGraph(5,5,CANVAS_WIDTH,CANVAS_HEIGHT);
      getContentPane().add(canvas);
      //getContentPane().add(drawpanel);
      // getContentPane().add(canvas);
      
   }
}


Canvas att rita rektanglar med innehåll i...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.AlphaComposite;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;

public class CanvasGraph extends Canvas {
   private static final long serialVersionUID = 1L;
   public static final int AXIS_MARGIN = 68;      // totala marginalen ovan+under och vänster+höger
   public static final int X_MARKERS_SPACE = 20;   // antal pixlar mellan varje markör på x-axeln
   public static final int Y_MARKERS_SPACE = 10;   // sätter steglängden hos markörer
   public static final int MARKER_LENGTH = 1;      // markörernas halva längd
   public static final int SCALEFACTOR_Y = 100;   // y-axeln ska visa 100ggr mindre värden än dess längd i pixlar
   
   private int canvasWidth;
   private int canvasHeight;
   private ImageA imgA;
   private ImageB imgB;
   private int rule;
   private static Point2D origo;
   /*
    * Konstruktor. Skapar en canvas med höjd, bredd och placeras
    * med offset i x- och y-led i den behållare där den ingår.
    * Ritar en Canvas som buffrade bilder sedan placeras på.
    */
   public CanvasGraph(int offsetX, int offsetY,int width, int height) {
      canvasWidth = width;
      canvasHeight = height;
      //setBackground(Color.WHITE);
      setBounds(offsetX, offsetY, width, height);
      rule = AlphaComposite.SRC_OVER;
      imgA = new ImageA(canvasWidth,canvasHeight,Color.WHITE);                    // skapa en buffrad bild med x-y-axel
      imgB = new ImageB(canvasWidth-AXIS_MARGIN,canvasHeight-AXIS_MARGIN,Color.BLUE); // skapa en buffrad bild med plottad funktion
   }
   public void paint(Graphics gr) {
      super.paint(gr);
      Graphics2D g = (Graphics2D) gr;   
      g.drawImage(imgA, null, 0, 0);                           // rita den buffrade bilden
      float alpha = 0.5f;                                    // genomskinlighetsgrad för nästa bild
      AlphaComposite comp = AlphaComposite.getInstance(rule, alpha);
      g.setComposite(comp);      
      g.drawImage(imgB, null, (int) origo.getX(),AXIS_MARGIN/2);      // rita den buffrade bilden
      g.dispose();
   }
   public static void setOrigo(Point2D origo) {
      CanvasGraph.origo = origo;
   }
   public static Point2D getOrigo() {
      return origo;
   }
}


Buffrad bild som innehåller axlar...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/*
 * Skapar en buffrad bild som ligger i botten av ett lager med flera bilder.
 * Bilden består av en färgad rektangel som det går att rita i.
 * Denna basbild innehåller en skalad x- och y-axel.
 */
public class ImageA extends BufferedImage {
   private Graphics2D g;
   private Rectangle2D rek;
   private int canvasWidth;
   private int canvasHeight;
   private int xAxisLength;
   private int yAxisLength;
   private int xAxisStart;
   private int xAxisEnd;
   private int yAxisStart;
   private int yAxisEnd;
   private Point2D xEnd;
   private Point2D yEnd;
   private Point2D origo;
   private int numberOfxMarkers;
   private int numberOfyMarkers;
   public ImageA(int width, int height, Color color) {
      super(width, height, BufferedImage.TYPE_INT_ARGB);
      canvasWidth = width;
      canvasHeight = height;      
      g = this.createGraphics();
      g.setStroke(new BasicStroke(1.0f));
      rek = new Rectangle2D.Double(0,0,width,height);
      g.setPaint(color);
      g.fill(rek);
      g.draw(rek);
      g.setPaint(Color.BLACK);
      drawAxis();
      drawMarkers();
      g.dispose();
   }
   private void drawMarkers() {
      numberOfxMarkers = xAxisLength/CanvasGraph.X_MARKERS_SPACE;
      numberOfyMarkers = yAxisLength/CanvasGraph.Y_MARKERS_SPACE;
      int dx = xAxisLength/numberOfxMarkers;
      int dy = yAxisLength/numberOfyMarkers;
      int xs = xAxisStart;
      int xe = xAxisEnd;
      int ys = yAxisStart;
      int ye = yAxisEnd;
      Font font = new Font("SansSerif", Font.PLAIN, 14);
      AffineTransform affineTransform = new AffineTransform();
      affineTransform.rotate(Math.toRadians(90), 0, 0);      
      Font rotatedFont = font.deriveFont(affineTransform);
      g.setFont(rotatedFont);
      for(int i=xs;i<=xe;i+=dx) {      // börja rita x-markörer från origo
         drawXMarker(i,i-xs);
      }
      font = new Font("SansSerif", Font.PLAIN, 11);
      affineTransform = new AffineTransform();
      affineTransform.rotate(Math.toRadians(0), 0, 0);      
      rotatedFont = font.deriveFont(affineTransform);
      g.setFont(rotatedFont);
      for(int i=ys;i>=ye;i-=dy) {      // börja rita y-markörer från origo
         drawYMarker(i,(ys-i)/100.0);
      }
   }
   /*
    * Ritar markörer utmed x-axeln på de positioner som anges av
    * parametern xpos.
    */
   private void drawXMarker(int xpos,int scaleNumber) {
      String s = String.valueOf(scaleNumber);
      Point xm1 = new Point(xpos,(int)origo.getY()+CanvasGraph.MARKER_LENGTH);
      Point xm2 = new Point(xpos,(int)origo.getY()-CanvasGraph.MARKER_LENGTH);
      Line2D.Double marker = new Line2D.Double(xm1,xm2);
      g.draw(marker);
      drawXScale(s,xpos-3,(int)(origo.getY()+5));
   }
   /*
    * Ritar markörer utmed y-axeln på de positioner som anges av
    * parametern ypos.
    */
   private void drawYMarker(int ypos, double scaleNumber) {
      String s = String.valueOf(scaleNumber);
      Point ym1 = new Point((int)origo.getX()-CanvasGraph.MARKER_LENGTH,ypos);
      Point ym2 = new Point((int)origo.getX()+CanvasGraph.MARKER_LENGTH,ypos);
      Line2D.Double marker = new Line2D.Double(ym1,ym2);
      g.draw(marker);
      drawYScale(s,(int)(origo.getX()),ypos);
   }
   /*
    * Graderar x-axeln med tal
    */
   private void drawXScale(String s, int xpos, int ypos) {   
      g.setPaint(Color.BLUE);
      g.drawString(s, xpos-1, ypos+1);
   }
   /*
    * Graderar y-axeln med tal
    */
   private void drawYScale(String s, int xpos, int ypos) {   
      g.setPaint(Color.RED);
      g.drawString(s, xpos-20, ypos+3);
   }
   private void drawAxis() {
      xAxisLength = canvasWidth - CanvasGraph.AXIS_MARGIN;            
      yAxisLength = canvasHeight- CanvasGraph.AXIS_MARGIN;            
      xAxisStart = canvasWidth - xAxisLength - CanvasGraph.AXIS_MARGIN/2;    
      yAxisEnd = canvasHeight - yAxisLength - CanvasGraph.AXIS_MARGIN/2;                                 
      yAxisStart = canvasHeight - CanvasGraph.AXIS_MARGIN/2;      
      xAxisEnd = xAxisLength + xAxisStart;
      CanvasGraph.setOrigo(new Point(xAxisStart,yAxisStart));
      origo = CanvasGraph.getOrigo();
      xEnd = new Point(xAxisEnd,yAxisStart);
      yEnd = new Point(xAxisStart,yAxisEnd);
      Line2D.Double xAxel = new Line2D.Double(origo,xEnd);
      Line2D.Double yAxel = new Line2D.Double(origo, yEnd);
      g.draw(xAxel);
      g.draw(yAxel);
   }
}


Buffrad bild som håller den plottade kurvan...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/*
 * Skapar en buffrad bild.
 * Bilden består av en färgad rektangel som det går att rita i.
 * Denna bild innehåller en plottad kurva.
 */
public class ImageB extends BufferedImage {
   private Graphics2D g;
   private Rectangle2D rek;
   private Point2D origo;
   public ImageB(int width, int height, Color color) {
      super(width, height, BufferedImage.TYPE_INT_ARGB);
      origo = CanvasGraph.getOrigo();
      g = this.createGraphics();
      g.setStroke(new BasicStroke(1.0f));
      rek = new Rectangle2D.Double(0,0,width,height);
      g.setPaint(color);
      g.fill(rek);   
      g.draw(rek);
      g.setPaint(Color.BLACK);
      plotFunction(SwingWindow.A,SwingWindow.B,SwingWindow.C);
      g.dispose();
   }
   /*
    * Ritar en funktion y(x) i x-y-grafen. y(x) = a + bx + cx^2
    * y = 2.31 - 0.0047*R + 1.93*10^-6*R^2
    */
   private void plotFunction(double a, double b, double c) {
      double x1 = 0;
      double y1 = 0;
      double x2 = 0;
      double y2 = 0;   
      while(y2>=0) {      
         y2 = (a + b*x2 + c*Math.pow(x2, 2))*100;
         g.drawLine(x(x1), y(y1), x(x2), y(y2));
         x1 = x2;
         y1 = y2;
         x2 = x2+1;
      }
   }
   /*
    * Parametern x refererar till en x-koordinat med ett origo som har x=0 och y=0
    * Returnerar den absoluta x-koordinaten i förhållande till det origo
    * som ritats i canvas med de faktiska x- och y-koordinaterna.
    */
   private int x(double x) {
      return (int)(origo.getX()+x-CanvasGraph.AXIS_MARGIN/2);
   }
   /*
    * Parametern y refererar till en y-koordinat med ett origo som har x=0 och y=0
    * Returnerar den absoluta y-koordinaten i förhållande till det origo
    * som ritats i canvas med de faktiska x- och y-koordinaterna.
    */
   private int y(double y) {
      return (int)(origo.getY()-y-CanvasGraph.AXIS_MARGIN/2);
   }

}


En lyssnarklass för knappar fast den nyttjar jag inte till något vettigt ännu...
Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;

public class Listener extends JFrame {
   private static final long serialVersionUID = 1L;
   public Listener() {
      
   }

   public class Avbryt implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         System.exit(0);         
      }      
   }
   
   public class PlotFunction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
      //   SwingWindow.getCanvas().plotFunction(SwingWindow.A,SwingWindow.B,SwingWindow.C);
      }      
   }
   
   public class Repaint implements ActionListener {
      public void actionPerformed(ActionEvent e) {
      //   SwingWindow.getCanvas().repaint();      
      }      
   }
   public class Render implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         System.out.println("RENDER");
               
      }      
   }
}

Författare:  AndLi [ 10.58 2019-06-21 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Projektet går ut på att uppfinna hjulet själv igen?
Annars finns det ju massor av färdiga grafritare, men det är alltid bra att göra en första själv, så man inser hur komplext det faktiskt är...

Författare:  4kTRB [ 18.10 2019-06-21 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Ja jo lite så kan man ju tycka att det är.

Sedan tycker jag själv att det är kul att lära sig det här och
kunna få det precis som jag själv vill ha det.

Det finns sedan oändligt med möjligheter om man skulle
behärska det mesta av Javabiblioteken med grafik, men det
tar sin tid så klart.

Jag är inne på att försöka simulera fysikaliska förlopp med grafik,
så jag läser lite i en bok med fysik för spel men jag har tyvärr
inte läst all den matematiken med tredimensionella vektorer
och tensorberäkning som ofta ingår.

Författare:  4kTRB [ 18.35 2019-07-27 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Ett kort att ansluta till 2 av Arduinos analoga ingångar.

Då olika NTC-värden ska mätas behövs olika bryggor för att
få rätt spänningar så därför valde jag att ha plug-in-bryggor.

Den nedan är avsedd för ett NTC runt 560 ohm.

Författare:  4kTRB [ 11.34 2019-07-28 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Buffrade bilder och Canvas fungerar inte riktigt bra så därför
lät jag klassen Graph att utöka från klassen JComponent som
är en lättviktigare komponent.

Det fungerar alldeles förträffligt bra att nu dra i en slider för att
justera en marker. Sedan kan jag finjustera med en spinner.

När jag drar i slidern så ändras värdet i spinnern och tvärt om.
Det är spinnern som har händelsehanteraren och ritar om de
buffrade bilderna med uppdaterade värden för markeringslinjerna
och tillhörande värden som syns, och följer med, linjerna.

På något sätt tänkte jag inkludera en graf i NTC-interfacet så jag måste
då också lösa hur jag ska få axlarna att graderas riktigt beroende på
vilken kurva jag får. Max y-värde ges ju av kurvans formel och max x-värde
av mellan vilka motståndsvärden kurvan ritas.

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import javax.swing.JComponent;

public class Graph extends JComponent {
   private static final long serialVersionUID = 1L;
   public static final int AXIS_MARGIN = 68;         // totala marginalen ovan+under och vänster+höger
   public static final int HALF_AXIS_MARGIN = AXIS_MARGIN/2;
   public static final int X_MARKERS_SPACE = 20;      // antal pixlar mellan varje markör på x-axeln
   public static final int Y_MARKERS_SPACE = 10;      // sätter steglängden hos markörer
   public static final int MARKER_LENGTH = 1;         // markörernas halva längd
   public static final double SCALEFACTOR_Y = 100.0;   // y-axeln ska visa 100ggr mindre värden än dess längd i pixlar   
   private int jComponentWidth;
   private int jComponentHeight;
   private ImageA imgA;
   private ImageB imgB;
   private static Point2D origo;
   private Graphics2D g;
   private int markerLineX1pos;
   private int markerLineY1pos;
   private int markerLineX2pos;
   private int markerLineY2pos;
   private AlphaComposite compA;
   private AlphaComposite compB;
   private int yAxisStart;
   private int xAxisStart;
   private int xAxisEnd;   
   private int yAxisEnd;
   private String sY1;
   private String sY2;
   private String sX1;
   private String sX2;
   private Font f;
   /*
    * Konstruktor. Skapar en JComponent med höjd, bredd och placeras
    * med offset i x- och y-led i den behållare där den ingår.
    * Buffrade bilder placeras sedan på denna JComponent.
    */
   public Graph(int offsetX, int offsetY,int width, int height) {
      jComponentWidth = width;
      jComponentHeight = height;
      setBackground(Color.WHITE);
      setBounds(offsetX, offsetY, width, height);
      imgA = new ImageA(jComponentWidth,jComponentHeight,Color.WHITE);                    // skapa en buffrad bild med x-y-axel
      imgB = new ImageB(jComponentWidth-AXIS_MARGIN,jComponentHeight-AXIS_MARGIN,Color.WHITE); // skapa en buffrad bild med plottad funktion
      markerLineX1pos = markerLineX2pos = (int) origo.getX();
      markerLineY1pos = markerLineY2pos = (int) origo.getY();      
      compA = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);   // genomskinlighetsgrad
      compB = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
      yAxisStart = (int) origo.getY();
      xAxisStart = (int) origo.getX();
      xAxisEnd = jComponentWidth - HALF_AXIS_MARGIN;
      yAxisEnd =  HALF_AXIS_MARGIN;
      sY1 = sX1 = sY2 = sX2 = Double.toString(0.0);                  // utgångsläge för markörer X1,Y1,X2,Y2
      f = new Font("SansSerif",Font.BOLD,12);                        // text/font markörvärde label
   }
   public void paint(Graphics gr) {
      super.paint(gr);      
      g = (Graphics2D) gr;
      g.setFont(f);
      g.setComposite(compA);
      g.drawImage(imgA, null, 0, 0);                           // rita den buffrade bilden                     
      g.setComposite(compB);   
      g.drawImage(imgB, null, xAxisStart ,HALF_AXIS_MARGIN);         // rita den buffrade bilden
      drawMarkerLineX1(markerLineX1pos);                         // rita en flyttbar x-markering i JComponent
      drawMarkerLineY1(markerLineY1pos);                        // rita en flyttbar y-markering i JComponent
      drawMarkerLineX2(markerLineX2pos);                         // rita en flyttbar x-markering i JComponent
      drawMarkerLineY2(markerLineY2pos);                        // rita en flyttbar y-markering i JComponent
      g.dispose();
   }
   /*
    * Ritar en lodrät markeringslinje i grafen på angiven X1-koordinat.
    */
   private void drawMarkerLineX1(int x) {
      g.setPaint(Color.BLUE);
      sX1 = Double.toString(x-Graph.HALF_AXIS_MARGIN);
      g.drawString(sX1, x+3, yAxisEnd+10);                     // rita en label med aktuellt X1-värde
      g.drawLine(x, HALF_AXIS_MARGIN, x, yAxisStart);
   }
   /*
    * Ritar en lodrät markeringslinje i grafen på angiven X2-koordinat.
    */
   private void drawMarkerLineX2(int x) {
      g.setPaint(Color.ORANGE);
      sX2 = Double.toString(x-Graph.HALF_AXIS_MARGIN);
      g.drawString(sX2, x+3, yAxisEnd+21);                     // rita en label med aktuellt X2-värde
      g.drawLine(x, HALF_AXIS_MARGIN, x, yAxisStart);
   }
   /*
    * Ritar en vågrät markeringslinje i grafen på angiven Y1-koordinat.
    */
   private void drawMarkerLineY1(int y) {
      g.setPaint(Color.BLUE);
      sY1 = Double.toString((yAxisStart-y)/SCALEFACTOR_Y);
      g.drawString(sY1, xAxisEnd-10, y-3);                     // rita en label med aktuellt Y1-värde
      g.drawLine(HALF_AXIS_MARGIN, y, xAxisEnd, y);
   }
   /*
    * Ritar en vågrät markeringslinje i grafen på angiven Y2-koordinat.
    */
   private void drawMarkerLineY2(int y) {
      g.setPaint(Color.ORANGE);
      sY2 = Double.toString((yAxisStart-y)/SCALEFACTOR_Y);
      g.drawString(sY2, xAxisEnd-35, y-3);                     // rita en label med aktuellt Y2-värde
      g.drawLine(HALF_AXIS_MARGIN, y, jComponentWidth - HALF_AXIS_MARGIN, y);
   }
   
   /*
    * Flyttar/uppdaterar y-koordinaten för den vågräta markeringslinjen Y1
    * Händelsehanterare i GUI aktiverar denna metod
    */
   public void setMarkerLineY1pos(int y) {
      markerLineY1pos= yAxisStart - y;
      repaint();
   }
   /*
    * Flyttar/uppdaterar y-koordinaten för den vågräta markeringslinjen Y2
    * Händelsehanterare i GUI aktiverar denna metod
    */
   public void setMarkerLineY2pos(int y) {
      markerLineY2pos= yAxisStart - y;
      repaint();
   }
   /*
    * Flyttar/uppdaterar x-koordinaten för den lodräta markeringslinjen X1
    * Händelsehanterare i GUI aktiverar denna metod
    */
   public void setMarkerLineX1pos(int x) {
      markerLineX1pos= x + xAxisStart;
      repaint();
   }
   /*
    * Flyttar/uppdaterar x-koordinaten för den lodräta markeringslinjen X2
    * Händelsehanterare i GUI aktiverar denna metod
    */
   public void setMarkerLineX2pos(int x) {
      markerLineX2pos= x + xAxisStart;
      repaint();
   }

   public static void setOrigo(Point2D origo) {
      Graph.origo = origo;
   }
   public static Point2D getOrigo() {
      return origo;
   }
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/*
 * Skapar en buffrad bild som ligger i botten av ett lager med flera bilder.
 * Bilden består av en färgad rektangel som det går att rita i.
 * Denna basbild innehåller en skalad x- och y-axel.
 */
public class ImageA extends BufferedImage {
   private Graphics2D g;
   private Rectangle2D rek;
   private int jComponentWidth;
   private int jComponentHeight;
   private int xAxisLength;
   private int yAxisLength;
   private int xAxisStart;
   private int xAxisEnd;
   private int yAxisStart;
   private int yAxisEnd;
   private Point2D xEnd;
   private Point2D yEnd;
   private Point2D origo;
   private int numberOfxMarkers;
   private int numberOfyMarkers;
   public ImageA(int width, int height, Color color) {
      super(width, height, BufferedImage.TYPE_INT_ARGB);
      jComponentWidth = width;
      jComponentHeight = height;      
      g = this.createGraphics();
      g.setStroke(new BasicStroke(1.0f));
      rek = new Rectangle2D.Double(0,0,width,height);
      g.setPaint(color);
      g.fill(rek);
      g.draw(rek);
      g.setPaint(Color.BLACK);
      drawAxis();
      drawMarkers();
      g.dispose();
   }
   /*
    * Ritar markeringar med jämna mellanrum på de båda axlarna.
    *
    */
   private void drawMarkers() {
      numberOfxMarkers = xAxisLength/Graph.X_MARKERS_SPACE;
      numberOfyMarkers = yAxisLength/Graph.Y_MARKERS_SPACE;
      int dx = xAxisLength/numberOfxMarkers;
      int dy = yAxisLength/numberOfyMarkers;
      int xs = xAxisStart;
      int xe = xAxisEnd;
      int ys = yAxisStart;
      int ye = yAxisEnd;
      Font font = new Font("SansSerif", Font.PLAIN, 14);
      AffineTransform affineTransform = new AffineTransform();
      affineTransform.rotate(Math.toRadians(90), 0, 0);      
      Font rotatedFont = font.deriveFont(affineTransform);
      g.setFont(rotatedFont);
      for(int i=xs;i<=xe;i+=dx) {      // börja rita x-markörer från origo
         drawXMarker(i,(i-xs));
      }
      font = new Font("SansSerif", Font.PLAIN, 11);
      affineTransform = new AffineTransform();
      affineTransform.rotate(Math.toRadians(0), 0, 0);      
      rotatedFont = font.deriveFont(affineTransform);
      g.setFont(rotatedFont);
      for(int i=ys;i>=ye;i-=dy) {      // börja rita y-markörer från origo
         drawYMarker(i,(ys-i)/Graph.SCALEFACTOR_Y);
      }
   }
   /*
    * Ritar markörer utmed x-axeln på de positioner som anges av
    * parametern xpos.
    */
   private void drawXMarker(int xpos,double scaleNumber) {
      String s = String.valueOf((int)scaleNumber);
      Point xm1 = new Point(xpos,(int)origo.getY()+Graph.MARKER_LENGTH);
      Point xm2 = new Point(xpos,(int)origo.getY()-Graph.MARKER_LENGTH);
      Line2D.Double marker = new Line2D.Double(xm1,xm2);
      g.draw(marker);
      drawXScale(s,xpos-3,(int)(origo.getY()+5));
   }
   /*
    * Ritar markörer utmed y-axeln på de positioner som anges av
    * parametern ypos.
    */
   private void drawYMarker(int ypos, double scaleNumber) {
      String s = String.valueOf(scaleNumber);
      Point ym1 = new Point((int)origo.getX()-Graph.MARKER_LENGTH,ypos);
      Point ym2 = new Point((int)origo.getX()+Graph.MARKER_LENGTH,ypos);
      Line2D.Double marker = new Line2D.Double(ym1,ym2);
      g.draw(marker);
      drawYScale(s,(int)(origo.getX()),ypos);
   }
   /*
    * Graderar x-axeln med tal
    */
   private void drawXScale(String s, int xpos, int ypos) {   
      g.setPaint(Color.BLUE);
      g.drawString(s, xpos-1, ypos+1);
   }
   /*
    * Graderar y-axeln med tal
    */
   private void drawYScale(String s, int xpos, int ypos) {   
      g.setPaint(Color.RED);
      g.drawString(s, xpos-20, ypos+3);
   }
   /*
    * Ritar de två axlarna med origo i sydväst.
    * Axlarnas längd i pixlar begränsas av JComponent:ens höjd och bredd och
    * den valda marginalen från dess ytterkanter till där axlarna ritas.
    */
   private void drawAxis() {
      xAxisLength = jComponentWidth - Graph.AXIS_MARGIN;            
      yAxisLength = jComponentHeight- Graph.AXIS_MARGIN;            
      xAxisStart = jComponentWidth - xAxisLength - Graph.HALF_AXIS_MARGIN;    
      yAxisEnd = jComponentHeight - yAxisLength - Graph.HALF_AXIS_MARGIN;                                 
      yAxisStart = jComponentHeight - Graph.HALF_AXIS_MARGIN;      
      xAxisEnd = xAxisLength + xAxisStart;
      Graph.setOrigo(new Point(xAxisStart,yAxisStart));
      origo = Graph.getOrigo();
      xEnd = new Point(xAxisEnd,yAxisStart);
      yEnd = new Point(xAxisStart,yAxisEnd);
      Line2D.Double xAxel = new Line2D.Double(origo,xEnd);
      Line2D.Double yAxel = new Line2D.Double(origo, yEnd);
      g.draw(xAxel);
      g.draw(yAxel);
   }
}


Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/*
 * Skapar en buffrad bild.
 * Bilden består av en färgad rektangel som det går att rita i.
 * Denna bild innehåller en plottad kurva.
 */
public class ImageB extends BufferedImage {
   private Graphics2D g;
   private Rectangle2D rek;
   private Point2D origo;
   public ImageB(int width, int height, Color color) {
      super(width, height, BufferedImage.TYPE_INT_ARGB);
      origo = Graph.getOrigo();
      g = this.createGraphics();
      g.setStroke(new BasicStroke(1.0f));
      rek = new Rectangle2D.Double(0,0,width,height);
      g.setPaint(color);
      g.fill(rek);   
      g.draw(rek);
      g.setPaint(Color.BLACK);
      plotFunction(SwingWindow.A,SwingWindow.B,SwingWindow.C);      // funktionskonstanter hämtas från main-klassen
      g.dispose();
   }
   /*
    * Ritar en funktion y(x) i x-y-grafen. y(x) = a + bx + cx^2
    * y = 2.31 - 0.0047*R + 1.93*10^-6*R^2
    *
    */
   private void plotFunction(double a, double b, double c) {
      double x1 = 0;
      double y1 = 0;
      double x2 = 0;
      double y2 = 0;   
      while(y2>=0) {      
         y2 = (a + b*x2 + c*Math.pow(x2, 2))*100;
         g.drawLine(x(x1), y(y1), x(x2), y(y2));
         x1 = x2;
         y1 = y2;
         x2 = x2+1;
      }
   }
   /*
    * Parametern x refererar till en x-koordinat med ett origo som har x=0 och y=0
    * Returnerar den absoluta x-koordinaten i förhållande till det origo
    * som ritats i canvas med de faktiska x- och y-koordinaterna.
    */
   private int x(double x) {
      return (int)(origo.getX()+x-Graph.AXIS_MARGIN/2);
   }
   /*
    * Parametern y refererar till en y-koordinat med ett origo som har x=0 och y=0
    * Returnerar den absoluta y-koordinaten i förhållande till det origo
    * som ritats i canvas med de faktiska x- och y-koordinaterna.
    */
   private int y(double y) {
      return (int)(origo.getY()-y-Graph.AXIS_MARGIN/2);
   }

}

Kod: [Expandera/Minimera] [Hämta] (Untitled.txt)
import javax.swing.JFrame;
import java.awt.SystemColor;
import javax.swing.JButton;
import javax.swing.Box;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JSpinner;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Color;
import javax.swing.SpringLayout;
import javax.swing.SpinnerNumberModel;
import javax.swing.JSlider;

public class SwingWindow extends JFrame {
   
   private static final long serialVersionUID = 1L;
   public final int WINDOW_WIDTH = 800;
   public final int WINDOW_HEIGHT = 520;
   public static final int JC_WIDTH = 772;
   public static final int JC_HEIGHT = 365;
   public final int SPINNER_X_STARTVALUE = 0;
   public final int SPINNER_Y_STARTVALUE = 0;
   // y = 2.31 - 0.0047*x + 1.93*10^-6*x^2
   public static final double A = 2.31;
   public static final double B = -0.0047;
   public static final double C = 0.00000193;
   private static JButton b0;
   private static JButton b1;
   private static JButton b2;
   private static JSpinner spinner_X1;
   private static JSpinner spinner_Y1;
   private static JSpinner spinner_X2;
   private static JSpinner spinner_Y2;
   private static int spinner_X1_value;
   private static int spinner_Y1_value;
   private static int spinner_X2_value;
   private static int spinner_Y2_value;

   private JSlider sliderX1;
   private JSlider sliderY1;
   private JSlider sliderX2;
   private JSlider sliderY2;

   private Graph graph;
   public static SwingWindow swingwindow;
   private Box horizontalBox;
   /**
    * Launch the application.
    */
   public static void main(String[] args) {
      //swingwindow = new SwingWindow();
      //swingwindow.setVisible(true);
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               swingwindow = new SwingWindow();
               swingwindow.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });    
   }

   /**
    * Create the application.
    */
   public SwingWindow() {
      super("Swing");   
      setMaximumSize(new Dimension(1000, 800));
      getContentPane().setBackground(new Color(240, 230, 140));
      getContentPane().setLayout(null);
      setBounds(400, 100, WINDOW_WIDTH, WINDOW_HEIGHT);
      setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);   
      setUpGUI();
   }
   /**
    * Initialize the contents of the frame.
    */
   private void setUpGUI() {      
      JPanel panel = new JPanel();
      panel.setBackground(SystemColor.menu);
      panel.setBounds(5, 376, 772, 100);
      getContentPane().add(panel);
      SpringLayout sl_panel = new SpringLayout();
      panel.setLayout(sl_panel);
      
      Box horizontalBox_1 = Box.createHorizontalBox();
      sl_panel.putConstraint(SpringLayout.WEST, horizontalBox_1, 10, SpringLayout.WEST, panel);
      sl_panel.putConstraint(SpringLayout.EAST, horizontalBox_1, -10, SpringLayout.EAST, panel);
      horizontalBox_1.setOpaque(true);
      sl_panel.putConstraint(SpringLayout.NORTH, horizontalBox_1, 11, SpringLayout.NORTH, panel);
      panel.add(horizontalBox_1);
      
      JLabel lblYMarker = new JLabel("Y1 marker");
      horizontalBox_1.add(lblYMarker);
      
      Component rigidArea = Box.createRigidArea(new Dimension(20, 20));
      rigidArea.setMinimumSize(new Dimension(15, 20));
      rigidArea.setPreferredSize(new Dimension(15, 20));
      rigidArea.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea);
      
      spinner_Y1 = new JSpinner();
      spinner_Y1.setValue(0);
      spinner_Y1.setDoubleBuffered(true);
      spinner_Y1.setMinimumSize(new Dimension(15, 20));
      spinner_Y1.setPreferredSize(new Dimension(15, 20));
      spinner_Y1.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_Y1_value = (int) spinner_Y1.getValue();
            sliderY1.setValue(spinner_Y1_value);
            graph.setMarkerLineY1pos(spinner_Y1_value);
         }
      });
      horizontalBox_1.add(spinner_Y1);
      
      Component rigidArea_5 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_5.setMinimumSize(new Dimension(15, 20));
      rigidArea_5.setPreferredSize(new Dimension(15, 20));
      rigidArea_5.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_5);
      
      JLabel lblXMarker = new JLabel("X1 marker");
      horizontalBox_1.add(lblXMarker);
      
      Component rigidArea_1 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_1.setMinimumSize(new Dimension(15, 20));
      rigidArea_1.setPreferredSize(new Dimension(15, 20));
      rigidArea_1.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_1);
      
      spinner_X1 = new JSpinner();
      spinner_X1.setModel(new SpinnerNumberModel(0, 0, 700, 1));
      spinner_X1.setValue(0);
      spinner_X1.setDoubleBuffered(true);
      spinner_X1.setMinimumSize(new Dimension(15, 20));
      spinner_X1.setPreferredSize(new Dimension(15, 20));
      spinner_X1.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_X1_value = (int) spinner_X1.getValue();
            sliderX1.setValue(spinner_X1_value);
            graph.setMarkerLineX1pos(spinner_X1_value);
         }
      });
      horizontalBox_1.add(spinner_X1);
      
      Component rigidArea_8 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_8.setMinimumSize(new Dimension(15, 20));
      rigidArea_8.setPreferredSize(new Dimension(15, 20));
      rigidArea_8.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_8);
      
      JLabel lblXMarker_1 = new JLabel("Y2 marker");
      horizontalBox_1.add(lblXMarker_1);
      
      Component rigidArea_6 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_6.setMinimumSize(new Dimension(15, 20));
      rigidArea_6.setPreferredSize(new Dimension(15, 20));
      rigidArea_6.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_6);
      
      spinner_Y2 = new JSpinner();
      spinner_Y2.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_Y2_value = (int) spinner_Y2.getValue();
            sliderY2.setValue(spinner_Y2_value);
            graph.setMarkerLineY2pos(spinner_Y2_value);
         }
      });
      spinner_Y2.setDoubleBuffered(true);
      spinner_Y2.setMinimumSize(new Dimension(15, 20));
      spinner_Y2.setPreferredSize(new Dimension(15, 20));
      horizontalBox_1.add(spinner_Y2);
      
      Component rigidArea_7 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_7.setMinimumSize(new Dimension(15, 20));
      rigidArea_7.setPreferredSize(new Dimension(15, 20));
      rigidArea_7.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_7);
      
      JLabel lblXMarker_2 = new JLabel("X2 marker");
      horizontalBox_1.add(lblXMarker_2);
      
      Component rigidArea_9 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_9.setMinimumSize(new Dimension(15, 20));
      rigidArea_9.setPreferredSize(new Dimension(15, 20));
      rigidArea_9.setMaximumSize(new Dimension(15, 20));
      horizontalBox_1.add(rigidArea_9);
      
      spinner_X2 = new JSpinner();
      spinner_X2.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            spinner_X2_value = (int) spinner_X2.getValue();
            sliderX2.setValue(spinner_X2_value);
            graph.setMarkerLineX2pos(spinner_X2_value);
         }
      });
      spinner_X2.setDoubleBuffered(true);
      spinner_X2.setPreferredSize(new Dimension(15, 20));
      spinner_X2.setMinimumSize(new Dimension(15, 20));
      horizontalBox_1.add(spinner_X2);
      horizontalBox = Box.createHorizontalBox();
      sl_panel.putConstraint(SpringLayout.WEST, horizontalBox, 0, SpringLayout.WEST, horizontalBox_1);
      sl_panel.putConstraint(SpringLayout.EAST, horizontalBox, -10, SpringLayout.EAST, panel);
      panel.add(horizontalBox);
      
      b0 = new JButton("Plotta Kurva");
      b0.setDoubleBuffered(true);
      b0.setPreferredSize(new Dimension(130, 23));
      b0.setMaximumSize(new Dimension(130, 23));
      b0.addActionListener(new Listener().new PlotFunction());
      
      Component horizontalGlue = Box.createHorizontalGlue();
      horizontalBox.add(horizontalGlue);
      horizontalBox.add(b0);
      
      Component rigidArea_2 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_2.setMaximumSize(new Dimension(22, 20));
      rigidArea_2.setMinimumSize(new Dimension(22, 20));
      rigidArea_2.setPreferredSize(new Dimension(30, 20));
      horizontalBox.add(rigidArea_2);
      
      b1 = new JButton("Radera Kurva");
      b1.setDoubleBuffered(true);
      b1.setPreferredSize(new Dimension(130, 23));
      b1.setMaximumSize(new Dimension(130, 23));
      b1.addActionListener(new Listener().new Repaint());
      horizontalBox.add(b1);
      
      Component rigidArea_3 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_3.setMaximumSize(new Dimension(22, 20));
      rigidArea_3.setMinimumSize(new Dimension(22, 20));
      rigidArea_3.setPreferredSize(new Dimension(30, 20));
      horizontalBox.add(rigidArea_3);
      
      b2 = new JButton("------------");
      b2.setDoubleBuffered(true);
      b2.setPreferredSize(new Dimension(130, 23));
      b2.setMaximumSize(new Dimension(130, 23));
      // b2.addActionListener(new Listener().new Render());
      horizontalBox.add(b2);
      
      JButton b3 = new JButton("Avsluta");
      b3.setDoubleBuffered(true);
      b3.setMinimumSize(new Dimension(72, 23));
      b3.setPreferredSize(new Dimension(130, 23));
      b3.setMaximumSize(new Dimension(130, 23));
      b3.addActionListener(new Listener().new Avbryt());
      
      Component rigidArea_4 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_4.setMaximumSize(new Dimension(22, 20));
      rigidArea_4.setMinimumSize(new Dimension(22, 20));
      rigidArea_4.setPreferredSize(new Dimension(30, 20));
      horizontalBox.add(rigidArea_4);
      horizontalBox.add(b3);
      
      Component horizontalGlue_1 = Box.createHorizontalGlue();
      horizontalBox.add(horizontalGlue_1);
      
      Box horizontalBox_2 = Box.createHorizontalBox();
      sl_panel.putConstraint(SpringLayout.NORTH, horizontalBox, 6, SpringLayout.SOUTH, horizontalBox_2);
      sl_panel.putConstraint(SpringLayout.NORTH, horizontalBox_2, 6, SpringLayout.SOUTH, horizontalBox_1);
      sl_panel.putConstraint(SpringLayout.WEST, horizontalBox_2, 0, SpringLayout.WEST, horizontalBox_1);
      sl_panel.putConstraint(SpringLayout.EAST, horizontalBox_2, 0, SpringLayout.EAST, horizontalBox_1);
      panel.add(horizontalBox_2);
      
      sliderY1 = new JSlider();
      sliderY1.setPreferredSize(new Dimension(220, 26));
      sliderY1.setMajorTickSpacing(1);
      sliderY1.setMaximum(298);
      sliderY1.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            int value = sliderY1.getValue();
            spinner_Y1.setValue(value);            
         }
      });
      sliderY1.setBackground(SystemColor.menu);
      sliderY1.setValue(0);
      sliderY1.setForeground(Color.WHITE);
      horizontalBox_2.add(sliderY1);
      
      sliderX1 = new JSlider();
      sliderX1.setPreferredSize(new Dimension(220, 26));
      sliderX1.setMajorTickSpacing(1);
      sliderX1.setMaximum(700);
      sliderX1.setValue(0);
      sliderX1.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            int value = sliderX1.getValue();
            spinner_X1.setValue(value);
         }
      });
      
      Component rigidArea_10 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_10.setPreferredSize(new Dimension(15, 20));
      rigidArea_10.setMinimumSize(new Dimension(15, 20));
      rigidArea_10.setMaximumSize(new Dimension(15, 20));
      horizontalBox_2.add(rigidArea_10);
      
      sliderX1.setForeground(Color.WHITE);
      horizontalBox_2.add(sliderX1);
      
      Component rigidArea_11 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_11.setPreferredSize(new Dimension(15, 20));
      rigidArea_11.setMinimumSize(new Dimension(15, 20));
      rigidArea_11.setMaximumSize(new Dimension(15, 20));
      horizontalBox_2.add(rigidArea_11);
      
      sliderY2 = new JSlider();
      sliderY2.setMinorTickSpacing(1);
      sliderY2.setMajorTickSpacing(1);
      sliderY2.setMaximum(298);
      sliderY2.setValue(0);
      sliderY2.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            int value = sliderY2.getValue();
            spinner_Y2.setValue(value);
         }
      });
      sliderY2.setPreferredSize(new Dimension(220, 26));
      sliderY2.setForeground(Color.WHITE);
      horizontalBox_2.add(sliderY2);
      
      Component rigidArea_12 = Box.createRigidArea(new Dimension(20, 20));
      rigidArea_12.setPreferredSize(new Dimension(15, 20));
      rigidArea_12.setMinimumSize(new Dimension(15, 20));
      rigidArea_12.setMaximumSize(new Dimension(15, 20));
      horizontalBox_2.add(rigidArea_12);
      
      sliderX2 = new JSlider();
      sliderX2.setMinorTickSpacing(1);
      sliderX2.setMajorTickSpacing(1);
      sliderX2.setMaximum(700);
      sliderX2.setValue(0);
      sliderX2.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            int value = sliderX2.getValue();
            spinner_X2.setValue(value);
         }
      });
      sliderX2.setPreferredSize(new Dimension(220, 26));
      sliderX2.setSnapToTicks(true);
      sliderX2.setForeground(Color.WHITE);
      horizontalBox_2.add(sliderX2);
      graph =  new Graph(5,5,JC_WIDTH,JC_HEIGHT);
      getContentPane().add(graph);      
   }
}

Författare:  4kTRB [ 14.33 2019-08-25 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Gjorde det lättare för mig och inhandlade en
Adafruit PT100 RTD Temperature Sensor Amplifier - MAX31865

Så nu ska jag lära mig programmera den och SPI dessutom.

Bild

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

Har nu lyckats att mäta med MAX31865 kortet efter diverse
inställningar i Eclipse för att det skulle bli rätt med <SPI.h>
och <Adafruit_MAX31865.h>. Det går bra att ha dessa lokalt
i mappen med programkoden om man bara ser till att ändra
till "SPI.h" och "Adafruit_MAX31865.h" på rätt ställen men det behövs inte
om man talar om för Eclipse att de finns i .arduinocdt mappen.

Anslöt en trimpot som en 2-tråds RTD och kör exemplet från Adafruit.

Författare:  4kTRB [ 08.29 2019-10-13 ]
Inläggsrubrik:  Re: Mätapplikation med Arduino och Java

Har tagit en paus med projektet och det senaste jag gjort var att jag städade upp i koden ordentligt. När jag labbar med kod så kommer jag på nya enklare lösningar och lägger till det och rensar inte alltid bort den gamla koden, sånt som är onödigt. Sedan har jag testat en simulerad datainsamling med vridpotentiometrar för NTC och temperatur och det fungerar som tänkt.

Jag är i alla fall fast besluten att ha ett fungerande NTC-mätinstrument på labbänken framöver. Det återstår trots allt inte särskilt mycket för att det ska bli verklighet. Tänkte mig en låda med usb och anslutningsanordning för NTC brevid ett värmeelement.

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