Maker Pro
Maker Pro

rand function in AVR C

NMNeil

Oct 3, 2014
111
Joined
Oct 3, 2014
Messages
111
This is a section of code that's giving me problems in a project and I can't work out why.
The purpose is to use the rand function to generate a number between 1 and 100 then use this number to randomly alter the delay time that an led is on.

#include <util/delay.h>
#include <avr/io.h>
#include <stdlib.h>

#define led_port PORTB
#define led_DDR DDRB
#define led_pin PINB0



int main()
{
led_DDR |= 1 << led_pin; //set to output


while (1)
{
uint8_t ran_num = 0; //set the random number variable and clear it at each loop
ran_num = rand() % 100; //get a random number between 1 and 100 and put it into ran_num variable
led_port |= 1 << led_pin; //turn on the LED
_delay_ms(ran_num); //random number put into the delay function
led_port &= ~ 1 << led_pin; //turn the led off
_delay_ms(100); //slight delay before looping again
}
return 0;
}

I'm using Proteus 8 and have simplified my project to an LED to resistor to ground from PB01 as an indicator.
The code compiles no problem but when I run it chaos ensues with Proteus throwing a stream of literally thousands of identical warnings.
PC=0x003A [AVR CPU] LPM Accessed outside program memory
I changed Proteus to several different AVR MCU's, but it always gets the same response.
I have checked that I'm getting an integer between 1 and 100 from rand() and that if I change the _delay_ms() to a number rather than the ran_num it works fine.
An internet search turned up nothing.
What am I missing?
 

JWHassler

Dec 22, 2014
86
Joined
Dec 22, 2014
Messages
86
You are 'return'ing from main()... don't know if that's THE problem, but it's hardly ever a good idea
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,700
Joined
Nov 17, 2011
Messages
13,700
You are 'return'ing from main()... don't know if that's THE problem, but it's hardly ever a good idea
The compiler will remove the return() upon optimization as this line of code is never reached (the while loop is endles).

Code:
uint8_t ran_num = 0; //set the random number variable and clear it at each loop
This line is placed at the wrong location. There's no use in initializing the variable at each loop start as the next instruction will assign a new value to the variable.
Put this variable outside the while loop, e.g. directly before the while() statement.

Code:
ran_num = rand() % 100; //get a random number between 1 and 100 and put it into ran_num variable
This line will, contrary to the comment, generate a random number between 0...99.

Code:
led_port |= 1 << led_pin; //turn on the LED
...
led_port &= ~ 1 << led_pin; //turn the led off
I'm not quite sure about the operator precedence here, but I suggest you clarify your intention using parentheses like this:
Code:
led_port |= (1 << led_pin); //turn on the LED
...
led_port &= ~ (1 << led_pin); //turn the led off

Btw.: are you aware that the random numbers in the range 0... ~20 ms will not lead to a well perceptible blinking effect?
 

NMNeil

Oct 3, 2014
111
Joined
Oct 3, 2014
Messages
111
Thanks for your replies.
The return at the end of main is put there as a default by Proteus. Just to make sure I commented it out and it made no difference.
Put the bit shifting into parenthesis and made the ran_num variable global, that also made no difference.
Next step is to program an ATTiny 2313 hook up an led and see what happens. It could simply be a problem with Proteus.
 

NMNeil

Oct 3, 2014
111
Joined
Oct 3, 2014
Messages
111
Found the problem.
I went to upload a simple code just to test it using Atmel Studio 7. It said no. Seems that the _delay_ms or _us function can only take a direct integer, not a derived one.
Used a simple delay function from AVR freaks and it works just fine.
The electronics learner mantra.
"To learn electronics properly, fail and fail often. Then find out why you failed"
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,700
Joined
Nov 17, 2011
Messages
13,700
Seems that the _delay_ms or _us function can only take a direct integer, not a derived one.
No, _delay_ms requires a double as argument. The complier probably converts a supplied interger implicitly to double without making any fuss about it. But when you use a variable, teh type should match, otherwise the CPU will try to access a double where only an ineger is stored which may lead to access conflicts.
 
Top