How to change current code to read from 2 different OneWire devices? - arduino

I've been given this code which reads from a OneWire temperature device DS18b20. I'd like to add another sensor to the same pin but not quite sure how to best do it. I didn't write this code myself. I'm using an NodeMCU devkit v0.9. The code below is just a section of the full code and there are separate scripts/tabs. Let me know if I should add anything else. Any help is greatly appreciated.
#include <Arduino.h> // not automatically included?
#include <OneWire.h> // for temp sensor
#include <Wire.h> // I2C for ADC & RTC
#include <DHT.h> // Humidity sensor
#include "sens.h"
#define TEMP_PIN D2 // Where DS18B20 is connected
#define ADDR_LEN 8 // 1-Wire address length // NOT SURE WHAT THESE DO!!
#define DATA_LEN 9 // 1-Wire data length // NOT SURE WHAT THESE DO!!
#define HUMI_PIN D1 // Where the DHT11 is
#define RTC_ADDR 0x68 // Clock's I2C address
#define ADC_ADDR 0x48 // ADC's I2C address
#define SDA D3 // I2C pins
#define SCL D4
OneWire ow(TEMP_PIN); // Setup 1-Wire
byte addr[ADDR_LEN]; // To store 1-Wire address
byte data[DATA_LEN]; // To store 1-Wire data
DHT dht(HUMI_PIN, DHT11); // Setup DHT
String leading0(const int c) {
// Add a leading zero when stringifying a byte, used for the date
return (c < 10) ? ("0" + String(c)) : String(c);
}
byte bin2bcd( const byte bin ) {
// does as the name suggests, RTC uses BCD
return (bin / 10 * 16) + (bin % 10);
}
byte bcd2bin( const byte bin ) {
// does as the name suggests, RTC uses BCD
return (bin / 16 * 10) + (bin % 16);
}
void senssetup() {
// Setup sensors, called in setup()
dht.begin();
Wire.begin(SDA, SCL);
}
float gettemp() {
int i = 0;
ow.reset_search();
do {} while (!ow.search(addr) && i++ < 0xff);
// Search for 1-Wire devices
if (i == 0x100) {
if (debug) Serial.println("No devices found!");
// Nothing connected
return 0;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
if (debug) Serial.println("CRC 1 failed!");
// Checksum thing when getting device's address
return -1;
}
if (addr[0] != 0x10 && addr[0] != 0x28) {
if (debug) Serial.println("Not a DS18B20");
// Wrong 1-Wire device
return -2;
}
ow.reset();
ow.select(addr);
ow.write(0x44, 0);
// HEX 44 tells it to convert temperature to readable binary
delay(1000);
// It takes ~750ms to convert data, 1s is used to be safe (1s is used in the default library too)
if (!ow.reset()) {
if (debug) Serial.println("Device not present");
// Device has disconnected or broken during conversion?
return -3;
}
ow.select(addr);
ow.write(0xbe, 0);
// Tells it we're reading
for (i = 0; i < DATA_LEN; i++) {
data[i] = ow.read(); // Read data
}
if (debug && OneWire::crc8(data, 8) != data[8])
Serial.println( "CRC Check 2 failed" );
// Checksum on data; this fails sometimes, I don't know why
// temperature is always at the right value so ignore it
int dat = ((data[1] << 8) | data[0]);
if (dat > 32767)
dat -= 65536;
// 16 bit data in 2's complement has a sign
return dat / 16.0;
// last 4 binary digits are fractional
}

You should split the search part from the getting temperature part.
NOTE: I'm not into NodeMCU, so you'll have to adapt it to that language before using it. I'd use C.
For instance, you can use a function to get all addresses of the temperature sensors and put them in an address array:
#define MAX_DEVICES 5
byte addresses[MAX_DEVICES][ADDR_LEN];
byte numOfAddresses;
void getAllAddresses()
{
numOfAddresses = 0;
ow.reset_search();
byte address[ADDR_LEN];
while (ow.search(address) && (numOfAddresses < MAX_DEVICES))
{
if ( OneWire::crc8( address, 7 ) != address[7] )
continue; // CRC 1 failed
if ( address[0] != 0x10 && address[0] != 0x28 )
continue; // Not a DS18B20
byte i;
for (i = 0; i < ADDR_LEN; i++)
addresses[numOfAddresses][i] = address[i];
numOfAddresses++;
}
if (debug)
{
Serial.print("Found ");
Serial.print(numOfAddresses);
Serial.println(" temperature sensors");
}
}
Then you can modify your function to get the temperature of the i-th sensor:
float gettemp(byte index)
{
if (index >= numOfAddresses)
{
if (debug) Serial.println( "Index not valid" );
return -200; // Don't use 0, -1, ..., since they are valid temperatures
}
ow.reset();
ow.select(addresses[index]);
ow.write(0x44, 0); // HEX 44 tells it to convert temperature to readable binary
[...]
(just replace every call to addr with a call to addresses[index].
In your code, then, instead of calling gettemp you will have to call gettemp(0) for the first sensor, gettemp(1) for the second and so on.
You will need to call getAllAddresses before the first call to gettemp, otherwise it will always return -200. You can call it at startup or every X seconds or at each measurement, that's completely up to you

Related

Using a HashMap to store the sensor addresses with tempetures on Arduino

I have started a small project to hopefully replace RPis running a Java library with Arduinos.
(I am normally working with Java, so not as familiar with C)
There are multiple temp sensors connected to the board. I read the values and want to store them with a reference to the sensor address. When a value changes, an update of all the sensors with their address and the temperatures is send to the server (hence I need the store to compare the values every 10 seconds).
I am trying to use the HashMap from Arduino Playground, as on a first look it seemed to do what I need and seems lightweight.
However, when reading the address of the temp sensor from a variable from the HashMap it doesn't return the right one (when there is some data pre-set in the hashmap):
int strLen = sAddress.length();
char *cAddress = (char *)malloc(strLen+1);
sAddress.toCharArray(cAddress, strLen+1);
byte position = sensorHashMap.getIndexOf(cAddress);
However, if I replace the *cAddress with:
char *cAddress = "28aae25501412c";
it does find it. So what am I doing wrong?
My approach to store the temp values with the address as a reference might not be the best, and it seems that the code crashes later on when trying to update the value but I haven't gone down that far yet. If there is a better solution than I am very open to some suggestions off course.
The full code below:
#include <HashMap.h>
#include <OneWire.h>
#include <ESP8266WiFi.h>
#include <DS18B20.h>
char wifiSSID[] = "xxxx";
char wifiPassword[] = "xxxx";
unsigned long lastTempCheck = 0;
const byte HASH_SIZE = 10; // Max 10 (temp) sensors etc
HashType<char*, float> hashRawArray[HASH_SIZE];
HashMap<char*, float> sensorHashMap = HashMap<char*, float>( hashRawArray , HASH_SIZE );
int sensorsRegistered = 1;
WiFiClient client;
DS18B20 ds(5); // Is D1
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.begin(wifiSSID, wifiPassword);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("---");
Serial.println("Connected to wifi");
Serial.print("Connected, IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Setup completed, ready to run...");
// Test data
sensorHashMap[0]("name", 18);
sensorHashMap[1]("test", 200);
sensorHashMap[2]("qwer", 1234);
sensorHashMap[3]("28fffa6f51164ae", 123);
sensorHashMap[4]("28aae25501412c", 456);
}
void loop() {
// Duty cycle of the application
delay(100);
if ((millis() < lastTempCheck) || (millis() - lastTempCheck > 1000 * 10)) {
// Verifying the HashMap works with the pre-set values.
Serial.print("Checking pre-set values: ");
Serial.println( sensorHashMap.getIndexOf("28fffa6f51164ae"), DEC );
Serial.print("Checking sensor value: ");
Serial.println( sensorHashMap.getValueOf("28fffa6f51164ae") );
while (ds.selectNext()) {
float temp = ds.getTempC();
uint8_t address[8];
ds.getAddress(address);
String sAddress = "";
for (uint8_t i = 0; i < 8; i++) {
sAddress += String(address[i], HEX);
}
int strLen = sAddress.length();
char *cAddress = (char *)malloc(strLen+1);
sAddress.toCharArray(cAddress, strLen+1);
//char *cAddress = "28aae25501412c";
byte position = sensorHashMap.getIndexOf(cAddress);
Serial.print("Position: ");
Serial.println( position);
Serial.println( sensorHashMap.getIndexOf(cAddress), DEC );
if (position < HASH_SIZE) {
Serial.print("Updating sensor value, currently: ");
Serial.println( sensorHashMap.getValueOf(cAddress));
sensorHashMap[position](cAddress, temp); //ds.getTempC()
} else {
Serial.print("Creating sensor value, id is going to be ");
Serial.println(sensorsRegistered);
sensorHashMap[sensorsRegistered](cAddress, temp);
sensorsRegistered++;
}
free(address);
}
lastTempCheck = millis();
}
}

Waterproofed water-temperature DS18B20 only returns -127 for degree in Celsius

For a project in university, I have to measure various quality of the water, including the temperature. The temperature sensor is DS18B20, and I use an Arduino Mega board to run the whole show. Individual running with DS18B20 only fails to return any meaningful number. Instead of 25C (or something like that), it returns -127.
The code below is from Dallas Temperature (with small changes, like having delay and removing some comment lines)
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 48
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
}
void loop(void)
{
delay(500);
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
Serial.print("Temperature for the device 1 (index 0) is: ");
Serial.println(sensors.getTempCByIndex(0));
delay(2500);
}
This one is actually from the Wiki page of DFRobot (where my sensor is originated from)
#include <OneWire.h>
int DS18S20_Pin = 48; //DS18S20 Signal pin on digital 48
//Temperature chip i/o
OneWire ds(DS18S20_Pin); // on digital pin 48
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
float temperature = getTemp();
Serial.println(temperature);
delay(100); //just here to slow down the output so it is easier to read
}
float getTemp(){
//returns the temperature from one DS18S20 in DEG Celsius
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return -1000;
}
if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print("Device is not recognized");
return -1000;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++ ) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two's compliment
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
This specific code returns -1000 every time, which I presume is the equivalence of -127 above.
Edit: The problem was identified as faulty electric wire. Yes, hardware problem.
From the library:
// Error Codes
#define DEVICE_DISCONNECTED_C -127
https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/b34be08d603242bb534e7b717dac48baf60c5113/DallasTemperature.h#L36
So you're device is not connected / not communicating. Check your wiring and your pin numbers.

Trying to send a float value over SPI between 2 Arduinos

I am currently trying to send a float value across two Arduinos via SPI. Currently I am working to send a static value of 2.25 across and then read it via the Serial.println() command. I would then want to pass a float value from a linear displacement sensor. My end goal is to be able to have the master ask for information, the slave gathers the appropriate data and packages it and then master receives said data and does what it needs with it.
Currently I am getting an error "call of overloaded 'println(byte [7])' is ambiguous" and I am not to sure why I am getting this error. I am currently a mechanical engineering student and I am crash-coursing myself through C/C++. I am not entirely positive about what I am doing. I know that a float is 4 bytes and I am attempting to create a buffer of 7 bytes to store the float and the '\n' char with room to spare. My current code is below.
Master:
#include <SPI.h>
void setup() {
pinMode(SS,OUTPUT);
digitalWrite(SS,HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
}
void loop() {
digitalWrite(SS,LOW);
float a = 2.25;
SPI.transfer(a);
SPI.transfer('\n');
digitalWrite(SS,HIGH);
}
My slave code is as follows:
#include <SPI.h>
byte buf[7];
volatile byte pos = 0;
volatile boolean process_it = false;
void setup() {
Serial.begin(9600);
pinMode(MISO,OUTPUT);
digitalWrite(MISO,LOW);
SPCR |= _BV(SPE); // SPI Enable, sets this Arduino to Slave
SPCR |= _BV(SPIE); // SPI interrupt enabled
}
ISR(SPI_STC_vect) {
// Interrupt Service Routine(SPI_(SPI Transfer Complete)_vector)
byte c = SPDR;
// SPDR = SPI Data Register, so you are saving the byte of information in that register to byte c
if (pos < sizeof buf) {
buf[pos++] = c;
if (c == '\n') {
process_it = true;
}
}
}
void loop() {
if (process_it = true) {
Serial.println(buf);
pos = 0;
process_it = false;
}
}
I figured out what I needed to do and I wanted to post my finished code. I also added an ability to transfer more than one float value.
Master:
#include <SPI.h>
float a = 3.14;
float b = 2.25;
uint8_t storage [12];
float buff[2] = {a, b};
void setup()
{
digitalWrite(SS, HIGH);
SPI.begin();
Serial.begin(9600);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void loop()
{
digitalWrite(SS, LOW);
memcpy(storage, &buff, 8);
Serial.print("storage[0] = "); Serial.println(storage[0]); // the
following serial prints were to check i was getting the right decimal
numbers for the floats.
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
SPI.transfer(storage, sizeof storage ); //SPI library allows a user to
transfer a whole array of bytes and you need to include the size of the
array.
digitalWrite(SS, HIGH);
delay(1000);
}
For my Slave code:
#include <SPI.h>
byte storage [8];
volatile byte pos;
volatile boolean process;
float buff[2];
void setup()
{
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
SPCR |= _BV(SPIE);
pos = 0;
process = false;
Serial.begin(9600);
}
ISR(SPI_STC_vect)
{
byte gathered = SPDR;
if( pos < sizeof storage)
{
storage[pos++] = gathered;
}
else
process = true;
}
void loop()
{
if( process )
{
Serial.print("storage[0] = "); Serial.println(storage[0]);
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
memcpy(buff,&storage,8);
Serial.print("This is buff[0]");Serial.println(buff[0]);
Serial.print("This is buff[1]");Serial.println(buff[1]);
storage[pos] = 0;
pos = 0;
process = false;
}
}
The immediate problem is that Serial.print doesn't know what to do with a byte array. Either declare it as a char array or cast it in the print statement:
char buf[7];
OR
Serial.print((char*) buf);
Either way, though, it's not going to show up as a float like you want.
An easier way to do all this is to use memcpy or a union to go back and forth between float and bytes. On the master end:
uint8_t buf[4];
memcpy(buf, &a, 4);
Then use SPI to send 4 bytes. Reverse it on the peripheral end.
Note that sending '\n' as the termination byte is a bad idea because it can lead to weird behavior, since one of the bytes in the float could easily be 0x0a, the hexadecimal equivalent of '\n'.

Arduino SD card fails to write when used with another SPI device

I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).

Arduino Code not executing after Wire.endTransmission line

I am working on a project, syncing Nintendo Nunchuk with Arduino. I found a code online for the same from http://letsmakerobots.com/node/5684
Here, is the code
#include <Wire.h>;
void setup(){
Serial.begin(19200);
nunchuck_setpowerpins();
nunchuck_init();
Serial.print("Nunchuck ready\n");
}
void loop(){
nunchuck_get_data();
nunchuck_print_data();
delay(1000);
}
//======================================================================================================================================================================================================//
//Do not modify!!!!!!!!
//======================================================================================================================================================================================================//
//
// Nunchuck functions
//
static uint8_t nunchuck_buf[6]; // array to store nunchuck data,
// Uses port C (analog in) pins as power & ground for Nunchuck
static void nunchuck_setpowerpins()
{
#define pwrpin PORTC3
#define gndpin PORTC2
DDRC |= _BV(pwrpin) | _BV(gndpin);
PORTC &=~ _BV(gndpin);
PORTC |= _BV(pwrpin);
delay(100); // wait for things to stabilize
}
// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
void nunchuck_init()
{
Wire.begin(); // join i2c bus as master
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.send(0x40); // sends memory address
Wire.send(0x00); // sends sent a zero.
Wire.endTransmission(); // stop transmitting
}
// Send a request for data to the nunchuck
// was "send_zero()"
void nunchuck_send_request()
{
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.send(0x00); // sends one byte
Wire.endTransmission(); // stop transmitting
}
// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
int nunchuck_get_data()
{
int cnt=0;
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ()) {
// receive byte as an integer
nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());
cnt++;
}
nunchuck_send_request(); // send request for next data payload
// If we recieved the 6 bytes, then go print them
if (cnt >= 5) {
return 1; // success
}
return 0; //failure
}
// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits. That is why I
// multiply them by 2 * 2
void nunchuck_print_data()
{
static int i=0;
int joy_x_axis = nunchuck_buf[0];
int joy_y_axis = nunchuck_buf[1];
int accel_x_axis = nunchuck_buf[2]; // * 2 * 2;
int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;
int z_button = 0;
int c_button = 0;
// byte nunchuck_buf[5] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((nunchuck_buf[5] >> 0) & 1)
z_button = 1;
if ((nunchuck_buf[5] >> 1) & 1)
c_button = 1;
if ((nunchuck_buf[5] >> 2) & 1)
accel_x_axis += 2;
if ((nunchuck_buf[5] >> 3) & 1)
accel_x_axis += 1;
if ((nunchuck_buf[5] >> 4) & 1)
accel_y_axis += 2;
if ((nunchuck_buf[5] >> 5) & 1)
accel_y_axis += 1;
if ((nunchuck_buf[5] >> 6) & 1)
accel_z_axis += 2;
if ((nunchuck_buf[5] >> 7) & 1)
accel_z_axis += 1;
Serial.print(i,DEC);
Serial.print("\t");
Serial.print("joy:");
Serial.print(joy_x_axis,DEC);
Serial.print(",");
Serial.print(joy_y_axis, DEC);
Serial.print(" \t");
Serial.print("acc:");
Serial.print(accel_x_axis, DEC);
Serial.print(",");
Serial.print(accel_y_axis, DEC);
Serial.print(",");
Serial.print(accel_z_axis, DEC);
Serial.print("\t");
Serial.print("but:");
Serial.print(z_button, DEC);
Serial.print(",");
Serial.print(c_button, DEC);
Serial.print("\r\n"); // newline
i++;
}
// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
{
return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1; // voodoo
}
// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
{
return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1; // voodoo
}
// returns value of x-axis joystick
int nunchuck_joyx()
{
return nunchuck_buf[0];
}
// returns value of y-axis joystick
int nunchuck_joyy()
{
return nunchuck_buf[1];
}
// returns value of x-axis accelerometer
int nunchuck_accelx()
{
return nunchuck_buf[2]; // FIXME: this leaves out 2-bits of the data
}
// returns value of y-axis accelerometer
int nunchuck_accely()
{
return nunchuck_buf[3]; // FIXME: this leaves out 2-bits of the data
}
// returns value of z-axis accelerometer
int nunchuck_accelz()
{
return nunchuck_buf[4]; // FIXME: this leaves out 2-bits of the data
}
When I write, Serial.Println("End"), in the line after Wire.endTransmission(); in function nunchuck_init(), it does not display on Serial Monitor.
Also, it does not display Nunchuck ready on Serial Monitor since it is written after nunchuck_init() has been called.
I am working on Arduino 0023, Windows 7.
A existing problem with the stock Arduino Wire library is that there is no timeout.
It is possible for the endTransmission function to hang the microcontroller in different scenarios.
This issue has been discussed in several other forums, and the best solution I've found so far is to use an alternate library.
The Arduino I2C Master Library by Wayne Truchsess
http://www.dsscircuits.com/index.php/articles/66-arduino-i2c-master-library
With proper timeout, it fixed the problem on my system reading the MMA7455 accelero
In the source code provided, there's an example where it shows how the same piece of program is done using Wire vs the I2C Master Library.
You can use that example to easily modify your code to adopt the new library.

Resources