Reading an absolute encoder with gray code output - arduino

I have an absolute encoder(Hengstler AD36) that gives 12 bit position value with gray code. I am trying to convert that value to decimal, I mean in degrees 0 to 360.
I have the 12 bit value in gray code by using Arduino.I have read the Arduino port and converted it in Python, but I need to do it in Arduino. But, I couldn't convert it to any meaningful numbers in Arduino.
///Pin setup for the Sensor
const int CLOCK_PIN = 18;
const int DATA_PIN = 19;
const int DATA_PIN2 = 17;
///12-bit sensor
const int BIT_COUNT = 12;
void setup() {
//setup our pins
pinMode(DATA_PIN, INPUT);
pinMode(CLOCK_PIN, OUTPUT);
//give some default values
digitalWrite(CLOCK_PIN, HIGH);
Serial.begin(9600);
}
void loop() {
unsigned long reading1 = readPosition1();
Serial.print(reading1,BIN);
Serial.print(",");
delay(50);
}
//read the current angular position
int readPosition1() {
unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
delayMicroseconds(25); // delay for clock
return sample1;
}
//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
unsigned long data = 0;
for (int i=0; i<bit_count; i++) {
data <<= 1;
digitalWrite(clock_pin, LOW);
delayMicroseconds(1);
digitalWrite(clock_pin, HIGH);
delayMicroseconds(1);
data |= digitalRead(data_pin);
}
return data;
}
How can I convert data to decimal (0 to 360 degrees)?
The main problem that I couldn't solve, I found some functions that convert gray code to binary, then it is easy to convert it to decimal. However, these functions take input as string or int, and I have no idea about converting data value to int.
Any help would be greatly appreciated.
Thanks.

Related

(.text+0x0): multiple definition of `__vector_13'

Using NewPing.h seems to be the main issue.
Code:
#include <LedControl.h>
#include "pitches.h"
#include "SR04.h"
#include "NewPing.h"
#define TRIGGER_PIN 13
#define ECHO_PIN 8
#define MAX_DISTANCE 200
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
long duration;
int distance;
int DIN = 12;
int CS = 11;
int CLK = 10;
LedControl lc=LedControl(DIN,CLK,CS,0);
const int buzzer = 9;
void setup(){
lc.shutdown(0,false); //The MAX72XX is in power-saving mode on startup
lc.setIntensity(0,15); // Set the brightness to maximum value
lc.clearDisplay(0); // and clear the display
pinMode(buzzer, OUTPUT); //buzzer shit
pinMode(TRIGGER_PIN, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(ECHO_PIN, INPUT); // Sets the echoPin as an INPUT
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
}
void loop(){
unsigned int uS = sonar.ping();
Serial.print(uS / US_ROUNDTRIP_CM);
byte a[8]= {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,};
byte b[8]= {0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,};
byte c[8]= {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,}; //done
byte d[8] = {0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,}; //done
byte e[8]= {0x18,0x5a,0x3c,0x18,0x18,0x24,0x5a,0x18,}; //done
byte f[8]= {0x99,0x5a,0x18,0x18,0x18,0x00,0x5a,0x99,}; //done
byte g[8]= {0x99,0x18,0x18,0x18,0x18,0x00,0x18,0x99,};
byte h[8]= {0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,};
if (uS <= 20){
printByte(a);
tone(buzzer, 1000);
delay(100);
printByte(b);
noTone(buzzer);
delay(100);
printByte(c);
tone(buzzer, 1000);
delay(100);
printByte(d);
noTone(buzzer);
delay(100);
printByte(e);
tone(buzzer, 1000);
delay (100);
printByte(f);
noTone(buzzer);
delay (100);
printByte(g);
tone(buzzer, 1000);
delay (100);
printByte(h);
noTone(buzzer);
delay(1000);
}
}
void printByte(byte character [])
{
int i = 0;
for(i=0;i<8;i++)
{
lc.setRow(0,i,character[i]);
}
}
The main thing that stands out in the error is the line
"(.text+0x0): multiple definition of `__vector_13'
C:\Users\name\AppData\Local\Temp\arduino_build_789753\libraries\NewPing\NewPing.cpp.o (symbol from plugin):(.text+0x0): first defined here".
However, I don't exactly know how to solve it.

speed,time,cycle and direction stepper motor by arduino

I want my stepper motor to run at a specified speed for a specified time and stop for a set time and then repeat the same cycle.
In fact, the number of times the user has to do this will determine the user
I have the last code that failed, but this is not working properly for more than 30 seconds and the steppper motor rotates permanently.
#include <Stepper.h>
const int stepPin = 6; //PUL -Pulse
const int stepsPerRevolution = 1600;
const int dirPin = 7; //DIR -Direction
const int enPin = 8; //ENA -Enable
int one = 30000;//user input
int c = 2;// user input
int rpm = 1200;//user input
unsigned long t = 0;
Stepper myStepper(stepsPerRevolution, 6, 7);
void setup() {
Serial.begin(9600);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
myStepper.setSpeed(rpm);
}
void loop() {
Cycle();
digitalWrite(enPin, HIGH);
}
void Cycle() {
int cycle = 1;
for (cycle ; cycle <= c; cycle++) {
t = millis();
while ((millis() - t) < one) {
myStepper.step(stepsPerRevolution);//counter clockwise rotation
}
delay(3000);
}
}
int one = 30000;//user input
If you're going to use an int as your timing variable, then you need to look up what is the maximum value that an int can hold on your particular board. If you're using something like an UNO or a Mega then that's 32767 and that will probably explain why it doesn't work with anything over about 32 seconds.

Received data are correct on scope not in program

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;
}

Arduino Interrupt misbehaving

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

Arduino RF Data Transmission

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();
}

Resources