Connect with us

rand function in AVR C

Discussion in 'Microcontrollers, Programming and IoT' started by NMNeil, Nov 20, 2016.

Scroll to continue with content
  1. NMNeil

    NMNeil

    109
    10
    Oct 3, 2014
    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?
     
  2. JWHassler

    JWHassler

    78
    16
    Dec 22, 2014
    You are 'return'ing from main()... don't know if that's THE problem, but it's hardly ever a good idea
     
  3. Harald Kapp

    Harald Kapp Moderator Moderator

    9,902
    2,097
    Nov 17, 2011
    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?
     
  4. NMNeil

    NMNeil

    109
    10
    Oct 3, 2014
    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.
     
  5. NMNeil

    NMNeil

    109
    10
    Oct 3, 2014
    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"
     
  6. Harald Kapp

    Harald Kapp Moderator Moderator

    9,902
    2,097
    Nov 17, 2011
    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.
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-