Jump to content

Featured Posts

6 minutes ago, davidb said:

you will enjoy it - the hours fly by, but you will have something to show at the end of it!

 

yes, a bit like wasting away the evenings drinking cider, though I think a "Programming in C" headache is not quite as bad as a Henry Weston headache. 😀

 

.................Dave

Link to post
Share on other sites
5 minutes ago, buccaneer66 said:

Is the C headache as bad as an old rosie one.

 

Must confess I drink too much of the strong cider. Old Rosie is lower in alcohol than many of the "vintage ciders" but does give a very special headache. I think its because it comes in such a big bottle 😀

Link to post
Share on other sites
12 minutes ago, dmr said:

 

yes, a bit like wasting away the evenings drinking cider, though I think a "Programming in C" headache is not quite as bad as a Henry Weston headache. 😀

 

.................Dave

It's better when you mix the two, I think I wrote some of my best code at college after a good lunchtime session. Problem was I couldn't always work out how the code worked when I next looked at it.

Link to post
Share on other sites
15 minutes ago, dmr said:

 

You can see the library source code if you want to understand what is going on, or even customise it a bit,  or just copy the useful bits directly into your own code.

Most of the libraries are very nicely/properly written in a object oriented/computer science style (abstraction etc etc) and I am not convinced this is good when memory is in such short supply. Sometimes good old dirty code is the way to go 😀.

 

................Dave


yes a big think with C seems to be to make it transportable, but as you say, with limited resources and only one target micro, that is BS or at least not appropriate!

Link to post
Share on other sites
3 minutes ago, nicknorman said:


yes a big think with C seems to be to make it transportable, but as you say, with limited resources and only one target micro, that is BS or at least not appropriate!

 

Much of my early programming, and hardware interfacing, was done on an old Digico mini computer, a UK rival to the DEC PDP machines. This ran at about 5MHz and had 128kbyte of RAM  that had to hold the operating system, compiler and user software. Each user program had to live within an 8kbyte page. There was not much room for modern software niceties. A bit like an Arduino but in a much much bigger box.

 

................Dave

Link to post
Share on other sites
56 minutes ago, dmr said:

 

You can see the library source code if you want to understand what is going on, or even customise it a bit,  or just copy the useful bits directly into your own code.

Most of the libraries are very nicely/properly written in a object oriented/computer science style (abstraction etc etc) and I am not convinced this is good when memory is in such short supply. Sometimes good old dirty code is the way to go 😀.

 

................Dave

Just use a Teensy 3.6.  Loads of interruptable pins, loads of memory….  Arduino IDE compatible.

Link to post
Share on other sites
11 minutes ago, system 4-50 said:

Just use a Teensy 3.6.  Loads of interruptable pins, loads of memory….  Arduino IDE compatible.

 

I did look but I think the power consumption is a bit high??? For projects where power is not an issue the Teensy range looks really good.

 

..................Dave

Link to post
Share on other sites
11 hours ago, nicknorman said:


yes a big think with C seems to be to make it transportable, but as you say, with limited resources and only one target micro, that is BS or at least not appropriate!

When the arduino project first started there was only one microprocessor, so that was a valid criticism. These days there are a whole range of them that the Arduino IDE can compile too, built on to a variety of boards, official arduino and others. Don't forget that it started as and continues to be mainly an educational project and ease of use for newbies is the priority, not the tightest code, smallest memory use, fastest response, or lowest power consumption. If you absolutely need those, then other controllers are better.

Jen

Edited by Jen-in-Wellies
Link to post
Share on other sites
13 hours ago, Jen-in-Wellies said:

get rid of the huge number and lengths of delays in the sketch, so the program loops much more quickly.

So, I shall have a go at this for a start, am I correct in thinking that the processor runs through the whole program at it's best speed and each delay completely stops the process for that ampunt of time?

 

The blinking alarm light is perhaps the main feature of the project because it gives a remote indication of the need to attend to stoking, but that could easily be replaced with a flasher unit (like in an old car indicator) unless a separate flashing loop could be run within the Arduino.

Link to post
Share on other sites
20 minutes ago, davidb said:

So, I shall have a go at this for a start, am I correct in thinking that the processor runs through the whole program at it's best speed and each delay completely stops the process for that ampunt of time?

 

The blinking alarm light is perhaps the main feature of the project because it gives a remote indication of the need to attend to stoking, but that could easily be replaced with a flasher unit (like in an old car indicator) unless a separate flashing loop could be run within the Arduino.

Yes the processor runs at a fixed speed. A delay is created by the processor chasing its own tail round a “do nothing” loop so whilst it doesn’t stop, it is entirely consumed by the loop and can do nothing else (except service interrupts).

 

To deal with the flashing, consider having a variable that is incremented on each loop of the program. When the variable is below some value x the light is switched on, when the variable is above that value it is switched off, and then when it reaches a third value (2 x) it is set back to zero. The light will change state after x times round the main programme. The downside is that the flashing rate will depend on how long it takes the processor to go round the programme (which is why the best, though more complex solution is to use a hardware timer). But in your case I think the time taken by the programme will be fairly consistent and so the flashing rate will be pretty stable.

Edited by nicknorman
Link to post
Share on other sites
1 hour ago, nicknorman said:

When the variable is below some value x the light is switched on, when the variable is above that value it is switched off, and then when it exceeds reaches a third value (2 x) it is set back to zero

 

Always consider you might somehow manage to go twice round the loop without checking.

  • Greenie 3
Link to post
Share on other sites

@davidb, there is an example sketch in the Arduino IDE called BlinkWithoutDelay,  that uses millis() in the way we are suggesting. Go through it till it makes sense. The same approach can be extended to the other timing events you want to do. Much better way of doing it than the "Hello World" Blink sketch. I was at the same stage you were at a few years ago!

Jen

Edited by Jen-in-Wellies
Link to post
Share on other sites
14 hours ago, nicknorman said:

You are continuing to convince me that Arduinos are crap!

 

Not wishing to teach grandma, but perhaps it is an issue with variables needing the ‘volatile’ keyword? I’m sure interrupts must work on the Arduino, otherwise there would be outcry.

 

The advantage of the ISR to set flag, then poll flag in main routine, is that you can press the button any time, for a short time, and it will be captured, whereas with a fully polled system it might not be, unless you are wastefully polling the button very fast.

But interrupts (and concurrency in general) are powerful and dangerous magic. The button example is OK, but anything much more complex than that needs an understanding of locking, semaphores and race conditions. This is not beginner stuff.

 

MP.

 

ETA. My go-to technique for delays without blocking is the millis() function. At the start of the delay, record the the value of millis(), In the event loop keep checking until the new value of millis() is the recorded value, plus the required delay. Use the correct code to avoid problems with millis() wraparound. 

 

I keep intending to write a small timer-task system as an alternative: "callback this function in n ms" with a wait queue. That's more CPU efficient, since you can sort callbacks by time-to-run, and only check the first in the event loop.

Edited by MoominPapa
Link to post
Share on other sites
1 hour ago, nicknorman said:

Yes the processor runs at a fixed speed. A delay is created by the processor chasing its own tail round a “do nothing” loop so whilst it doesn’t stop, it is entirely consumed by the loop and can do nothing else (except service interrupts).

 

To deal with the flashing, consider having a variable that is incremented on each loop of the program. When the variable is below some value x the light is switched on, when the variable is above that value it is switched off, and then when it reaches a third value (2 x) it is set back to zero. The light will change state after x times round the main programme. The downside is that the flashing rate will depend on how long it takes the processor to go round the programme (which is why the best, though more complex solution is to use a hardware timer). But in your case I think the time taken by the programme will be fairly consistent and so the flashing rate will be pretty stable.

 

Using the millis() function (elapsed milliseconds since program started) is much better. Counting execution loops will change the timing if you expand/change the code, and be dependent on which IF clauses get executed etc.

 

There is a tiny problem in that millis will "roll over" once in a while (every few days I think) so the code should be written to cope with this. Its probably ok to have a tiny tiny chance of a bad flash once in a while but not to cause the software to lock up for several days.

 

.................Dave

Link to post
Share on other sites
17 minutes ago, dmr said:

 

Using the millis() function (elapsed milliseconds since program started) is much better. Counting execution loops will change the timing if you expand/change the code, and be dependent on which IF clauses get executed etc.

 

There is a tiny problem in that millis will "roll over" once in a while (every few days I think) so the code should be written to cope with this. Its probably ok to have a tiny tiny chance of a bad flash once in a while but not to cause the software to lock up for several days.

 

.................Dave

Roughly every three weeks with a long variable. You can code to avoid this being a problem with arduino projects that are going to be run all the time, like the OP's by coding correctly. Search for millis() rollover for various ways, but the best is to make the variable an unsigned long, rather than an integer. The sums still work, even when some of the numbers are now negative.

Edited by Jen-in-Wellies
Link to post
Share on other sites
13 minutes ago, dmr said:

 

Using the millis() function (elapsed milliseconds since program started) is much better. Counting execution loops will change the timing if you expand/change the code, and be dependent on which IF clauses get executed etc.

 

There is a tiny problem in that millis will "roll over" once in a while (every few days I think) so the code should be written to cope with this. Its probably ok to have a tiny tiny chance of a bad flash once in a while but not to cause the software to lock up for several days.

 

.................Dave

I catch the rollover (at the expense of a single inaccurate timing when it happens) by adding an extra check for millis being less than my previous recorded value or greater than the previous recorded value + the delay time

 

using the loop from blink without delay as an example my modification is in Red (original line in green).

 

void loop()
{
  // here is where you'd put code that needs to be running all the time.
 
  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {

  if((currentMillis - previousMillis > interval) || (currentMillis < previousMillis)) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
 
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }

Edited by Jess--
Link to post
Share on other sites
13 minutes ago, Jen-in-Wellies said:

Roughly every three weeks with a long variable. You can code to avoid this being a problem with arduino projects that are going to be run all the time, like the OP's by coding correctly. Search for millis() rollover for various ways, but the best is to make the variable an unsigned long, rather than an integer.

 

Yes, but an unsigned long will still fail but not quite so quickly 😀

 

Its a bit like a mini version of the famous millineum bug.

 

...............Dave

Link to post
Share on other sites
37 minutes ago, MoominPapa said:

But interrupts (and concurrency in general) are powerful and dangerous magic. The button example is OK, but anything much more complex than that needs an understanding of locking, semaphores and race conditions. This is not beginner stuff.

 

MP.

 

ETA. My go-to technique for delays without blocking is the millis() function. At the start of the delay, record the the value of millis(), In the event loop keep checking until the new value of millis() is the recorded value, plus the required delay. Use the correct code to avoid problems with millis() wraparound. 

 

I keep intending to write a small timer-task system as an alternative: "callback this function in n ms" with a wait queue. That's more CPU efficient, since you can sort callbacks by time-to-run, and only check the first in the event loop.

Yes there are potential dragons! My Alternator controller project gets the individual cell voltages from my BMS project over CANbus. CANBUS receive is interrupt driven and “mysteriously” write new values of cell voltage. These are 4 byte floating point number so imagine the mayhem that could very occasionally occur if the main loop chanced to be reading the cell voltage and had read the first one or two bytes, whereupon the interrupt service routine decides to change the number!

 

But for checking a button press, I don’t think it’s too difficult!

1 minute ago, dmr said:

 

Yes, but an unsigned long will still fail but not quite so quickly 😀

 

Its a bit like a mini version of the famous millineum bug.

 

...............Dave

Or gps week rollover bug

Link to post
Share on other sites
39 minutes ago, dmr said:

 

Using the millis() function (elapsed milliseconds since program started) is much better. Counting execution loops will change the timing if you expand/change the code, and be dependent on which IF clauses get executed etc.

 

There is a tiny problem in that millis will "roll over" once in a while (every few days I think) so the code should be written to cope with this. Its probably ok to have a tiny tiny chance of a bad flash once in a while but not to cause the software to lock up for several days.

 

.................Dave

Of course the millis() function uses a hardware timer and interrupts, it’s just that the hard work setting it up has been done for you!

 

I know I am always banging on about PICs but the MPLABX IDE has a thing called MCC, Microchip Code Configurator. You select which peripherals you want use, eg a timer. You specify the timer period and if you want it interrupt driven etc. The MCC creates the initialisation code enables the specific interrupt and adds a bare interrupt service routine to which you can add whatever you like. So for example if you want a delay of a second, it is better to have a 1 second timer rather than a 1mS timer which has to be serviced 1000 times to get the 1 second, especially if that means the CPU a can be dozing (saving power) whilst awaiting the 1s.

Edited by nicknorman
Link to post
Share on other sites
28 minutes ago, dmr said:

 

Yes, but an unsigned long will still fail but not quite so quickly 😀

 

Its a bit like a mini version of the famous millineum bug.

 

...............Dave

 

No, you can write code that calculates the _difference_ between two values from millis() and returns the elapsed time between them, even if the millis() value rolled over after the first call to millis() and before the second one. Of course if millis() rolled over more than once between the two calls, all bets are off. That's a non-problem in almost all cases.

 

MP.

 

 

Link to post
Share on other sites
2 hours ago, MoominPapa said:

 

No, you can write code that calculates the _difference_ between two values from millis() and returns the elapsed time between them, even if the millis() value rolled over after the first call to millis() and before the second one. Of course if millis() rolled over more than once between the two calls, all bets are off. That's a non-problem in almost all cases.

 

MP.

 

 

 

I was just saying that an unsigned long by itself is not a solution..

Most things can be fixed with suitable code.

As said in a previous post, one solution is to test for millis returning a lower value than the stored time and then applying the appropriate correction.

A problem I have when working with limited memory is deciding how much code and hence memory (and effort) should go into fixing something that will probably never happen. If the rollover just messes up a blinking LED then its no big deal. If its debouncing a switch and totally disables that switch for several days then its bad.

 

I have the same issue when writing proper code for the PC and doing error handlers/error messages. Sometimes I think an error is so obscure that its quite likely nobody will ever see my lovely error message.

 

.............Dave

 

,

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.