The dtostrf() function converts the double value passed in val into an ASCII representationthat will be stored under s. The caller is responsible for providing sufficient storage in s. Conversion is done in the format "[-]d.ddd". The minimum field width of the output string (including the '.' and the possible sign for negative values) is given in width, and prec determines the number of digits after the decimal sign. width is signed value, negative for left adjustment. The dtostrf() function returns the pointer to the converted string s.
- To display the degree sign (°C or °F) on the mini OLED using u8glib, use te string:
°C : "\260C"
°F : "\260F"
NANO_DHT11_I2C_OLED.ino
// Read DHT11 humidity/temperature sensors
// display on 0.96 inch 128X64 I2C OLED
#include "DHT.h"
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
#define DHTPIN 2 // what pin we're connected to
// Uncomment whatever type you're using!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// Initialize DHT sensor for normal 16mhz Arduino
//DHT dht(DHTPIN, DHTTYPE);
// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you
// might need to increase the threshold for cycle counts considered a 1 or 0.
// You can do this by passing a 3rd parameter for this threshold. It's a bit
// of fiddling to find the right value, but in general the faster the CPU the
// higher the value. The default for a 16mhz AVR is a value of 6. For an
// Arduino Due that runs at 84mhz a value of 30 works.
// Example to initialize DHT sensor for Arduino Due:
DHT dht(DHTPIN, DHTTYPE, 6);
char str[10];
void drawTest(void) {
u8g.setFont(u8g_font_unifont);
u8g.drawStr( 0, 20, "DHTxx test!");
}
void setup() {
Serial.begin(9600);
Serial.println("DHTxx test!");
dht.begin();
u8g.firstPage();
do {
drawTest();
} while( u8g.nextPage() );
}
void loop() {
// Wait a few seconds between measurements.
delay(2000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius
float t = dht.readTemperature();
// Read temperature as Fahrenheit
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// Compute heat index
// Must send in temp in Fahrenheit!
float hi = dht.computeHeatIndex(f, h);
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.print(" *C ");
Serial.print(f);
Serial.print(" *F\t");
Serial.print("Heat index: ");
Serial.print(hi);
Serial.println(" *F");
// picture loop
u8g.firstPage();
do {
u8g.setFont(u8g_font_helvB08);
u8g.drawStr( 0, 15, "Humidity:");
u8g.drawStr( 80, 15, dtostrf(h, 5, 2, str));
u8g.drawStr( 120, 15, "%");
u8g.drawStr( 0, 30, "Temperature:");
u8g.drawStr( 80, 30, dtostrf(t, 5, 2, str));
u8g.drawStr( 120, 30, "\260C");
u8g.drawStr( 80, 45, dtostrf(f, 5, 2, str));
u8g.drawStr( 120, 45, "\260F");
u8g.drawStr( 0, 60, "Heat index:");
u8g.drawStr( 80, 60, dtostrf(hi, 5, 2, str));
u8g.drawStr( 120, 60, "\260F");
} while( u8g.nextPage() );
}
This example show a Arduino Nano, connect with GY-271 Digital Compass module and 0.96" 128x64 OLED via a common I2C bus. GY-271 is a Digital Compass module using HMC5883L, a 3-Axis Digital Compass IC. The reading from GY-271 (x, y, abd z) is display on the OLED. Arduino Nano communicate with GY-271 via I2C bus using Wire library. Arduino Nano communicate with 0.96" 128x64 OLED via the same I2C bus, using u8glib library. I'm not sure is it 100% compatible to use both Wire and u8glib libraries, both share the common I2C bus. Anyway in this example it work.
Connection:
VCC of GY-271, OLED and Arduino Nano connect together.
GND of GY-271, OLED and Arduino Nano connect together.
SCL of GY-271 and OLED connect to A5 of Arduino Nano.
SDA of GY-271 and OLED connect to A4 of Arduino Nano.
DRDY of GY-271 no connection.
(In the following Fritzing drawing, the HMC5883 breakout not exactly my GY-271 module, just to show the connect of SCL and SDA.)
Nano_OLED_Compass.ino
#include "U8glib.h"
#include <Wire.h> //I2C Arduino Library
#define address 0x1E //0011110b, I2C 7bit address of HMC5883
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
int x,y,z; //triple axis data
char bufferX [20];
char bufferY [20];
char bufferZ [20];
void draw(void) {
u8g.setFont(u8g_font_unifont);
u8g.drawStr( 0, 20, bufferX);
u8g.drawStr( 0, 40, bufferY);
u8g.drawStr( 0, 60, bufferZ);
}
void setup(void) {
x = 0;
y = 0;
z = 0;
Wire.begin();
//Put the HMC5883 IC into the correct operating mode
Wire.beginTransmission(address); //open communication with HMC5883
Wire.write(0x02); //select mode register
Wire.write(0x00); //continuous measurement mode
Wire.endTransmission();
}
void loop(void) {
//Tell the HMC5883 where to begin reading data
Wire.beginTransmission(address);
Wire.write(0x03); //select register 3, X MSB register
Wire.endTransmission();
//Read data from each axis, 2 registers per axis
Wire.requestFrom(address, 6);
if(6<=Wire.available()){
x = Wire.read()<<8; //X msb
x |= Wire.read(); //X lsb
z = Wire.read()<<8; //Z msb
z |= Wire.read(); //Z lsb
y = Wire.read()<<8; //Y msb
y |= Wire.read(); //Y lsb
}
sprintf(bufferX, "x : %d", x);
sprintf(bufferY, "y : %d", y);
sprintf(bufferZ, "z : %d", z);
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
delay(100);
}
Then I tried to find the bearing by calling atan2((double)y, (double)x) * 180/M_PI, but get a very big error without calibration. Finally I found a library with auto calibration, read next: HMC5883L library with calibration, for Arduino. About 3-Axis Digital Compass IC HMC5883L:
To capture analog input in accurate timing, we are going to implement TIMER1 ISR (Interrupt Service Routine) in this example, and call analogRead() to capture analog input inside ISR.
Connecttion between Arduino Nano and OLED, refer to last post.
To understand Arduino Timer and Interrupt, it have a good tutorial HERE.
I2C_OLED_scope.ino
// Display analog input to mini-OLED I2C,
// capture input inside TIMER1 ISR
// http://arduino-er.blogspot.com/
// OLED display: ref u8glib: https://code.google.com/p/u8glib/
// To install u8glib on Arduino IDE: http://goo.gl/j3olBA
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
const int WIDTH=128;
const int HEIGHT=64;
const int LENGTH=WIDTH;
const int LED = 13;
boolean LEDst = false;
//true: request capture analog input in ISR
//false: stop capture, draw waveform in loop
boolean capture = false;
const int analogInPin = A0;
int analogInValue = 0;
int x;
int y[LENGTH];
/*
reference: Arduino Timer and Interrupt Tutorial
http://blog.oscarliang.net/arduino-timer-and-interrupt-tutorial/
For our TIMER1 Interrupt:
Clock Freq = 16MHz
no prescale, 1
16MHz - 0.0625us/cycle
To calculator preload value to generate 1ms(1KHz)
(65536 - t) x 0.0625us = 1000us
t = 65536 - 1000/0.0625 = 49536
To calculator preload value to generate 0.5ms(2KHz)
(65536 - t) x 0.0625us = 500us
t = 65536 - 500/0.0625 = 57536
*/
const int TCNT1_PRELOAD = 57536;
void clearY(){
for(int i=0; i<LENGTH; i++){
y[i] = -1;
}
}
void drawY(){
u8g.drawPixel(0, y[0]);
for(int i=1; i<LENGTH; i++){
u8g.drawLine(i-1, y[i-1], i, y[i]);
}
}
void setup(void) {
pinMode(LED, OUTPUT);
// initialize Timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = TCNT1_PRELOAD;
TCCR1B |= (1 << CS10); // no prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
x = 0;
clearY();
capture = true;
interrupts(); // enable all interrupts
}
void loop(void) {
if(!capture){
u8g.firstPage();
do {
drawY();
} while( u8g.nextPage() );
//start capture another frame
x = 0;
clearY();
capture = true;
}
delay(100);
}
ISR(TIMER1_OVF_vect){
TCNT1 = TCNT1_PRELOAD; // preload timer
if(capture){
//toggle LED
digitalWrite(LED, LEDst=!LEDst);
analogInValue = analogRead(analogInPin);
y[x] = map(analogInValue, 0, 1023, HEIGHT-1, 0);
x++;
if(x >= WIDTH){
capture = false;
}
}
}
Display oscilloscope-like waveform on 0.96" 128X64 I2C OLED with Arduino Nano. Read analog input (A0) and plot the waveform acordingly.
// ref u8glib: https://code.google.com/p/u8glib/
// To install u8glib on Arduino IDE: http://goo.gl/j3olBA
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
const int WIDTH=128;
const int HEIGHT=64;
const int LENGTH=WIDTH;
const int analogInPin = A0;
int analogInValue = 0;
int x;
int y[LENGTH];
void clearY(){
for(int i=0; i<LENGTH; i++){
y[i] = -1;
}
}
void drawY(){
u8g.drawPixel(0, y[0]);
for(int i=1; i<LENGTH; i++){
if(y[i]!=-1){
//u8g.drawPixel(i, y[i]);
u8g.drawLine(i-1, y[i-1], i, y[i]);
}else{
break;
}
}
}
void setup(void) {
x = 0;
clearY();
}
void loop(void) {
analogInValue = analogRead(analogInPin);
y[x] = map(analogInValue, 0, 1023, HEIGHT-1, 0);;
u8g.firstPage();
do {
drawY();
} while( u8g.nextPage() );
//delay(10);
x++;
if(x >= WIDTH){
x = 0;
clearY();
}
}
This example read analog input inside loop(), it's not in fixed timing, and affected by the slow operation of displaying. To read input in accurate timing, Refer to next post "Capture analog input in Timer Interrupt".
It's a 1.3"" 128X64 OLED module, I2C/SPI interface (4-wire SPI selected), with SH1106 driver (SSD1306 compatible), 3.3/5V compatible. This post show how to modify from HelloWorld of u8glib library, to make it work. TO download and install u8glib library, refer to last post "Hello World 0.96 inch 128X64 I2C OLED, on Arduino Uno, using u8glib library". It work on both Arduino Uno with 5V, and Arduino Due with 3.3V.
Connection between the OLED module to Arduino Uno (Arduino Due): 4 wire SPI OLED - Arduino Uno (Due)
GND - GND
VCC - 5V (3.3V for Arduino Due)
D0 - 10
D1 - 9
RST - 13
DC - 11
CS - 12
To make the HelloWorld work with this OLED module, add the following constructor calls: U8GLIB_SH1106_128X64 u8g(10, 9, 12, 11, 13);
It's a 0.96" 128X64 OLED, I2C (or IIC) interface, with SSD1306 driver, 3.3/5V compatible.
There are 4 pin on the OLED module, GND, VCC, SCL and SDA. Connect to Arduino as:
GND - GND on Arduino Uno
VCC - 5V on Arduino Uno
SCL - A5 on Arduino Uno
SDA - A4 on Arduino Uno