How i write multiple float data to Arduino from Rpi as master via i2c? - raspberry-pi3

I read many post how Rpi receives float data via Arduino via i2c, with Rpi as master.
But i need write floats values to arduino and i don't found any example. I want to use python smbus.
Any one have a example?
Thanks a lot!

After many tests, i can exchange multiple data between arduino as slave and Raspberry pi3 as master.
Arduino code:
#include <Wire.h>
byte data[12];
int command;
typedef struct processData{
float temp1;
float temp2;
float temp3;
float temp4;
float vazao_quente;
float vazao_fria;
byte pump_speed;
//bool pump_status;
byte bstatus;
//bool heater_status;
byte chksum;
};
typedef union I2C_Send{
processData data;
byte I2C_packet[sizeof(processData)];
};
I2C_Send send_info;
void parseValues(byte data[]){
union float_tag{
byte b[4];
float fval;
}ft;
ft.b[0] =data[1];
ft.b[1] = data[2];
ft.b[2] = data[3];
ft.b[3] = data[4];
Serial.println(ft.fval);
}
void setup()
{
Wire.begin(12); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent);
Serial.begin(9600); // start serial for output
setrnddata();
}
void loop()
{
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
command = Wire.read();
if (command==1){
int i=0;
while(1 <= Wire.available()) // loop through all but the last
{
data[i] = Wire.read(); // receive byte as a character
i = i+1;
}
parseValues(data);
}
}
void requestEvent()
{
if(command==2){
Wire.write(send_info.I2C_packet,sizeof(processData));
}
}
Raspberry code:
from datetime import datetime
from datetime import timedelta
from smbus import SMBus
import struct
start_time = datetime.now()
def millis():
dt = datetime.now()-start_time
ms = (dt.days*24*60*60 + dt.seconds)*1000+dt.microseconds / 1000.0
return ms
#inicia escravo i2c
bus = SMBus(1)
arduinoAddress = 12
#interval request
interval = 150
temperatura = 10.2
vazao = 5.3
command = 20
teste = 30
if __name__ == '__main__':
prevmillis = millis()
while True:
currentmillis = millis()
if(currentmillis - prevmillis > interval):
#write
bytescommand = struct.pack('=2fbb',temperatura,vazao,command,teste)
bus.write_block_data(arduinoAddress,1,list(bytescommand))
print(list(bytescommand))
#request
block = bus.read_i2c_block_data(arduinoAddress,2,27)
output = struct.unpack('6f3b',bytes(block))
print(output)
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
prevmillis = currentmillis
I hope helps someone!
Thanks!

Related

Sending a string to UART gives garbage with printf

I'm trying to format data sent over a USB UART with printf and it's giving me garbage. I can send a simple string and that works but anything I try to format gives junk. Looking through the code I think it has to do with my string not being in program space but I'm not sure.
Here is my main:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_uart();
int degree = 0;
char buffer[50];
while(1) {
degree = (degree + 1) % 360;
send_str(PSTR("\n\nHello!!!\n\n"));
memset(buffer, 0, 50);
sprintf_P(buffer, PSTR("%d degrees\n"), degree);
send_str(buffer);
_delay_ms(20);
}
}
The output looks like this:
Hello!!!
����/�������(/����#Q��������
Hello!!!
����/�������(/����#Q��������
The USB UART code I found in a tutorial. The relevant parts look like this:
void send_str(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
usb_serial_putchar(c);
}
}
int8_t usb_serial_putchar(uint8_t c)
{
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) return -1;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
if (transmit_previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return -1;
}
transmit_previous_timeout = 0;
}
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + TRANSMIT_TIMEOUT;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long? This happens if the user
// is not running an application that is listening
if (UDFNUML == timeout) {
transmit_previous_timeout = 1;
return -1;
}
// has the USB gone offline?
if (!usb_configuration) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
SREG = intr_state;
return 0;
}

convert analog read to range to time

I'm trying to blink a led with analog sensor between 8 and 40 times a minutes
I have try this code but I realize that I had to convert the valorSensor to time. How is the way to do it?
int led = 13;
int pinAnalogo = A0;
int analogo;
int valorSensor;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
analogo = analogRead(pinAnalogo);
valorSensor = map(analogo, 0, 1023, 4, 80);
digitalWrite(led, HIGH);
delay(valorSensor);
digitalWrite(led, LOW);
delay(valorSensor);
}
The problem here is not so much the code but biology. To see a blinking (and not just a flicker you will need times from 250ms and up) 24 frames/sec are perceived as motion so to get a "blink" you might start with 4 frames/sec (=250ms)
So my proposal is a blink without delay as function and a tuning parameter (blinkSpeedMultiplyer) for testing
/* Blink without Delay as function
Turns on and off a light emitting diode (LED) connected to a digital pin,
without using the delay() function. This means that other code can run at the
same time without being interrupted by the LED code.*/
// constants won't change. Used here to set a pin number:
const int blinkSpeedMultiplyer = 50; // very low
const int ledPin = 13;
const int pinAnalogo = A0;
// Variables will change:
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long startTime = millis(); // will store last time LED was updated
unsigned long blinkTime; // interval at which to blink (milliseconds)
int analogo;
int valorSensor;
int ledState = LOW; // ledState used to set the LED
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogo = analogRead(pinAnalogo);
valorSensor = map(analogo, 0, 1023, 4, 80);
blinkLed(valorSensor); // call the function
}
// Function to blink without blocking delay
void blinkLed(int inValue) {
blinkTime = blinkSpeedMultiplyer * inValue;
if (millis() - startTime >= blinkTime) {
// save the last time you blinked the LED
startTime = millis();
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}

Attiny85 with ArduinoUno for I2c comm

I am working on attiny85 for I2C communication. I have gone through different libraries already like Wire.h, TinyWire.h, tinyWireM.h, tinyWireS.h.
In the start I want to send some byte of data through I2C comm and tried to scope the pin with oscilloscope but its not giving me the appropriate results. Looking on the internet about different ways to make attiny85 work with I2c is really heartless and I could not achieve the task. Finally, I tried to make attiny85 as master and arduino Uno as slave as it was spare in my box.
I tried to make attiny85 as master and send data to arduino and looks the output on serial monitor but its showing zero.
For the reference, the master and slave codes are attached and my task is just simple to check on serial.
Attiny85 as Master
#include <TinyWireM.h>
void setup()
{
TinyWireM.begin();
}
void loop()
{
TinyWireM.begin();
TinyWireM.beginTransmission(0x08);
TinyWireM.send(0x99);
int Byte1 = TinyWireM.endTransmission();
delay(1000);
}
Arduino as Slave
#include <Wire.h>
const byte add = 0x08;
int byte1;
void setup()
{
Wire.begin(add);
Wire.onReceive(receiveEvent);
Serial.begin(9600);
}
void loop()
{
Serial.println ("Data receiving");
Serial.println(byte1);
delay(1000);
}
void receiveEvent(int bytes)
{
byte1 = Wire.read();
}
But I am not able to get the output on serial monitor of arduino.
What am i doing wrong here?
I have used Atiny85 as a slave using TinyWireS lib (https://github.com/nadavmatalon/TinyWireS) some time back and it worked fine.
Below were the pin configurations
ATtiny85 pin 5 with Arduino Uno A4 and
ATtiny85 pin 7 with Arduino Uno A5
Below are my codes
Atiny.
#include "TinyWireS.h"
const byte SLAVE_ADDR = 100;
const byte NUM_BYTES = 4;
volatile byte data = { 0, 1, 2, 3 };
void setup() {
TinyWireS.begin(SLAVE_ADDR);
TinyWireS.onRequest(requestISR);
}
void loop() {}
void requestISR() {
for (byte i=0; i<NUM_BYTES; i++) {
TinyWireS.write(data[i]);
data[i] += 1;
}
}
Uno.
#include <Wire.h>
const byte SLAVE_ADDR = 100;
const byte NUM_BYTES = 4;
byte data[NUM_BYTES] = { 0 };
byte bytesReceived = 0;
unsigned long timeNow = millis();
void setup() {
Serial.begin(9600);
Wire.begin();
Serial.print(F("\n\nSerial is Open\n\n"));
}
void loop() {
if (millis() - timeNow >= 750) { // trigger every 750mS
Wire.requestFrom(SLAVE_ADDR, NUM_BYTES); // request bytes from slave
bytesReceived = Wire.available(); // count how many bytes received
if (bytesReceived == NUM_BYTES) { // if received correct number of bytes...
for (byte i=0; i<NUM_BYTES; i++) data[i] = Wire.read(); // read and store each byte
printData(); // print the received data
} else { // if received wrong number of bytes...
Serial.print(F("\nRequested ")); // print message with how many bytes received
Serial.print(NUM_BYTES);
Serial.print(F(" bytes, but got "));
Serial.print(bytesReceived);
Serial.print(F(" bytes\n"));
}
timeNow = millis(); // mark preset time for next trigger
}
}
void printData() {
Serial.print(F("\n"));
for (byte i=0; i<NUM_BYTES; i++) {
Serial.print(F("Byte["));
Serial.print(i);
Serial.print(F("]: "));
Serial.print(data[i]);
Serial.print(F("\t"));
}
Serial.print(F("\n"));
}

Arduino Serial.write to Processing returning 0?

I've currently got an Arduino program communicating accelerometer values via a Serial event to processing working perfectly. I'm trying to add a thermometer to my setup however processing is only receiving 0 from reading the pin. If I Serial.print the reading in setup it does print to the serial monitor just fine, however I can't get it to send proper values alongside my accelerometer readings.
Arduino code:
int inByte = 0;
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
establishContact(); // send a byte to establish contact until receiver responds
}
void loop() {
if (Serial.available() > 0) {
// get incoming byte:
inByte = Serial.read();
// send sensor values:
Serial.write(analogRead(A3)); // X AXIS
Serial.write(analogRead(A2)); // Y AXIS
Serial.write(analogRead(A1)); // Z AXIS
Serial.write(analogRead(A0)); // TEMPERATURE
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}
Processing code:
import processing.serial.*;
Serial myPort;
int[] serialInArray = new int[4];
int serialCount = 0;
int xInput, yInput, zInput;
float temperature;
boolean firstContact = false;
void setup() {
size(600, 600, P3D);
pixelDensity(2);
noStroke();
background(0);
printArray(Serial.list());
String portName = Serial.list()[4];
myPort = new Serial(this, portName, 9600);
}
void draw() {
}
void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
// if this is the first byte received, and it's an A,
// clear the serial buffer and note that you've
// had first contact from the microcontroller.
// Otherwise, add the incoming byte to the array:
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
} else {
// Add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
// If we have 3 bytes:
if (serialCount > 2 ) {
zInput = serialInArray[0]-80;
yInput = serialInArray[1]-80+69;
xInput = serialInArray[2]-77;
temperature = serialInArray[3]; // should return voltage reading (i.e 16ºc = 130);
//println("x = " + xInput + ", y = " + yInput + ", z = " + zInput + ", Temp = " + serialInArray[3]);
// Send a capital A to request new sensor readings:
myPort.write('A');
// Reset serialCount:
serialCount = 0;
}
}
}
The accelerometer values print perfectly, but temperature just returns a 0. Serial.print(analogRead(A0)) in the serial monitor gives me the correct values, so the thermometer is definitely working.
Any help would be greatly appreciated, thank you!
In this line ,
if (serialCount > 2 ) {
change for
if (serialCount >= 4 ) {
OR try to use typecasting or change the temperature for integer !!!
int temperature;

Measuring Time of Flight with Arduino Uno

I am trying to implement a master/slave setup to determine the time of flight between two Arduino Uno boards and ultimately use that as a measure of distance between the two. Using the standard 16MHz crystal and the APC220 from DFRobot communicating between the two is easy but getting a time of flight reading is where I get stuck.
I use the following code on the master side to send the first signal and receive the echo from the slave:
// set pins:
const int switchPin = 3; // pin number of the switch
// variables:
int switchState = 0; // variable for reading switch status
int iDisplay = 1;
unsigned long start, finished, elapsed;
// initialize
void setup()
{
// initialize switch pin as input:
pinMode(switchPin, INPUT);
// initialize serial wireless communication:
Serial.begin(9600);
// read initial state of switch
switchState = digitalRead(switchPin);
}
void displayResult()
{
float h,m,s,ms;
unsigned long over;
elapsed=finished-start;
h=int(elapsed/3600000);
over=elapsed%3600000;
m=int(over/60000);
over=over%60000;
s=int(over/1000);
ms=over%1000;
Serial.print("Raw elapsed time: ");
Serial.println(elapsed);
Serial.print("Elapsed time: ");
Serial.print(h,0);
Serial.print("h ");
Serial.print(m,0);
Serial.print("m ");
Serial.print(s,0);
Serial.print("s ");
Serial.print(ms,0);
Serial.println("ms");
Serial.println();
}
// program loop
void loop()
{
if (Serial.available()>0 && iDisplay == 1)
{
finished=millis();
displayResult();
iDisplay = 0;//Only once
}
// read switch state and print line if state has changed
switch (digitalRead(switchPin)) { // read pin status
case HIGH:
if (switchState == LOW)
{ // check if message has to be sent
start=millis();
delay(200); // for debounce
iDisplay = 1;//Only once
Serial.println(100); // send message about switch
switchState = HIGH; // message has been sent
}
break;
case LOW:
if (switchState == HIGH)
{ // check if message has to be sent
start=millis();
delay(200); // for debounce
iDisplay = 1;//Only once
Serial.println(100); // send message about switch
switchState = LOW; // message has been sent
}
break;
}
}
And the following code for the slave:
// variables:
int intTime = 0;
// initialize
void setup()
{
// initialize serial wireless communication:
Serial.begin(9600);
}
// program loop
void loop()
{
if (Serial.available()>0)
{
intTime = Serial.parseInt();
if (intTime > 1)
{
Serial.println(intTime);
}
intTime = 0;
}
}
Yet this only returns the 200 Milliseconds from the debounce delay, can this be done with the Arduino? Am I getting the math or the code wrong?

Resources