I have 3 ultrasonic sensor connected to 1 Arduino Uno device. I want to send their data to another Arduino Uno with RF transmitter. I want to send the sensor's id number (1,2,3) and the data (0 or 1).
I want to transmit the data from printDistance method but the message that transmitter sends is char *msg. Do I have to send only char values?
#include <VirtualWire.h>
#undef int
#undef abs
#undef double
#undef float
#undef round
//Sonar 1
int echoPin1 =2;
int initPin1 =3;
int distance1 =0;
//Sonar 2
int echoPin2 =6;
int initPin2 =7;
int distance2 =0;
//Sonar 3
//int echoPin3 =8;
//int initPin3 =9;
//int distance3 =0;
void setup() {
// Initialise the IO and ISR
vw_set_ptt_inverted(true); // Required for RF Link module
vw_setup(2000);
vw_set_tx_pin(8);
pinMode(initPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(initPin2, OUTPUT);
pinMode(echoPin2, INPUT);
// pinMode(initPin3, OUTPUT);
// pinMode(echoPin3, INPUT);
// pinMode(initPin4, OUTPUT);
// pinMode(echoPin4, INPUT);
delay(2000);
Serial.begin(9600);
Serial.println(" ");
}
void loop() {
const char *msg; // this is your message to send
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx(); // Wait for message to finish
delay(200);
distance1 = getDistance(initPin1, echoPin1);
printDistance(1, distance2);
delay(10);
distance2 = getDistance(initPin2, echoPin2);
printDistance(2, distance2);
delay(10);
//distance3 = getDistance(initPin3, echoPin3);
//printDistance(3, distance3);
//delay(10);
// distance4 = getDistance(initPin4, echoPin4);s
// printDistance(4, distance4);
Serial.println(" ");
delay(5000);
// Serial.println(" ");
}
int getDistance (int initPin, int echoPin){
digitalWrite(initPin, HIGH);
delayMicroseconds(10);
digitalWrite(initPin, LOW);
delayMicroseconds(5);
unsigned long pulseTime = pulseIn(echoPin, HIGH);
int distance = pulseTime/58;
return distance;
}
void printDistance(int id, int dist){
Serial.print('<');
Serial.print( id );
Serial.print( '>' );
if (dist >= 30 || dist <= 0 ){
Serial.print("0");
}else {
Serial.print("1");
}
Serial.print('<');
Serial.print( '/' );
Serial.print( id );
Serial.print( '>' );
// Serial.println(" ");
}
uint8_t vw_send(uint8_t* buf, uint8_t len) sends an array of bytes, with maximum length 77. In C, the type for a byte is called char. In AVR, this has an alias uint8_t as well.
So you send an array of bytes, and it is up to you to decide how the chars in the array are interpreted. For example, you could use sprintf() to write numbers as ascii encoded strings. Then on the receiving end, you would have to use atoi() to get the number back out of the string.
You could also choose to simply fill the array with the actual number values. With this option, you have to break up ints into separate bytes, and combine them back together on the receiving end. In your particular case, the data already fits into bytes, so you don't have to do that.
Beware that vw_send((uint8_t *)msg, strlen(msg)); won't work correctly with this second method. strlen() will count up to the first byte that holds a 0, effectively truncating the array. You would only use this call when using the sprintf() approach.
It looks like you are sending the data for all three sensors at the same time, and that the data for each is either 0 or 1. Why not send a 3-byte message of 0s and 1s?
uint8_t msg[3];
msg[0] = 0;
msg[1] = 1;
msg[2] = 0; // fill these in as you like
vw_send(msg, 3);
I couldn't add code to comment.
I changed the code as this;
void printDistance(int id, int dist){
uint8_t msg[1];
if (dist >= 30 || dist <= 0 ){
msg[0] = 0;
vw_send(msg, 1);
//vw_wait_tx();
}else {
msg[0] = 1;
vw_send(msg, 1);
//vw_wait_tx();
}
Related
I am using a version of an Arduino CNC board that is found here to drive 4 wheels on a small wheeled robot. The shield came with A4988 stepper drivers and I got them to work fine, however the motors were much louder than intended so I went searching for another driver and found the TMC2208. I saw that the pin-outs were the same as long as the boards themselves aligned the enable pins on the shield.
The problem however seems to be in the code though. I am using the Accelstepper library in my code and everything works fine with the A4988 driver board. When I swapped just the boards, nothing happened in my program. I went looking on the TMCStepper library git to try and find some help. I managed to at lease get the steppers working using a version of the 'Simple' example. I tried to take out as much as possible while still being able to move the motors so that I could use it in my actual program. I still am not having any luck.
When I run this program
#include <TMCStepper.h>
#define EN_PIN 8 // Enable
#define DIR_PIN1 5 // Direction
#define STEP_PIN1 2 // Step
#define DIR_PIN2 6 // Direction
#define STEP_PIN2 3
#define DIR_PIN3 7 // Direction
#define STEP_PIN3 4
#define DIR_PIN4 13 // Direction
#define STEP_PIN4 12
#define SW_RX1 55 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX1 60 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define SW_RX2 56 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX2 61
#define SW_RX3 57 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX3 62
#define SW_RX4 58 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX4 63
#define R_SENSE 0.11f // Match to your driver
TMC2208Stepper driverX(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverY(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverZ(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverA(SW_RX1, SW_TX1, R_SENSE); // Software serial
void setup() {
pinMode(EN_PIN, OUTPUT);
pinMode(STEP_PIN1, OUTPUT);
pinMode(DIR_PIN1, OUTPUT);
pinMode(STEP_PIN2, OUTPUT);
pinMode(DIR_PIN2, OUTPUT);
pinMode(STEP_PIN3, OUTPUT);
pinMode(DIR_PIN3, OUTPUT);
pinMode(STEP_PIN4, OUTPUT);
pinMode(DIR_PIN4, OUTPUT);
digitalWrite(EN_PIN, LOW); // Enable driver in hardware
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin(); // SPI: Init CS pins and possible SW SPI pins
// UART: Init SW UART (if selected) with default 115200 baudrate
driverX.microsteps(16); // Set microsteps to 1/16th
}
void loop() {
// Run 5000 steps and switch direction in software
for (uint16_t i = 5; i>0; i++) {
digitalWrite(STEP_PIN1, HIGH);
digitalWrite(STEP_PIN2, HIGH);
digitalWrite(STEP_PIN3, HIGH);
digitalWrite(STEP_PIN4, HIGH);
delayMicroseconds(160);
digitalWrite(STEP_PIN1, LOW);
digitalWrite(STEP_PIN2, LOW);
digitalWrite(STEP_PIN3, LOW);
digitalWrite(STEP_PIN4, LOW);
delayMicroseconds(160);
}
the motors just continuously spin, so I know that the drivers actually work.
My main code is below.
#include <AccelStepper.h>
#include <TMCStepper.h>
const int stepperCount = 4;
AccelStepper BLStepper(AccelStepper::DRIVER, 2, 5);
AccelStepper FLStepper(AccelStepper::DRIVER, 3, 6);
AccelStepper FRStepper(AccelStepper::DRIVER, 4, 7);
AccelStepper BRStepper(AccelStepper::DRIVER, 12, 13);
#define R_SENSE 0.11f
// define pins numbers
#define stepX_PIN 2
#define dirX_PIN 5
#define stepX_RX 55
#define dirX_TX 60
#define stepY_PIN 3
#define dirY_PIN 6
#define stepY_RX 56
#define dirY_TX 61
#define stepZ_PIN 4
#define dirZ_PIN 7
#define stepZ_RX 57
#define dirZ_TX 62
#define stepA_PIN 12
#define dirA_PIN 13
#define stepA_RX 58
#define dirA_TX 63
#define enPin_PIN 8
TMC2208Stepper driverX(stepX_RX, dirX_TX, R_SENSE);
TMC2208Stepper driverY(stepY_RX, dirY_TX, R_SENSE);
TMC2208Stepper driverZ(stepZ_RX, dirZ_TX, R_SENSE);
TMC2208Stepper driverA(stepA_RX, dirA_TX, R_SENSE);
//Front left wheel
//const int stepX_PIN = 2;
//const int dirX_PIN = 5;
//Front right wheel
//const int stepY_PIN = 3;
//const int dirY_PIN = 6;
//Back left wheel
//const int stepZ_PIN = 4;
//const int dirZ_PIN = 7;
//Back right wheel
//const int stepA_PIN = 12;
//const int dirA_PIN = 13;
//const int enPin_PIN = 8;
char split = ':'; //this is the character that would be used for seperating the different parts of your commands
//the syntax for commands would be: command:value1:value2
int listSize = 5; //the amount of commands in the list
String commands[] = {"hello", "add", "sub", "YMOV", "XMOV"}; //the list of every command name
void setup()
{
Serial.begin(115200); //sets the data transfer rate for the serial interface
//9600 is good for basic testing, but should be as high
//as possible for both devices
FRStepper.setMaxSpeed(300);
FRStepper.setAcceleration(200);
BRStepper.setMaxSpeed(300);
BRStepper.setAcceleration(200);
FLStepper.setMaxSpeed(300);
FLStepper.setAcceleration(200);
BLStepper.setMaxSpeed(300);
BLStepper.setAcceleration(200);
pinMode(stepX_PIN, OUTPUT);
pinMode(dirX_PIN, OUTPUT);
pinMode(stepY_PIN, OUTPUT);
pinMode(dirY_PIN, OUTPUT);
pinMode(stepZ_PIN, OUTPUT);
pinMode(dirZ_PIN, OUTPUT);
pinMode(stepA_PIN, OUTPUT);
pinMode(dirA_PIN, OUTPUT);
pinMode(enPin_PIN, OUTPUT);
digitalWrite(enPin_PIN, LOW);
digitalWrite(dirX_PIN, HIGH);
digitalWrite(dirY_PIN, HIGH);
digitalWrite(dirZ_PIN, HIGH);
digitalWrite(dirA_PIN, HIGH);
//digitalWrite(stepX_PIN, HIGH);
//digitalWrite(stepY_PIN, HIGH);
//digitalWrite(stepZ_PIN, HIGH);
//digitalWrite(stepA_PIN, HIGH);
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin();
FRStepper.setEnablePin(enPin_PIN);
FLStepper.setEnablePin(enPin_PIN);
BRStepper.setEnablePin(enPin_PIN);
BLStepper.setEnablePin(enPin_PIN);
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
}
void loop()
{
CommCheck(); //checks serial buffer for data commands
runMotors();
}
void runMotors()
{
if ((FLStepper.distanceToGo() != 0) || (FRStepper.distanceToGo() != 0) || (BLStepper.distanceToGo() != 0) || (BRStepper.distanceToGo() != 0))
{
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
FLStepper.run();
BLStepper.run();
FRStepper.run();
BRStepper.run();
if ((FLStepper.distanceToGo() == 0) && (FRStepper.distanceToGo() == 0))
{
CommConfirm();
}
}
//if (movementComplete == true)
//{
//CommConfirm();
//}
//if (
//if ((FLStepper.distanceToGo() == 0) || (FRStepper.distanceToGo() == 0) || (BLStepper.distanceToGo() == 0) || (BRStepper.distanceToGo() == 0))
//{
//CommConfirm();
//}
}
void CommCheck()
{
if(Serial.available()) //checks to see if there is serial data has been received
{
//int len = Serial.available(); //stores the character lengh of the command that was sent
//this is used for command parsing later on
String command = Serial.readString(); //stores the command as a text string
int len = command.length();
//Serial.println(command);
Serial.flush();
//command.remove(len-2,1); //removes characters added by the pi's serial data protocol
//command.remove(0,2);
//len -= 3; //updates the string length value for parsing routine
int points[2] = {0, 0}; //offset points for where we need to split the command into its individual parts
for(int x = 0; x < len; x++) //this loop will go through the entire command to find the split points based on
{ //what the split variable declared at the top of the script is set to.
//Serial.print("Char ");
//Serial.print(x);
//Serial.print("- ");
//Serial.println(command[x]);
if(command[x] == split) //this goes through every character in the string and compares it to the split character
{
if(points[0] == 0) //if the first split point hasn't been found, set it to the current spot
{
points[0] = x;
}
else //if the first spot was already found, then set the second split point
{ //this routine is currently only set up for a command syntax that is as follows
points[1] = x; //command:datavalue1:datavalue2
}
}
}
CommParse(command, len, points[0], points[1]); //now that we know the command, command length, and split points,
} //we can then send that information out to a routine to split the data
} //into individual values.
void CommParse(String command, int len, int point1, int point2)
{
//Serial.print("Command Length: ");
//Serial.println(len);
//Serial.print("Split 1: ");
//Serial.println(point1);
//Serial.print("Split 2: ");
//Serial.println(point2);
String com = command; //copy the full command into all 3 parts
String val1 = command; //this is needed for the string manipulation
String val2 = command; //that follow
com.remove(point1, len - point1); //each of these use the string remove to delete
val1.remove(point2, len - point2); //the parts of the command that aren't needed
val1.remove(0, point1 + 1); //basically splitting the command up into its
val2.remove(0, point2 + 1); //individual pieces
val2.remove(val2.length()-1,1);
CommLookup(com, val1, val2); //these pieces are then sent to a lookup routine for processing
}
void CommLookup(String com, String val1, String val2)
{
int offset = 255; //create a variable for our lookup table's offest value
//we set this to 255 because there won't be 255 total commands
//and a valid command can be offset 0, so it's just to avoid
//any possible coding conflicts if the command sent doesn't
//match anything.
for(int x = 0; x < listSize; x++) //this goes through the list of commands and compares
{ //them against the command received
if(commands[x] == com)
{
offset = x; //if the command matches one in the table, store that command's offset
}
}
switch(offset) //this code compares the offset value and triggers the appropriate command
{
case 0: //essentially a hello world. | Syntax: hello:null:null
CommHello(); //this activates the hello world subroutine | returns Hello!
break;
case 1: //adds both values together and return the sum. | Syntax: add:value1:value2
CommAdd(val1.toInt(), val2.toInt()); //this activates the addition subroutine | returns value1 + value2
break;
case 2: //subtracts both values and return the difference | Syntax: subtract:value1:value2
CommSub(val1.toInt(), val2.toInt()); //this activates the subtraction subroutine | returns value1 - value2
break;
case 3:
yMovement(val1.toInt(), val2.toInt());
break;
case 4:
xMovement(val1.toInt(), val2.toInt());
default: //this is the default case for the command lookup and will only
Serial.println("Command not recognized"); //trigger if the command sent was not known by the arduino
break;
}
}
void CommHello() //each of these routines are what will be triggered when they are successfully processed
{
Serial.println("Hello!");
CommConfirm();
}
void CommAdd(int val1, int val2)
{
Serial.println(val1 + val2);
CommConfirm();
}
void CommSub(int val1, int val2)
{
Serial.println(val1 - val2);
CommConfirm();
}
void yMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println("YMOVNEG");
int yMoveNew = (val1 * (-20.72));
//Serial.println(val1 * (-1));
//delay(500);
FRStepper.move(-yMoveNew);
BRStepper.move(-yMoveNew);
FLStepper.move(-yMoveNew);
BLStepper.move(-yMoveNew);
}
else {
//Serial.println(val1);
int yMoveNew = (val1 * (20.72));
//Serial.println(yMoveNew);
//Serial.println(val1);
//delay(500);
FRStepper.move(yMoveNew);
BRStepper.move(yMoveNew);
FLStepper.move(yMoveNew);
BLStepper.move(yMoveNew);
}
}
void xMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println(val1);
int xMoveNew = (val1 * (-20.72));
//Serial.println(xMoveNew);
//Serial.println(val1 * (-1));
//delay(1000);
FLStepper.move(-xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(-xMoveNew);
//delayMicroseconds(500);
}
else {
int xMoveNew = (val1 * (20.72));
//Serial.println(val1);
//delay(1000);
FLStepper.move(xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(xMoveNew);
//delayMicroseconds(500);
}
}
void CommConfirm()
{
Serial.println("Done");
delay(750);
}
When I run my code, a Pi sends two values that equals step counts, however with the new drivers nothing happens. I tried also looking at and following the AccelStepper example on the git but I guess I have something wrong.
Any help would be appreciated.
I use Arduino shiftIn instruction to receive data from a MLX90316.
It uses one wire for MOSI an MISO.
Data consists of 4 bytes (2+2)
First 2 bytes are an angle value. Second 2 bytes ares the reversed value of angle (1st complement)
First 2 bytes are correct on scope and program (0x00 and 0x22)
Second 2 bytes are correct on scope (0xFF and 0XDD), but are frequently (not always) wrong in program (0xFF and 0xDC or 0xFF and 0xCC...)
In fact only last byte is sometimes wrong when I print it.
I have tried to change Serial speed to 9600 bps (same result)
I have tried to change delayMicroseconds value before last shiftIn (same result)
/* MLX90316 Rotary Position Sensor */
int readAngle();
int pinSS = 10; // Green Wire
int pinDATA = 11; // Yellow Wire
int pinSCK = 13; // Grey Wire
unsigned int r1=0;
unsigned int r2=0;
unsigned int r3=0;
unsigned int r4=0;
int angle;
void setup(){
delayMicroseconds(16000); // 16ms slave start-up
pinMode(pinSS,OUTPUT); // Pin Slave Select
pinMode(pinSCK, OUTPUT); // Pin Clock
digitalWrite(pinSS, HIGH); // de-select chip
Serial.begin(115200);
Serial.println("MLX90316 Rotary Position Sensor");
}
void loop() {
angle = readAngle();
Serial.println("");
Serial.print("r1=");Serial.println(r1,HEX);
Serial.print("r2=");Serial.println(r2,HEX);
Serial.print("r3=");Serial.println(r3,HEX);
Serial.print("r4=");Serial.println(r4,HEX);
delay(10000);
}
int readAngle() {
// Start with clock LOW
digitalWrite(pinSCK, LOW);
// Data pin in write mode
pinMode(pinDATA, OUTPUT);
// take the SS pin low to select the chip:
digitalWrite(pinSS, LOW);
delayMicroseconds(30);
// Send START bytes
shiftOut(pinDATA, pinSCK, MSBFIRST, 0xAA);
delayMicroseconds(25);
shiftOut(pinDATA, pinSCK, MSBFIRST, 0xFF);
delayMicroseconds(30); // 30 us between START bytes and DATA
// Data pin in read mode
pinMode(pinDATA, INPUT_PULLUP);
// Receive data
r1 = shiftIn(pinDATA, pinSCK, MSBFIRST);
delayMicroseconds(25);
r2 = shiftIn(pinDATA, pinSCK, MSBFIRST);
delayMicroseconds(25);
r3 = shiftIn(pinDATA, pinSCK, MSBFIRST);
delayMicroseconds(30);
r4 = shiftIn(pinDATA, pinSCK, MSBFIRST);
// take the SS pin high to de-select the chip:
delayMicroseconds(5);
digitalWrite(pinSS, HIGH);
}
I expect the output of 0x00 0x22 0xFF 0xDD
I don't know which Arduino you are using but the shift in and out functions are very simple software implementations.
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
}
return value;
}
The MLX90316 allows only a clock speed of 145kHz, so this direct port access could be too fast and the data is not ready when you read it.
But since you have a scope available you could simply check that timing and write your own shiftIn if necessary.
I think this "version" should work for your chip (untested)
uint8_t shiftIn2(uint8_t dataPin, uint8_t clockPin) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
delayMicroseconds(4);
digitalWrite(clockPin, LOW);
value |= digitalRead(dataPin) << (7 - i);
delayMicroseconds(4);
}
return value;
}
My goal is to transfer a speed value from an encoder from a slave Arduino to a master Arduino via SPI. I am currently getting zeros on the master side serial print and I'm not sure what I am doing wrong. I have increased the amount of time to wait several times to see if it was a processing time issue but I had it waiting for 100mS with still no change. I know an unsigned int is 4 bytes and I am unsure if a union is the best option in this case seeing I might be overwriting my data due to the separate interrupts but I am unsure. I thought to use a struct since I'll have to move to transferring an array of floats and ints over SPI from various sensors including this encoder later. Below is my code and thank you for any help received:
Slave
#include "math.h"
#define M_PI
byte command = 0;
const int encoder_a = 2; // Green - pin 2 - Digital
const int encoder_b = 3; // White - pin 3 - Digital
long encoder = 0;
int Diameter = 6; // inches
float previous_distance = 0;
unsigned long previous_time = 0;
void setup (void)
{
Serial.begin(115200);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
pinMode(encoder_a, INPUT_PULLUP);
pinMode(encoder_b, INPUT_PULLUP);
attachInterrupt(0, encoderPinChangeA, CHANGE);
attachInterrupt(1, encoderPinChangeB, CHANGE);
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
union Data{
float f;
byte buff[4];}
data;
byte c = SPDR;
data.f = assembly_speed();
command = c;
switch (command)
{
// no command? then this is the command
case 0:
SPDR = 0;
break;
// incoming byte, return byte result
case 'a':
SPDR = data.buff[0];
break;
// incoming byte, return byte result
case 'b':
SPDR = data.buff[1];
break;
// incoming byte, return byte result
case 'c':
SPDR = data.buff[2];
break;
// incoming byte, return byte result
case 'd':
SPDR = data.buff[3];
break;
}
}
void loop (void)
{
// if SPI not active, clear current command
if (digitalRead (SS) == HIGH)
command = 0;
}
void encoderPinChangeA()
{
encoder += digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1;
}
void encoderPinChangeB()
{
encoder += digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1;
}
float distance_rolled()
{
float distance_traveled = (float (rotation()) / 8) * PI * Diameter;
return distance_traveled;
}
int rotation()
{
float eigth_rotation = encoder / 300;
return eigth_rotation;
}
float assembly_speed()
{
float current_distance = (float (rotation()) / 8) * PI * Diameter;
unsigned long current_time = millis();
unsigned long assemblySpeed = (((current_distance - previous_distance) /
12) * 1000) / (current_time - previous_time); // gives ft/s
previous_distance = current_distance;
previous_time = current_time;
return assemblySpeed;
}
Master
#include <SPI.h>
void setup (void)
{
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(SS, OUTPUT);
Serial.begin (115200);
Serial.println ();
digitalWrite(SS, HIGH);
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds(10000);
return a;
}
union Data
{
float f;
byte buff[4];
}
data;
void loop (void)
{
digitalWrite(SS, LOW);
transferAndWait ('a');
data.buff[0] = transferAndWait ('b');
data.buff[1] = transferAndWait ('c');
data.buff[2] = transferAndWait ('d');
data.buff[3] = transferAndWait (0);
digitalWrite(SS, HIGH);
Serial.print("data.f = ");Serial.print(data.f);Serial.println(" Ft/s");
delay(200);
}
I'm having some problems with some C code I'm writing for an arduino project. The goal is to digitize a large quantity of analog signals with external multiplexed ADCs, then load these digital values into an external shift register and shift them into the Arduino using SPI.To test my code I only have one ADC multiplexing 4 signals.
The interrupt pin (20) is connected to a comparator circuit which looks at the raw analog signal and pulls the pin high when the voltage is 1V or higher. When the ISR is called it will disable global interrupts "noInterrupts()" set an event flag, detach pin 20 from the interrupt handler, enable global interrupts "interrupts()" and finally return to where it left off.
I'm facing a couple issues, first the ISR is called once fine, a second time fine but after the second ISR call it is not called again untill, which is my seconds issue, the interrupt pin goes low. As per the AttachInterupt() function the ISR should only be called when pin 20 is high. This can be seen in the first and second picture I have attached. Another thing I notice is that the duration that the interrupt pin is high has no effect on whether a 3rd ISR is called.
I'm not sure if this is an issue with my understanding of the interrupt-handling of the Arduino, or a code screw up resulting in a stack overflow or something like that.
// the sensor communicates using SPI, so include the library:
#include <SPI.h>
//Constants
#define RD 41 //pin 41 conneced to read pin
#define INT1 37 //pin 37 connecte to interrupt 1
#define CLK_INH 53 //pin 53 connected to clk inhibit
#define LD 40 //pin 40 connected to load pin
#define INPUT_MAX 3 //input selector limit (Zero Indexed)
#define SENSORS 3 //how many sensors are used (Zero Indexed)
#define DATA_DUMP 38 //pin 29 controlls the data dump deature
#define BYTE_LEN 1 //number of ADC used
#define DEBUG1 17
#define DEBUG2 16
//Controls
unsigned char selector = 0; //ACD input selector
volatile byte eventFlag = LOW; //Control Flag, set to True when event occurs
bool lastButtonState = true;
//Counters
unsigned int i = 0; //eventLog[i]: event counter
unsigned int j = 0; //eventLog[i].data[j]: data counter
//Function Delcarations
unsigned char inputSelector (unsigned char my_selector);
void lockAndPop ();
void dataDump ();
void debug (int pin);
bool fallingEdge (bool); //check for a falling edge of a digital read
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
// put your setup code here, to run once:
pinMode(RD, OUTPUT); //Read pin, 0 = begin analog conversion (ADC)
pinMode(INT1, INPUT); //Interrupt pin, 0 = conversion complete (ADC)
pinMode(CLK_INH, OUTPUT); //Clock inhibit pin, 1= no change on output (ShiftRegister)
pinMode(LD, OUTPUT); //Shift/Load pin, 1 = data is shifted (ShiftRegister)
pinMode(DATA_DUMP, INPUT);
pinMode(DEBUG1, OUTPUT);
pinMode(DEBUG2, OUTPUT);
DDRA = 0xFF; //Set port A to ouput
SPI.begin();
//SPI.mode1 Clock idel low CLOP = 0, Data sampled on falling edge CPHA = 1
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE1));
digitalWrite(RD, HIGH); //Stop conversion
digitalWrite(CLK_INH, HIGH); //No change on the output
digitalWrite(LD, LOW); //Load the shift register
digitalWrite(DEBUG1, LOW);
digitalWrite(DEBUG2, LOW);
attachInterrupt(digitalPinToInterrupt(20), pin_ISR, HIGH); //Call pin_ISR when pin20 goes high
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct //event structure, containts a timestamp element and an array of 18 data points
{
unsigned long int timeStamp;
unsigned char data[SENSORS];
} Event;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Event eventLog[200]; //an array of structures representing 200 events, once the 200 events have been filled the data will be printed
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
if(fallingEdge(digitalRead(DATA_DUMP))){ //If there is falling edge on the data dump button, call the dataDump function
dataDump();
}
debug(DEBUG2);
if(eventFlag) //if the Event flag is set to true by ISR begin the conversion steps
{
debug(DEBUG1);
digitalWrite(RD,LOW); //Start conversion
while(digitalRead(INT1)){} //Wait for conversion to complete
eventLog[i].timeStamp = micros();
for (j=0; j<=SENSORS; j++) {
lockAndPop(); //lock digital value and reset conversion
PORTA = inputSelector(selector); //increment the selector pin
digitalWrite(RD, LOW); //Start new conversion
digitalWrite(CLK_INH, LOW); //Start the data transfer
eventLog[i].data[j] = SPI.transfer(0); //read a single byte from the SPI line
digitalWrite(CLK_INH, HIGH); //Inhibit clock
digitalWrite(LD, LOW);
while(digitalRead(INT1)){} //wait for previous conversion to end
}
i++;
digitalWrite(RD, HIGH);
selector = 0;
if(i>=200){
dataDump(); //if the event log hits 200 before a data dump is request, dump the data
}
eventFlag = LOW;
attachInterrupt(digitalPinToInterrupt(20), pin_ISR, HIGH);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void pin_ISR() {
noInterrupts();
detachInterrupt(digitalPinToInterrupt(20));
eventFlag = HIGH;
interrupts();
return;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char inputSelector (unsigned char my_selector){
if(my_selector==INPUT_MAX){ //if the current selector is at the highest value reset to 0
return 0;
}
return my_selector++; //increment the input selector by 1
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lockAndPop (){
digitalWrite(LD, HIGH); //Lock in digital value
digitalWrite(RD, HIGH); //Reset conversion
return;
}
void dataDump (){
detachInterrupt(digitalPinToInterrupt(20));
char buf[100], *pos = buf; //create a buffer of 100 charaters, anda pointer to the begining of that buffer
char *base = buf; //create a base address to reset the buffer
unsigned int eventCount = i; //how many events occured before dump command was called
unsigned int localCount;
unsigned int localData;
Serial.begin(115200);
Serial.println(i);
for (localCount = 0; localCount<=eventCount; localCount++){
pos += sprintf(pos, "%lu", eventLog[localCount].timeStamp); //sprintf will append the data to the pointer "pos", and return the number of byte append.
for (localData = 0; localData<=SENSORS; localData++){
pos += sprintf(pos, " %d", (unsigned int)(eventLog[localCount].data[localData]));
}
Serial.println(buf);
pos = base;
}
i=0;
j=0;
Serial.end();
attachInterrupt(digitalPinToInterrupt(20), pin_ISR, HIGH);
return;
}
void debug(int pin){
digitalWrite(pin, HIGH);
digitalWrite(pin, LOW);
return;
}
bool fallingEdge (bool currentButtonState){
if(!currentButtonState&&lastButtonState){
lastButtonState = currentButtonState;
return 1;
}
lastButtonState = currentButtonState;
return 0;
}
There is a bit of noise happening on the ISR pin, but this shouldn't matter as I'm disabled that particular pin within the service routine so I wouldn't think this is an issue
I am using an Mcp41010 digipot chip and am wondering how to vary the wiper position of the chip with an analog input voltage that I can adjust, I need a way of decrementing(--) the wiper position if the voltage goes over a certain point and incrementing(++) the wiper position of the chip back to the normal position this is some code that i found that just fades the wiper position up and down I need a way of controlling it. I am still very new to arduino so sorry if my explanation was clear enough.
int CS_signal = 12; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 52; // Clock signal on pin 4 of Arduino
int MOSI_signal = 51; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int initial_value = 100; // Setting up the initial value
void initialize() { // send the command byte of value 100 (initial value)
spi_out(CS_signal, cmd_byte2, initial_value);
}
void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip
digitalWrite (CS, LOW); // to start the transmission, the chip select must be low
spi_transfer(cmd_byte); // invio il COMMAND BYTE
delay(2);
spi_transfer(data_byte); // invio il DATA BYTE
delay(2);
digitalWrite(CS, HIGH); // to stop the transmission, the chip select must be high
}
void spi_transfer(byte working) {
for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
} else {
digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low
digitalWrite (CLK_signal,HIGH) ; // Pulse the CLK_signal high
working = working << 1 ; // Bit-shift the working byte
digitalWrite(CLK_signal,LOW) ; // Pulse the CLK_signal low
}
}
void setup() {
pinMode (CS_signal, OUTPUT);
pinMode (CLK_signal, OUTPUT);
pinMode (MOSI_signal, OUTPUT);
initialize();
Serial.begin(9600); // setting the serial speed
Serial.println("ready!");
}
void loop() {
for (int i = 0; i < 255; i++) {
spi_out(CS_signal, cmd_byte2, i);
Serial.println(i); delay(10);
}
for (int i = 255; i > 0; --i) {
spi_out(CS_signal, cmd_byte2, i);
Serial.println(i);
delay(10);
}
}
int CS_signal = 12; // Chip Select signal onsul pin 2 of Arduino
int CLK_signal = 52; // Clock signal on pin 4 of Arduino
int MOSI_signal = 51; // MOSI signal on pin 5 of Arduino
byte cmd_byte2 = B00010001 ; // Command byte
int initial_value = 100; // Setting up the initial value
void initialize() { // send the command byte of value 100 (initial value)
spi_out(CS_signal, cmd_byte2, initial_value);
}
void spi_out(int CS, byte cmd_byte, byte data_byte){ // we need this function to send command byte and data byte to the chip
digitalWrite (CS, LOW); // to start the transmission, the chip select must be low
spi_transfer(cmd_byte); // invio il COMMAND BYTE
delay(2);
spi_transfer(data_byte); // invio il DATA BYTE
delay(2);
digitalWrite(CS, HIGH); // to stop the transmission, the chip select must be high
}
void spi_transfer(byte working) {
for(int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (MOSI_signal,HIGH) ; // If the MSB is a 1 then set MOSI high
} else {
digitalWrite (MOSI_signal, LOW) ; } // If the MSB is a 0 then set MOSI low
digitalWrite (CLK_signal,HIGH) ; // Pulse the CLK_signal high
working = working << 1 ; // Bit-shift the working byte
digitalWrite(CLK_signal,LOW) ; // Pulse the CLK_signal low
}
}
void setup() {
pinMode (CS_signal, OUTPUT);
pinMode (CLK_signal, OUTPUT);
pinMode (MOSI_signal, OUTPUT);
initialize();
Serial.begin(9600); // setting the serial speed
Serial.println("ready!");
}
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
if(sensorValue <= 200){
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
int i = sensorValue;{
spi_out(CS_signal, cmd_byte2, i);
Serial.println(i);
}
}
}