Down FOR loop doesn't stop counting

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

I think this Atmel Studio related

 

I have struck yet another problem with my code - this time I have a for loop that counts down from 7 to 0 but doesn't stop at zero - it just keeps going!!!!

 

I have made a new project in AS/MS (below) to simulate my actual code and I would be grateful if someone would cut and paste to a 329P or 2560 and see if it does the same thing for them. 

 

I have included screen grabs to show my outputs. You will notice that the actual code from the array does print out as wanted but not really the point when I want an 8byte output.

 

/*
 * Basic Test Loop.c
 *
 */

 #define F_CPU 16000000UL	// Define MCU clock speed (for delays only)

#include <stdint.h>			// Needed for uint8_t
#include <avr/io.h>			// AVR Pin and Register Names
#include <util/delay.h>		// Usage -> milli Seconds  = '_delay_ms(50);' micro Seconds = '_delay_us();'

uint8_t ROM_NO[10] = {'A','B','C',0x44,0x45,'F','G','H'};
//uint8_t i=0x07;

int main(void)
{
	 // uint8_t i;

	UCSR0B = 0x08;	// USART 0		=
	UCSR0C = 0x06;
	UBRR0L = 0X67;

	_delay_ms   (5);

 for (uint8_t i = 0x07;i >=0;i--)
			   {
					 _delay_ms(125);
					  UDR0 = ROM_NO[i];
			   }

	  /*for (i = 7;i >= 0;i--)
			 {

					 while ( !( UCSR0A & (1<<UDRE0)) )
					 ;
					 UDR0 = ROM_NO[i];
			 }

	 	  */

    /* Replace with your application code */
    while (1)
   ;
   return 0;
}

2560 Version

 

328P Version

 

 

I've stopped the outputs scrolling on both to take the screen grab.

 

Additionally, on the 328P version I get 10-11 bytes of crap before my 48......41 desired output is displayed.

 

I tried to download and configure Codeblocks for use with AVR and MinGW compiler to test the above routine but I couldn't get it to build.

 

I have no idea what's going on any thoughts

 

Thanks

 

 

This topic has a solution.
Last Edited: Sat. Jan 23, 2021 - 08:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Go on.   An unsigned variable is ALWAYS positive.

If you want an end-condition,  you use > 0 .  Then it will stop at 0.

 

Your head will hurt less if you think in terms of loop passes.

e.g.  if you want 8 loops

for (uint8_t count = 0; count < 8; count++) { ... }

for (uint8_t count = 8; count > 0; count--) { ... }

The second is probably more efficient but I would just choose the style you feel happiest with.

The Compiler will do a good job if you give it simple, clear statements.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to use int8_t not uint8_t for i.   For uint8_t i = 0, i -1 = 255.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When counting down, using int8_t is probably less brain hurting.

To count down from 7 to 0 using unsigned type then you can do

    for (uint8_t x = 8; x--; )

 

which is equivalent to

    for (uint8_t x = 8; x != 0; )
    {
        /* decrement x first thing */
        x--;
      
    }

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi David 

 

Sorry I don't understand the context of your 'Go on' statement.

 

 An unsigned variable is ALWAYS positive.

 

Right so you can count up and include zero but cannot count down and include zero so presumably it never gets to zero, jumps out when zero or the Zero register isn't set - interesting subtlety.

 

Anyway, based on your reply I changed my 'uint8_t' to a 'signed char' and used a -1 instead of 0 - all sorted.

 

Thank you

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Of course it gets to 0 but your test was ">=". For 1 to 255 the > bit is true and for 0 the = bit is true so it's ALWAYS either greater than or equal to 0. The loop never ends.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When the uint8_t decrements from zero it becomes 255 (0b11111111)  That is just the way that things work.

 

An int8_t decrements from zero it becomes -1 (0b11111111)

 

You just have to be careful when you decrement from zero.

Equally,  you have to be careful when you increment from 255.

 

As I said in #2.   Keep to simple numbers that humans are happy with.   e.g. count from 1 to 8

You can hand trace the for loop with pencil and paper.

Always check the limits of any sequence.   e.g. start, start+1,   end, end+1

 

This quite possible to do this even for big loops.   You are only calculating 4 values.

 

Oh.   I am sure that everyone on this Forum has encountered the <= 0 or > 255 feature of uint8_t

Put it down to experience !!

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Docara wrote:
... if someone would cut and paste to a 329P or 2560 and see if it does the same thing for them.
Confirmed though by a linter producing an error on the 'for' that indicates an infinite loop.

#include <stdint.h>

uint8_t UDR0;
uint8_t ROM_NO[8] = {'A','B','C',0x44,0x45,'F','G','H'};

int main() {
for (uint8_t i = 0x07;i >=0;i--)
			   {
					  UDR0 = ROM_NO[i];
			   }
}

Correction is from uint8_t to int8_t.

 


PC-lint Plus Online Demo - Gimpel Software - The Leader in Static Analysis for C and C++ with PC-lint Plus

 

"Dare to be naïve." - Buckminster Fuller