I have a project that is potentially going to use the built in SPI interface. I have a Mini Pro setup to read a rotary encoder off the standard hardware interrupts and I am also trying to read from a digital caliper:
Or here:
I want to try to use the SPI interface to read the serial data streaming from the calipers. It comes in with a 48 bit format plus a extra stop bit at the end. I think I can handle the first 48 bits (6 bytes) no problem using the standard SPI (slave mode3 - I invert the signals with my level shifters). My question is how do I shut down the slave to ignore the extra stop clock? I am rather new to the AVR nomenclature and some of the example code I have seen is a bit confusing to me. I understand the electrical interface and level shift no problem as I deal with that daily. Just I'm not very experienced with SPI or the AVR style code.
BTW - The typical timing for the stop bit is in the 55 to 60uS range. Can I just issue something directly to the SPI control register to shut it down without relying on a hardware SS pin to shut it down?
Here is the example code I have been studying>
// Written by Nick Gammon
// February 2011
#include <SPI.h>
char buf [100];
volatile byte pos;
volatile boolean process_it;
void setup (void)
{
Serial.begin (115200); // debugging
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// get ready for an interrupt
pos = 0; // buffer empty
process_it = false;
// now turn on interrupts
SPI.attachInterrupt();
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR; // grab byte from SPI Data Register
// add to buffer if room
if (pos < sizeof buf)
{
buf [pos++] = c;
// example: newline means time to process buffer
if (c == '\n')
process_it = true;
} // end of room available
} // end of interrupt routine SPI_STC_vect
// main loop - wait for flag set in interrupt routine
void loop (void)
{
if (process_it)
{
buf [pos] = 0;
Serial.println (buf);
pos = 0;
process_it = false;
} // end of flag set
} // end of loop
In particular the code
// turn on SPI in slave mode
SPCR |= _BV(SPE);
The above leaves me a bit slack jawed and cross eyed! I take it the _BV() is a way to define binary values? Then where is the secret decoder for the SPE or other options that goes in there? Is there an accompanying setting to shutdown the interface or to essentially put it in non slave select mode for just a short period of time , perhaps 70us? The idea is I want to ignore the last stop bit in the transaction as a start of a new byte. See in my application even though it's a slave I will not respond back to a master since the master is just a dumb digital caliper spewing data every 300mS. I'm really just trying to take advantage of the existing interrupt capability that the SPI offers over doing this with polling or moving up to another board with more hardware interrupt pins.
The comment is wrong, it just turns the SPI hardware on. If it's in slave or master mode is determined by the bit MSTR of the same register. To to set it to slave mode you must clear that bit:
SPCR &= ~_BV(MSTR);
You turn the SPI off with the following line:
SPCR &= ~_BV(SPE);
You can use the SS pin (connected to another GPIO) to reset the SPI shift register. That way you can ignore the stop bit without disabling the hardware. See section 18.3.1 of the datasheet.
Caliper Data to Serial Monitor
I have successfully created a Usable Arduino Caliper Data Interface
The LM339 voltage comparator is used to Convert signals to TTL for the Input Data.
A Boss Music Pedal Foot Switch is used to send the data to the monitor (Instead of Continously)
This Works Perfectly with the Arduino Uno Rev 3.
My Hope is that someone will help me to use the Leonardo Board to send keyboard data to Excel.
Please post Arduino Leonardo caliper data to Excel... And I will post some wonderful SPC analysis!!!
Please visit my Youtube Channel supertechqc to see my prototype.
/*
________________________________________________________________
************Program Name:Digital Caliper Data SPC
************By J. Poston:
**********Date Initiated:4-22-213
************Date Revised:5-15-2013
******Purpose of Program:Measure data output of calipers
*****Description of Code: Main Loop code for reading the calipers.
Subroutines to test out different operations of the code and
hardware
*Description of Hardware: See Bottom of Sketch
****Notes: Works fine with the UNO---->Goal Use the Leonardo for sending
data in keyboard functions (can't find code yet!)
>>>>>>>>>>>>>>>>>Visit Youtube: QCSuperTech<<<<<<<<<<<<<<<<<<<<<
*/
/*
________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^^Declaration of Variables^^^^^^^^^^^^^^^^
*/
int dataIn = 4;
int clockIn = 2;
const int buttonPin = 5; // the number of the pushbutton pin
int buttonState =0; // variable for reading the pushbutton status
const int ledPins[] = {
6, 7, 8, 9, 10, 11, 12,13 }; // an array of pin numbers to which LEDs are attached
const int pinCount = 8; // the number of pins (i.e. the length of the array)
const int i=10; //Determines the DELAY Low and High for each led state
int isin=0; //inch=1?mm=0
int isfs=0; //
int index;
unsigned long xData,oData;//
long previousMillis = 0; // will store last time LED was updated
long interval = 500; // interval at which to blink (milliseconds)
long previousGetMillis = 0; //
long Timeout = 8; // 8ms
//int m=0; //Generic interger used for experimenting
const int ledon=3; // verification for experimenting change
int m;
//______________________________________________________________
/*
________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^Set Up (run once)^^^^^^^^^^^^^^^^^^^^^^^^
*/
void setup()
{
// initialize the digital pin as an output.
//*************************************************************************************************
int thisPin;
// the array elements are numbered from 0 to (pinCount - 1).
// use a for loop to initialize each pin as an output:
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
pinMode(ledPins[thisPin], OUTPUT);
}
//************************************************************************************************
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
//***********************************************************************************************
digitalWrite(dataIn, 1);
digitalWrite( clockIn, 1);
pinMode(dataIn, INPUT); //DATA line goes to Arduino digital pin 4
pinMode(clockIn, INPUT);
Serial.begin(9600);
delay(500);
attachInterrupt(0,getBit,RISING); //CLOCK line goes to Arduino digital pin 2
index =0;
xData=0;
oData=999;
// scanner();//Runs the SubRoutine
Print_Header();//Runs the Subroutine
//Footer();//Runs the SubRoutine
pinMode(ledon,OUTPUT); //makes digital pin 3 and output
Test_Light(); //Runs the subroutine that makes pin 3 blink and LED
}
//______________________________________________________________
/*
________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^^^Loop (Repeats)^^^^^^^^^^^^^^^^^^^^^^^^^
*/
void loop()
{
//ledon == LOW;
//*************************************************************************************************
// read the state of the pushbutton value: 4-13-2013
buttonState = digitalRead(buttonPin);
delay(5);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
//do
//{ Test_Light();}
//while (buttonState == LOW);
if (buttonState == HIGH) {
// ledon==LOW;
//***********************************************************************************************
if ((index !=0) && (millis() - previousGetMillis > Timeout) ) {
index=0;
xData=0;
};
if (index >23) {
if (oData !=xData) {
if (isfs==1)
Serial.print('-');
//**********************************************************************************************
// IF INCHES FORMAT AND PRINT SEQUENCE
if (isin==1){ //
xData *=5;
Serial.print(xData/10000);
Serial.print('.');
if ((xData % 10000)<1000){
if ((xData % 10000)<100){
if ((xData % 10000)<10){
Serial.print('0');
};
Serial.print('0');
};
Serial.print('0');
};
Serial.println(xData % 10000);
delay(100); //keeps inches from spitting out lots of the same measures
}
//**************************************************************************************
// IF MILLIMETERS FORMAT AND PRINT SEQUENCE
else { // mm
Serial.print(xData/100);
Serial.print('.');
if ((xData % 100)<10) //0
Serial.print('0');
Serial.println(xData % 100);
};
};
oData =xData;
index=0;
delay(5);
xData=0;
//*************************************************************************************************
scanner();
};
if (millis() - previousMillis > interval) {
previousMillis = millis();
}
}
}
void getBit(){
previousGetMillis=millis();
if(index < 20){
if(digitalRead(dataIn)==1){
xData|= 1<<index;
};
}
else {
if (index==20)
isfs=digitalRead(dataIn);
if (index==23) //24 1=inch
isin=digitalRead(dataIn);
};
index++;
}
//______________________________________________________________
/*
________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^^Sub Routines^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
void Print_Header()
{
Serial.println("****************************************************************");
Serial.println(" Program: Digital Caliper Data SPC (Running) ");
Serial.println("****************************************************************");
}
//______________________SubRoutine: Footer____________________
void Footer()
{
Serial.println(" ");
Serial.println(" ");
Serial.println(" SetUp End ");
Serial.println("****************************************************************");
Serial.println(" ");
Serial.println(" ");
Serial.println(" ");
delay(4000);
}
//**********************************Subroutine Scanner***************************************************
void scanner()
{
tone(3,2000,300);
// loop from the lowest pin to the highest:
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
// turn the pin on:
digitalWrite(ledPins[thisPin], HIGH);
delay(i);
// turn the pin off:
digitalWrite(ledPins[thisPin], LOW);
}
// loop from the highest pin to the lowest:
for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) {
// turn the pin on:
digitalWrite(ledPins[thisPin], HIGH);
delay(i);
// turn the pin off:
digitalWrite(ledPins[thisPin], LOW);
noTone(3);
}
}
void Test_Light()
{
delay(100);
for(m=0;m<20;m++)
{
digitalWrite(ledon,HIGH);
delay(30);
digitalWrite(ledon,LOW);
delay(30);}
}