I am trying to decode the SENT signal from my high pressure sensor using an arduino. I am trying to calculate the pulse duration of falling edges using input capture registers feature of timer1. But I cannot understand is the output from the capture register is clocks or the pulse duration between the falling edges or what does it capture. Please explain me understand this. I will provide my code below.
const int capturePin = 8; // The pin where the input signal is connected
volatile unsigned long pulseDuration = 0;
volatile unsigned long clocks = 0;
void setup() {
pinMode(capturePin, INPUT);
Serial.begin(9600);
noInterrupts();
// Configure Timer1 for Input Capture mode with falling edge trigger
TCCR1A = 0; // Clear Timer1 control registers
TCCR1B = 0;
// Set the prescaler
TCCR1B |= 0b10000010;
// Enable Input Capture Interrupt
TIMSK1 |= 0b00100000;
// Set the initial value for the Input Capture Register
ICR1 = 0;
// Enable global interrupts
interrupts();
}
// Interrupt service routine for Input Capture
ISR(TIMER1_CAPT_vect) {
clocks = ICR1;
pulseDuration = clocks / 16;
}
void loop() {
// This is where you can use the pulse duration
// For example, you can print it to the Serial monitor
Serial.print("clocks: ");
Serial.println(clocks);
Serial.print("pulseDuration: ");
Serial.print(pulseDuration);
Serial.println(" microseconds");
// Add a delay or perform other tasks as needed
//delay(1000); // Delay for 1 second (adjust as needed)
}
But this code is only giving me the minimum values all the time. When I connected some pressure sources and tried to read the pressure from the sensor and it still shows the same minimum value?
What can be the issue ?
I am using this code now and it works fine for now. But I have a question regarding this is whether this will continuously keep calculating the pressure or it stops after some values ? Because I once saw that it calculates a certain number of values and then it stops after a while.
#include <Wire.h> // Include Wire library for I2C
#include <LiquidCrystal_I2C.h> // Include LiquidCrystal library for I2C
LiquidCrystal_I2C lcdPressure(0x27, 16, 2);
// Connect data pin of sensor to D8 of the Arduino Uno/Nano/Mini
// Time for one tick (in µs)
constexpr uint8_t tick_time = 3;
constexpr auto serial_baud = 115200;
/************************************************************/
constexpr uint8_t tick_syn = 56;
constexpr uint8_t tick_offest = 12;
constexpr uint16_t cycl_tick = F_CPU / 1000000 * tick_time; // CPU cycles per tick
// Allow +/- 20% difference
constexpr uint16_t cycl_syn_min = cycl_tick * tick_syn * 4 / 5;
constexpr uint16_t cycl_syn_max = cycl_tick * tick_syn * 6 / 5;
constexpr auto LOOKUP_SIZE = 256;
constexpr auto LOOKUP_DIV = 4;
uint16_t cycl_syn;
uint16_t cycl_offset;
int8_t cycl_lookup[LOOKUP_SIZE];
constexpr uint8_t BUFFER_SIZE = 32;
volatile uint16_t buffer[BUFFER_SIZE];
volatile uint8_t buffer_write_pointer;
volatile uint8_t buffer_read_pointer;
uint16_t last_icr = 0;
volatile bool error = false;
ISR(TIMER1_CAPT_vect) {
uint16_t value = ICR1;
buffer[buffer_write_pointer] = value - last_icr;
last_icr = value;
buffer_write_pointer++;
if (buffer_write_pointer >= BUFFER_SIZE) {
buffer_write_pointer = 0;
}
if (buffer_write_pointer == buffer_read_pointer) {
error = true;
}
}
bool buffer_available() {
return buffer_write_pointer != buffer_read_pointer;
}
uint16_t buffer_read() {
while (!buffer_available()) {
// wait for data
}
uint16_t ret = buffer[buffer_read_pointer];
auto new_p = buffer_read_pointer + 1;
if (new_p >= BUFFER_SIZE) {
new_p = 0;
}
uint8_t oldSREG = SREG;
cli();
buffer_read_pointer = new_p;
SREG = oldSREG;
return ret;
}
uint16_t get_syn_cycl() {
while (true) {
uint16_t dx = buffer_read();
if (dx >= cycl_syn_min && dx <= cycl_syn_max) {
return dx;
}
}
}
void wait_for_syn() {
while (true) {
uint16_t dx = buffer_read();
auto t = dx > cycl_syn ? dx - cycl_syn : cycl_syn - dx;
if ( t < 10) {
return;
}
}
}
void setup() {
Serial.begin(serial_baud);
lcdPressure.init(); // Initialize the temperature LCD
lcdPressure.backlight(); // Turn on the backlight for temperature LCD
lcdPressure.setCursor(0, 0);
lcdPressure.print("Press: bar");
Serial.print("cycl_tick = ");
Serial.println(cycl_tick);
TCCR1A = 0;
TCCR1B = 1;
TCCR1C = 0;
TIMSK1 = (1 << ICIE1);
cycl_syn = get_syn_cycl();
cycl_offset = cycl_syn * (tick_offest * 2 - 1) / tick_syn / 2; // cycl_tick * 11.5
for (uint16_t c = 0; c < LOOKUP_SIZE; c++) {
int8_t value = c * tick_syn * LOOKUP_DIV / cycl_syn;
if ( value >= 16) {
value = -1;
}
cycl_lookup[c] = value;
}
auto cycl_syn1 = get_syn_cycl();
auto dx = cycl_syn > cycl_syn1 ? cycl_syn - cycl_syn1 : cycl_syn1 - cycl_syn;
Serial.print("cycl_syn = ");
Serial.println(cycl_syn);
Serial.print("cycl_syn ok? ");
Serial.println(dx < 10 ? "yes" : "no");
Serial.print("cycl_offset = ");
Serial.println(cycl_offset);
if (LOOKUP_SIZE < (cycl_syn * 17 / tick_syn / LOOKUP_DIV)) {
Serial.println("Lookup table would exceed expected size!");
while (true) {
;
}
}
Serial.println("Lookup table:");
for (int x = 0; x < 16; x++) {
Serial.print(x * 16, HEX);
Serial.print(": ");
for (int y = 0; y < 16; y++) {
Serial.print(cycl_lookup[x * 16 + y], HEX);
Serial.print(" ");
}
Serial.println("");
}
Serial.println("************************");
Serial.flush();
error = false;
}
constexpr char toHex[] = "0123456789ABCDEF";
void loop() {
constexpr auto FRAME_SIZE = 8;
char frame[FRAME_SIZE + 1];
wait_for_syn();
for (int c = 0; c < FRAME_SIZE; c++) {
auto dx = buffer_read();
dx = (dx - cycl_offset) / LOOKUP_DIV;
if (dx > LOOKUP_SIZE || cycl_lookup[dx] < 0) {
frame[c] = '!';
} else {
frame[c] = toHex[cycl_lookup[dx]];
}
}
// Extract the 2nd, 3rd, and 4th hex digits and convert to a numerical value
char hexDigits[] = {frame[1], frame[2], frame[3], '\0'};
int digitalValue = strtol(hexDigits, NULL, 16);
// Calculate the pressure using the provided formula
float pressure = 0.25 * digitalValue - 50;
Serial.print("Digital Value: ");
Serial.println(digitalValue);
Serial.print("Pressure: ");
Serial.println(pressure,2);
lcdPressure.setCursor(6, 0);
lcdPressure.print(pressure);
Serial.write(frame, FRAME_SIZE);
Serial.println("");
delay(1000);
}
In the original code the ISR checks for a ringbuffer overflow and sets error to true. loop() checked it and stopped.
You probably want to add overflow checking again to detect corrupt frames:
BTW.: The code has problems with integer overflows when tick_time > 3 or the CPU is clocked faster than 16Mhz. Also when the sensor is sending a padding, it can be detected as sync and ruin the calculation of the lookup table in setup().