SPI Arduino Interface with Absolute Encoder - arduino

I am trying to retrieve data from an RLS absolute rotary encoder via SPI through Arduino Uno. I have managed to learn the basics of SPI, but I can't seem to get this working. I keep printing the transfer data and keep getting 255.
I also use the recommended pins for Arduino Uno here: https://www.arduino.cc/en/reference/SPI
Here is the link to the Absolute Encoder DataSheet: https://resources.renishaw.com/en/details/data-sheet-orbis-true-absolute-rotary-encoder--97180
Any help is appreciated.
Here is my code I have been trying:
#include <SPI.h>
unsigned int data;
int CS = 10; //Slave Select Pin
// The SS pin starts communication when pulled low and stops when high
void setup() {
Serial.begin(9600);
RTC_init();
}
int RTC_init() {
pinMode(CS, OUTPUT);
SPI.begin();
SPI.setBitOrder(LSBFIRST); // Sets Bit order according to data sheet (LSBFIRST)
SPI.setDataMode(SPI_MODE2); // 2 or 3, Not sure (I have tried both)
digitalWrite(CS, LOW); // Start communications
/*
Commands List:
Command "1" (0x31) – position request (total: 3 bytes) + 4 for multi-turn
Command "3" (0x33) – short position request (total: 2 bytes) + 4 for multi-turn
Command "d" (0x64) – position request + detailed status (total: 4 bytes) + 4 for multi-turn
Command "t" (0x74) – position request + temperature (total: 5 bytes) + 4 for multi-turn
Command "v" (0x76) – serial number (total: 7 bytes)
*/
unsigned int data = SPI.transfer(0x33); // Data
digitalWrite(CS, HIGH); // End communications
return(data);
}
void loop() {
Serial.println(RTC_init());
}

First, you forgot to set your CS pin to output. That won't help.
void setup()
{
Serial.begin(9600);
digitalWrite(CS, HIGH); // set CS pin HIGH
pinMode(CS, OUTPUT); // then enable output.
}
SPI is a two way master/slave synchronous link, with the clock being driven by bytes being sent out by the master. This means that when transacting on SPI, you are expected to send out as many bytes as you want to receive.
As shown on the timing diagram on page 14 of the datasheet, you are expected to send one byte with the command, then as many null bytes as the response requires minus 1.
The diagram shows the clock being low at idle, and input bits being stable when the clock goes low, that's SPI mode 1.
To read the position, for a non-multiturn encoder.
unsigned int readEncoderPos()
{
// this initialization could be moved to setup(), if you do not use
// the SPI to communicate with another peripheral.
// Setting speed to 1MHz, but the encoder can probably do better
// than that. When having communication issues, start slow, then set
// final speed when everything works.
SPI.beginTransaction(SPISettings(1'000'000, MSBFIRST, SPI_MODE1));
digitalWrite(CS, LOW);
// wait at least 2.5us, as per datasheet.
delayMicroseconds(3);
unsigned int reading = SPI.transfer16(0x3300); // 0x3300, since we're sending MSB first.
digitalWrite(CS, HIGH);
// not needed if you moved SPI.beginTransaction() to setup.
SPI.endTransaction();
// shift out the 2 status bits
return reading >> 2;
}

Related

Arduino built in example: "Dimmer" not responsive to serial data

Following this tutorial:
Arduino LED Dimmer Example
I added the Serial.println(brightness); at the bottom to see what gets written to the brightness variable and only get back 48 no matter the value sent by serial to the arduino.
As you can see the value of brightness goes from 50 to 48 where it settles. The sent data is in pink and the black data is the response from the arduino.
What else could I try.
Thanks
Using the Hercules utility to establish a serial link to the arduino.
Hercules Utility Showing communication with Arduino
The oscilloscope sees this:
PWM signal from oscilloscope
const int ledPin = 9; // the pin that the LED is attached to
void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the ledPin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
byte brightness;
// check if data has been sent from the computer:
if (Serial.available()) {
// read the most recent byte (which will be from 0 to 255):
brightness = Serial.read();
// set the brightness of the LED:
analogWrite(ledPin, brightness);
Serial.println(brightness);
}
}
your problem is obvious in the image you provided , for example in the image it shows
when send 100 , the arduino responded with 49 , 48 , 48 which is the ascii representation of the 100 , refer to ascii table where
'1' is equivalent to 49
'0' is equivalent to 48
which means that you send to the arduino the number 100 not as a number but as a string where your terminal sends 1 first in its ascii representation which is 49 then it sends 0 in its ascii representation which is 48 then it sends another 0 in its ascii representation which is 48.
to solve this problem:
in your pc side , try to change that in your terminal settings
or
in your arduino code , instead of brightness = Serial.read(); write brightness = Serial.parseInt(); , refer to Serial.parseInt() docs where it says that :
Looks for the next valid integer in the incoming serial. The function terminates if it times out
meaning that it will convert "100" (string) into 100 (number) in your arduino side .
also change byte brightness; into int brightness; as Serial.parseInt() returns the next valid int
Thank you abdo salm, your suggestion educated me and resolved my problem at the same time. Answer updated for anyone who stumbles across the same rookie issue (see snippet below).
So in conclusion, the example code expected a number in the range of
00000000 to 11111111 (0 to 255 as a single binary byte)
I was instead sending multiple bytes that represented One, Zero and Zero on the ASCII table
11000100 (49)
11000000 (48)
11000000 (48)
erroneously thinking I was sending 100 which is 110010000 in binary.
I altered the code with brightness = Serial.parseInt(); as abdo salm suggested.
Here is the Hercules (or similar) friendly version of the Arduino Dimmer Example.
const int ledPin = 9; // the pin that the LED is attached to
int brightness;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the ledPin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// check if data has been sent from the computer:
if (Serial.available()) {
// read the most recent byte (which will be from 0 to 255):
brightness = Serial.parseInt();
// set the brightness of the LED:
analogWrite(ledPin, brightness);
Serial.println(brightness);
}
}

radio control with arduino

Hi I am attempting to read from an rc transmitter using an Arduino Uno board, I have a signal pin connected from the receiver to pin 9 on the Arduino. Here is the code I would really appreciate some help all I am trying to achieve is the read the pmw from the receiver. I am able to plug a servo into the receiver and that works fine along with a motor I am just struggling when I try and use the Arduino with the receiver. When I run my program all I get in the Serial monitor are values such as 9991,9972,10030,10050 that are completely unrelated.
I want to have a pmw value that I can map to 0-255 in order to control a motor
My Circuit:
battery -> ESC(for BEC to regulate five volts back to receiver)-> receiver -> ch3 signal pin -> Arduino uno (pin9)
void setup() {
Serial.begin(9600);
}
void loop() {
int pwm = pulseIn(9, HIGH, 25000);
Serial.println(pwm);
delay (5);
}
You are using pulseIn which returns a time (in ms). The time being how long it waited for a HIGH signal. If you want the actual value, use analogRead. You can still use pulseIn, just don't use the return value
void setup() {
Serial.begin(9600);
}
void loop() {
byte pwm = analogRead(A5) / 4;
Serial.println(pwm);
delay(5);
}

Arduino RFID (Wiegand) Continuous reading

I have this RFID reader "Rosslare AY-X12", and it's working with Wiegand 26bit. I have an arduino mini Pro and connected together it's working fine but it only reads the card one time and then I have nothing.
When I put on the card arduino reads that card but only one time during the card is near by the reader and it again reads that card when I put off the card and then I put on. But I want to read that card continuously, I mean when the card is near by the Reader still reading the card, every 1ms reads that card.
Do you have any idea how to do that ? Is there any RFID arduino library which can do that? I had got the Mifare and its can do that. But this 125Khz reader which can communicate over Wiegand can't do that or I don't know how to do that.
I'm using this library : https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
My previous answer was deleted. I am going to make another attempt to answer the questions.
Do you have any idea how to do that ?
This cannot be done by Arduino because Arduino in your case is just reading the D0 and D1 pulses from your RFID reader. Since your RFID reader Rosslare AY-X12 does not send out continuous output of wiegand protocol, there is no way Arduino can read more than what was not sent to it.
The common RFID readers will not send continuous data of the same card because in the common use case (entry/exit/attendance), normally one tap is to check-in and another tap is to check-out. If the RFID reader sends continuous data of the same card, the main system receiving the multiple wiegand data will be confused and will not be able to determine if the user actually wish to check-in or check-out.
Is there any RFID arduino library which can do that?
No. There is no such RFID Arduino library. If the RFID reader is not sending out continuous data, there is no way the receiver (Arduino) can receive them.
Is there a way to achieve this?
Yes, there are some readers that has the option to turn on the continuous output of data, for example 714-52 Mifare® ID Reader with selectable outputs. In its specification :
Continuous output with tag in field or single transmission
With this reader configured to continuous output, you can then use Arduino and the monkeyboard wiegand library to read the data.
I wrote my own wiegand code. Its not that difficult. I attached interrupts to the data pins and when they change I log the zero or one. You then build up the binary string and once timed out because no bits coming in. Then you convert the binary to decimal.
#include <LiquidCrystal.h>
int data0 = 2; //set wiegand data 0 pin
int data1 = 3; //set wiegand data 1 pin
unsigned long bit_holder; //unsigned long (positive 32 bit number)
unsigned long oldbit = 0;
volatile int bit_count = 0;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
unsigned long badge;
unsigned int timeout;
unsigned int t = 800;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.print("Present Badge");
delay(2);
Serial.println("Present Badge");
pinMode(data0, INPUT);
digitalWrite(data0, HIGH);
pinMode(data1, INPUT);
digitalWrite(data1, HIGH);
attachInterrupt(0, zero, FALLING); //attach interrupts and assign functions
attachInterrupt(1, one, FALLING);
}
void zero(){
bit_count ++;
bit_holder = (bit_holder << 1) + 0; //shift left one and add a 0
timeout = t;
}
void one(){
bit_count ++;
bit_holder = (bit_holder << 1) + 1; //shift left one and add a 1
timeout = t;
}
void loop() {
timeout --;
if (timeout == 0 && bit_count > 0){
lcd.clear();
lcd.print("Dec:");
lcd.print(bit_holder);
lcd.setCursor(0,1);
lcd.print("Hex:");
lcd.print(String(bit_holder,HEX));
Serial.print("bit count= ");
Serial.println(bit_count);
Serial.print("bits= ");
Serial.println(bit_holder,BIN);
oldbit = bit_holder; //store previous this value as previous
bit_count = 0; //reset bit count
bit_holder = 0; //reset badge number
}
}
You may need to find a reader that offer a continuously reading, as I know almost of Wiegand Reader in the market can't perform a continuously reading because they have a "onboard" control that controls this...
Maybe you can try with Arduino Serial RFID Reader...
try a this timer libary Timer1 and mayby try this code it worked for me, my tags and cards now reads continuously.
Greetings from Denmark
Gregor
#include <Timer1.h>
//******************************************************************
// ATmega168, ATmega328:
// - Using Timer 1 disables PWM (analogWrite) on pins 9 and 10
// ATmega2560:
// - Using Timer 1 disables PWM (analogWrite) on pins 11 and 12
// - Using Timer 3 disables PWM (analogWrite) on pins 2, 3 and 5
// - Using Timer 4 disables PWM (analogWrite) on pins 6, 7 and 8
// - Using Timer 5 disables PWM (analogWrite) on pins 44, 45 and 46
//******************************************************************
unsigned int lastTime;
#include <SoftwareSerial.h>
SoftwareSerial RFID = SoftwareSerial(2,4);
char character;
String our_id;
void setup()
{
// Disable Arduino's default millisecond counter (from now on, millis(), micros(),
// delay() and delayMicroseconds() will not work)
disableMillis();
// Prepare Timer1 to count
// On 16 MHz Arduino boards, this function has a resolution of 4us
// On 8 MHz Arduino boards, this function has a resolution of 8us
startCountingTimer1();
lastTime = readTimer1();
Serial.begin(9600);
RFID.begin(9600);
}
void loop()
{
unsigned int now = readTimer1();
while (RFID.available()>0)
{
character = RFID.read();
our_id += character;
lastTime = now;
}
if (our_id.length() > 10) {
our_id = our_id.substring(1,13);
Serial.println(our_id);
our_id = "";
}
delay(1000);
}

Programming Arduino with ADXL345 to raise interrupt on inactivity

I need to use a sparkfun breakout board ADXL345 to detect when my motor system has stopped vibrating. I am also using a Sparkfun RedBoard (Arduino uno).
Things I am doing to configure for this behavior:
enable INACTIVITY event
route INACTIVITY events to INT 1 (pin 2 on the RedBoard)
raise INACTIVITY interrupt without delay
set low threshold for INACTIVITY (rule out too high of a setting)
INACTIVITY considers all axes
clear interrupt data register
Having done all these things I do not receive interrupts after going from shaking the devise to setting it down.
//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>
//Assign the Chip Select signal to pin 10.
int CS=10;
//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1
char THRESH_ACT = 0x24; // Activity threshold
char THRESH_INACT = 0x38; // Inactivity threshold to 3g
char TIME_INACT = 0x26; // time before raising interrupt
char INT_ENABLE = 0x2E; // Enabling the interrupt lines
char INT_MAP = 0x2F;
char ACT_INACT_CTL = 0x27; // mask byte for controlling
char INT_SOURCE = 0x30;
//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
void setup(){
//Initiate an SPI communication instance.
SPI.begin();
//Configure the SPI connection for the ADXL345.
SPI.setDataMode(SPI_MODE3);
//Create a serial connection to display the data on the terminal.
Serial.begin(9600);
//Set up the Chip Select pin to be an output from the Arduino.
pinMode(CS, OUTPUT);
//Before communication starts, the Chip Select pin needs to be set high.
digitalWrite(CS, HIGH);
// Create an interrupt that will trigger when inactivity is detected
attachInterrupt(0, interruptHandler, RISING);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeRegister(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeRegister(POWER_CTL, 0x08); //Measurement mode
// Send the inactivity && activity to PIN 1
// 0xF7 && 0xEF
writeRegister(INT_MAP,0xF7 && 0xEF);
// Set the inactivity threshold to 3g (0x38)
// writeRegister(THRESH_INACT,0x38);
writeRegister(THRESH_INACT,1);
// Raise the inact interrupt immediately after going below threshold
writeRegister(TIME_INACT,0);
// Map INACT event (only) to PIN 1
writeRegister(ACT_INACT_CTL, 0x0F);
// Enab le inactivity to generate interrupts
writeRegister(INT_ENABLE, 0x08);
readRegister(INT_SOURCE, 1, values); // Clear the INT_SOURCE register
Serial.println("Waiting for interrupt!");
}
void interruptHandler(){
// readRegister(INT_SOURCE, 1, values); // Clear the INT_SOURCE register
Serial.println("something raise an interrupt!");
}
void loop(){
//Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
//The results of the read operation will get stored to the values[] buffer.
readRegister(DATAX0, 6, values);
//The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
//The X value is stored in values[0] and values[1].
x = ((int)values[1]<<8)|(int)values[0];
//The Y value is stored in values[2] and values[3].
y = ((int)values[3]<<8)|(int)values[2];
//The Z value is stored in values[4] and values[5].
z = ((int)values[5]<<8)|(int)values[4];
//Print the results to the terminal.
Serial.print(x, DEC);
Serial.print(',');
Serial.print(y, DEC);
Serial.print(',');
Serial.println(z, DEC);
delay(500);
}
//This function will write a value to a register on the ADXL345.
//Parameters:
// char registerAddress - The register to write a value to
// char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
//Set Chip Select pin low to signal the beginning of an SPI packet.
digitalWrite(CS, LOW);
//Transfer the register address over SPI.
SPI.transfer(registerAddress);
//Transfer the desired register value over SPI.
SPI.transfer(value);
//Set the Chip Select pin high to signal the end of an SPI packet.
digitalWrite(CS, HIGH);
}
//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
// char registerAddress - The register addresse to start the read sequence from.
// int numBytes - The number of registers that should be read.
// char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
//Since we're performing a read operation, the most significant bit of the register address should be set.
char address = 0x80 | registerAddress;
//If we're doing a multi-byte read, bit 6 needs to be set as well.
if(numBytes > 1)address = address | 0x40;
//Set the Chip select pin low to start an SPI packet.
digitalWrite(CS, LOW);
//Transfer the starting register address that needs to be read.
SPI.transfer(address);
//Continue to read registers until we've read the number specified, storing the results to the input buffer.
for(int i=0; i<numBytes; i++){
values[i] = SPI.transfer(0x00);
}
//Set the Chips Select pin high to end the SPI packet.
digitalWrite(CS, HIGH);
}
Here is a tutorial, arduino library and example sketch. If you haven't run through something like this, might be worth a try starting with someone else's code that is working (maybe you've already done that).
In the example sketch from above, they are enabling interrupts in the code, they just don't seem to tie them into the Arduino's external interrupt system. Once you verify that the example code is working, you can call attachInterrupt() and abandon the polling approach (as you are doing in your example).

Arduino ultrasonic distance sensor

I am trying to receive information from my sensor, however my output is just 0 all the time, is there something wrong in my code? Everything hardware related is done well.
loop()
{
long duration, inches, cm;
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
Serial.print(inches);
Serial.print("in; ");
Serial.print(cm);
Serial.print("cm");
Serial.println();
}
long microsecondsToInches(long microseconds)
{
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
return microseconds / 29 / 2;
}
The sensor you have does not use PWM as a way of sending distance. Rather it uses a serail connection. The issue is that you do NOT have a extra serial hardware on the Arduino.
You could use the arduino's serail port to read the sensors data, but you would not be able to log anything to the screen
The speed at which the serial connection runs is 9600 baud, which is to fast to emulate in software.
I advice you to buy a sensor that uses the standard PWM mode of communication. Doing this will save a several headaches .But I should tell you there is a way. It is using the software serial library. The library will help you use digital pins like they are serail pins.
http://arduino.cc/en/Reference/SoftwareSerial
http://www.suntekstore.com/goods-14002212-3-pin_ultrasonic_sensor_distance_measuring_module.html
http://iw.suntekstore.com/attach.php?id=14002212&img=14002212.doc
You are using code for the Parallax PING, which uses a different protocol from the one you have. Here is a link to the datasheet of your sensor. It outputs through standard serial at 9600bps every 50ms.
After many tries and thanks to the help of John b, this was figured out as the proper answer on how to use this kind of sensor properly, it works exactly as needed, the output being perfectly measured
#include <SoftwareSerial.h>
// TX_PIN is not used by the sensor, since that the it only transmits!
#define PING_RX_PIN 6
#define PING_TX_PIN 7
SoftwareSerial mySerial(PING_RX_PIN, PING_TX_PIN);
long inches = 0, mili = 0;
byte mybuffer[4] = {0};
byte bitpos = 0;
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
}
void loop() {
bitpos = 0;
while (mySerial.available()) {
// the first byte is ALWAYS 0xFF and I'm not using the checksum (last byte)
// if your print the mySerial.read() data as HEX until it is not available, you will get several measures for the distance (FF-XX-XX-XX-FF-YY-YY-YY-FF-...). I think that is some kind of internal buffer, so I'm only considering the first 4 bytes in the sequence (which I hope that are the most recent! :D )
if (bitpos < 4) {
mybuffer[bitpos++] = mySerial.read();
} else break;
}
mySerial.flush(); // discard older values in the next read
mili = mybuffer[1]<<8 | mybuffer[2]; // 0x-- : 0xb3b2 : 0xb1b0 : 0x--
inches = 0.0393700787 * mili;
Serial.print("PING: ");
Serial.print(inches);
Serial.print("in, ");
Serial.print(mili);
Serial.print("mili");
Serial.println();
delay(100);
}

Resources