Frequenzzähler mit Ausgabe auf HD44780 Display

Hallo,

ich habe einen kapazitiven Sensor, der seine Messwerte als Frequenz ausgobt, die ich mit dem angehängten Code messe - das funktioniert auch gut.
Nun sollen die Messwerte noch auf einem HD44780 LCD ausgegeben werden.
Leider funktioniert das allerdings nicht. Es wird einfach überhaupt nichts angezeigt. Der Displaycode für sich sowohl der "Frequenzcode" funktionieren.
Leider weiß ich nicht, wie ich die beiden zusammenbringe

Kann mir hier jemand helfen?

Grüße
tim

// Timer and Counter example
// Author: Nick Gammon
// Date: 17th January 2012

// Input: Pin D5



#include "Wire.h"
#include "Adafruit_LiquidCrystal.h"
Adafruit_LiquidCrystal lcd(4, 2, 6, 7, 8, 9);
byte block_1[8] = {  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
byte block_2[8] = {  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111};
byte block_3[8] = {  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111};
byte block_4[8] = {  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111};
byte block_5[8] = {  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
byte block_6[8] = {  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
byte block_7[8] = {  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
byte block_8[8] = {  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};

unsigned long i = 3000;
int sensorValue = 9999;
int k = 6000;
int gegossen = 0;
boolean watering = LOW;

// these are checked for in the main program
volatile unsigned long timerCounts;
volatile boolean counterReady;

// internal to counting routine
unsigned long overflowCount;
unsigned int timerTicks;
unsigned int timerPeriod;

void startCounting (unsigned int ms) 
  {
  counterReady = false;         // time not up yet
  timerPeriod = ms;             // how many 1 ms counts to do
  timerTicks = 0;               // reset interrupt counter
  overflowCount = 0;            // no overflows yet

  // reset Timer 1 and Timer 2
  TCCR1A = 0;             
  TCCR1B = 0;              
  TCCR2A = 0;
  TCCR2B = 0;

  // Timer 1 - counts events on pin D5
  TIMSK1 = bit (TOIE1);   // interrupt on Timer 1 overflow

  // Timer 2 - gives us our 1 ms counting interval
  // 16 MHz clock (62.5 ns per tick) - prescaled by 128
  //  counter increments every 8 µs. 
  // So we count 125 of them, giving exactly 1000 µs (1 ms)
  TCCR2A = bit (WGM21) ;   // CTC mode
  OCR2A  = 124;            // count up to 125  (zero relative!!!!)

  // Timer 2 - interrupt on match (ie. every 1 ms)
  TIMSK2 = bit (OCIE2A);   // enable Timer2 Interrupt

  TCNT1 = 0;      // Both counters to zero
  TCNT2 = 0;     

  // Reset prescalers
  GTCCR = bit (PSRASY);        // reset prescaler now
  // start Timer 2
  TCCR2B =  bit (CS20) | bit (CS22) ;  // prescaler of 128
  // start Timer 1
  // External clock source on T1 pin (D5). Clock on rising edge.
  TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12);
  }  // end of startCounting

ISR (TIMER1_OVF_vect)
  {
  ++overflowCount;               // count number of Counter1 overflows  
  }  // end of TIMER1_OVF_vect


//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer 2 every 1 ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz

ISR (TIMER2_COMPA_vect) 
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = TCNT1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  // see if we have reached timing period
  if (++timerTicks < timerPeriod) 
    return;  // not yet

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;

  // end of gate time, measurement ready

  TCCR1A = 0;    // stop timer 1
  TCCR1B = 0;    

  TCCR2A = 0;    // stop timer 2
  TCCR2B = 0;    

  TIMSK1 = 0;    // disable Timer1 Interrupt
  TIMSK2 = 0;    // disable Timer2 Interrupt
    
  // calculate total count
  timerCounts = (overflowCopy << 16) + timer1CounterValue;  // each overflow is 65536 more
  counterReady = true;              // set global flag for end count period
  }  // end of TIMER2_COMPA_vect

void setup () 
  {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(11, HIGH); //grünes kabel
  digitalWrite(12, LOW);
 
  pinMode(4, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(5, INPUT);
  analogWrite(3, 128);
  // set up the LCD's number of rows and columns:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Feuchte:");
  lcd.createChar(0, block_1);
  lcd.createChar(1, block_2);
  lcd.createChar(2, block_3);
  lcd.createChar(3, block_4);
  lcd.createChar(4, block_5);
  lcd.createChar(5, block_6);
  lcd.createChar(6, block_7);
  lcd.createChar(7, block_8);
  } // end of setup










void loop () 
  {



    
  // stop Timer 0 interrupts from throwing the count out
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // stop timer 0
  TCCR0B = 0;    
  
  startCounting (500);  // how many ms to count for

  while (!counterReady) 
     { }  // loop until count over

  // adjust counts by counting interval to give frequency in Hz
  float frq = (timerCounts *  1000.0) / timerPeriod;
  frq=frq/270;
  Serial.print ("Sensor: ");
  Serial.println ((unsigned long) frq);

  
  // restart timer 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;
  
  // let serial stuff finish
  delay(200);

  
    lcd.clear();
    lcd.print("Feuchte:");
    lcd.setCursor(8, 0);
    lcd.print("Feuchte:");
    lcd.setCursor(12, 0);
    lcd.print(k);

  lcd.setCursor(5, 1); lcd.write(0x0);
  lcd.setCursor(6, 1); lcd.write(0x1);
  lcd.setCursor(7, 1); lcd.write(0x2);
  lcd.setCursor(8, 1); lcd.write(0x3);
  lcd.setCursor(9, 1); lcd.write(0x4);
  lcd.setCursor(10, 1); lcd.write(0x5);
  lcd.setCursor(11, 1); lcd.write(0x6);
  lcd.setCursor(12, 1); lcd.write(0x7);
  
  i = i + 1;





  }   // end of loop

Du darfst die Pins, an denen das Lcd angeschlossen wird, nicht noch mal im Setup als Output festlegen. Das passiert schon in der Library.

Hallo,

ich habe diese jetzt entfernt aber das gleiche Ergebnis. Der Code funktioniert alleine ja auch.
Vermutlich liegt das an den Timern und Interrupt.
Man müsste das ganze anhalten können, dann wird es angezeigt und wieder gemessen.
Das Messen nur alle paar Minuten mal stattfinden. Die Anzeige soll dann dauerhaft das jeweilige Ergebnis anzeigen

zeigt er denn im SerialMonitor was ab?

Wenn ja, dann direkt dahinter

  Serial.print ("Sensor: ");
  Serial.println ((unsigned long) frq);

die LCD-Ausgabe setzen.

Ja seriell funktioniert wie gewünscht und dort hatte ich die LCD-Ausgabe auch gesetzt.
Habe auch schon die LCD Ausgabe zwischen
noInterrupts();
und
interrupts();

gesetzt, allerdings auch ohne Erfolg

Wird der Sketch denn fehlerfrei kompiliert?

Ja, ohne Probleme

timtailors:
Ja, ohne Probleme

Und dein Display ist auch ok?
Dann würde ich testweise eine Printausgabe in das Setup setzen.

Ja, wie gesagt, der LCD Code in einem eigenen Sketch funktioniert und der Frequenzzählersketch eben auch.
Offenbar wird da etwas dann beim zusammenfügen durch Interrupts o.ä in der LCD-Ausgabe gestört.

Wie im angehängten Code oben ersichtlich ist auch eine Ausgabe im Setup bereits vorhanden

timtailors:
Ja, wie gesagt, der LCD Code in einem eigenen Sketch funktioniert und der Frequenzzählersketch eben auch.
Offenbar wird da etwas dann beim zusammenfügen durch Interrupts o.ä in der LCD-Ausgabe gestört.

Wie im angehängten Code oben ersichtlich ist auch eine Ausgabe im Setup bereits vorhanden

Ok, übersehen.
Wird das auch nicht angezeigt?

Nein, leider nicht.

Sobald ich dieses Teil aus der Schleife entferne, dann geht es wieder

  // stop Timer 0 interrupts from throwing the count out
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // stop timer 0
  TCCR0B = 0;    
  
  startCounting (500);  // how many ms to count for

  while (!counterReady) 
     { }  // loop until count over

  // adjust counts by counting interval to give frequency in Hz
  float frq = (timerCounts *  1000.0) / timerPeriod;
  frq=frq/270;
  Serial.print ("Sensor: ");
  Serial.println ((unsigned long) frq);
Serial.print (i);
 
    
    i = i + 1;

  // restart timer 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;
  
  // let serial stuff finish
  delay(200);

Habe auch schon versucht diesen in eine Schleife mit Zähler zu packen und dann alle paar Sekunden nur aufzurufen, aber ads funktioniert auch nicht, da irgendein Interrupt dazwischenfunkt

Das ist ein Timer-Problem. Du must das Display auf andere Pins legen.
https://arduino-info.wikispaces.com/Timers-Arduino

Oder du verwendest für das Display I2C, dann sind auch gleich mehr Eingänge frei.

Hallo,

ja das vermute ich ja auch schon die ganze Zeit, aber weiß hier wirklich nicht mehr weiter welche Pins ich hier verlegen müsste

I2C ist bei diesem Display m.w nicht möglich

Lässt sich diese Timergeschichte nicht einfach stoppen? Ich muss den Messwert nur alle 6 Stunden einmal abrufen. Dazwischen dürfen diese Timer gerne deaktiviert sein.

Das Display kannst du leicht erweitern, mit solchem Modul.

http://www.ebay.de/itm/I2C-Serielle-Schnittstelle-Modul-fur-LCD-Display-1602-IIC-SPI-TWI-Arduino-/221717504003?hash=item339f64a003:g:9hoAAOSwBahVB42x

Wenn du die Pins ändern möchtest, betrifft es die "6,7,8,9", die geändert werden müssen.
Was den Timer betrifft, da bin ich nicht fitt.

Hallo,

du möchtest mit Timer 0 6h Intervalle messen? Wenn ja, was für eine Verschwendung. Mit Timer 0 wird "intern" mehr gemacht als du siehst. millis, delay, micros. Deswegen versaut man sich alles wenn man unbekümmert am Timer 0 rumfummelt. Nimm millis und einen Vergleichwert für deine 6h. millis alleine reicht bis 49 Tage. Nimm das Timer 0 Gedöhns ganz raus.

Doc_Arduino:
Hallo,

du möchtest mit Timer 0 6h Intervalle messen? Wenn ja, was für eine Verschwendung. Mit Timer 0 wird "intern" mehr gemacht als du siehst. millis, delay, micros. Deswegen versaut man sich alles wenn man unbekümmert am Timer 0 rumfummelt. Nimm millis und einen Vergleichwert für deine 6h. millis alleine reicht bis 49 Tage. Nimm das Timer 0 Gedöhns ganz raus.

Naja, du darfst nicht so streng sein. Soweit ich gelesen habe ist der Sketch von Nick Gammon und verwendet Timer 1 und Timer 2.

Ich freue mich ja, dass ihr helfen wollt, aber lest euch bitte doch einmal genau durch um was es geht...

Der Timer wird für die Frequenzmessung benötigt. Es wird damit ein Bodenfeuchtesensor abgefragt, der den Wert als Frequenz ausgibt. Diese möchte ich nun alle 6 Stunden einmal messen.

Das spielt aber alles erstmal keine Rolle. Mir geht es nur darum in den Code des Frequenzzählers den Code der LCD-Ausgabe zu implementieren.

Sehr nett,dass du das Modul für mich noch herausgesucht hast. Ich würde es zunächst aber gerne ohne betreiben. Ausgänge sind genug noch vorhanden und das ganze soll später batteriebetrieben werden und da hätte ich gerne so wenig Module wie möglich

timtailors:
Ich freue mich ja, dass ihr helfen wollt, aber lest euch bitte doch einmal genau durch um was es geht...

Der Timer wird für die Frequenzmessung benötigt. Es wird damit ein Bodenfeuchtesensor abgefragt, der den Wert als Frequenz ausgibt. Diese möchte ich nun alle 6 Stunden einmal messen.

Das spielt aber alles erstmal keine Rolle. Mir geht es nur darum in den Code des Frequenzzählers den Code der LCD-Ausgabe zu implementieren.

Sehr nett,dass du das Modul für mich noch herausgesucht hast. Ich würde es zunächst aber gerne ohne betreiben. Ausgänge sind genug noch vorhanden und das ganze soll später batteriebetrieben werden und da hätte ich gerne so wenig Module wie möglich

Ok, das versteh ich ja alles.

Aber da du den Sketch offensichtlich nicht selbst geschrieben hast, warum wendest du dich nicht an den Ersteller?
Wir kennen den Sketch auch nicht weiter und können mangels Hardware auch nicht alles nachvollziehen.

Daher der Tipp mit I2C, dann könnte man das Problem mit den betroffenen Pins umgehen.
Später kannst du immer noch am Sketch Änderungen vornehmen, damit es so läuft wie du möchtest.

Oder du wartest eben, bis einer sich komplett in den Sketch einliest.

Ok, ja das wäre noch eine Möglichket, ich dachte nur ich frage hier, weil der Ursprungssketch ja problemlos funktioniert.

Mal schauen, vielleicht meldet sich ja hier noch jemand, der sich mit dieser Timer, Interrupt-Thematik auskennt. Ich habe es mir schon durchgelesen, aber verstehe es momentan leider noch nicht

Hallo,

warum stoppst du Timer 0 überhaupt? Wegen dem Frequenzzähler?
Wenn du Timer 0 nicht stoppst, funktioniert dann der Frequenzzähler noch richtig oder nicht?
Probiere mal.

Ansonsten reicht es auch aus den Timer, egal welcher, zu stoppen in dem man die CSxx Bits auf 0 setzt. Also den Prescaler auf 0. Würde bedeuten das Register TCCR0A muß man nicht anfassen. Entweder man sichert nun TCCR0B komplett wie du das schon machst oder man ändert die Bits einzeln. Komplett ist einfacher. :slight_smile:
Wenn das nicht klappt, versuche mal direkt davor und direkt danach die Interrupts aus- und wieder einzuschalten.

cli();         // Interrupts ausschalten
TCCR0B = 0;    // Reset TCCR1B Register
sei();         // Interrupts einschalten
cli();         // Interrupts ausschalten
TCCR0B = oldTCCR0B;  // TCCR1B Register wiederherstellen
sei();         // Interrupts einschalten

Probiere mal ...

Welchen Arduino hast du überhaupt?