Hi!
I am trying to repurpose this project https://www.makingstuff.info/Projects/Digital_Calipers
into something else that records the data and RTC time on an SD card every 10 minutes.
The problem is that the moment I modify the code in a wat that increases the loop run time the data is no longer readable.
Please can some one try to tell me how or where in the code I could insert a "delay(100);" that does not affect the data read? I am just asking for this, I just want to understand the code and make possible to do other things while I read the calipers data.
Here is the code:
//Digital caliper code to read the value off of a cheap set of digital calipers
//By Making Stuff Youtube channel https://www.youtube.com/c/makingstuff
//This code is open source and in the public domain.
const byte clockPin = 2; //attach to clock pin on calipers
const byte dataPin = 3; //attach to data pin on calipers
//Milliseconds to wait until starting a new value
//This can be a different value depending on which flavor caliper you are using.
const int cycleTime = 32;
unsigned volatile int clockFlag = 0;
long now = 0;
long lastInterrupt = 0;
long value = 0;
float finalValue = 0;
float previousValue = 0;
int newValue = 0;
int sign = 1;
int currentBit = 1;
void setup() {
Serial.begin(115200);
pinMode(clockPin, INPUT);
pinMode(dataPin, INPUT);
//We have to take the value on the RISING edge instead of FALLING
//because it is possible that the first bit will be missed and this
//causes the value to be off by .01mm.
attachInterrupt(digitalPinToInterrupt(clockPin), clockISR, RISING);
}
void loop() {
if(newValue)
{
if(finalValue != previousValue) {
previousValue = finalValue;
Serial.println(finalValue,2);
}
newValue = 0;
}
//The ISR Can't handle the arduino command millis()
//because it uses interrupts to count. The ISR will
//set the clockFlag and the clockFlag will trigger
//a call the decode routine outside of an ISR.
if(clockFlag == 1)
{
clockFlag = 0;
decode();
}
}
void decode(){
unsigned char dataIn;
dataIn = digitalRead(dataPin);
now = millis();
if((now - lastInterrupt) > cycleTime)
{
finalValue = (value * sign) / 100.00;
currentBit = 0;
value = 0;
sign = 1;
newValue = 1;
}
else if (currentBit < 16 )
{
if (dataIn == 0)
{
if (currentBit < 16) {
value |= 1 << currentBit;
}
else if (currentBit == 20) {
sign = -1;
}
}
currentBit++;
}
lastInterrupt = now;
}
void clockISR(){
clockFlag = 1;
}
You are right, It is not included. I wanted to simplify the problem for those that tried to help.
My goal is to be able to do things like set the device to sleep write on a card or just use a delay(1000). The problem is that this breaks the timing of the readings, note that the code reads bits of information one by one after a clock flag. If you use the anything that delays this cycle then the reading is not happening. I want to understand better the code so I can add things onto it.
To begin, I would like to get help to add a delay(1000) without affecting the reading. adding the SD code will be very easy for me after that. Thank you!
one approach could be to setup a timer-interrupt that occurs fast = often enough to sample each bit.
and therefore the frequency of the clock-signal must be known.
no sure but would this not be a better way 'read in' the bit steam...
(compiles, NOT tested)
//Digital caliper code to read the value off of a cheap set of digital calipers
const byte clockPin = 2; //attach to clock pin on calipers
const byte dataPin = 3; //attach to data pin on calipers
uint8_t currentBit = 0;
const uint32_t dataReady = 0xFFE00000, signBit = 0x00100000;
volatile uint32_t dataIn;
uint32_t Mask = 1, previousValue = 0, isrTime = millis();
void setup() {
Serial.begin(115200);
pinMode(clockPin, INPUT);
pinMode(dataPin, INPUT);
//We have to take the value on the RISING edge instead of FALLING
//because it is possible that the first bit will be missed and this
//causes the value to be off by .01mm.
attachInterrupt(digitalPinToInterrupt(clockPin), clockISR, RISING);
}
void loop() {
uint32_t temp = dataIn;
if (temp & dataReady)
{
if (previousValue != temp) {
previousValue = temp;
float measurement = (((temp << 1) & (~dataReady)) >> 2) / 100.0;
if (temp & signBit) measurement *= -1;
Serial.println(measurement);
}
}
}
void clockISR() {
if (millis() - isrTime > 32) currentBit = 0; //time between 2 data streamss output approxx 115ms
isrTime = millis();
if (currentBit++ < 24) {
if (currentBit == 1) dataIn = 0;
if (digitalRead(dataPin)) dataIn |= Mask;
Mask <<= 1;
}
if (currentBit == 24) {
Mask = 1;
currentBit = 0;
dataIn |= dataReady;
}
}
IMHO is would then be easier to add other bits of codes (like saving to SD card) to it...
one approach instead of using delay is to only 'save to SD card' on every count of the received measurement ie based on the link shared in post #9, you should get approximately 8 measurements per second so if you want to save one measurement every second then only save every 8th measurement.
in another tutorial people said it is 100miliseconds . When the code is running "as is" I get a reading every 131,5 miliseconds. If I alter that timing more than a milisecond I dont get a reading
yes, right now that is what i am doing and it does the job but it was not as staright forward as you you and I thought. However this solution does not allow me to power down the devices and save battery. I know how to make all the components sleep, that is why I am only asking people to help me understand how to insert a "delay(1000)"
If I understood your approach, you doubled the "cycletime" and hope that this will delay the measurement. I tried this because I understood the code the same way as you but it does not work, the reading becomes 0.
I have an oscilloscope and I have messed around with the code a lot. I understand somewhat the code, that is why is so puzzling that anything I try is not working
it's hard to understand what you want here as you are not sharing any code (or even some form or pseudo code!)
If you are able to make ur devices sleep, then why not 'wake' them up every 1000ms and then capture/save the first reading received after 'wakeup' and then go back to sleep?
There are programming-tecniques that you do not yet know and understanding them requires to learn something new.
This programming-technique is not a variation of basic commands. It is something new. And this new needs some time to learn.
The code that you posted uses an interrupt that is caused by the signal-change of the clock-signal.
This single line of code is executed each time the clocksignal gos from LOW to HIGH = RISING
User @sherzaad posted a code-version that does not only set a flat but does reading in the bits of the dataline.
Did you at least test sherzaads code?
You should really test it and report what results you get.
There are 10 ways how some kind of "alter timing" can be coded.
It is crucial that you post your attempts what you have really coded.
You want to have this functionality
and you are asking for inserting a delay
it is not done this way
take a reading
make the microcontroller freeze for 1000 milliseconds
take a reading
make the microcontroller freeze for 1000 milliseconds
take a reading
make the microcontroller freeze for 1000 milliseconds
..
it is done this way:
take a reading as fast as you can (with the exact timing as in your code
check if more than 1000 milliseconds of time have passed by
when REALLY 1000 milliseconds have passed by store value on SD-card
if not just drop the reading
This means you take a lot of readings but you just drop all readings
that are "too early"
Only if 1000 milliseconds of time have really passed by you do something with the reading.
In this way the timing for reading stays the same as it already works
but you don't freeze the microcontroller with a dleay(1000)
you check very fast and very very often
have 1000 milliseconds passed by.
You can read the details how this is coded in this tutorial linked below
.You will still have some questions just ask them.
A different approach is to setup an interrupt that is not invoked on an IO-pin changing from LOW to HIGH but that is invoked once every x milliseconds.
For setting up how many milliseconds depends on at what time-intervalls the clock-pulses occur and how long one clock pulse is.
This timer-interrupt must occur fast enough to detect each HIGH-time of the clock-pulses.
example-numbers: the clock-pulse is HIGH for 30 milliseconds
The timer-interrupt must be invoked minimum once every 15 milliseconds. Better every 10 milliseconds.
It depends on your microcontrollers own clock-frequency and on the frequency of the DRO-meter if this method works.
This is the reason why I asked for the frequency of the clock-signal.
And you sould clearly post what exact type of microcontroller you are using. Because setting-up such a timer-interrupt is different for each microcontroller-type.
Thank you for the reply and Stephan’s
. I will try to get the timing of the clock for you. So far I can tell you that I am successfully able to make an if the way you suggested, by making a lot of measurements but only showing one every N seconds. I am also now able to save things onto an SD card by adding the sd.print() code into the decode function.
I tried also to print the bits that are read and then converted into the value. Those bits are 16 in this version of the code and it takes 131 ms to read them.
My problem I guess is that I don’t understand how code works
What is clockflag used for?
How does clock pin interrupt works?
I believe that if I am able to tell when the first bit is coming I can read the data.
ultimately I what to be able stop and start making readings , and one example of this is inserting somewhere a delay(1000) , which I haven’t been able yet
using a delay in this case will be difficult because delay() freezes the microcontroller.
It is done by using a variable that is set to values that mean "on" or "off"
and then making readings is only done if the condition myVariable == readingsOn
is true
you want to modify an existing code.
If you want to become independant of getting each and every detail presented by other users the way is to learn programming yourself.
And the basic things are not learned with this application.
They are best learned with much easier examples that don't use interrupts etc.
It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.
as a short and therefore maybe still hard to understand explanation.
An interrupt does what the name says:
interrupt the actual code regardless of which line of code gets executed in the interrupting moment and start executing the code inside the interrupt-function.
If the interrupt-function has finished go on executing the code that was interrupted as no interruption would have happened.
This is the way to catch the first bit. Through using the interrupt on the signal makes possible to catch the moment when data-transmission starts