Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 3 months ago.
High accuracy measurement on NUCLEO L432KC
Hi there, I've created following code to measure the time between two pulses:
my code
#include "mbed.h"
Timer t; // timer to measure time between two sensor signals
Serial device(USBTX, USBRX); // for debug output on terminal
InterruptIn sensor(PA_9); // for sensor signal
int32_t delta_us = 0;
void signalOccurred() {
delta_us = t.read_us(); // global delta_us holds time difference between the last two signals now
t.reset(); // reset the timer
}
void sendMessage() {
device.printf("Delta = %d\r\n", delta_us); //Debug out
//send value via CAN here...
}
int main() {
Timer sendViaCAN;
device.baud(115200);
device.printf("========== Device started up ==========\r\n");
t.start(); //global
sendViaCAN.start();
sensor.rise(&signalOccurred); // attach the address of the signalOccurred function to the rising edge
// spin in a main loop and if signal occurs interrupt it!
while(1) {
if (sendViaCAN.read_ms() >= 20) {
sendViaCAN.reset();
sendMessage();
}
}
}
I've tested it with an Arduino board which has an hardware PWM. The problem with this code is, that it is giving me different results: the values changes several µs. This is not enough accuracy for me and I think the problem lies on the software side. - Is it possible to get a better accuracy with the NUCLEO L432KC?
1 Answer
8 years, 3 months ago.
Hello Peter,
I have tested the code below on NUCLEO-F103RB (using an LPC1768 mbed board as PWM signal generator) and it worked with 1us accuracy (in range from 10us to 4s).
#include "mbed.h"
//
enum State
{
IDLE,
READY,
MEASURING,
FINISHED,
TIMEOUT
};
//
const float MEASUREMENT_TIMEOUT = 5.0f; // measurement timeout in seconds
//
Serial pc(USBTX, USBRX);
InterruptIn input(PA_9);
Timeout timeout;
volatile State state;
volatile uint32_t now;
volatile uint32_t begin;
volatile uint32_t period;
/**
* @brief ISR handling 'measurement timeout'
* @note Called when input line is idle longer than expected.
* Signals 'end of measurement' by setting state to TIMEOUT.
* @param None
* @retval None
*/
void measurementTimeout(void) {
input.disable_irq();
timeout.detach();
state = TIMEOUT;
}
/**
* @brief Measures pulse period (time elapsed between two rising edges)
* @note Waits until a rising edge is detected at input or timeout occured.
* @param None
* @retval None
*/
void measurePeriod(void) {
bool finished;
state = READY;
timeout.attach(callback(measurementTimeout), MEASUREMENT_TIMEOUT);
input.enable_irq();
do {
finished = ((state == FINISHED) || (state == TIMEOUT));
} while (!finished);
}
/**
* @brief ISR handling signal rise at input
* @note Called on signal rise at input
* @param
* @retval
*/
void onInputRise(void) {
now = us_ticker_read();
switch (state) {
case READY:
state = MEASURING;
begin = now;
break;
case MEASURING:
input.disable_irq();
timeout.detach();
state = FINISHED;
period = now - begin;
break;
default:
break;
}
}
/**
* @brief
* @note
* @param
* @retval
*/
int main(void) {
state = IDLE;
input.mode(PullDown);
input.disable_irq();
input.rise(callback(onInputRise));
while (1) {
switch (state) {
case IDLE:
measurePeriod();
break;
case FINISHED:
state = IDLE;
pc.printf("Pulse period = %dus\r\n", period);
wait(1); // prevents PC's serial terminal from overloading when period is very short
break;
case TIMEOUT:
state = IDLE;
pc.printf("Measurement timeout. No signal detected at input.\r\n");
break;
default:
break;
}
}
}
Zoltan