How to set up sample rate 250Hz in teensy 3.6

Status
Not open for further replies.

Sudipto Trivedy

New member
I am using teensy 3.6 for the first time and I want to setup sample rate 250 Hz in teensy. Please help me with the sample code.

int sensorPin = A0;
int sensorValue = 0;
float voltage = 0.0;
char incomingByte;
String stringSend = ' ';
boolean STAT = false;
boolean STAT1 = false;
ADC adc;
void setup() {
Serial1.begin(9600);
analogReadResolution(12);
while (!Serial1) {
; // wait for serial port to connect. Needed for native USB port only
}
pinMode(sensorPin, INPUT);
}

void loop() {
if (Serial1.available() > 0) { // if the data came
incomingByte = Serial1.read();
Serial.println(incomingByte);
if(incomingByte == '0') {
STAT = true;
}
else if(incomingByte == '1'){
STAT = false;
stringSend = '#';
Serial1.print(stringSend);
delay(100);
}
else{

}
}
if(STAT)SendData();
}
void SendData(){
sensorValue = analogRead(sensorPin);
voltage = sensorValue * (5.0 / 4095.0);
//Serial.println(voltage);
stringSend = (String)voltage + ',';
Serial1.print(stringSend);
delay(100);
}
void SendLast(){
stringSend = '#';
Serial1.print(stringSend);
delay(100);
}
This is my code
 
Hello.

There are some things in your code I don't understand. Have you tried compiling it? When I do it returns an error because you are using and ADC object without including the corresponding library.
Anyway, by looking at your code it seems you don't really use the ADC object, so you can simply delete the line "ADC adc;"

The SendLast() function is also never used.

But returning to your question. I think the easiest way to set a fixed sampling rate is to use a IntervalTimer object.

An example:

Create a global IntervalTimer object: IntervalTimer myTimer;
Create a sampling function to be called 250 times per second (250 Hz): void sampleSensor() { sensorValue = analogRead(sensorPin); }
In your setup, begin calling the function: myTimer.begin(sampleSensor, 4000); // sampleSensor will be called every 4000 microseconds (or, 250 times per second)
 
You do not need the while statment at
while (!Serial1) {
just Serial.Begin

You also have potential trouble with
sensorValue * (5.0 / 4095.0)
since the Teensy will be working with a 3.3V reference - depends on what the actual math you need but that looks like something from a classic 5V Arduino

Also when posting code, if you use code tags it formats better, most easily done pressing the button with # on it in the edit box

From the looks of it you will be capturing at 250hz, but the actual print 'senddata' block has a delay 100 in it so you will only get printed data at 10hz. If you want 250 prints a second better method would be to set a flag in sampleSensor, and print when that flag is set, then clear the flag. This will push the USB interface pretty hard and will probably cause missed mesaages and other problems, better solution would be to write into a buffer and send the buffer contents every second or so. More complex ways to do it, but having an even and odd buffer is probably the easiest way to avoid problems where the read out collides with the write.

A lot depends on why you need values at 250hz - if you can preprocess them in sampleSensor a lot of data rate problems go away.
 
Not sure why the prior post was deleted?

... based on this note in prior post
A lot depends on why you need values at 250hz - if you can preprocess them in sampleSensor a lot of data rate problems go away.

That suggests there isn't enough info to understand what the desired end solution would be.

Members of the forum typically help solve the problem - not just provide a solution. That prior post offers some valuable suggestions - if they were to be followed a solution would be closer and posting that code would allow learning in the process.
 
Not sure why the prior post was deleted?

... based on this note in prior post


That suggests there isn't enough info to understand what the desired end solution would be.

Members of the forum typically help solve the problem - not just provide a solution. That prior post offers some valuable suggestions - if they were to be followed a solution would be closer and posting that code would allow learning in the process.

I am really sorry, I don't know how it got deleted. After Siridakis suggestion I wrote the below code:
Code:
int sensorPin = A0;
int sensorValue = 0;
float voltage = 0.0;
char incomingByte;
String stringSend = ' ';
boolean STAT = false;
boolean STAT1 = false;
IntervalTimer myTimer;
void setup() {
Serial1.begin(9600);
analogReadResolution(12);
while (!Serial1) { 
; // wait for serial port to connect. Needed for native USB port only 
}
pinMode(sensorPin, INPUT);
myTimer.begin(sampleSensor, 4000);
}

void loop() {
if (Serial1.available() > 0) { // if the data came
incomingByte = Serial1.read();
Serial.println(incomingByte);
if(incomingByte == '0') {
STAT = true;
}
else if(incomingByte == '1'){
STAT = false;
stringSend = '#';
Serial1.print(stringSend);
delay(100);
}
else{

}
}
if(STAT)SendData();
}
void SendData(){
//sensorValue = analogRead(sensorPin);
voltage = sensorValue * (5.0 / 4095.0);
//Serial.println(voltage);
stringSend = (String)voltage + ',';
Serial1.print(stringSend);
delay(100);
}
void sampleSensor() {
	sensorValue = analogRead(sensorPin);
}
Then I got Gremlin's post and I made below modifications:
Code:
int sensorPin = A0;
int sensorValue = 0;
float voltage = 0.0;
char incomingByte;
String stringSend = ' ';
boolean STAT = false;
boolean STAT1 = false;
boolean timer = false;
IntervalTimer myTimer;
void setup() {
Serial1.begin(9600);
analogReadResolution(12);
pinMode(sensorPin, INPUT);
myTimer.begin(sampleSensor, 4000);
}

void loop() {
if (Serial1.available() > 0) { // if the data came
incomingByte = Serial1.read();
Serial.println(incomingByte);
if(incomingByte == '0') {
STAT = true;
}
else if(incomingByte == '1'){
STAT = false;
stringSend = '#';
Serial1.print(stringSend);
delay(100);
}
else{

}
}
if(STAT && timer){
	SendData();
	timer = false;
}
void SendData(){
//sensorValue = analogRead(sensorPin);
voltage = sensorValue * (5.0 / 4095.0);
//Serial.println(voltage);
stringSend = (String)voltage + ',';
Serial1.print(stringSend);
delay(100);
}
void sampleSensor() {
	sensorValue = analogRead(sensorPin);
	timer = true;
}
I am using this code for Spirometry. For that reason I need to set up the sampling rate at 250 Hz. As part of spirometry differential pressure sensor output is coming in A0 pin of the Teensy.

Please send me the buffer sample code for 250Hz.
 
You still have delay(100); in your send data block. If you get rid of that and maybe add a delay(1); at the end of void loop() to allow any background stuff to happen does this do what you need it to do?

Buffering may not be required, depends if what you have is good enough.
 
On loop exit Teensy will 'only' check all Serial[#] devices for available and call out to serialAvailable[#]() functions with a call to yield() - that same yield() call is made from delay():
Code:
 // from ...\hardware\teensy\avr\cores\teensy3\main.cpp
	setup();
	while (1) {
		loop();
		yield();
	}


So delay(100) may be extreme - delay(1) would just add some wait to prevent looping too fast if needed - that limits loop() to 1000/second - otherwise Teensy 3.6 will aim for a million or more if not doing anything.
 
On loop exit Teensy will 'only' check all Serial[#] devices for available and call out to serialAvailable[#]() functions with a call to yield() - that same yield() call is made from delay():
Code:
 // from ...\hardware\teensy\avr\cores\teensy3\main.cpp
	setup();
	while (1) {
		loop();
		yield();
	}


So delay(100) may be extreme - delay(1) would just add some wait to prevent looping too fast if needed - that limits loop() to 1000/second - otherwise Teensy 3.6 will aim for a million or more if not doing anything.

Yes, a delay of 100 is pretty long.

As the requirement is getting 250 Hz, fine-tuning is necessary. I mean it is advisable to check out what the software is doing. To do so you can add a sort of timestamp to your loop and send out a string to the USB. You need to define at least one variable to store the timestamp,for example, "unsigned long InitTime;". Then you assign to the variable the current value of timestamp in milliseconds, "InitTime = millis();" and send out the string to USB. Once you read the output you can select a more appropriate delay(delaytime). Ideally, you desire that your loop runs in 4 ms(1/250) . After your adjust the delaytime value recheck your loop time and iterate if necessary.
"
...
unsigned long InitTime;
..
void loop() {

...
InitTime = millis();
...
-> Serial1 output to USB
delay(delaytime);
}
"
[You can also take two timestamps within the loop and send out the difference between the two values to the USB]
 
@Sudipto Trivedy It will be interesting to know a little about the hardware, for example, the spirometer tube, used for your spirometry application. Your post disclosed to me that spirometry is a popular application (1,2) I fiddle around with an air data computer and seems fine for this application(it works! :)). It is possible that in the future this application is added to Basic Air Data ADC.

P.S. Interrupt based sensor reading is fine. However we moved to a simpler model to be easily integrated within third-party proejcts.
 
Status
Not open for further replies.
Back
Top