Share tips you have come across

Been done a gazillion times but always worth a mention.
Just remember to add an extra circuit for better temperature control !
Some of those things fluctuate wildly.

And it's best to insulate it with some high-temp blanket, especially around the electronics.

1 Like

Further to post #459


An oscilloscope can be a valuable tool when tracking down problems in your Arduino projects.

We need to trigger the scope at the right time before signal analysis can proceed.

Code to produce a pulse of ~63ns can be inserted at an appropriate location in your existing sketch.

The scope can then use this pulse to trigger the display.


Below are Debugging Macros to control output pins for diagnostics.

Also included are some useful Port Manipulation macros that you can use in your sketches for an Arduino UNO.

//*******************************************************************************
//For diagnostic purposes OR just to create fast pulses.
//
//To guarantee that interrupts do not occur during pulse creation,
//it is best to use cli() and sei() to disable then enable interrupts.
//
//BTW: Remember it takes about 400ns for the code to go from
//the closing } to the opening { in loop()
//*******************************************************************************

//macro definition for a pulse on UNO pin 11 i.e. PINB3
#define PULSE11          cli(); PINB = bit(PINB3); PINB = bit(PINB3); sei()

int led = 11;

//===============================================================================
void setup()
{
  pinMode(led, OUTPUT);

} //END of setup()

//===============================================================================
void loop()
{
  //pulse of 62.5ns
  //PULSE11;                      //62.5ns wide pulse on pin 11

  //cli();                      //Disable interrupts

  //pulse of 62.5ns
  //PINB = bit(PINB3);          //Toggle pin 11
  //PINB = bit(PINB3);          //Toggle pin 11

  //  S a m e   a s   a b o v e
  //pulse of 62.6ns
  //PINB = _BV(PINB3);          //Toggle on pin 11
  //PINB = _BV(PINB3);          //Toggle on pin 11

  //pulse of ~126ns
  //PINB |= _BV(PINB3);         //Toggle pin 11
  //PINB |= _BV(PINB3);         //Toggle pin 11

  //pulse of 126ns
  //                  --1111
  //                  --321098
  //PORTB = PORTB | 0b00001000; //set D11 (high)
  //PORTB = PORTB & 0b11110111; //clear D11 (low)
  //

  //Delay of ~62.5ns
  //asm("nop\n");               //Each "nop\n" gives 62.5ns delay

  //Delay of 126ns
  //asm("nop\n" "nop\n");       //Each "nop\n" gives 62.5ns delay

  //sei();                      //Enable interrupts

  //Other delays, remember these are blocking
  //delay(1);
  //delayMicroseconds(10);

} //END of loop()


//*******************************************************************************
//                   Some macros that you might find useful


//*******************************************************************************
//                           m y U N O M a c r o s . h
//*******************************************************************************
//Port manipulation Macros for the Arduino UNO
//
// myUNOMacros.h
// this file goes into the C:\Users\YOURUSER\Documents\Arduino\libraries\ folder.
//
// LarryD
// These Macros can be used with UNO board
//
//
// ATMEL ATMEGA8 & 168/328  ARDUINO UNO
//
//                  +-\/-+
//            PC6  1|    |28  PC5 (A 5)
//      (D 0) PD0  2|    |27  PC4 (A 4)
//      (D 1) PD1  3|    |26  PC3 (A 3)
//      (D 2) PD2  4|    |25  PC2 (A 2)
// PWM+ (D 3) PD3  5|    |24  PC1 (A 1)
//      (D 4) PD4  6|    |23  PC0 (A 0)
//            VCC  7|    |22  GND
//            GND  8|    |21  AREF
//            PB6  9|    |20  AVCC
//            PB7 10|    |19  PB5 (D 13)
// PWM+ (D 5) PD5 11|    |18  PB4 (D 12)
// PWM+ (D 6) PD6 12|    |17  PB3 (D 11) PWM
//      (D 7) PD7 13|    |16  PB2 (D 10) PWM
//      (D 8) PB0 14|    |15  PB1 (D 9)  PWM
//                  +----+
//
// ****************************************************************************
// Note:
// PIND D0 to D7
// D0=0x01 D1=0x02 D2=0x04 D3=0x08 D4=0x10 D5=0x20 D6=0x40 D7=0x80
//
// PINB D8 to D13
// D8=0x01 D9=0x02 D10=0x04 D11=0x08 D12=0x10 D13=0x20
//
// PINC D14 to D19
// D14=0x01 D15=0x02 D16=0x04 D17=0x08 D18=0x10 D19=0x20
// ****************************************************************************
//
// SETd?          Makes D?     HIGH
// RESETd?        Makes D?     LOW
// TOGGLEd?       Makes D?     go to the opposite state
// TESTd?         Reads D?     the pins state is read
//
//===============================================================================
// Port D port pins 0-7
//                              DDDDDDDD
//                              76543210
//#define SETd0       PORTD |= B00000001  // Pin D0 HIGH Shared with USB RX
//#define RESETd0     PORTD &= B11111110  // Pin D0 LOW Shared with USB TX
//#define TOGGLEd0    PIND   = B00000001  // Toggle digital pin D0 Shared with USB RX
//#define TESTd0      (PIND  & B00000001) // D0 is tested

//#define SETd1       PORTD |= B00000010  // Pin D1 HIGH Shared with USB RX
//#define RESETd1     PORTD &= B11111101  // Pin D1 LOW Shared with USB TX
//#define TOGGLEd1    PIND   = B00000010  // Toggle digital pin D1 Shared with USB TX
//#define TESTd1      (PIND  & B00000010) // D1 is tested

//                            DDDDDDDD
//                            76543210
#define SETd2       PORTD |= B00000100  // D2 HIGH       ~187.5ns to go HIGH
#define RESETd2     PORTD &= B11111011  // D2 LOW        ~187.5ns to go LOW
#define TOGGLEd2     PIND  = B00000100  // D2 Toggle     ~62.5ns to toggle a pin
#define TESTd2      (PIND  & B00000100) // D2 is tested  ~125ns to read a pin

#define SETd3       PORTD |= B00001000  // D3 HIGH
#define RESETd3     PORTD &= B11110111  // D3 LOW
#define TOGGLEd3     PIND  = B00001000  // D3 Toggle
#define TESTd3      (PIND  & B00001000) // D3 is tested

#define SETd4       PORTD |= B00010000  // D4 HIGH
#define RESETd4     PORTD &= B11101111  // D4 LOW
#define TOGGLEd4     PIND  = B00010000  // D4 Toggle   
#define TESTd4      (PIND  & B00010000) // D4 is tested

#define SETd5       PORTD |= B00100000  // D5 HIGH
#define RESETd5     PORTD &= B11011111  // D5 LOW
#define TOGGLEd5     PIND  = B00100000  // D5 Toggle 
#define TESTd5      (PIND  & B00100000) // D5 is tested

#define SETd6       PORTD |= B01000000  // D6 HIGH
#define RESETd6     PORTD &= B10111111  // D6 LOW
#define TOGGLEd6     PIND  = B01000000  // D6 Toggle  
#define TESTd6      (PIND  & B01000000) // D6 is tested

#define SETd7       PORTD |= B10000000  // D7 HIGH
#define RESETd7     PORTD &= B01111111  // D7 LOW
#define TOGGLEd7     PIND  = B10000000  // D7 Toggle  
#define TESTd7      (PIND  & B10000000) // D7 is tested

// Port B port pins 0-5
//                              DDDDDD
//                              111100
//                              321098
#define SETd8       PORTB  = B00000001  // D8 HIGH
#define RESETd8     PORTB &= B11111110  // D8 LOW
#define TOGGLEd8     PINB  = B00000001  // D8 Toggle
#define TESTd8      (PINB  & B00000001) // D8 is tested

#define SETd9       PORTB |= B00000010  // D9 HIGH
#define RESETd9     PORTB &= B11111101  // D9 LOW
#define TOGGLEd9     PINB  = B00000010  // D9 Toggle
#define TESTd9      (PINB  & B00000010) // D9 is tested

#define SETd10      PORTB |= B00000100  // D10 HIGH
#define RESETd10    PORTB &= B11111011  // D10 LOW
#define TOGGLEd10    PINB  = B00000100  // D10 Toggle
#define TESTd10     (PINB  & B00000100) // D10 is tested

#define SETd11      PORTB |= B00001000  // D11 HIGH
#define RESETd11    PORTB &= B11110111  // D11 LOW
#define TOGGLEd11    PINB  = B00001000  // D11 Toggle
#define TESTd11     (PINB  & B00001000) // D11 is tested

#define SETd12      PORTB |= B00010000  // D12 HIGH
#define RESETd12    PORTB &= B11101111  // D12 LOW
#define TOGGLEd12    PINB  = B00010000  // D12 Toggle
#define TESTd12     (PINB  & B00010000) // D12 is tested

#define SETd13      PORTB |= B00100000  // D13 HIGH
#define RESETd13    PORTB &= B11011111  // D13 LOW
#define TOGGLEd13    PINB  = B00100000  // D13 Toggle
#define TESTd13     (PINB  & B00100000) // D13 is tested


// Port C port pins 0-5
//                              DDDDDD
//                              111111
//                              987654
#define SETd14      PORTC |= B00000001  // D14 HIGH
#define RESETd14    PORTC &= B11111110  // D14 LOW
#define TOGGLEd14    PINC  = B00000001  // D14 Toggle
#define TESTd14     (PINC  & B00000001) // D14 is tested

#define SETd15      PORTC |= B00000010  // D15 HIGH
#define RESETd15    PORTC &= B11111101  // D15 LOW
#define TOGGLEd15    PINC  = B00000010  // D15 Toggle
#define TESTd15     (PINC  & B00000010) // D15 is tested

#define SETd16      PORTC |= B00000100  // D16 HIGH
#define RESETd16    PORTC &= B11111011  // D16 LOW
#define TOGGLEd16    PINC  = B00000100  // D16 Toggle
#define TESTd16     (PINC  & B00000100) // D16 is tested

#define SETd17      PORTC |= B00001000  // D17 HIGH
#define RESETd17    PORTC &= B11110111  // D17 LOW
#define TOGGLEd17    PINC  = B00001000  // D17 Toggle
#define TESTd17     (PINC  & B00001000) // D17 is tested

#define SETd18      PORTC |= B00010000  // D18 HIGH
#define RESETd18    PORTC &= B11101111  // D18 LOW
#define TOGGLEd18    PINC  = B00010000  // D18 Toggle
#define TESTd18     (PINC  & B00010000) // D18 is tested

#define SETd19      PORTC |= B00100000  // D19 HIGH
#define RESETd19    PORTC &= B11011111  // D19 LOW
#define TOGGLEd19    PINC  = B00100000  // D19 Toggle
#define TESTd19     (PINC  & B00100000) // D19 is tested


//*******************************************************************************
//                           D e b u g M a c r o s . h
//*******************************************************************************
//   Example of use:
//   #define DEBUG  //                              <---<<< this line must appear before the include line
//
//   #include <DebugMacros.h>
//
//If you comment the line:    #define DEBUG
//the Macro lines are defined as blank, thus would be ignored by the compiler
//#define DEBUG  // if this line is NOT commented, these macros will be included in the sketch
//examples:
//  This  converts to >>>>----------------------->  This OR a Blank Line.
// DPRINTLN("Testing123");                          Serial.println("Testing123");
// DPRINTLN(0xC0FFEEul,DEC);                        Serial.println(0xC0FFEEul,DEC);
// DPRINTLN(12648430ul,HEX);                        Serial.println(12648430ul,HEX);
// DPRINTLNF("This message came from your flash");  Serial.println(F("This message came from your flash"));
// DPRINT(myVariable);                              Serial.print(myVariable);
// DELAY(100);                                      delay(100);
// PINMODE(9600);                                   pinMode(9600);
// TOGGLEd13;                                       PINB = 0x20;  // D13 Toggle,for UNO ONLY
//
// Also, this works  #define INFO(...)  { Console->printf("INFO: "); Console->printf(__VA_ARGS__); }   >>>--->   where {} allows multiple lines of code.
// See: http://forum.arduino.cc/index.php?topic=511393.msg3485833#new

#ifdef DEBUG
//OR the next two lines
//#define DEBUG 1
//#if DEBUG || (another thing etc.)

//examples:
//#define DPRINT(args...)  Serial.print(args)  OR use the following syntax:
#define SERIALBEGIN(...)   Serial.begin(__VA_ARGS__)
#define DPRINT(...)        Serial.print(__VA_ARGS__)
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#define DRINTF(...)        Serial.print(F(__VA_ARGS__))
#define DPRINTLNF(...)     Serial.println(F(__VA_ARGS__)) //printing text using the F macro
#define DELAY(...)         delay(__VA_ARGS__)
#define PINMODE(...)       pinMode(__VA_ARGS__)
#define TOGGLEd13          PINB = 0x20                    //UNO's pin D13
#define PULSEd13           PINB = 0x20; PINB = 0x20       //a 62.5ns pulse is output on pin 13 "UNO"

#define DEBUG_PRINT(...)   Serial.print(F(#__VA_ARGS__" = ")); Serial.print(__VA_ARGS__); Serial.print(F(" "))
#define DEBUG_PRINTLN(...) DEBUG_PRINT(__VA_ARGS__); Serial.println()

//*******************************************************************************
#else

#define SERIALBEGIN(...)
#define DPRINT(...)
#define DPRINTLN(...)
#define DPRINTF(...)
#define DPRINTLNF(...)
#define DELAY(...)
#define PINMODE(...)
#define TOGGLEd13
#define PULSEd13

#define DEBUG_PRINT(...)
#define DEBUG_PRINTLN(...)

#endif

//*******************************************************************************

Further to post # 504

https://forum.arduino.cc/t/share-tips-you-have-come-across/428745/504?u=larryd

These Solderless Breadboard helpers are great for speeding up wiring.**

Other SMDs can be mounted on Machine Pin Headers as well.

Below are a few more ways that you can take advantage of the footprints of SMDs.

Some suggestions of use: **pull-ups/pulldowns, switches, capacitors, ferrite beads, jumpers, current limiting for LEDs, test points.

These helpers are: low profile, less likely to short, and are self-contained.

Make your helpers up ahead of time.

An eye loupe would be beneficial if you are over 50 :wink: .

1 Like

I would love to be able to afford one of these.

A few weeks back I used the following technique to troubleshoot a software issue.
Many here have done similar.
The following discussion might help new users.

If others can add to this discussion please do so.
• New users should also remember, using Serial.print() is still a valid way to troubleshoot many/most problems.


You will need to have either a digital oscilloscope or a logic analyzer.

Images seen below were made on a 350 MHz Rigol oscilloscope; however, a lower band width digital scope will work, too.


A HIGH pulse is used as a trigger signal to the scope.
You will need a spare pin on the Arduino where you can observe this pulse.
The easiest way to set the scope trigger is to use pulse width trigger.
Your scope should have the following trigger capabilities:
• P > , Trigger when the positive pulse width of the input signal is greater than the specified Pulse Width Setting.
• P < , Trigger when the positive pulse width of the input signal is lower than the specified Pulse Width Setting.
• P > L and P < H, Trigger when the positive pulse width of the input signal is greater than the specified Lower Limit of Pulse Width and lower than the Upper Limit of Pulse Width.

Experiment with the Auto/Normal/Single modes during troubleshooting.


We first define the macros needed to generate the trigger pulse widths.
Pin 13 on an UNO is used for our the pulse pin.
The pin is set to OUTPUT.
It is important to include cli(); and sei(). These will prevent interrupts from affecting the pulse widths.

It is also important to remember, SEI, CLI, and PINB add ≈ 186ns to the time interval between two pulses.
i.e. subtract 186ns from your measurements between two trigger pulses.


#define PULSE63_13 cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()
#define PULSE126_13 cli(); PINB = bit(PINB5); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE189_13 cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE252_13 cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE315_13 cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE378_13 cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
• etc.


  1. We will time how long it takes loop( ) to execute.
    • Place PULSE63_13; as the first line in the loop( ) function.
    • The trigger is set to + pulse > 50ns and < 80ns (pin 13).
    • We can now measure the time between pin 13 pulses; let the scope determine this by turning on measurement Low going pulse.

  1. We will time how long a 10ms millis( ) BWD timer actually is.
    • Place PULSE126_13; as the first line in the if( ) evaluation.
    • The trigger is set to + pulse > 110ns and < 130ns (pin 13).
    • You can now measure the time between pin 13 pulses; let the scope determine this by turning on measurement Low going pulse.

The comment in red should say: CLI, SEI and PINB ≈ 186ns

  1. We will time how long it takes to do a digitalWrite( ).
    • Place PULSE189_13; before and after the digitalWrite( )
    • The trigger is set to + pulse > 170ns and < 200ns (pin 13).
    • You can now measure the time between pin 13 pulses; let the scope determine this by turning on measurement Low going pulse.

  1. We want to see how many iterations are being performed in a for( ) loop.
    • Place PULSE252_13; as the first code line in the loop.
    • The trigger is set to + pulse > 240ns and < 270ns (pin 13).
    • You can count the number of 252ns pulses that you see, determining the number of iterations.

  1. We will check to see if a case is run in a switch. . .case structure.
    • Place a number of PULSE315_13; in each case of the switch. . .case
    • The trigger is set to + pulse > 300ns and < 326ns (pin 13). Check the number of 315ns pulses you see, determining if a case is being run.

  1. We want a hardware trigger each time there is an input pin interrupt.
    • Place PULSE378_13; in the ISR.
    • The trigger is set to + pulse > 366ns and < 386ns (pin 13).



Attached is the sketch used in this discussion.


//*********************************************************************************
// Version   YY/MM/DD   Description
// =======   ========   ===========
// 1.00      21/11/30   Working sketch
//

//*******************************************************************************
#define diagnostics

#ifdef diagnostics
#define PULSE63_13     cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()
#define PULSE126_13    cli(); PINB = bit(PINB5); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE189_13    cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE252_13    cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE315_13    cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#define PULSE378_13    cli(); PINB = bit(PINB5); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); asm("nop\n"); PINB = bit(PINB5); sei()
#else
#define PULSE63_13     //Not defined 
#define PULSE126_13    //Not defined     
#define PULSE189_13    //Not defined     
#define PULSE252_13    //Not defined     
#define PULSE315_13    //Not defined     
#define PULSE378_13    //Not defined     
#endif

//*******************************************************************************

#define CLOSED            LOW
#define OPEN              HIGH

#define ENABLED           true
#define DISABLED          false

const byte pulsePin     = 13;
const byte LED_1        = 12;
const byte LED_2        = 8;

const byte mySwitch     = 2;

bool switchFlag         = DISABLED;

byte lastMySwitch       = OPEN;

unsigned int counter    = 0;

//timing stuff
unsigned long switchMillis;
unsigned long timeClosed;
unsigned long stateMachineMillis;


//*******************************************************************************
void setup()
{
  pinMode(pulsePin, OUTPUT);
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

  pinMode(mySwitch, INPUT_PULLUP);

  //set up interrupt for pin 2
  attachInterrupt(digitalPinToInterrupt(mySwitch), pin_2_ISR, HIGH);

} //END of setup()

//*******************************************************************************
void loop()
{
  //to check loop() execution
  //PULSE63_13;

  //************************************
  //is it time to check the switches ?
  if (millis() - switchMillis >= 10)
  {
    //to check 50ms TIMER duration
    //PULSE126_13;

    //restart the TIMER
    switchMillis = millis();

    checkSwitches();
  }

  //************************************
  //toggle LED2 when mySwitch is CLOSED
  if (switchFlag == ENABLED)
  {
    byte num = 10;
    
    if(counter > 5)
    {
      num = 3;
    }
    
    for (byte x = 0; x < num; x++)
    {
      //to check how many iterations occur
      //PULSE252_13;

      //toggle the LED
      digitalWrite(LED_2, !digitalRead(LED_2));

    } //END of for()

    switchFlag = DISABLED;

    digitalWrite(LED_2, LOW);

  } //END of  if(switchState == CLOSED)

  //************************************
  //is it time to check the State Machine ?
  if (millis() - stateMachineMillis >= 50)
  {
    //reset the TIMER
    stateMachineMillis = millis();

    //checkStateMachine();
  }

  //************************************
  //other non blocking code goes here
  //************************************

} //END of loop()


//*******************************************************************************
void pin_2_ISR()
{
  //provide an ISR hardware output trigger
  //PULSE378_13;

} //END of ISR


//*******************************************************************************
void checkStateMachine()
{
  switch (counter)
  {
    //**********************
    case 0:
      //do nothing;

      break;

    //**********************
    case 1:
      PULSE315_13;

      break;

    //**********************
    case 2:
      PULSE315_13;
      PULSE315_13;

      break;

    //**********************
    case 3:
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;

      break;

    //**********************
    case 4:
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;

      break;

    //**********************
    case 5:
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;
      PULSE315_13;

      break;

  } //END of switch...case

} //END of checkStateMachine()


//*******************************************************************************
void checkSwitches()
{
  //************************************                          m y S w i t c h
  byte currentState = digitalRead(mySwitch);

  if (lastMySwitch != currentState)
  {
    //update to the new state
    lastMySwitch = currentState;

    //*******************
    //was the switch closed ?
    if (currentState == CLOSED)
    {
      counter++;

      timeClosed = millis();

      switchFlag = ENABLED;

      //to check timing of a digitalWrite()
      //PULSE189_13;
      digitalWrite(LED_1, HIGH);
      //to check timing of a digitalWrite()
      //PULSE189_13;

    }

    //switch was released
    else
    {
      //was this a long push ?
      if (millis() - timeClosed > 2000)
      {
        //reset the counter
        counter = 0;
      }

      digitalWrite(LED_1, LOW);

    }

  } //END of if (lastMySwitch != currentState)

} //END of checkSwitches()

2 Likes

Got to try this. Looks like a great way to teach how to use of scope.