LM317 to output 3.3 Volts

I created a simple circuit using the LM317 to output 3.3 volts from a 5V or greater input voltage. Why? Because, a number of modules for the Arduino (or Pinguino) take 3.3 Volts. It’s true, some of the Arduinos do have a 3.3V voltage regulator (and thus a source of 3.3V), however, that might not have sufficient amperage. Also, if  you are a fan of the DIY (Do-It-Yourself)  Pinguinos (as I am), you will need a 3.3V source to accompany them since they do not have one.

So, it is quite handy to have a 3.3V power source around! Here is what the circuit looks like:

LM317 3.3 V Circuit Top ViewLM317 Circuit Side View

I save the foam pads, that came with PC motherboards I bought, and cut out pieces to place under the circuits I make to protect against short circuits. The pads are held in place with two-sided sticky tape.

Here Is the Fritzing circuit diagram:

 

LM317 3.3V Circuit Diagram

If you’d like the Fritzing source to the above diagram, download it from here.

The LM317 is an adjustable  linear voltage regulator. It can take an input voltage of 3-40 Volts DC and outputs a fixed voltage from 1.2 to 37 Volts DC. The output is controlled by resistors on the adjustment pin. Here is a handy calculator to calculate the resistance needed to obtain the desired output voltage. I use 545 Ohms (470 + 75) to output the desired 3.3V.

Notice that I have a two pin header or a power jack as input source (on the right of the pictures) and the output is a two pin header (on the left in the pictures).

I tested this circuit using the ESP8266 and the NL6621-Y1 modules that I wrote about in earlier articles. These modules require 3.3V and both worked fine.

I thought about integrating this circuit on the DIY Pinguino boards I made and might do that next time I get around to making more of them. However, I think the stand alone circuit is more flexible to use. For example, you can attach a USB to RS-232 cable (like this):

USB to Serial Cabledirectly to the circuit (5V Input and GND) and to the wireless module (Tx and Rcv from the cable, 3.3V and GND from the circuit)  and not even need an Arduino / Pinguino.

Serial Port Communication via Python

There are many Linux (and Windows) programs ‘out there’ that allow you to do serial port communications.  However, I needed some things that those programs did not provide (on my Linux system) so I came up with my Serial Port Communication via Python script. If you want something that you can learn from and/or customize further this script is for you (if you are using Linux that is). Here is the script:

                                Serial Port Communication via Python

#!/bin/env python
#
# From: earl@microcontrollerelectonics.com
#

import serial,sys,glob,select

dev  = "/dev/ttyACM*"
scan = glob.glob(dev)
rate = "115200"

if (len(scan) == 0):
  dev  = '/dev/ttyUSB*'
  scan = glob.glob(dev)
  if (len(scan) == 0):
    print "Unable to find any ports scanning for /dev/[ttyACM*|ttyUSB*]" + dev 
    sys.exit()

serport = scan[0]

if (len(sys.argv) > 1):
 l = len(sys.argv) - 1
 while(l>0):
   if (sys.argv[l][0] == '/'): serport = sys.argv[l]
   else:                       rate    = sys.argv[l]
   l = l - 1

ser = serial.Serial(port=serport,baudrate=rate,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS,timeout=1)
print("connected to: " + ser.portstr)

while True:
  try:
    line = ser.readline()
    if line:
# Uncomment the next line to display the input from the serial port in hex format
#     for x in line: print ("%s") % (x.encode('hex')),
      print (line),
  except KeyboardInterrupt:
    sys.exit()
  except:
    pass
  while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
    line = sys.stdin.readline()
    line = line.replace("\n","\r\n")
# Uncomment the next two lines to display the typed in characters in hex format
#    for x in line: print ("%s") % (x.encode('hex')),
#    print
    ser.write(line)

ser.close()
sys.exit()

It takes from zero to two parameters. Given no parameters, it defaults to 115200 BAUD and will search for ‘active’ serial ports with the name /dev/ttyUSB* or /dev/ttyACM* and use the first one it finds. If you want to override or specify either the serial port or BAUD rate just give it either or both parameters. If you give it both parameters, they can be in any order as the script can tell what is a port versus what is the rate. When running, the script will ‘echo’ any characters coming from the serial port to the console and ‘echo’ any characters typed in from the console to the serial port. Use a Ctrl-C to exit the script. Note that the comments tell you how to change certain features of the program.

With this script you have basic serial port communications (quite usable) and it can be easily added to for enhanced functionality.

Again, there are other serial communication programs/scripts (which run under Linux). Perhaps the most common one used is minicom. Another quite useful program is screen.  Although screen is primarily used as a terminal multiplexer (i.e. using virtual terminals in a login session), it can be used as a serial terminal communication program too. For example:

screen /dev/ttyUSB0 115200

Also note that the Arduino IDE has a built in serial monitor (the newer versions have a serial plotter too) so that serial communications with your Arduino is relatively easy during code development. The Pinguino IDE does not have a serial monitor built in so my script can be used for that sometimes needed functionality.

You may notice that this script is an updated version of one I wrote about before (here) which I used to communicate with the Arduino MiniPirate sketch.

If you do put my script to use or enhance it, i’d be interested to see what features you add. Leave a comment!

FS1000A Wireless RF433 Transmit and Receive Module Pair

I like experimenting with wireless devices, as you can tell from the many posts about them here! 😎 I am trying out an FS1000A Wireless RF433 Transmit and Receive Module pair this time.

They use use the RF 433Mhz  frequency with ASK modulation. (You can also get these with the 315Mz frequency instead.)  I got mine from Elecrow.com.  They look like this:

FS1000A Wireless RF433 Transmit and Receive Module Pair

 

FS1000A RF433 Transmit and Receive Module PairHere is a graphic on how they work together:

FS1000A Wireless RF433 Transmit and Receive Module PairBasically you can use one Arduino to control the Transmitter and one Arduino to control the Receiver. An Arduino RF library comes in handy for that. In the past, you’d use the VirtualWire library for controlling these modules, now however, there is a better library called RadioHead which supersedes it. Download it from HERE. Once you install it from the Arduino IDE (Sketch -> Include Library -> Add .ZIP Library) there will be a number of examples to choose from. You can use the File -> Examples -> RadioHead -> Ask -> ask_receiver and ask_transmitter sketches.

I modified them a bit as shown below.

Here is the sketch for the Arduino Receiver:

#include <RH_ASK.h>
#include <SPI.h>

// Arduino                     Receiver
//  GND--------------------------GND
//  D11--------------------------Data
//  5V---------------------------VCC

RH_ASK driver(2000, 11, 12);

void setup() {
  Serial.begin(9600);
  if (!driver.init()) Serial.println("init failed");
}

void loop() {
  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);

  if (driver.recv(buf, &buflen)) {
    driver.printBuffer("Received:", buf, buflen);
  }
}

Here is the sketch for the Arduino Transmitter:

#include <RH_ASK.h>
#include <SPI.h> 

// Arduino                     Transmitter
//  GND--------------------------GND
//  D12--------------------------Data
//  5V---------------------------VCC

RH_ASK driver(2000, 11, 12);

void setup() {
  Serial.begin(9600);   
  if (!driver.init()) Serial.println("init failed");
}

void loop() {
  const char *msg = "hello";
  driver.send((uint8_t *)msg, strlen(msg));
  driver.waitPacketSent();
  delay(200);
}

As you can tell from the comments in the code, they are very easy to hook up. Both use only three pins (VCC, GND and DATA). Here is the Fritzing Diagram showing how they are connected:

FS1000A RF433 Transmit and Receive ModulesYou can download the custom fritzing parts from here. If you want my fritzing diagram, download it from here.

Updated Note (6/21/2018): In the receiver code, the printBuffer function ‘dumps’ the buffer in HEX (probably for better diagnostics). Here is the code for the receiver, if you want a normal print of the received characters:

#include <RH_ASK.h>
#include <SPI.h>

// Arduino                     Receiver
//  GND--------------------------GND
//  D11--------------------------Data
//  5V---------------------------VCC

RH_ASK driver(2000, 11, 12);

void setup() {
  Serial.begin(9600);
  if (!driver.init()) Serial.println("init failed");
}

void loop() {
  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);
  uint8_t i;
  if (driver.recv(buf, &buflen)) {
//    driver.printBuffer("Received:", buf, buflen);
    Serial.print("Received:");
    for (i = 0; i < buflen; i++) Serial.print(buf[i]);
    Serial.println("");
  }
}

NL6621-Y1 Wireless Module

There is a new kid on the block, the NL6621-Y1 Wireless Module from Nufront.  The NL6621 WiFi SOC is powered by a 160 MHz ARM Cortex-M3 (NL6621M). Everything is integrated in the NL6621M SOC including 448KB of RAM.

Here is what the NL6621-Y1 wireless module looks like:

 

The NL6621-Y1 wireless module Back Image The NL6621 wireless module Front Image The NL6621 wireless module PCB Layout

 

 

 

 

Supposedly it is much better than the ESP8266 from Expressif. However, the ESP8266 has a lot of code and documentation for it whereas there is very little information or code for the  NL6621-Y1 wireless module (as of this post).

Nufront does have several GitHub repositories for it here:

https://github.com/NufrontIOT

The common module (NL6621-Y1) seems to have the NL6621_SerialNet_SDK installed as that is what services the serial AT command set which allows the module to be configured via a serial interface.

I have the NL6621-Y1 wireless module from Elecrow and I wanted to see if I could get it working (attached to an Arduino Leonardo) similar to how I attached an ESP8266 in an earlier post.

Hooking it up, hardware wise, is a breeze. Attach the NL6621-Y1 3.3V pin to the Arduino 3.3V pin, GND to GND, NL6621-Y1 TXD to Arduino RXD and NL6621-Y1 RXD to Arduino TXD.

Arduino Leonardo connected to an NL6621The NL6621 Wireless ModuleAt first, I used the multiserial mega Arduino script (HERE) to experiment with the AT commands. That script basically takes characters you type in the serial console and sends them to the 2nd serial port and it echos any data coming from the 2nd serial port to the 1st.  I set both serial port BAUD rates to 115200. Sending “AT+HELP” will list all the supported AT commands.

Searching GOOGLE I could not find any information on the AT command set so I took a look at the SerialNet SDK source. Here is a chart showing what I gleaned from that code:

NL6621-Y1 Wireless Module AT commands

AT 		TEST AT COMMAND
		AT

AT+HELP 	HELP 		
		AT+HELP

AT+VER 		AT commands version check
		AT+VER

AT+SVER 	SDK version 			
		AT+SVER

AT+SAVE 	SAVE CONFIGURATION 		
		AT+SAVE

AT+FACTORY 	RESTORE FACTORY SETTINGS 	
		AT+FACTORY

AT+RST 		RESET         			
		AT+RST

AT+SYSTIME	SYSTEM TIME			
		AT+SYSTIME

AT+BAUDRATE 	CHECK/SET BAUD RATE 		
		AT+BAUDRATE=?
		AT+BAUDRATE=baudrate (300 - 1250000)
		
AT+UARTFT 	CHECK/SET UART AUTO FRAME INTERVAL TIME
		AT+UARTFT=?
		AT+UARTFT=time  (30-10000) ms

AT+UARTFL 	CHECK/SET UART FRAME LENGTH
		AT+UARTFL=?
		AT+UARTFL=length (32-1400) bytes

AT+MSLP 	CHECK POWER SLEEP MODE 		
		AT+MSLP

AT+LSLPT 	SET SHALLOW SLEEP WAKEUP TIME AND MODE
		AT+LSLPT=mode,time,dtim

AT+IPCONFIG 	CHECK CURRENT IP ADDRESS
		AT+IPCONFIG

AT+PING 	PING SPECIFIC IP ADDRESS
		AT+PING=address,count

AT+MAC 		CHECK MAC ADDRESS 	
		AT+MAC

AT+WQSOPT 	CHECK/SET WIFI PARAMETERS 
		AT+WQSOPT=?
		AT+WQSOPT=mode,channel,encry,authmode,WmmEn
		mode		0:STA 1:ADHOC 2:SOFTAP
		channel	        1-13
		encry		0:none 1:wep 2:tkip
                                3:ccmp 4:auto
		authmode	0:open 1:share 2:wpa 3:wpa2
		WmmEn (wifi)	0:disable 1:enable
                               (multimedia extensions) 

AT+WPHYMODE 	CHECK/SET PHYSICAL LAYER WORK MODE
		AT+WPHYMODE=?
		AT+WPHYMODE=mode  (1: b/g 2: b)

AT+WTXRATE 	CHECK/SET TRANSMIT SPEED
		AT+WTXRATE=?
		AT+WTXRATE=rate  (0,1,2,5.5,6,9,12,18,24,36,48,54)

AT+WSCANAP 	SCAN NEAR BY AP INFO
		AT+WSCANAP=rssiFilter (0-127)

AT+WSBCN 	CHECK/SET BEACON SET CYCLE
		AT+WSBCN=?
		AT+WSBCN=period

AT+WSCAP 	CHECK CURRENT AP/ SET AP TO CONNECT
		AT+WSCAP=?
		AT+WSCAP=ssid,password,trytimes

AT+WSMTCONF 	ENTER INTO DIRECT CONFIG MODE 
		AT+WSMTCONF

AT+WSTOP 	CLOSE CURRENT WIFI FUNCTION 	
		AT+WSTOP

AT+NQSCNN 	CHECK/SET TRANSPARENT TRANSMISSION PARAMETERS
		AT+NQSCNN=?
		AT+NQSCNN=protocol,type,port,ip  
                     (protocol: 0=udp 1=tcp
                      type: 0=client 1=server)

AT+NLOCIP	CHECK/SET IP ADDRESS and DHCP enable/disable
		AT+NLOCIP=?
		AT+NLOCIP=ip,mode,trytimes
                 (mode: 0=DHCP disable 1=DHCP enable)

AT+WSACONF      SOFTWARE AP Config
		AT+WSACONF

AT+AIRKISS      AirKiss Configuration
		AT+AIRKISS

AT+BCTTXSTART   UDP Broadcast Switch Start on Port
		AT+BCTTXSTART=port  (1 to 65535)

AT+BCTTXSTOP    UDP Broadcast Stop
		AT+BCTTXSTOP

AT+BCTTXDATA    UDP Broadcast Data
		AT+BCTTXDATA=length,data

AT+BCTRXSTART   UDP Broadcast Receive
		AT+BCTRXSTART=port

AT+BCTRXSTOP    UDP Broadcaset Receive Stop
		AT+BCTRXSTOP

AT+QUIT 	QUIT (quits command mode)
                DATAMODE: Runs TCP Server on port 8101
                +++ exits back to CMDMODE

Example: Enter DataMODE

============================================================

AT+QUIT

(then telnet to the IP address of the NL6621 on port 8101)

+++ (exits back to CMD Mode)

 

Example: Scan for Wireless APs
============================================================

AT+WSCANAP=127

 

Example: Set NL6621-Y1 to be an AP
============================================================

AT+WQSOPT=2,11,3,3,0                     //SOFTAP,11,ccmp,wpa2,disable
AT+WSCAP=nufront,123abcdef,0        //SSID,password,retries
AT+IPCONFIG                                      //Show IP configuration

 

Example: Set NL6621-Y1 to STATION mode and connect to an AP
============================================================

AT+WQSOPT=0,11,3,3,0                                //Station,11,ccmp,wpa2,disable
AT+WSCAP=your_ap_ssid,yourpassword,5   //SSID,Password,retries
AT+IPCONFIG                                                 //Show IP configuration

 

Here is an Arduino sketch which sets the wireless options and connects the NL6621-Y1 wireless module to my TP-Link router. Note: If you use this code make sure to change the SSID and PASS variables to match your router!

The NL6621-Y1 Wireless Module Arduino Sketch

/*
Arduino Leonardo <--> NL6621-Y1 
Email:  earl@microcontrollerelectonics.com
*/

#define SSID "TP-LINK_2.4GHz_4463DB"
#define PASS "44620"
#define CONNECT_ATTEMPTS 2

void setup() {

  Serial.begin(115200);
  Serial1.begin(115200);

  Serial1.println("AT+RST");
  delay(3000);
  
  Serial1.println("AT");
  delay(1000);

  if (Serial1.find("+OK")) Serial.println("Module is ready");
  else {
    Serial.println("NL6621 Module did not respond.");
    Serial.println("Enter Commands Manually.");
    while (1) chk_serial_io();
  }
  
  boolean connected = false;
  for (int i = 0; i < CONNECT_ATTEMPTS; i++) {
    if (connectWiFi()) {
      connected = true;
      break;
    }
  }
  if (!connected) Serial.println("Enter Commands Manually.");
  else {
    Serial.println("AT+IPCONFIG");
    Serial1.println("AT+IPCONFIG");
  }
}

void loop() {
  while (1) chk_serial_io();
}

void chk_serial_io() {
  while(Serial1.available()) {
    int inByte = Serial1.read();
    Serial.write(inByte);
  }
  while(Serial.available()) {
    int inByte = Serial.read();
    Serial1.write(inByte);
  }
}

boolean connectWiFi() {
  String cmd = "AT+WQSOPT=0,11,3,3,0";
  Serial.println(cmd);
  Serial1.println(cmd);
    
  if (Serial1.find("+OK")) {
    Serial.println("Station Mode Set OK!");
  }
  else {
    chk_serial_io();
    return false;
  }
  
  cmd = "AT+WSCAP=";
  cmd += SSID;
  cmd += ",";
  cmd += PASS;
  cmd += ",";
  cmd += CONNECT_ATTEMPTS;
  Serial.println(cmd);
  Serial1.println(cmd);
  
  return true;
}

One thing I don’t like about the NL6621-Y1 is that it does not have a unique (i.e. official)  MAC address. When you send this:  AT+MAC  the result is +OK=MAC:00:01:02:03:04:05.

Anyway, it will be interesting to see what the open source community comes up with to do with this new wireless chip.

How to Power an LED (Arduino vs. Pinguino)

How to Power an LED (Arduino vs. Pinguino) might seem silly, however, if you take a look at the following graphic, you will hopefully notice something interesting. The Pinguino sources the power to the ‘user’ LED differently that does an Arduino. The Pinguino wiring is represented by the green LED and the Arduino wiring is represented by the red LED.

 

How to Power an LED (Arduino vs. Pinguino)

How to Power an LED (Arduino vs. Pinguino)

The Arduino powers the LED via a Pin connection versus the Pinguino which sources power to the LED from VCC. So when you write your code to turn on/off the LED notice also the differences. To turn on the Pinguino user LED the Pin is brought LOW via digitalWrite(USERLED,LOW) and turned off via digitalWrite(USERLED,HIGH). Notice this is the opposite to the Arduino code. To turn on the Arduino user LED (on Pin 13 usually) the Pin is brought HIGH via digitalWrite(13,HIGH) and turned off via digitalWrite(13,LOW).

The Pinguino IDE has a ‘built-in’ variable USERLED which references the pin for the user LED on the target Pinguino board. The Pinguino IDE also has a ‘built-in’ toggle() function:

toggle(USERLED);

to do basically the same as:

digitalWrite(USERLED, !digitalRead(USERLED));

If you code and run the standard ‘blink’ sketch or just toggle() you might not notice or care about the difference in wiring, as the LED blinks (regardless of whether it was on or off initially).

I2C Wire Chat Between Two Arduinos

Someone asked me the other day if it was possible to have a ‘chat’ between Arduinos using the I2C Wire library. I came up with  ‘proof of concept’ code called ‘I2C Wire Chat Between Two Arduinos’. Here is the sketch:

I2C Wire Chat Between Two Arduinos

/* 
 
 I2C wire chat
 From: earl@microcontrollerelectronics.com

 Analog Pin 5 SCL
 Analog Pin 4 SDA
 Common ground

*/

#include <Wire.h>
#define WireDevice 8

String buffer;
int mode;

void setup() { Serial.begin(9600); }

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    if (c != '\n') {
      if (c == '\r') continue;
      buffer += c;
      continue;
    }
    else {  
      buffer += '\0';
      if (buffer[0] == '#') {
        if (buffer[1] == 'm') {
          if (mode != 'm') {
            mode = 'm';
            master();
            Serial.println("Master mode");
          }
        }
        if (buffer[1] == 's') {
          if (mode != 's') {
            mode = 's';
            slave();
            Serial.println("Slave mode");
          }
        }
        buffer = "";
        continue;
      }
      if (mode == 'm') {
        Wire.beginTransmission(WireDevice); 
        int i = 0;
        while (buffer[i]) { Wire.write(buffer[i]); i +=1; }
        Wire.endTransmission();    
      }
      else Serial.println("Invalid Mode");
      buffer = "";
    } 
  }
}

void master() {
  Wire.begin();
  Serial.println("Master Initialized");
}

void slave() {
  Wire.begin(8);                
  Wire.onReceive(receiveEvent);
  Serial.println("Slave Initialized");
}

void receiveEvent(int howMany) {
  while (1 < Wire.available()) {
    char c = Wire.read();
    Serial.print(c);     
  }
  char c = Wire.read();
  Serial.println(c);     
}

Setup two Arduinos connected by a length of CAT5 cable (you really only need 3 wires). Connect Analog Pins 5 (SCL), 4 (SDA) and Ground as shown in this Fritzing diagram:

I2C Wire Chat Between Two Arduinos

I2C Wire Chat Between Two Arduinos

Make sure each serial port is set to 9600 BAUD and type: #s in one Arduino and #m in the other making sure that ‘New Line’ is sent as the end character. This will put one in slave mode and the other in master mode. Due to the design of the I2C Wire library one has to be master and one slave. Only the master can send data (the slave receives), so it is not simultaneous transmit/receive. Whatever is typed in the master serial console is sent to the slave which displays it on its serial console. To switch back and forth (master <=> slave) just alternate the #s and #m. So you can in essence have a ‘chat’ with the I2C Wire library.

It basically functions the same as a Walkie-talkie radio.

One could even take the sketch further to automatically switch the master to slave and slave to master. For example, when the master is finished it could send a # as the last character which could function as the toggle. I will leave it to the reader to implement this. 😎

Well.. OK.. just so you can see how the code develops, here is the final version with the ‘toggle’ master/slave being the ‘#’ as the last character in the transmission buffer:

I2C Wire Chat Between Two Arduinos  [Final Version]

/* 
 
 I2C wire chat
 From: earl@microcontrollerelectronics.com

 Analog Pin 5 SCL
 Analog Pin 4 SDA
 Common ground

*/

#include <Wire.h>
#define WireDevice 8

String buffer;
int mode;

void setup() { 
  Serial.begin(9600);
  mode = 's';
  toggle_mode();
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    if (c != '\n') {
      if (c == '\r') continue;
      buffer += c;
      continue;
    }
    else {  
      buffer += '\0';
      if (buffer[0] == '#') {
        if (buffer[1] == 'm') {
          if (mode != 'm') toggle_mode();
        }
        if (buffer[1] == 's') {
          if (mode != 's') toggle_mode();
        }
        buffer = "";
        continue;
      }
      if (mode == 'm') {
        Wire.beginTransmission(WireDevice); 
        int i = 0;
        while (buffer[i]) { Wire.write(buffer[i]); i +=1; }
        Wire.endTransmission();    
        i -= 1;
        if (buffer[i] == '#') toggle_mode();
      }
      else Serial.println("Invalid Mode");
      buffer = "";
    } 
  }
}

void toggle_mode() {
  if (mode != 's') {
    mode = 's';
    slave();
    Serial.println("Slave mode");
  }
  else {
    mode = 'm';
    master();
    Serial.println("Master mode");
  }
}

void master() {
  Wire.begin();
  Serial.println("Master Initialized");
}

void slave() {
  Wire.begin(8);                
  Wire.onReceive(receiveEvent);
  Serial.println("Slave Initialized");
}

void receiveEvent(int howMany) {
  while (1 < Wire.available()) {
    char c = Wire.read();
    Serial.print(c);     
  }
  char c = Wire.read();
  if (c == '#') {
    Serial.println();
    toggle_mode();
  }
  else Serial.println(c);     
}

Over and Out!

Arduino as a Network Monitor

I have set up an Arduino as a Network monitor so I can be silently alerted if a WEB server on the LAN/Internet goes down. In a previous post, here, I show the relay circuit I am using in this sketch to flash a CFL lamp. This sketch also uses the same ENC28J60 module to connect to the LAN/Internet.

Arduino Leonardo and SPI Communications using the ENC28J60 ethernet moduleThe uniqueness of this code is that it uses PING against multiple servers. I tried and tried to get this function using the UIPEthernet library working without success. I finally switched to the EtherCard library and found the solution for PINGing multiple servers. The EtherCard library also solves the problem of the CS Pin on the Arduino Leonardo that I document here. (The EtherCard library allows the code to select which pin will be used for the CS pin.)

There are several interesting things to note about this sketch:

  1. It uses PROGMEM so the IP Addresses are preserved thru each PING loop
  2. The IP address for the ENC28J60 module is dynamically set (the comments show how to switch to a static IP)
  3. MAXCYCLES can be set to re-ping and not alert in case your LAN is not perfect (the device you are pinging might miss a few)
  4. Since this is wired as a temporary setup, I blink the light when the sketch first starts to make sure the wiring is correct
  5. An LCD is used to display the IP address and millisecond PING times (this same info is also displayed to the serial port)

Here is the sketch:

// From earl@microcontrollerelectronics.com

#include <avr/pgmspace.h>
#include <EtherCard.h>
#include <LiquidCrystal.h>

#define CS_PIN        10
#define pinToToggle   9

static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };

// myip,gwip,mask,dns Only needed if using a Static IP
static byte myip[]  = { 192,168,2,50 };
static byte gwip[]  = { 192,168,2,1 };
static byte mask[]  = { 255,255,255,0 };
static byte dns[]   = { 8,8,8,8 };

byte Ethernet::buffer[700];
static int32_t timer;
static int polling;

//change these to the IPs that you want to ping
const char srv0[]  PROGMEM = "192.168.2.1";
const char srv1[]  PROGMEM = "192.168.0.105";
const char srv2[]  PROGMEM = "192.168.2.104";
const char srv3[]  PROGMEM = "192.168.0.103";
const char srv4[]  PROGMEM = "192.168.2.101";
const char srv5[]  PROGMEM = "192.168.2.153";
const char srv6[]  PROGMEM = "192.168.0.107";
const char srv7[]  PROGMEM = "192.168.0.104";
const char srv8[]  PROGMEM = "192.168.2.102";
const char srv9[]  PROGMEM = "192.168.0.176";

// Make sure this list matches the above list
const char* const servers[] PROGMEM = {srv0,srv1,srv2,srv3,srv4,srv5,srv6,srv7,srv8,srv9};

#define NUMSRVRS (sizeof(servers) / sizeof(servers[0]))
#define MAXCYCLES 3
#define PING_DELAY 2000000

static int cycles;

char sbuffer[30];

static int i;

float ms;

long interval              = 500;
unsigned long currentTime  = 0;
unsigned long previousTime = 0;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void blink() {
  currentTime = millis();
  if(currentTime - previousTime > interval) {
    previousTime = currentTime;
    digitalWrite(pinToToggle, !digitalRead(pinToToggle));
  }
}

static void gotPinged (byte* ptr) {
  ether.printIp(">>> ping from: ", ptr);
} 

void setup () {
  
  pinMode(pinToToggle,OUTPUT);
  
  lcd.begin(16, 2);
    
  Serial.begin(57600);

// Uncomment to wait till serial port is ready
//  while (!Serial) { }

  Serial.println(F("Ping Servers\n"));
  
  if (!ether.begin(sizeof Ethernet::buffer, mymac, CS_PIN))
    Serial.println(F("Failed to access Ethernet controller\n"));
  
  strcpy_P(sbuffer, (char*)pgm_read_word(&(servers[0])));
  ether.parseIp(ether.hisip,sbuffer);

// Comment these two lines and uncomment staticSetup
// to use static vs DHCP IP address
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed\n"));
    
//  if (!ether.staticSetup(myip, gwip, dns, mask))
//    Serial.println(F("Failed to set Static IP"));

  while (ether.clientWaitingGw())
    ether.packetLoop(ether.packetReceive());
  
  Serial.println("Gateway found");
  
  ether.printIp("IP:  ",     ether.myip);
  ether.printIp("GW:  ",     ether.gwip);
  ether.printIp("Netmask: ", ether.netmask);
  ether.printIp("DNS IP: ",  ether.dnsip);
  Serial.println();
  
  ether.registerPingCallback(gotPinged);
  
  timer   = -9999999;
  polling = 0;
  i       = NUMSRVRS;
  cycles  = 0;
    
  digitalWrite(pinToToggle, !digitalRead(pinToToggle));
  delay(2000);
  digitalWrite(pinToToggle, !digitalRead(pinToToggle));
 
}

void loop () {
  
// Uncomment to change to no delay 
// if ( ( (micros() - timer) >= PING_DELAY) || !polling  ) {

//Comment this next line, if the above line is uncommented
 if ((micros() - timer) >= PING_DELAY) {
   if (polling) {
     ether.printIp("\n",ether.hisip);
     Serial.println(F("Timeout\n"));
     lcd.setCursor(0, 1);
     lcd.print("Timeout");
     if (cycles >= MAXCYCLES) while (1) blink();
   }
   else {
     polling = 1;
     lcd.clear();
     lcd.setCursor(0, 0);
     ++i;
     if (i >= NUMSRVRS) i = 0;
     strcpy_P(sbuffer, (char*)pgm_read_word(&(servers[i])));
     lcd.print(sbuffer);
     ether.parseIp(ether.hisip,sbuffer);
     ether.printIp("Pinging: ", ether.hisip);
   }
    
   cycles += 1;
   ether.clientIcmpRequest(ether.hisip);
   timer = micros();

  }

  word len = ether.packetReceive(); 
  word pos = ether.packetLoop(len); 

  if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) {
    Serial.print("  ");
    ms = (micros() - timer) * 0.001;
    Serial.print(ms, 3);
    Serial.println(" ms\n");
    lcd.setCursor(0, 1);
    lcd.print(ms);
    lcd.print(" ms");
    polling   = 0;
    cycles    = 0;
  }
   
}

To use it in your environment, change the IP addresses to PING (and number of them) to suit your LAN. Also see the comments to use a static versus dynamic IP address for the monitor itself.

Emergency Phone Call Alert to an Arduino via an Asterisk PBX

Recently, I created this simple circuit (and corresponding code) which makes an emergency phone call alert to an Arduino via an Asterisk PBX.  This project was for someone who needed to be alerted (silently) if someone made an emergency phone call on their Asterisk PBX. By the way, the free and open source Asterisk PBX is a fantastic phone system which can be easily adapted (via custom scripting) to do amazing things!

For this project, the Asterisk dialing plan for the emergency number is set to invoke an AGI script (which in this case was written in python). The AGI python script reads the SIP configuration and creates an Asterisk call file for each SIP peer which puts them all in a conference room. The scenario for this is something like a condominium where there might not be a dedicated person to answer the emergency call, instead everyone in the building (so to speak) is called. The python script also accesses the WEB page of the server running on an Arduino which will rapidly flash an “emergency” light.

I created this simple relay circuit with an S108T02 solid state relay to control the light (CFL). Here is the Fritzing diagram:

S108T02 Relay Fritzing Diagram

You can download the Fritzing code for the circuit here and modify it for your needs. Here is what the circuit looks like when it is built:

S108T02 Relay CircuitEmergency Phone Call Alert to an Arduino via an Asterisk PBX Circuit

 

Note that the board is about double the size needed so I can add a second relay if future needs require.  🙄

The Arduino code uses the UIPEthernet library to basically create a WEB server. When it is 1st accessed the light is turned on. Access it again and it is turned off. It is a ‘toggle’ so it can be tested from a browser client.  The circuit is attached to an arduino via the pinToToggle value (and also +5V and GND). Additionally the Arduino is connected to an ENC28J60 module for LAN/Internet access. See my previous posts here and here for connecting an Arduino Leonardo to an ENC28J60.

Here is the Arduino code:

//From earl@microcontrollerelectronics.com

#include <SPI.h>
#include <UIPEthernet.h>

byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x31 };                                      

// Change this to match your network
IPAddress ip(192, 168, 0, 50);  
                      
EthernetServer server(80);

long interval              = 500; 
unsigned long currentTime  = 0;
unsigned long previousTime = 0; 
int ledState               = LOW;

// Pin the relay is connected to
#define pinToToggle 8

void setup() {
  pinMode(pinToToggle,OUTPUT);
  Serial.begin(115200);
  Serial.println("ARDUINO WEB SERVER ");
  Serial.println();
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("IP Address: ");
  Serial.println(Ethernet.localIP());
}
 
void loop() {
  EthernetClient client = server.available();
  if (client) {  
    Serial.println("-> New Connection");
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          client.println("<!DOCTYPE html>");
          client.println("<html xmlns='http://www.w3.org/1999/xhtml'>");
          client.println("<head>\n<meta charset='UTF-8'>");
          client.println("<title>Arduino WEB Server</title>");
          client.println("</head>\n<body>");
          client.println("<H2>Arduino Leonardo</H2>");         
          client.println("<pre>");
          if (ledState == LOW) {
            ledState = HIGH;
            client.println("Light On!<br>");
            digitalWrite(pinToToggle,HIGH);
          }
          else {
            ledState = LOW;
            client.println("Light Off!<br>");
            digitalWrite(pinToToggle,LOW);
          }
          client.println("</pre>");
          client.print("</body>\n</html>");
          break;
        }
        if (c == '\n') currentLineIsBlank = true;
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(10);
    client.stop();
    Serial.println("   Disconnected\n");
  }
  if (ledState == HIGH) {
    currentTime = millis();
    if(currentTime - previousTime > interval) {
      previousTime = currentTime;   
      digitalWrite(pinToToggle, !digitalRead(pinToToggle));
    }
  }
}

The python AGI script:

#!/bin/env python
#
# Copyright (C) 2006-2016 earl@micpc.com
#

import sys, string, os, re, urllib2

SENDMAIL = "/usr/sbin/sendmail" 

class AGI:
    """
    Class AGI facilitates writing AGI scripts in Python.
        
    Exported functions:
    
        Write(message):
            Writes message to Asterisk Console.
    	    
        Cmd(command):
            Send command to Asterisk, read result.
            The result is a two element tuple:
                [0] A text string giving the entire result returned by Asterisk
                [1] The "result=" integer extracted from the result line
            
            If we get an unhappy response from Asterisk or if the result 
            returned to the right of the equals sign is not an integer we 
            issue an error message and terminate the script.
	
    Exported Variables:
    	
        env
            Dictionary containing the various environment startup items, as 
            passed to us by Asterisk.
    """

    def Write(self,data):
	"""
	Write unbuffered line output to STDERR.
	Ensures data is flushed out.
	"""
	sys.stderr.write(str(data) + "\n")
	sys.stderr.flush()

    def Error(self,data):
	"""
	Write unbuffered line output to STDERR.
	Ensures data is flushed out.
	"""
	sys.stderr.write(str(data) + "\n")
	sys.stderr.flush()

    def Cmd(self,command):
        """
        Send an AGI command to Asterisk; read back the response.
        The result is a two element tuple:
            [0] A text string giving the entire result returned by Asterisk
            [1] The "result=" integer extracted from the result line
            
        If we get an unhappy response from Asterisk or if the result 
        returned to the right of the equals sign is not an integer we 
        issue an error message and terminate the script.
        """
        try:
	    sys.stdout.write(str(command) + "\n")
	    sys.stdout.flush()
    	    Response = sys.stdin.readline()
    	    if Response[:11] <> '200 result=':
                #we didn't get a happy response for AGI
                raise "AgiError"
            #accumulate integer portion                
            J = 11
            while J < len(Response) and (Response[J] in '0123456789'):
                J += 1
            res = Response[11:J]
            try:
                ResInt = int(res)
            except ValueError:
                #there is no integer immediately to the right of the equal sign
                raise "AgiError"
        except "AgiError":
            self.Error('Unexpected response to AGI command.')
            self.Error('Command: %s'%command)
            self.Error('Response: %s'%Response)
            self.Error('Script terminated.')
            sys.exit()
        return (Response,ResInt)
        
    def __init__(self):
    	"""
	Read until blank line to get the AGI environment.
        The lines read are used to build the dictionary 'env'.
	"""
        self.env = {}
	while 1:
	  line = string.strip(sys.stdin.readline())
          if line == '':
            break
          key,data = string.split(line,':')
          key = string.strip(key)
          data = string.strip(data)
          if key <> '':
            self.env[key] = data

# change this to match your Arduino WEB address
try:
  urllib2.urlopen("http://192.168.0.50").read()
except:
  pass

A = AGI()

sys.stderr.write(str(A.env) + "\n")
sys.stderr.flush()

cid     = A.env['agi_callerid']
cidname = A.env['agi_calleridname']

p1 = re.compile('^\s*\[(.*?)\]')
p2 = re.compile('^\s*(\w+)\s*=>\s*(.+)\s*;?.*$')
p3 = re.compile('^\s*(\w+)\s*=\s*(.+)\s*;?.*$')

in_file = open("/etc/asterisk/sip.conf","r")
for in_line in in_file.readlines():
  in_line = string.strip(in_line[:-1])
  m1 = p1.match(in_line)
  if m1:
    s = p1.split(in_line)
    if (s[1] == 'general'): continue
    if (s[1] == 'authentication'): continue
    user = s[1]
    callfile = "/var/spool/asterisk/outgoing/" + user
    ufile = open(callfile,'w')
    rec  = "Channel: SIP/"
    rec += user + "\n"
    rec += "MaxRetries: 5\nExtension: 700\nContext: wholegang\n"
    rec += "Priority: 1\n"
    rec += "Callerid: EMERGENCY " + cid + " : " + cidname + "\n"
    rec += "RetryTime:30\nWaitTime: 60\n"
    ufile.write(rec)
    ufile.close()
    continue
in_file.close()

body  = "\n***Emergency Call***\n"
for k,v in A.env.iteritems():
  body += k + " : " + v + "\n"

body += "\n"
body += "Phone Call from Number: " + A.env['agi_callerid']
body += " Id: " + A.env['agi_calleridname']
body += "\n"

p = os.popen("%s -t" % SENDMAIL, "w")
p.write("To: my_email_address@mydomain.com\n")
p.write("Subject: Emergency Call\n")
p.write("\n") 
p.write(body)
status = p.close()

sys.exit()

If you try this out make sure to change the IP addresses in both scripts to match that of your Arduino. Also note that the python AGI script emails someone that the call was made. Check out the bottom part of the AGI script and change the email address to the correct one. (Or comment out that part if you don’t want it to email anyone.)

Do-It-Yourself Pinguino PIC18F4550 Board

I just got a good deal on several PIC18F4550 chips. So, I decided to make a Do-It-Yourself Pinguino PIC18F4550 Board to test them out. The Pinguino boards are based on the same concept as an Arduino. However,  instead of Atmel chips, Microchip PIC® chips are used. All of the Pinguino boards use PIC® chips with on board USB, so the boards are quite easy to access/program. The goal of the Pinguino project is to bring the simplicity of Arduino language to the Microchip PIC® microcontrollers with built-in USB hardware. (Visit the Pinguino project WEB site here.)

The IDE for the Pinguino boards is similar to the Arduino IDE and sketches are also similar, so Arduino users should feel right at home.  Pinguino Hardware and Software, like the Arduino, is all Open Source.

Here is a schematic, a breadboard layout and the DIY Pinguino circuit board I created using the PIC18F4550 microcontroller chip:

 

PIC18F4550_diagram

Pinguino PIC18F4550 Fritzing Diagram

 

 

Do-It-Yourself Pinguino PIC18F4550 Board

Do-It-Yourself Pinguino PIC18F4550 Board

You might notice that in the circuit I built (although not shown in the schematic),  I added a 6-pin ICSP header so I could initially load the bootloader by attaching a PICkit 3 programmer:
PicKit3

6-pin-ICSP-pinoutPic18f4550_icsp

The PICkit 3  plugs nicely into the 6 pin header. The graphic above shows how the ICSP pins of both the PICkit and PIC18F4550 are connected. The bootloader (Version 4) I used can be downloaded here.

Here are the top and back views of the board:

Pinguino_TopPinguino_Bottom

I soldered on  four 10-pin female headers so that connections can be easily made to any pin. I also plugged in two 10-pin male-male headers (un-plugable) so that I can use any jumper wire that I may have around.  The male header PINs between the LEDs are all wired to +5V and the male header PINs at the other end of the board are all wired to GND so there is easy and ample connection to either. I used a type B female USB connector (so it fit the USB printer cables I have so many of).

usb-B-pinout usb2-Bpinout-600

 

 

If you’d like the Fritzing diagram for this board you can download it here or the original SVG graphic here. For more information about the Pinguino project visit their Wiki.

Controlling and Monitoring an Arduino Galileo via Node.js

It is very handy to be able to control and monitor things with an Arduino. It is even more handy when you can control and monitor things remotely from wherever you are via the Internet. For arguments sake, lets say we want to both control specific devices we have attached to our Arduino and we want to know when certain events happen (that sensors attached to our Arduino can tell us about).

For the controlling part we could use a WEB application but the WEB is not good for monitoring. This is because the WEB is stateless, it is not a true two way communications system. If we really wanted to use WEB technology, we would need to keep polling (refreshing) from our page which is unnecessary overhead. Yes, we could use an XMLHttpRequest, better know as AJAX, however that too is not the right approach for event monitoring.

Event monitoring in the PC world is normally done via Simple Network Management Protocol (SNMP). That complexity is not needed for something we can implement much more simply. The Arduino Galileo runs Node.js (referred to as node) which makes it very handy and easy to implement a means of both controlling and monitoring events. This is because we can add the socket.io module to node and have true two way communications for both controlling and monitoring. The node server running on the Galileo can monitor for events we want to watch and notify any applications/devices connected to it. The node server can also handle any control requests.

For proof of concept, I coded a node server which uses the mraa module to interface with the Galileo GPIO pins. You can download it here.

Copy it to your Galielo, and extract it with:

tar -xvf galileo_node_server.tar

You will also need to install these node modules (via npm):

npm install http socket.io fs ip mraa

Then start the server via:

node galileo.js

The default port is 8888 which you can  override as an optional parameter if you need to. There is an index.html file that node will send to your browser if you browse to that IP and port. Here is what the WEB (node) page looks like.

Controlling and Monitoring an Arduino Galileo via Node.jsBasically it is a ‘chat’ session. Any commands entered will be sent to the node server and ‘echoed’ back to all applications/devices connected to the server. So you can actually use it as a ‘chat server’ too. Any commands that begin with ‘mraa’ are processed using the mraa module. Then syntax of the command is displayed in case of incorrect parameters.

Additionally, I have coded an Apache Cordova application that you can run on your Android smart phone. You can download it here. The complete Cordova source for the apk can be downloaded here in case you want to make changes. When you install and run the apk, it will first ask you the IP address and port where the node server is running. Then it will connect (via socket.io to the node server) and allow the two way ‘chat’. Here is what the Cordova apk looks like:

Controlling and Monitoring an Arduino Galileo via Node.jsControlling and Monitoring an Arduino Galileo via Node.jsThe next step I have planned is to add sensors for monitoring and add code to the node server to send the monitored data to connected applications/devices. It is interesting to note that this same node.js server code (with the mrra code commented out) will run on a Raspberry Pi. The Cordova app would not need modified (however you might want to change the image/logo from the Galileo to a Raspberry).  😎

 

Update: 12/28/2015 This project is now on GitHub https://github.com/earlt/galileo-node.git

Load more