Hi
I finaly made my ATTiny85 talk with my Arduino Uno. Only strange thing is that small negative integers like 2 become something like 253 when received by the master.
How do I send and receive a negative integer?
My slave read a wheel encoder. My master request current count when needed.
This is the code on the slave
#include "TinyWireS.h" // wrapper class for I2C slave routines
#include "PinChangeInterrupt.h"
#define I2C_SLAVE_ADDR 0x26 // i2c slave address (38)
int pin = 3;
int chA = 4;//pin 3
int chB = 1;//pin 2
volatile int state = HIGH;
volatile int a=0;
volatile int b=0;
volatile int t=0;
void setup()
{
pinMode(pin, OUTPUT);
pinMode(chA, INPUT);
pinMode(chB, INPUT);
TinyWireS.begin(I2C_SLAVE_ADDR); // init I2C Slave mode
TinyWireS.onRequest(requestEvent);
attachPcInterrupt(chA, tickA, CHANGE);
attachPcInterrupt(chB, tickB, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}
void requestEvent()
{
TinyWireS.send(t);
t=0;
}
void tickA()
{
a=digitalRead(chA);
if (a==b) {
t=t+1;
}
else {
t=t-1;
}
state = !state;
}
void tickB()
{
b=digitalRead(chB);
if (a!=b) {
t=t+1;
}
else {
t=t-1;
}
state = !state;
}
This is the code on the master
#include <Wire.h>
#define I2C_SLAVE_ADDR 0x26
volatile boolean haveData = false;
volatile int value =0;
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(I2C_SLAVE_ADDR,2);
if (Wire.available()) {
value=Wire.read();
}
Serial.println (value);
delay(1500);
}
Your slave is sending an int (two bytes), but the TinyWireS.send() only sends a single byte of data with each function call. That's all it is designed to do.
void requestEvent()
{
TinyWireS.send(t);
t=0;
}
Your master is requesting two bytes, but only getting one.
Wire.requestFrom(I2C_SLAVE_ADDR,2);
if (Wire.available()) {
value=Wire.read();
}
Wish I could answer your question about how to send a negative number using an int. You could try I2C_Anything.h, but from my experience, that doesn't seem to work very well with ATtiny85.
What's the resistance of the pull-ups? What's the total length of your I2C bus? It's possible that the problem is now in the hardware and not in the software.
Hi pylon
The pull-ups are 4.7K.
I think it has to do with converting between integer and bytes. I have rewriten the requestEvent again:
void requestEvent()
{
byte lowByte = (byte) (t & 0xff);
byte highByte = (byte) ((t >> 8) & 0xff);
if(firstbyte == true){ // on the first byte we do the math
t=0;
firstbyte = false; //so next time though we send the next byte
TinyWireS.send(lowByte);
}
else {
TinyWireS.send(highByte);
firstbyte = true;
changed = false;
}
}
Now the ATtiny85 continue to read the encoder and send data.
Its only the lowByte that contains a value when recieved by the master.
Master loop now contains:
byte hb;
byte lb;
Wire.requestFrom(I2C_SLAVE_ADDR,1);
if (Wire.available()) {
lb=Wire.read();
}
Wire.requestFrom(I2C_SLAVE_ADDR,1);
if (Wire.available()) {
hb=Wire.read();
}
hb alwways contain 0. Only lb has a value.
When encoder readings on slave are negative they are near 256. I can find the right value by subtracting 256 from lb value if lb is higher than 126.
So it's me not mastering converting from integer to bytes and back again.
My problem is not yet solved but reduced to binary arithmetic that I don’t fully understand yet.
Nice. Now you just need a loop on each side to handle the multiple RequestFrom() / RequestEvent(). Maybe transfer a float next.
With my ATtiny85 testing, I was able to transfer 2 consecutive bytes without the stall you're experiencing.
If you use a Union, you could just let the complier do the conversion between data types. To do the bit shifting, as you know, you need to understand how the bits are placed (such as for negative numbers).
But you are right about errors in my requestEvent. So I corrected the code and now it is working. Yippee
So here's a good example (full code) for other beginners like me.
Slave code:
#include "TinyWireS.h" // wrapper class for I2C slave routines
#include "PinChangeInterrupt.h"
#define I2C_SLAVE_ADDR 0x26 // i2c slave address (38)
int pin = 3; //LED indicating raising and falling edges in both encoder channels
int chA = 4;//Encoder channel A
int chB = 1;//Encoder channel B
volatile int state = HIGH;
volatile int a=0;
volatile int b=0;
volatile int t=0;
boolean changed = true;
boolean firstbyte = true;
byte lowByte;
byte highByte;
void setup()
{
pinMode(pin, OUTPUT);
pinMode(chA, INPUT);
pinMode(chB, INPUT);
TinyWireS.begin(I2C_SLAVE_ADDR); // init I2C Slave mode
TinyWireS.onRequest(requestEvent);
attachPcInterrupt(chA, tickA, CHANGE);
attachPcInterrupt(chB, tickB, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}
void requestEvent()
{
if(firstbyte == true){ // on the first byte we do the math
lowByte = (byte) (t & 0xff);
highByte = (byte) ((t >> 8) & 0xff);
t=0;
firstbyte = false; //so next time though we send the next byte
TinyWireS.send(lowByte);
}
else {
TinyWireS.send(highByte);
firstbyte = true;
}
}
void tickA()
{
a=digitalRead(chA);
if (a==b) {
t=t+1;
}
else {
t=t-1;
}
state = !state;
}
void tickB()
{
b=digitalRead(chB);
if (a!=b) {
t=t+1;
}
else {
t=t-1;
}
state = !state;
}
And the code on the Master (Arduino):
#include <Wire.h>
#define I2C_SLAVE_ADDR 0x26
volatile boolean haveData = false;
volatile int value =0;
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
byte hb;
byte lb;
Wire.requestFrom(I2C_SLAVE_ADDR,1);
if (Wire.available()) {
// hb=Wire.read();
lb=Wire.read();
}
Wire.requestFrom(I2C_SLAVE_ADDR,1);
if (Wire.available()) {
hb=Wire.read();
}
value = ((hb<<8)+lb);
Serial.print(lb);
Serial.print(", ");
Serial.print(hb);
Serial.print(", ");
Serial.println (value);
delay(1500);
}
I wish I would have found an example like this two days ago. Now I hope other can use it in their projects.
Thank you pylon for leading my attention in the right direction.
(Digitizing a analog 0-5v wind vane in the top of my mast. Converting analogRead to i2c data stream to avoid interference and voltage drop in the cable.)