'Newbie' question..

Status
Not open for further replies.

JohnPunnett

Active member
Hi all,

Hope you do not mind me posting here. I am new to Forum & Teensy 3.2 so Hello. Teensy looks like a fantastic product.

Anyway, as a first project I just want to change an Analog voltage every few secs to a different level - I am doing this with a simple Analog write to A14. In the background I want to read an analog input voltage (say from A0) every 100msecs & to send data to Serial Monitor. As I understand the easiest way to do this is to use some kind of Timer Interrupt that every 100msecs executes an Analog Read & Serial Print. Does this sound reasonable & also what would be the easiest Timer function for this purpose. I've a little experience with the Arduino Uno & IDE & am using the Arduino IDE for programming.

Many thanks for any help/ suggestions - John.
 
Thks Ben - I appreciate the quick response & the welcome. I've had a look at what you suggested & I'm not sure the elapsed Milli's approach would work? In the main Loop I actually have a loop within a loop so for example the Outer loop initially sets Analog volts to 2.5V for 1 sec, then it enters inner loop where I set Analog to 1V for 2 secs followed by 0.5V for 5 secs. The inner loop is repeated 10 times before the outer loop again executes. The whole process repeats until I execute. I have generated the time delays using delay function. The whole time the main loop is running I want to read an Analog Input voltage say every 100msecs. I thought you'd need to use a timer interrupt of course I could be wrong. This is my code so far which works but as you can see its only possible to update the serial monitor with the analog input volts when I change the analog output voltage I want to be able to do this every 100msecs. Once again many thanks for your help & support - John

pinMode(led, OUTPUT);
analogWriteResolution(12);
analogReadResolution(12);
Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop()
{

analogWrite(A14, 3103);
digitalWrite(led, HIGH);
analogValue = analogRead(analogInPin);
Serial.println(analogValue);
delay(1000); // wait for a second
for (int i=0; i <=10; i++){
analogWrite(A14, 515);
digitalWrite(led, HIGH);
analogValue = analogRead(analogInPin);
Serial.println(analogValue);
delay(5000); // wait for a second
analogWrite(A14, 1030);
digitalWrite(led, LOW);
analogValue = analogRead(analogInPin);
Serial.println(analogValue);
delay(2000);
}
}
 
Okay I *think* I kind of get what you want the Teensy to do.
For the analog output I suggest using two arrays that hold the voltage level and the time you want that level to be present on the output:
Code:
int voltage[3] = { 3103, 515, 1030 };
int duration[3] = { 1000, 5000, 2000 };

then you need two elapsedMillis objects:
Code:
elapsedMillis sinceRead;
elapsedMillis sinceWrite;

and an integer to keep track of which of the voltage levels we are currently at:

Code:
int currentVoltageIndex = 0; //can be 0, 1 or 2

now in your main loop, you can check how much time has passed and trigger regular analogRead()s:

Code:
if (sinceRead >= 100) {
    sinceRead = sinceRead - 100; //reset the timer
    int value = analogRead(analogInPin);
    Serial.print("Reading pin ");
    Serial.print(analogInPin);
    Serial.print(" at ");
    Serial.print(millis());
    Serial.print(" ms: ");
    Serial.println(value);
}

and you can check if it's time to change the anolg output with another if-statement:

Code:
if (sinceWrite >= duration[currentVoltageIndex]) {
    sinceRead = 0; //reset the timer
    currentVoltageIndex = currentVoltageIndex +1; //increment index
    if (currentVoltageIndex > 2) currentVoltageIndex = 0; //wrap-around to 0 instead of 3
    analogWrite(A14, voltage[currentVoltageIndex]); //output next voltage
    Serial.print("Changed output voltage to ");
    Serial.print( (voltage[currentVoltageIndex] / 4095.0 * 3.3);
    Serial.print(" V at ");
    Serial.print(millis());
    Serial.println(" ms");
}

I *think* this is what you want. I haven't tested this code, there may be some errors in it, but I hope you can see my train of thought.
 
Hi Ben,

Wow I really appreciate your comprehensive answer & support. I spent several hours reviewing the code last night & eventually managed to get it working (the several hours was not because your code had so many errors it was because I am rubbish at programming... :) ). I really like the idea of using the millis function & use of arrays - very neat.

The code almost does what I want. The only issue is that the sequence is not quite correct. I want to execute the first voltage just Once followed by 10 X repeats of the 2nd & 3rd voltages before repeating the whole thing again. If you look in my original code I had a loop counting to 10 to do this.. Not quite sure how to implement using your array approach?

Again any tips really appreciated.

Many thanks again, John
 
Last edited:
Just had a quick thought & I guess I could just increase the length of the voltage & duration arrays to include additional elements - something like:

int voltage[3] = { 3103, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030...... etc. };
int duration[3] = { 1000, 5000, 2000, 5000, 2000, 5000, 2000, 5000, 2000, 5000, 2000.....etc.};

but doesn't seem like a neat solution....?

John
 
You really should go back to school and learn C programming... ;)

When you increase the content of an array to for example 8 elements { 3103, 515, 1030, 515, 1030, 515, 1030, 515 }, you have also to declare it with 8 elements like this: int voltage[8] = ...
 
Ha... Yes you are correct - That was just a typo when I wrote the message.. I had the correct code on my Teensy... :) Thks & Yes I should definitely go back to school - John :)
 
Hi Ben,
'
I have one more quick question which I don't know if you can help with. I noticed that the width of the pulses I produce on the Analog write port is not consistent. I have been looking into & I think it is because you reset sinceWrite = 0 after update however, as I understand it would be more accurate to subtract duration[currentVoltageIndex] - but I can't do this cause sinceWrite is of type elapsedMillis and
duration[currentVoltageIndex] is type float.

Do you have any idea how to do this? My full code is as follows:

float voltage[21] = { 3103, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, 515, 1030, };
float duration[21] = { 100, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, 500, 150, };


int currentVoltageIndex = 0; //can be 0, 1 or 2
int analogInPin = A0;

elapsedMillis sinceRead;
elapsedMillis sinceWrite;







void setup() {
analogWriteResolution(12);
analogReadResolution(12);
Serial.begin(115200);
}

void loop() {

if (sinceRead >= 500) {
sinceRead = sinceRead - 500; //reset the timer
int value = analogRead(analogInPin);
Serial.print("Reading pin ");
Serial.print(analogInPin);
Serial.print(" at ");
Serial.print(millis());
Serial.print(" ms: ");
Serial.println(value);
}


if (sinceWrite >= duration[currentVoltageIndex]) {
sinceWrite = 0 ; //reset the timer
currentVoltageIndex = currentVoltageIndex + 1; //increment index
if (currentVoltageIndex > 20) {
currentVoltageIndex = 0; //wrap-around to 0 instead of 3
}
analogWrite(A14, voltage[currentVoltageIndex]); //output next voltage
Serial.print("Changed output voltage to ");
Serial.print( (voltage[currentVoltageIndex] / 4095.0 * 3.3));
Serial.print(" V at ");
Serial.print(millis());
Serial.println(" ms");


}

}
 
OK Ben - Managed to find where problem is - It was with all the Serial.print commands in the main loop - These obviously add delays to main loop which resulted in somewhat inaccurate pulse outputs on A14. I commented out all these commands & prog works great even if make the durations into single digit msecs...

Am happy :) Thks
 
If you need more precision, you could use elapsedMicros, and multiply all your numbers by 1000.

Best to use "unsigned long" instead of "float" for the array type. You ought to be able to achieve about 10 to 20 us precision, when the effects of USB communication interrupts are present.

IntervalTimer with elevated interrupt priority could allow you to get better than 1 us precision, but programming with interrupts is much harder.
 
Thank you Paul I will give it a go - learnt so much already just with this simple little project :) Great fun & looking to learning more. Cheers, John
 
Hey Paul you are right :) just gave it a quick go & achieved stable 20 usecs pulses on A14 output..... Nice - way too fast for this project but nice to know... Thks, John
 
Status
Not open for further replies.
Back
Top