EmonTX Serial Monitoring Problem - garbled characters

Hi all,

I have been trying to get some of my old emonTX kit back working again for a couple of projects. The first is some automation on our tumble dryer. The dryer is connected to a homemade heat recovery unit, which needs to be activated when the dryer is running. So my plan was to put a CT on the dryer power supply, and use this to switch the fans on the heat recovery.

As a bonus, I thought I could use one of my emonTX v2 units to monitor the dryer energy use as well (hopefully to demonstrate that the heat recovery is working!).

So I wrote a modified version of the CT123 sketch. As well as the monitoring, the sketch a) turns on the heat recovery (DryerPin digital output to other controller) and also controls a servo which opens/closes a damper in the duct.

Code is below.

When run the serial monitor, I initially get numbers I expect (around 2.6kW dryer power), but then the numbers start to become garbled, with strange characters coming in. I have checked baud rates and the usual suspects for this.

The serial seems to work ok itself- I can run simple “hello world” sketches no problem.

I’m having the issue with more than one Arduino-based board.

The common theme seems to be sketches which use the emontx library as far as I can tell. I have another sketch which is similar, but simply collects temperatures which I want to monitor on serial (as well as sending to emoncms). I get the same issue- random characters mixed with numbers and text.

Any thoughts on what could be going wrong? Is it the UART programmer? Is it to do with emontx library?

Any thoughts much appreciated!

Chris

/*
 EmonTx CT123 example
 
 An example sketch for the emontx module for
 CT only electricity monitoring.
 
 Part of the openenergymonitor.org project
 Licence: GNU GPL V3
 
 Authors: Glyn Hudson, Trystan Lea
 Builds upon JeeLabs RF12 library and Arduino
 
 emonTx documentation: 	http://openenergymonitor.org/emon/modules/emontx/
 emonTx firmware code explination: http://openenergymonitor.org/emon/modules/emontx/firmware
 emonTx calibration instructions: http://openenergymonitor.org/emon/modules/emontx/firmware/calibration

 THIS SKETCH REQUIRES:

 Libraries in the standard arduino libraries folder:
	- JeeLib		https://github.com/jcw/jeelib
	- EmonLib		https://github.com/openenergymonitor/EmonLib.git

 Other files in project directory (should appear in the arduino tabs above)
	- emontx_lib.ino
 
*/

/*Recommended node ID allocation
------------------------------------------------------------------------------------------------------------
-ID-	-Node Type- 
0	- Special allocation in JeeLib RFM12 driver - reserved for OOK use
1-4     - Control nodes 
5-10	- Energy monitoring nodes
11-14	--Un-assigned --
15-16	- Base Station & logging nodes
17-30	- Environmental sensing nodes (temperature humidity etc.)
31	- Special allocation in JeeLib RFM12 driver - Node31 can communicate with nodes on any network group
-------------------------------------------------------------------------------------------------------------
*/

#define FILTERSETTLETIME 5000                                           //  Time (ms) to allow the filters to settle before sending data

const int CT1 = 1; 
const int CT2 = 0;                                                      // Set to 0 to disable CT channel 2
const int CT3 = 0;                                                      // Set to 0 to disable CT channel 3

#define RF69_COMPAT 0 // SET TO 1 IF RFM69
#define RF_freq RF12_868MHZ                                                // Frequency of RF12B module can be RF12_433MHZ, RF12_868MHZ or RF12_915MHZ. You should use the one matching the module you have.
const int nodeID = 10;                                                  // emonTx RFM12B node ID
const int networkGroup = 210;                                           // emonTx RFM12B wireless network group - needs to be same as emonBase and emonGLCD

const int UNO = 1;                                                      // Set to 0 if your not using the UNO bootloader (i.e using Duemilanove) - All Atmega's shipped from OpenEnergyMonitor come with Arduino Uno bootloader
#include <avr/wdt.h>                                                     

#define RF69_COMPAT 0 // set to 1 to use RFM69CW 
#include <JeeLib.h>   // make sure V12 (latest) is used if using RFM69CW
ISR(WDT_vect) { Sleepy::watchdogEvent(); }                              // Attached JeeLib sleep function to Atmega328 watchdog -enables MCU to be put into sleep mode inbetween readings to reduce power consumption 

#include "EmonLib.h"
EnergyMonitor ct1,ct2,ct3;                                              // Create  instances for each CT channel

typedef struct { int power1, power2, power3, battery; } PayloadTX;      // create structure - a neat way of packaging data for RF comms
PayloadTX emontx;                                                       

const int LEDpin = 9;                                                   // On-board emonTx LED 

boolean settled = false;


#include <Servo.h>
Servo servoMain; // Define our Servo
int Pos=0;
boolean Signal;

const int DryerPin=6; //Output pin to signal to main Arduino for dryer operation.
const int Dryer_Threshold=100; //Power threshold (to be tested. Needs to be when dryer on, but not heating or motor on)
    
       
void setup() 
{
    
  servoMain.attach(10,2000,12000); 
  pinMode(3,INPUT);
  digitalWrite(LEDpin,HIGH);
  servoMain.write(Pos);//Start with damper closed
  delay(15);
    
   pinMode(DryerPin, OUTPUT);
   digitalWrite(DryerPin, LOW);
    
    
  Serial.begin(9600);
  Serial.println("emonTX CT123 example"); 
  Serial.println("OpenEnergyMonitor.org");
  Serial.print("Node: "); 
  Serial.print(nodeID); 
  Serial.print(" Freq: "); 
  if (RF_freq == RF12_433MHZ) Serial.print("433Mhz");
  if (RF_freq == RF12_868MHZ) Serial.print("868Mhz");
  if (RF_freq == RF12_915MHZ) Serial.print("915Mhz"); 
 Serial.print(" Network: "); 
  Serial.println(networkGroup);
             
  if (CT1) ct1.currentTX(1, 111.1);                                     // Setup emonTX CT channel (ADC input, calibration)
  if (CT2) ct2.currentTX(2, 111.1);                                     // Calibration factor = CT ratio / burden resistance
  if (CT3) ct3.currentTX(3, 111.1);                                     // Calibration factor = (100A / 0.05A) / 33 Ohms
  
  rf12_initialize(nodeID, RF_freq, networkGroup);                          // initialize RFM12B
  rf12_sleep(RF12_SLEEP);

  pinMode(LEDpin, OUTPUT);                                              // Setup indicator LED
  digitalWrite(LEDpin, HIGH);
  
  if (UNO) wdt_enable(WDTO_8S);                                         // Enable anti crash (restart) watchdog if UNO bootloader is selected. Watchdog does not work with duemilanove bootloader                                                             // Restarts emonTx if sketch hangs for more than 8s
}

void loop() 
{ 
        
   
        
  if (CT1) {
    emontx.power1 = ct1.calcIrms(1480) * 240.0;                         //ct.calcIrms(number of wavelengths sample)*AC RMS voltage
    Serial.println(emontx.power1); 
    delay(1000);                                        
  }
  
  if (CT2) {
    emontx.power2 = ct2.calcIrms(1480) * 240.0;
    Serial.print(" "); Serial.print(emontx.power2);
  } 

  if (CT3) {
    emontx.power3 = ct3.calcIrms(1480) * 240.0;
    Serial.print(" "); Serial.print(emontx.power3);
  } 
  
  emontx.battery = ct1.readVcc();                                      //read emonTx battey (supply voltage)



 //CHECK  IF DRYER IS RUNNING.
 
  if(emontx.power1<Dryer_Threshold) //If the dryer power consumption is less than 100W, assume it is not operating. This figure could probably be reduced.
  {
        servoMain.write(10);//close the damper
        digitalWrite(DryerPin,LOW); //Send signal to MVHR to shut down.
  }
 else
     {
       servoMain.write(180);//Open the damper
       digitalWrite(DryerPin,HIGH); //Send signal to MVHR to shut down.
     }
       
  
  //Serial.print(" "); Serial.print(emontx.battery);
  //Serial.println(); delay(100);

  // because millis() returns to zero after 50 days ! 
  if (!settled && millis() > FILTERSETTLETIME) settled = true;

  if (settled)                                                            // send data only after filters have settled
  { 
    send_rf_data();                                                       // *SEND RF DATA* - see emontx_lib
    digitalWrite(LEDpin, HIGH); delay(2); digitalWrite(LEDpin, LOW);      // flash LED
    emontx_sleep(5);                                                      // sleep or delay in seconds - see emontx_lib
  }

}

Edit - formatted text. BT, Moderator

Look at Serial in the Arduino documentation - you could add Serial.flush( ) which should stop the sketch until it’s finished, or you could add a delay( ) after the affected Serial.print( ).

Probably neither.

Hi Robert,
When you say something could be stealing processor time, do you mean in the
sketch? Or in the PC?

I’ve found that extending the delays in the RF functions seem to solve the
issue, but this means I have to wait a lot longer for serial data.

Chris

I meant in the sketch. I’d hope that your PC has a much more powerful processor than the Atmel 328P :wink:

It’s a pretty old laptop, but take your point!

The sketch is only a modified version of a standard emonTx sketch which has
similar serial outputs. So seems strange that I have this, presumably it’s
not an issue with emonTx?

Chris

Mostly, the emonTx is used principally with the RFMxxx output, and the serial output is used only for setup and calibration or debugging. If you’re using the serial output only, and not using the RF output, you could comment out those lines.
Also, I don’t know what your servo library is doing. That could be running something in the background.

Makes sense. Thanks.

Chris

It’s a hardware UART, so CPU loading shouldn’t cause garbled characters to be output. The interface between the CPU and the UART is byte-wide, i.e. the CPU puts the next byte to be output into the UART tx register, and the UART then clocks the 8-10 bits out as per the current configuration, independently of what the CPU is then doing. High CPU load might cause there to be a gap between outgoing bytes but with asynchronous comms that’s normal and fine, there’s no requirement for the bytes to be transmitted back-to-back at line speed.

I suspect the garbled transmission is more likely caused by the calls to put the processor to sleep while there’s a transmission in progress. That sleep mode likely puts the UART to sleep right while it’s outputting a byte. The receiver will definitely get confused by that. You could try commenting out all sleep calls and see if that fixes it.

It will probably be the sleep calls, the emonTx is going to sleep before the serial buffer had emptied. Try adding a delay e.g. delay(100); (10 or 50ms might actually be enough) after a block of serial prints before a sleep command.

Wouldn’t using Serial.flush as per @Robert.Wall’s suggestion effectively delay the sketch “just enough” for the serial transmission to complete, automatically making it the shortest delay without any risk of it being too short?

That sounds ideal for commencing a sleep routine to minimize battery drain, is there a down side to this method?

Yes, I think that would be a very effective way of knowing how long to wait before going to sleep. The part I had an issue with was:

“It’s likely to be something else stealing processor time while the serial output is still sending characters slowly”

I don’t think that’s correct, and if it were correct, there’s no bigger CPU hog than a call to delay() or flush() so they presumably wouldn’t help. If it’s the call to sleep in mid-transmission that’s causing the garbled data (which I suspect) then either a call to delay() or flush() before sleeping will fix it, and as you point out, flush() is the tighter of the two.

Serial.Flush() worked a treat. Thanks for your help everyone!