Arduino and ATtiny Serial Communication

The question I want to answer in this post is: “How to debug the ATtiny?”
Short Answer: One way to debug is to directly send and view the output of the pin via SoftwareSerial in Arduino IDE.

Long Answer: The Serial.print function is not available with the Arduino IDE when it is configured as ISP. The only commands supported by Arduino IDE when it is configured as ISP to program the ATtiny are:

  • pinMode()
  • digitalWrite()
  • digitalRead()
  • analogRead()
  • analogWrite()
  • shiftOut()
  • pulseIn()
  • millis()
  • micros()
  • delay()
  • delaymicroseconds()
  • SoftwareSerial

Furthermore, the ATtiny does not have a built in hardware UART thus is unable to provide direct hardware support for serial communication. The ATtiny has an USI that can be used to facilitate I2C and SPI communication, which are commonly used to link additional chips when there are insufficient I/O pins. Therefore, the Serial object is unavailable. Luckily, there are still several ways to achieve Serial communication between the ATtiny and Arduino IDE:

  1. TinyDebugSerial.
  2. TinyISP.
  3. SoftwareSerial.

This project will show how to achieve Serial communication between the ATtiny 85 and Arduino IDE using the SoftwareSerial method. It emulates the UART by allowing serial communication on the digital pins 0 (Rx) and 1 (Tx) of the Arduino, and using software to replicate the UART functionality (hence the name Software Serial).

Compared to the TinyDebugSerial, the SoftwareSerial method occupies more memory and may require TinyTuner to tune the internal oscillator. This is because, the internal oscillator of an ATtiny from the factory can be off by as much as 10%. This inaccuracy in the clock period can skew the rate of the data sent to and from the board, thus creates strange characters in the serial monitor. Compared to the TinyISP, the SoftwareSerial does not require the purchase of an additional hardware (if Arduino is readily available). The TinyISP is a replacement for the ArduinoISP. With TinyISP a serial/usb converter is already built onto the chip to provide direct serial communication.

It is important to note that prior to using the SoftwareSerial library, the Arduino needs to already be configured as ISP, the correct chip is selected, the correct internal oscillator frequency is selected and the burn bootloader command has been executed.

Schematic:

step2_a

  • The diagram provided is only an initial circuit illustration. Follow the steps below for a complete circuit implementation.
  • Resistor 220 Ω:  between the Arduino Tx pin and the ATtiny Tx pin. This provides isolation between the serial lines. A larger value resistor will also work.

Config Serial Communication:

  1. Make sure the Arduino Tx and Rx pins are not connected. The only wires connected between from Arduino to ATtiny are from Digital pins 10, 11, 12, 13, Reset to capacitor, power and ground. Since the Arduino IDE uploads the code on the same Tx and Rx lines, the Tx 1 and Rx 0 pins can not be connected to the ATtiny while uploading the sketch.With serial, only one device can be communicating on the line at a time.
  2. Upload the Arduino code.
  3. Connect Reset directly to ground (not through a capacitor). This forces the Arduino into reset to perform serial communication with the ATtiny.
  4. Connect the Tx pin declared in the Arduino code to the Rx pin on the Arduino (Digital pin 0 Rx).
  5. Connect the Tx pin on the Arduino (Digital pin 1 Tx).
  6. Open the Arduino serial monitor. Make sure the baud rate is set correctly as per the code.
  7. Repeat steps 2-7 every time the Arduino is re-connected.

Arduino Script:

#include 

const int LED = 0;
const int Rx = -1; //unused Rx
const int Tx = 3;
const int inputPin = 2; //wire act like antenna
SoftwareSerial mySerial(Rx, Tx);
const float VCC = 4.98;
int val = 0;

void setup()
{
pinMode(Rx, INPUT);
pinMode(Tx, OUTPUT); //initialize internal pull-up resistor
pinMode(LED, OUTPUT);
pinMode(inputPin, INPUT);
mySerial.begin(9600);
}

void loop()
{
digitalWrite(LED,HIGH);
delay(300);
digitalWrite(LED,LOW);
delay(300);
val = analogRead(inputPin);
mySerial.println(val);
delay(500);
}

Testing:

The Arduino is reading the values from the ATtiny wire and displaying it in the serial monitor with 9600 baud rate.

step4_a

step4_b

Arduino serial monitor.

 

Arduino and ATtiny

Lets play with the ATtiny! An IC from the family of Atmel’s AVR microcontroller. This will be a start to the many exciting projects to come, as microcontrollers are, without a doubt, amazing little things. Tricky to program, but are versatile, powerful and extremely tiny. We will start by showing how to use the Arduino to load programs onto the ATtiny.

The Arduino we have uses an ATmega 328 AVR microcontroller to provide a great and easy to use, hardware and software platform. But for projects that require compactness, low-cost and stand-alone characteristics, a microcontroller is the way to go. Unlike Arduino that comes with a USB port for “plug-and-play” capabilities, the ATtiny is just an IC by itself. It requires a piece of programmer hardware with USB port to interface with the laptop. Fortunately, the Arduino can be configured as an ISP (in-system programmer) to load programs onto the ATtiny. In fact, the ATtiny 44/45/84/85 can all be programmed with the Arduino (Atmega 328). However, there are some limitations to be noted:

  1. Number of I/O pins: The Atmega 328 is a 28 pin chip, the ATtiny 45 and 85 are 8 pin chips, and the ATtiny 44 and 84 are 14 pin chips. Therefore, this can limit the complexity of the hardware.
  2. Flash Memory: The Atmega 328 has 32 KB, the ATtiny 45 has 4 kB, and the ATtiny 85 has 8 KB. Therefore, this can limit the size of the software.
  3. RAM: The Atmega 328 has 2 KB, the ATtiny 45 has 256 bytes, and the ATtiny 85 has 512 bytes. Therefore, this can limit the size of the data received.
  4. Arduino Functions Available: There are only a limited commands supported, see here.

step1_a

step2_b

Schematic:

Step2_a.jpg

  • The diagram provided is only an initial circuit illustration. Additional components (i.e.: capacitor and LED) will be appended.
  • 10 uF capacitor: between reset and ground pin of the Arduino. This prevents resetting, which starts the bootloader. The capacitor ensures the Arduino IDE talks to the ArduinoISP, not the bootloader, during the upload of sketches.
  • LED and resistor: between ATtiny pin 0 and ground.

Config Arduino as ISP:

  1. Make sure the correct Arduino and COM port are correctly selected, and indicated on the display in the bottom right of the Arduino window.
  2. Arduino > File > Example > Open Arduino as ISP sketch > Upload sketch.
  3. Place filter capacitor between Arduino Reset pin and ground pin.
  4. Download the attiny45_85.zip files here.
  5. Arduino > File > Preferences > Change sketchbook location to where the downloaded ATtiny files will be saved.
  6. In the sketchbook folder > Create new folder called Hardware > Unzip attiny45_85.zip.
  7. Close and restart Arduino.
  8. Arduino > Tools > Board > ATtiny 85 > Clock: Internal 8 MHz > Arduino as ISP .
  9. Place resistor and LED at ATtiny pin 0 to ground.
  10. Arduino > Example > Basics > Blink > Change all Pin 13 to Pin 0 > Upload.
  11. The LED should blink at the rate it is set at.

Testing:

The Arduino is now ready to program the ATtiny. The ATtiny is used to blink 2 single LEDS

step4_b

Arduino temperature and FSR sensor

Here, we discover the use of other sensors with Arduino. The FSR and temperature sensors are used in conjunction to capture both pressure and temperature information. The temperature sensor used here is a solid-state non-contact type of sensor, which measures the radiation of a heat source through changes in the base-emitter junction of the transistor. Therefore, the amplitude of the signal is proportional to the changes in the temperature. The FSR (Force Sensitive Resistor) is a passive contact type of sensor, which measures the weight through physically asserting pressure to change the resistive value. Therefore, the resistance is inversely proportional to the force applied to the FSR.

Schematic:

step2_a

Arduino Script:


const int FSR_PIN = A1;
const float VCC = 4.98;
const float R_DIV = 1000.00;

const int tempPIN = A0;
const int LEDR = 8;
const int LEDG = 10;

void setup() {
 Serial.begin(9600);
 pinMode(FSR_PIN, INPUT);
 pinMode(tempPIN, INPUT);
 pinMode(LEDR, OUTPUT);
 pinMode(LEDG, OUTPUT);
}

void loop() {
 int fsrADC = analogRead(FSR_PIN);
 int tempADC = analogRead(tempPIN);

 if (fsrADC !=0 & tempADC != 0)
 {
 float fsrV = fsrADC * VCC / 1023; //10 bit ADC
 float fsrR = R_DIV *((VCC - fsrV) / fsrV); //from voltage divide equation

 float tempV = tempADC * VCC / 1023; // 10 bit
 float degC = tempV / 0.01; // LM35 transfer function Vout = 10 mV/C * Temp

 if (degC = 23)
 {
 digitalWrite(LEDR, HIGH);
 delay(250);
 digitalWrite(LEDR, LOW);
 delay(250);
 }
 else
 {
 digitalWrite(LEDG, HIGH);
 delay(250);
 digitalWrite(LEDG, LOW);
 delay(250);
 }
 Serial.print("Reistance: " + String(fsrR) + " ohms");
 Serial.println(" Deg: " + String(degC) + " C ");
 }
}

Python plot script:


import serial #Library for serial comm
import numpy as np #Library for array
import matplotlib.pyplot as plt #Library for plotting
from drawnow import * 

arduinoData = serial.Serial('com3', 9600)
Tarray = [] #empty array for arduino data
Rarray = []
plt.ion() #Tell matplotlib you want interactive mode to plot live data
cnt = 0

def makeFig(): #create function to make plot
 plt.ylim(20, 30)
 plt.title('My real-time sensor data')
 plt.grid(True)
 plt.ylabel('Temp C')
 plt.xlabel('N point')
 plt.plot(Tarray,'ro-', label='Degrees C')
 plt.legend(loc='upper left')

 plt2 = plt.twinx() #create twin of plt
 plt2.plot(Rarray, 'b^-', label='Resistance ohm')
 plt.ylim(2800,3000)
 plt2.set_ylabel('Resistance ohms')
 plt2.legend(loc='upper right')
 plt2.ticklabel_format(useOffset = False) #Force matplotlib to not autoscale yaxis.

while True: #While loop that loops forever
 while(arduinoData.inWaiting() == 0): #Wait until there is data
 pass #do nothing
 arduinoString = arduinoData.readline() #read the serial data
 dataArray = arduinoString.split(',') #split into array
 R = float(dataArray[0])
 T = float(dataArray[1])
 Tarray.append(T) #build array
 Rarray.append(R)
 drawnow(makeFig) #call function
 plt.pause(0.000001) #pause drawnow for short time
 cnt = cnt + 1
 if (cnt = 50):
 Tarray.pop(0)
 Rarray.pop(0)

Testing:

  • Measure the temperature from temperature sensor and the resistance from the FSR. We are unable to convert to resistance to force because we don’t have weights to perform the calibration.
  • The temperature is relatively stable at 25 C, while the resistance has a higher fluctuation.

step5_a

step5_b

Arduino Color Sensor

Color sensors can be found in various applications from environmental sensing to general robotics. For example, color sensors can be used to monitor the growth of algae, to sort items according to their color, or to determine light absorption through a medium. Color is not inherent to objects. Rather, the surface and material of an object reflect some light and absorb all others, in which the reflected light defines the color we see. In other words, color is different wavelengths of light reflected off an object. The reflection of the different combinations of wavelength, due to the material of the object, results in different colors.

step1_a

The range of frequency visible to the human eye is known as the visible spectrum, which ranges from about 400 nm to 700 nm, and defines the spectral of colors we see. However, the primary colors are Red, Green and Blue (RGB). By varying the amount of RGB light, all of the colors in the visible spectrum can be produced.

step1_b

Here, a simple color sensor is built and follows the project shown here.

Schematic:

* A RGB 4 pin common cathode LED is used here.

step2_a

Circuit schematic (D = digital, A = analog pins).

Arduino Script:


//Define color sensor LED pins
int ledArray[] = {2,3,4};

//boolean to know if the balance is set
boolean balanceSet = false;

//place holders for color detected
int red =0;
int green =0;
int blue =0;

//floats to hold color arrays
float colourArray[] = {0,0,0};
float whiteArray[] = {0,0,0};
float blackArray[] = {0,0,0};

//place holder for average
int avgRead;

void setup(){
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);

Serial.begin(9600);
}

void loop(){

checkBalance();
checkColour();
printColour();
}

void checkBalance(){
if(balanceSet == false){
setBalance();
}
}

void setBalance(){
//set white balance
delay(5000);
for(int i=0; i=2; i++){
digitalWrite(ledArray[i],LOW);
delay(100);
getReading(5); //function defined later
whiteArray[i] = avgRead; //defined in getReading()
digitalWrite(ledArray[i],HIGH);
delay(100);
}
//set black balance
delay(5000);
for(int i=0; i=2; i++){
digitalWrite(ledArray[i],LOW);
delay(100);
getReading(5);
blackArray[i]=avgRead;
digitalWrite(ledArray[i],HIGH);
delay(100);
}
balanceSet=true;
delay(5000);
}

//iterate thru RGB to find the color reflectivity
void checkColour(){
for(int i=0; i=2; i++){
digitalWrite(ledArray[i],LOW);
delay(100);
getReading(5);
colourArray[i] = avgRead;
float greyDiff = whiteArray[i] - blackArray[i];
colourArray[i] = (colourArray[i] - blackArray[i])/(greyDiff)*255;
digitalWrite(ledArray[i], HIGH);
delay(100);
}
}

void getReading(int times){
int reading;
int tally=0;
for(int i=0; i=times; i++){
reading = analogRead(0);
tally = reading + tally;
delay(10);
}
avgRead = (tally)/times;
}

void printColour(){
Serial.print("R=");
Serial.println(int(colourArray[0]));
Serial.print("G=");
Serial.println(int(colourArray[1]));
Serial.print("B=");
Serial.println(int(colourArray[2]));
}

Processing Script:

Download the Processing software, which can be found here. This software allows coding within the context of visual arts. This code reads the serial output from the Arduino, and visually displays the corresponding color.

import processing.serial.*;

String buff = "";
int val = 0;
int wRed, wGreen, wBlue;

Serial port;

void setup(){
size(900,600);
port = new Serial(this, "COM3", 9600); //Replace COM port
}

void draw(){
background(wRed,wGreen,wBlue);
// check for serial, and process
while (port.available(), 0) {
serialEvent(port.read());
}
}

void serialEvent(int serial) {
if(serial != '\n') {
buff += char(serial);
}
else {
int cRed = buff.indexOf("R");
int cGreen = buff.indexOf("G");
int cBlue = buff.indexOf("B");

if(cRed =0){
String val = buff.substring(cRed+3);
wRed = Integer.parseInt(val.trim());
}
if(cGreen=0){
String val = buff.substring(cGreen+3);
wGreen = Integer.parseInt(val.trim());
}
if(cBlue =0){
String val = buff.substring(cBlue+3);
wBlue = Integer.parseInt(val.trim());
}
buff = "";
}
} 

Testing:

  • Balance the sensor with Arduino code: The first time running the program, or resetting the Arduino, or restarting the Arduino, or starting Arduino serial monitor, or running the Processing sketch. the color sensor needs to be re-balanced. The code allows 5 sec during startup to bring a white paper over the sensor to generate a whiteArray balanced data, then it will turn-off the LED for 5 seconds to allow a black paper to be prepared and placed over the sensor to generate a blackArray balanced data. Try to place both white and black colored papers at the same height to achieve good balancing. Any white and/or black colored surface can be used.
  • Color change with Arduino: Open the serial monitor to observe the changes in RGB values, and test with different colored objects.
  • Color change with Processing: Open the Processing sketch, make sure the serial monitor from Arduino is closed, run the sketch. This requires a balancing of the sensor again. Test with different colored objects.
  • Improve color accuracy: Dimming the surrounding light or enclosing the circuit can help block external visible light from offsetting the accuracy of the color sensor.

step5_a

step5_c

RGB Color display from Processing.