Hi ALL,
Total Arduino/ATtiny85 noob here.
I am here with hopes that someone may elude to what my problem is likely to be.
I have written the attached program so as to be able to gain the benefit of floating point arithmetic in conjunction with a PICAXE.
As can be seen within my CODE, I am using I2C communications. Basically I am sending a 16bit word in two 8bit bytes from the PICAXE, doing the math with an ATtiny and returning the result back to the PICAXE also as a 16bit word. At the PICAXE end I am simply applying a decimal point for the resultant resistance measurement. ie 12345 = 123.45 Ohms.
This program works absolutely flawlessly between Arduino UNO (ATmega328P-PU) and PICAXE using the standard WIRE include and is 100% stable in every way, however it does not function properly using the ATtiny with TinyWire and seems rather flaky at best.
I am quite experienced with electronics in general and had no problem following along to upload ArduinoISP to a UNO, wiring and uploading the Bootloader to the ATtiny85 accordingly and did an initial test with the Blink program successfully.
I have the attached program code uploaded to the ATtiny and it initially functions fine, however after what appears to be a random amount of time the communications fail and it seems the ATtiny holds the SCL line LOW. This time span may be from a few seconds to several minutes, but regardless is unreliable.
Using the exact same circuit and swapping between the UNO and the ATtiny, the UNO is 100% perfect and the ATtiny fails. The 5V supplying the ATtiny is stable and there is a 100nF cap right at the I.C. at pin 8 (VCC).
Even if I give the ATtiny and UNO different I2C addresses and independently communicate to each having both in the circuit at the same time, I get the same result whereby the ATtiny ends up holding the SCL line LOW at some random point which obviously buggers up operations.
Because of this I am thinking the problem must be my vast inexperience with Arduino/ATtiny programming and there is something inherently wrong with my coding efforts. But then... the code works perfectly with a UNO ?!?
One thing is for sure, I am getting a bald patch from pulling my hair out
ATtiny CODE:
#include <TinyWire.h> // Include Arduino TinyWire library for I2C
#define SLAVE_ADDR 0x13 //Define Slave I2C Address. PICAXE equiv = times 2 (Shift value LEFT by 1 bit)
//Arduino 0x12 = PICAXE $24
word adc_value; //Received ADC Value from MASTER
float adc_Ref_Volts = 2.048; //ADC Reference Voltage
int VRef_Volts = 5; //Voltage at top of 1K 0.01%
word adc_Max = 65535; //Maximum possible ADC Value
float adc_Volts; //Calculated Volts referenced from adc_value and adc_Ref_Volts
int R1 = 1000; //Top resistor in voltage divider (1K 0.01%)
float R2; //Final calculated unknown resistor value in Ohms xxx.xx
word R2word; //R2 as WORD
void setup() {
pinMode(4, OUTPUT); //Initialise PB4 as OUTPUT for LED visual confirmation
TinyWire.begin(SLAVE_ADDR); //Initialize I2C communications as Slave
TinyWire.onReceive(receiveEvent); //Function to run when data received from master
TinyWire.onRequest(requestEvent); //Function to run when data requested from master
}
void receiveEvent() {
while (0 < TinyWire.available()) {
adc_value = TinyWire.read(); //Receive high byte
adc_value = adc_value << 8; //Shift high byte to be high 8 bits of 16bit WORD
adc_value += TinyWire.read(); //Receive low byte as lower 8 bits
}
digitalWrite(4, HIGH); //Activate LED confirming DATA has been received
adc_Volts = (adc_value * adc_Ref_Volts) / adc_Max; //Calculate ADC Volts
R2 = (adc_Volts * R1) / (VRef_Volts - adc_Volts); //Calculate Unknown Resistor Value
R2 = R2 * 100; //Shift decimal 2 places to the right
R2word = R2; //Convert R2 Float to a 16bit WORD
}
void requestEvent() {
TinyWire.write(R2word & 0xFF); //Send 16bit WORD result in two 8bit bytes via I2C to Master
TinyWire.write(R2word >> 8);
digitalWrite(4, LOW); //Deactivate LED confirming DATA has been successfully returned
}
void loop() {
}
Arduino UNO CODE:
#include <Wire.h> // Include Arduino Wire library for I2C
#define SLAVE_ADDR 0x13 //Define Slave I2C Address. PICAXE equiv = times 2 (Shift value LEFT by 1 bit)
//Arduino 0x12 = PICAXE $24
word adc_value; //Received ADC Value from MASTER
float adc_Ref_Volts = 2.048; //ADC Reference Voltage
int VRef_Volts = 5; //Voltage at top of 1K 0.01%
word adc_Max = 65535; //Maximum possible ADC Value
float adc_Volts; //Calculated Volts referenced from adc_value and adc_Ref_Volts
int R1 = 1000; //Top resistor in voltage divider (1K 0.01%)
float R2; //Final calculated unknown resistor value in Ohms xxx.xx
word R2word; //R2 as WORD
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //Initialise PB4 as OUTPUT for LED visual confirmation
Wire.begin(SLAVE_ADDR); //Initialize I2C communications as Slave
Wire.onReceive(receiveEvent); //Function to run when data received from master
Wire.onRequest(requestEvent); //Function to run when data requested from master
Serial.begin(9600); //Setup Serial Monitor
}
void receiveEvent() {
while (0 < Wire.available()) {
adc_value = Wire.read(); //Receive high byte
adc_value = adc_value << 8; //Shift high byte to be high 8 bits of 16bit WORD
adc_value += Wire.read(); //Receive low byte as lower 8 bits
}
Serial.print("Received ADC: ");
Serial.println(adc_value); //Print ADC Value to terminal screen
digitalWrite(LED_BUILTIN, HIGH); //Activate LED confirming DATA has been received
adc_Volts = (adc_value * adc_Ref_Volts) / adc_Max; //Calculate ADC Volts
R2 = (adc_Volts * R1) / (VRef_Volts - adc_Volts); //Calculate Unknown Resistor Value
Serial.print("Sent Ohms: ");
Serial.println(R2, 2); //Print Unknown Resistor Value to 2 decimal places to terminal screen
Serial.println();
R2 = R2 * 100; //Shift decimal 2 places to the right
R2word = R2; //Convert R2 Float to a 16bit WORD
}
void requestEvent() {
Wire.write(R2word & 0xFF); //Send 16bit WORD result in two 8bit bytes via I2C to Master
Wire.write(R2word >> 8);
digitalWrite(LED_BUILTIN, LOW); //Deactivate LED confirming DATA has been successfully returned
}
void loop() {
}
The only difference between the two coding snippets (whole program) is the omission of the serial terminal lines in the ATtiny CODE and of course the change to TinyWire from WIRE.
Additionally, not that I believe it makes any difference whatsoever, there is also a 24bit ADC I.C. on the I2C bus communicating the taken measurements to the PICAXE but I am only using the top 16bits of the returned measurement and in essence am completely eradicating any inherent INL or OFFSET errors.
Also to note, thinking that perhaps it is a timing issue, I have the ATtiny running at 16MHz with the internal clock and switching to a 16MHz external crystal makes absolutely no difference.
Putting a 10K pullup on the ATtiny reset pin also doesn't change anything.
And finally, are my comments regarding the BYTE's correctly commented (HIGH byte, LOW byte) ?
I'd appreciate any clues that could be offered.
Thanks in advance.
Regards,
Mort.