Hello everyone,
i would like to make communication between Arduino and a sensor. The goal is to send instruction on hexadecimal (read, write parameters) to sensor and also analyzed data from sensor. The diagram of communication is on attached file.
I have to use rising/falling edge function by timer and interrupt for decrypt data from sensor but i don't know is my code is the best solution or if there is another solution more easier. More over, i don't know how write program to send data to sensor.
The Biphase bit time is 1ms.
Could you help me for all please ? thank you.
why not use external interrupts or interrupt-on-change?
something like this maybe. I let you do the conversion of time to bit value
(Compiles, Not Tested!)
//PWM read using InterruptOnChange. Following code measures the time a PWM (HIGH and LOW)
#define MAX_SIZE 16 //"power of 2" buffer size is recommended to dramatically optimize all the modulo operations for ring buffers.
volatile uint32_t t_rise;
volatile uint8_t tail = 0;
uint32_t pwm_buf[MAX_SIZE];
uint8_t head = 1; //=1 to skip first stored value on powerup/reset
// Use one Routine to handle each group
ISR (PCINT0_vect) // handle pin change interrupt for PORTB (Arduino UNO: D8 to D13, MEGA: D10,D11,D12,D13,D53,D52,D51,D50)
{
}
ISR (PCINT1_vect) // handle pin change interrupt for PORTC (Arduino UNO: A0 to A5, Not Applied to MEGA)
{
}
ISR (PCINT2_vect) // handle pin change interrupt for PORTD (Arduino UNO: D0 to D7)/ PORTK (MEGA A8 to A15)
{
pwm_buf[tail] = micros() - t_rise;
t_rise = micros();
tail = (tail + 1) % MAX_SIZE;
}
void pciSetup(byte pin)
{
noInterrupts();
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
interrupts();
}
void setup() {
Serial.begin(115200);
// set pullups, if necessary
digitalWrite(7, INPUT_PULLUP);
// enable interrupt for pin...
pciSetup(7);
while (head > tail); //wait for 1st value to be stored (omitted value)
Serial.println("READY");
}
void loop() {
if (head != tail) {
noInterrupts(); //to avoid corruption uint32_t value
uint32_t pwm_value = pwm_buf[head];
interrupts();
head = (head + 1) % MAX_SIZE;
Serial.print("pulse width: ");
Serial.print(pwm_value);
Serial.println("us");
}
}
Hello everyone,
ok thank you sherzaad, it's working correctly thank you very much.
And after, i have to send several bit to read value of sensor.
The question is simple, how to send a successive bit to sensor and listen how bit is send to sensor ? (with loop "if time is < 500 µs then bit = 0 else bit = 1" or anothers solution s cleaner).
If you want help, please explain your last post better!
Triv38:
Hello everyone,
ok thank you sherzaad, it's working correctly thank you very much.
And after, i have to send several bit to read value of sensor.
The question is simple, how to send a successive bit to sensor and listen how bit is send to sensor ? (with loop "if time is < 500 µs then bit = 0 else bit = 1" or anothers solution s cleaner).
Thank you for your help.
this looks will a one wire communication, ie you send the command and receive the response on the same wire/pin. is this correct?
What are time timing requirements for SYNC and START???
this "if time is < 500 µs then bit = 0 else bit = 1" is not clear at all.
From the diagram in your initial post,"0" AND "1" has different timings. IMHO 500us cannot be the only timing!
Also is 500us the total duration of a "0"/"1" OR is it the ON duty time?!
English may not be your native language but please try to explain your requirements more clearly OR as previously suggested POST A LINK TO THE SENSOR DATASHEET!
Hello everyone,
Sorry for my English. In attached file, datasheet of sensor.
If i understand, in first diagram we have to check 2 timing :
first timing, duty cycle < 750µs => bit = 1
seconde timing, duty cycle >750 => bit = 0
Below, first drawing code :
//PWM read using InterruptOnChange. Following code measures the time a PWM (HIGH and LOW)
#define MAX_SIZE 16 //"power of 2" buffer size is recommended to dramatically optimize all the modulo operations for ring buffers.
volatile uint32_t t_rise;
volatile uint8_t tail = 0;
uint32_t pwm_buf[MAX_SIZE];
uint8_t head = 1; //=1 to skip first stored value on powerup/reset
int bit_value;
int inPin = 13; // pushbutton connected to digital pin 13
int val_DI;
int array_bit[26];
// Use one Routine to handle each group
ISR (PCINT0_vect) // handle pin change interrupt for PORTB (Arduino UNO: D8 to D13, MEGA: D10,D11,D12,D13,D53,D52,D51,D50)
{
}
ISR (PCINT1_vect) // handle pin change interrupt for PORTC (Arduino UNO: A0 to A5, Not Applied to MEGA)
{
}
ISR (PCINT2_vect) // handle pin change interrupt for PORTD (Arduino UNO: D0 to D7)/ PORTK (MEGA A8 to A15)
{
pwm_buf[tail] = micros() - t_rise;
t_rise = micros();
tail = (tail + 1) % MAX_SIZE;
}
void pciSetup(byte pin)
{
noInterrupts();
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
interrupts();
}
void setup() {
Serial.begin(115200);
// set pullups, if necessary
digitalWrite(7, INPUT_PULLUP);
// enable interrupt for pin...
pciSetup(7);
pinMode(inPin, INPUT); // sets the digital pin 13 as input
while (head > tail); //wait for 1st value to be stored (omitted value)
Serial.println("READY");
}
void loop()
{
val_DI = digitalRead(inPin);
if (val_DI == HIGH)
{
read_frame();
Serial.print("bit : ");
for (int y=0;y<26;y++)
{
Serial.print(array_bit[y]);
}
Serial.println(" ");
}
else
{
}
}
void read_frame()
{
for (int i=0;i<26;i++)
{
if (head != tail)
{
noInterrupts(); //to avoid corruption uint32_t value
uint32_t pwm_value = pwm_buf[head];
interrupts();
head = (head + 1) % MAX_SIZE;
/*
Serial.print("pulse width: ");
Serial.print(pwm_value);
Serial.println("us");
*/
if (pwm_value <750)
{
bit_value = 1;
}
else if (pwm_value > 750)
{
bit_value = 0;
}
/*
Serial.print("bit : ");
Serial.print(bit_value);
Serial.println(" ");
*/
}
array_bit[i]=bit_value;
}
}
I had a look at the datasheet and I hope you know what sequence of commands to need to send and read... I honestly dont have the time do to that.
Anyway assuming you know what you are doing, you could something like this to send you commands (you may need to fine tune the T_HBBIT timing to account for the inherrent delays due to the code itself. Also not sure is it the MSB or LSB that should go out first, so included a routines to do either)
Hi everone and happy new year for 2021. Hope a best year for all than the last
Thank you very much Sherzaad concerning your code. It helped me a lot i modify some point to match with i want. I wrote the function "send_biphase_msb_first" because, it's not working before.
I have just a little question to understand all.
I want to send a request at the address "0xA3" with msb first so in binary, 0b1010 0011. I send only the address.
when I analyzed trace on oscilloscope (as a function of time), result is : 0b0101 1100
so for lsb byte, bit 0 and 1 is inverted compared to bit 2 and 3.
Same behaviour for msb byte.
for addr = 0xA3 the above give you 0x3A when it should be 0xC5 but wait even that is wrong since you are using uint16_t
so that wound therefore be 0xC500!
To get 0xC5, this is how I would do it:
int addr = 0xA3; //address
int bits = 8; //number of bits to shift
int MSB_mask = (1 << (bits - 1));
int frame_out = 0;
for (int i = 0; i < bits; ++i) {
frame_out>>=1;
frame_out |= addr & MSB_mask;
addr <<= 1;
}
printf("0x%.2X", frame_out); //result = 0xC5
Hello Sherzaad,
I think that it is misunderstood. Actually, i want to send address 0xA3 with msb first so first byte 0xA and after 0x3.
With the previous code, when i decode trace on oscilloscope, i have 0x5C. so in binary i get :
adress value on arduino => 0xA3 => 0b1010 0011
address value on trace on oscilloscope => 0x5C => 0b0101 1100 instead of 0xA3 (see trace on oscilloscope on attached file).
Triv38:
i want to send address 0xA3 with msb first so first byte 0xA and after 0x3.
You have your concept of 'bytes' mixed up mate!
a byte is 8bits long. 0xA3 IS ONE BYTE!
Triv38:
address value on trace on oscilloscope => 0x5C => 0b0101 1100 instead of 0xA3 (see trace on oscilloscope on attached file).
that is right based on how you are sending stuff in YOUR CODE
in your code you are manipulate 0xA3 into 0x3A and output this with MSB first and that give your 0x5C (if you bits read bits right to left ie rightmost bit assumed to be bit0).
IF you read the scope trace LEFT TO RIGHT (since MSB is first bit out ie rightmost bit is actually bit7) you get 0x3A!
You are right, it is only 1 byte => ok
Sorry if i don't understand quickly but it's a brand new for me
If i resume, my goal is to send the address 0xA3 on output and NOT 0x5C. So when I analyzed trace on oscilloscope, i need to transmit address with function "msb_first" so :
first bit 2^7, after bit 2^6, after 2^5....
so for address 0xA3, software has to send on output :
first bit : 1 // second bit : 0 // third bit : 1 // fourth bit : 0 // fifth bit : 0 //sixth bit : 0 // seventh bit : 1 // eighth bit : 1
I try to run your code with this function (below) but the result doesn't match with address write on software.
you are right about one thing:
the 'send_biphase_msb_first(uint16_t frame, uint8_t bits)' routine which I created will NOT send out address 0xA3, as "first bit : 1 // second bit : 0 // third bit : 1 // fourth bit : 0 // fifth bit : 0 //sixth bit : 0 // seventh bit : 1 // eighth bit : 1"
beacuse it is a biphase output, waveform pattern which you posted in your first post.
as for sending out 0xA3 with MSBit first:
see the snippet I posted in reply #9 and remember if your are checking output on scope trace,
the rightmost bit will be bit7 NOT bit0
Hi,
i'm sorry, i make a fault concerning the direction of time on oscilloscope on trace.
The time go from left to right and not the inverse.
So the first bit sent to output is the bit at the leftmost and the last is at the right. (see my graph trace2 in attached file).
I wish to have the behavior as the diagram in attached file "trace3".
I try to test your code of the function "send_biphase_msb_first" routine but the behavior is not as expected (see "trace4")
I have on output "0b1000 0000" instead of "0b0111 1111".
Triv38:
Hi,
i'm sorry, i make a fault concerning the direction of time on oscilloscope on trace.
The time go from left to right and not the inverse.
So the first bit sent to output is the bit at the leftmost and the last is at the right. (see my graph trace2 in attached file).
I wish to have the behavior as the diagram in attached file "trace3".
I try to test your code of the function "send_biphase_msb_first" routine but the behavior is not as expected (see "trace4")
I have on output "0b1000 0000" instead of "0b0111 1111".
I continue to work to have the good behavior.
I found where there error was in that routine. just needed to move a line!
void send_biphase_msb_first(uint8_t frame, uint8_t bits) {
uint16_t previous_state = 0x01 & (!digitalRead(TxRx_PIN));
uint16_t MSB_mask = (1 << (bits - 1));
uint8_t bit = (frame & MSB_mask > 0) ? 1 : 0;
for (int i = 0; i < bits * 2; ++i) {
digitalWrite(TxRx_PIN, (previous_state ^ ((i & 0x01)&bit)));
if (i & 0x01) {
frame <<= 1;
bit = (frame & MSB_mask > 0) ? 1 : 0;
}
previous_state = 0x01 & (!digitalRead(TxRx_PIN)); //<--- line moved out of 'if' statement
delayMicroseconds(T_HBBIT);
}
}
Hi Sherzaad,
unfortunately, i try your function and it doesn't work. regardless of value of address in software, I have on output trace : 0b01111111.
If i request address 0x11, 0x A3... I have always same trace : 0b01111111.
Triv38:
Hi Sherzaad,
unfortunately, i try your function and it doesn't work. regardless of value of address in software, I have on output trace : 0b01111111.
If i request address 0x11, 0x A3... I have always same trace : 0b01111111.
It's not so easy
You're absolutely right! 8)
That's why it's always good to test more than one value!
Was just lucky to get the right answer....
Anyway... I think managed to crack it now. tested a couple of values using online c-compiler and it is seem to be give the expected output now.
int digitalRead_TxRx_PIN = 0; //inital state pin
void send_biphase_msb_first(int frame, int bits) {
int previous_state = 0x01 & (!digitalRead_TxRx_PIN);
int MSB_mask = (1 << (bits - 1));
int bit;
if(frame & MSB_mask) bit = 1;
else bit =0;
for (int i = 0; i < bits * 2; ++i) {
//your digitalWrite
digitalRead_TxRx_PIN = (previous_state ^ ((i & 0x01)&bit));
printf("%i",digitalRead_TxRx_PIN );
//----------------
if (i & 0x01) {
frame <<= 1;
if(frame & MSB_mask) bit = 1;
else bit =0;
previous_state = 0x01 & (!digitalRead_TxRx_PIN);
}
//delayMicroseconds(T_HBBIT);
}
}
int main() {
send_biphase_msb_first(0x7F, 8); //produces 1101010101010101
printf("\n");
digitalRead_TxRx_PIN = 0; //reset pin state
send_biphase_msb_first(0x11, 8); //produces 1100110100110010
printf("\n");
digitalRead_TxRx_PIN = 0; //reset pin state
send_biphase_msb_first(0xA3, 8); //produces 1011010011001010
}