Proper use of pointer in C (Atmel studio7)

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

I need help with use of pointers for accessing a variable using the pointer(s) in the atmel studio7 (in C). Should I use (continue to use) pointers in my codes, or just use direct access to the variables (because in many code examples on the net, I don't see that pointers are used), like in the code below (code also works without pointers)? Is it better to use pointers or not? I had noticed that *p_mode++; don't work and mode++; work well, is that a bug in Atmel studio?

Also I have noticed that PWM is never 0 or 100% with this code, maybe someone have any tips why?

Tnx


#define F_CPU 1000000UL 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define LED_ON PORTB |= (1<<PORTB0)
#define  LED_OFF PORTB &= ~(1<<PORTB0)
#define  LED_TOGGLE PINB|=(1<<PINB0)

void PWM_init (void);

uint16_t duty;
uint16_t *p_duty = &duty; // Is there need for use pointer?

uint8_t A = 1;      
uint8_t *p_A = &A;  // Is there need for use pointer?

uint8_t mode = 1; 
uint8_t *p_mode = &mode; // Is there need for use pointer?

//----------------------------
int main(void)
{
    DDRB |=(1<<DDB0);
    
    DDRB &= ~(1<<DDB2);
    PUEB |=(1<<DDB2);
    PUEB |=(1<<DDB1); 
    
    sei(); 
    
    PWM_init(); 
    duty = OCR0B;

    while (1) //Infinite loop
    {

//MOD 1-----
        if (*p_mode == 1)
        {
            if (duty < 800)
            {
                duty++;
            }
            else
            {
                duty = 0;
            }
            _delay_ms(2);
        }
//MOD 2----

        if (*p_mode == 2)
        {
            if (duty > 1)
            {
                duty--;
            }
            else
            {
                duty = 799;
            }
            _delay_ms(2);
        }

//BUTTON-----
    
        if (!(PINB & (1<<PINB2))) 
        {
            mode++; // *p_mode++;  Bug? It change the adresss of p_mode!
            if (*p_mode > 2)
            {
             *p_mode = 1; // here pointer vorks (value is added to variable mode)
            }
            _delay_ms(1000); 
        }

    OCR0B = duty;
    }
}

//+++++++++++++++++++++++++++++++++++++++

void PWM_init (void)
{
    TCCR0B |= (1<<CS00) | (1<<WGM02);
    TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B); 
    OCR0A = 800;  
}

ISR(TIM0_COMPA_vect) 
{
    LED_ON; 
}

ISR(TIM0_COMPB_vect) 
{
    LED_OFF;
}

 

This topic has a solution.
Last Edited: Sun. Jan 28, 2018 - 12:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In your code there is no use of using pointers whatsoever.

p_duty isn't even used at all (text search). Did you dumb your code down for the example?

 

It's hard to understand pointers and it is even harder if you don't have a good example or need for them.

If there is no real need for pointers, it's always better to avoid them.

By avoiding unneeded pointers your code is easier to read for human beings, and you've eliminated one of the biggest sources of bugs in C.

 

Pointers are mostly used to index data in array's.

They are also used in function arguments, but there it's often better practice to use references.

 

For learning about pointers, some quality reading should be the first start.

Then get yourself an IDE with an integrated debugger and write some simple programs on your main PC before attempting it on an AVR.

 

I use pointers every now and then when needed, but after 20 years I still find them confusing sometimes.

It's the nitty gritty details. For exeample I always tend to confuse the precedence of operators.

 *p_data++;     // What does this do?
 (*p_data)++;  
 *(p_data++);

// Just to be clear I always split stuff into multiple lines just to avoid confusion:

p_data++;        // Increment the pointer (in an arrar).
ret = *p_data;   // Assign the by p_data pointed value to ret.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

Last Edited: Fri. Jan 26, 2018 - 02:39 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gpugelni wrote:
I need help with use of pointers for accessing a variable using the pointer(s) in the atmel studio7 (in C). Should I use (continue to use) pointers in my codes, or just use direct access to the variables (because in many code examples on the net,

This might be just about language, but first you state that you need pointers, and then you ask if you need them. Which one is it?

 

I assume you are asking if you need pointers. The answer is: It depends

 

The pointer is a very generic tool in the "C tool box":

- They are used when dynamic memory allocation is used (and dynamic allocation is rare for small embedded systems).

- They are the underlying technology for accessing elements of an array (but you don't need to know that, just access array elements using the usual indexing operator [ ] )

- They are, implicitly, when an array is passed as a parameter for a function

- They are used, explicitly by the person writing the code, when a large object needs to be passed to a function as a parameter (rather than passing the object per se, a pointer to the object is passed).

- They are used when an object is passed to a function as a parameter, and the function does changes the object and these changes needs to be permanent after the function has returned (again, rather than passing the object per se, a pointer to the object is passed).

 

So.. Given it great generality, there is no simple answer to when pointers should be used or if they are necessary.

 

The simple answer is: You don't need to use pointers unless you need them ;-) My point is - if you're not in a situation here you have a problem you can't solve then you don't need pointers.

 

Right now it sounds like you have a hammer in your hand and are running around searching for a nail. Don't do that. The habit generates bad code ;-)

 


 

gpugelni wrote:
I had noticed that *p_mode++; don't work

It works just fine if you use it correctly. It will get the value that the pointer points to, and then the pointer itself will be incremented.

Unless you give a minimal but complete program that demonstrates a problem you have with that operation all discussions beyond this is meaningless.

 


 

Looking at the program you posted, none of the pointers are needed as far as I can see. Just access the duty, A and mode variables directly.

 


 

gpugelni wrote:
Also I have noticed that PWM is never 0 or 100% with this code, maybe someone have any tips why?

You need to tell us what AVR model you're using, or we can say very little.

 

Very little might be this: Timers can have a hard time, by design, to generate 0% duty cycle of a PWM signal (i.e. a signal steady low). If you want to obtain that, simply turn off the timer (often accomplished by turning off the input clock, by a special prescaler value) and then set the pin low using digital I/O.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Paulvdh wrote:
In your code there is no use of using pointers whatsoever.
+10

 

The reason you use pointers is because you need to able to pass the address of something between two modules so that the receiver can make modifications to something "owned" by the invoker.

 

You aren't using them in this way. If you wanted to get real mad you could do:

uint16_t duty;
uint16_t *p_duty = &duty;
uint16_t **p_p_duty = &p_duty;
uint16_t ***p_p_p_duty = &p_p_duty;

...

 ***p_p_p_duty = 12345;

but how would that actually be any "better" than the obvious:

uint16_t duty;

...

 duty = 12345;

Sure, if you want to deliberately obfuscate the code then go ahead. Otherwise forget it. The place you do want to use pointers is in something like:

void invoke_function(uint16_t *);

int main(void) {
    uint16_t error_count = 0;

    while (1) {
        invoke_function(&error_count);
        if (error_count > 10) {
            die_violently();
        }
}

void invoke_function(uint16_t * err_cnt) {
    if (do_something() == BIG_PROBLEM) {
        *err_cnt++;
    }
}

In this code "error count" is "owned" by main(). If it invoked the function with:

while(1) {
    invoke_function(error_count);
}

(where the function takes a value not a reference) then sure invoke_function could READ the current state of error_count but it could not write back to it (it's only passed in 3 or 7 or 8 or whatever - a value - the called function doesn't know where the variable lives so cannot change it).

 

By using

    invoke_function(&error_count);

that actually passes the location in RAM of the error_count variable into the function. So now, in the invoke_function code it can choose to either read or even write back into that variable as it knows where it is located (a "pointer" points to the place in memory where it lives).

 

That is when pointers are useful. But in your example you are over-complicating and making the code less efficient for no apparent gain.

Last Edited: Fri. Jan 26, 2018 - 04:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another example:

 

The XMEGA peripherals are defined as structures in the file iox<nnn>.h.  This makes it easy to use the same code for multiple instances of a peripheral by passing a pointer to the peripheral.  The XMEGA A family MCUs have up to eight USARTs, but the same functions can be used to Rx or Tx:

 

#include <avr/io.h>

char usart_get(USART_t *usart)
{
    while (!(usart->STATUS & USART_RXCIF_bm));
	
    return usart->DATA;
}

void usart_put(USART_t *usart, char d)
{
    while (!(usart->STATUS & USART_DREIF_bm));
	
    usart->DATA = d;
}

int main(void)
{
    // initialize USARTs C0, C1, D0, D1
    while (1) 
    {
	usart_put(&USARTC1, usart_get(&USARTC0));
	usart_put(&USARTD0, usart_get(&USARTC1));
	usart_put(&USARTD1, usart_get(&USARTD0));
	usart_put(&USARTC0, usart_get(&USARTD1));
    }
}

 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

Tnx all for replay. I was forgot to specify the name of MCU it's mighty ATtiny10, this is why is code so small and it is complete.

Also I'm programming Atmel MCU's for a long preiod, but no in C, now I must because of job, and I always wanted to learn C for AVR, so here I am.

 

JohanEkdahl wrote:
I assume you are asking if you need pointers. The answer is: It depends

Yes that is correct. Thanks for your explanation, it was very useful for me.

 

JohanEkdahl wrote:
Right now it sounds like you have a hammer in your hand and are running around searching for a nail. Don't do that. The habit generates bad code ;-)

smiley

 

JohanEkdahl wrote:
It works just fine if you use it correctly. It will get the value that the pointer points to, and then the pointer itself will be incremented. Unless you give a minimal but complete program that demonstrates a problem you have with that operation all discussions beyond this is meaningless.

I probably don't use it correctly. Code which I posted is complete, and work on the ATtiny10.

 

JohanEkdahl wrote:
You need to tell us what AVR model you're using, or we can say very little.

My mistake, ATtiny10.

 

--------------------------

 

Paulvdh wrote:
If there is no real need for pointers, it's always better to avoid them.

Good to know.

 

Paulvdh wrote:
Then get yourself an IDE with an integrated debugger and write some simple programs on your main PC before attempting it on an AVR

Because off this I have a hammer in my hand and running around searching for a nail.smiley

 

Paulvdh wrote:
I use pointers every now and then when needed, but after 20 years I still find them confusing sometimes. It's the nitty gritty details. For exeample I always tend to confuse the precedence of operators.

Tnx for tips!

 

--------------------------

 

clawson wrote:
but how would that actually be any "better" than the obvious:

That is what I was thinking, but wasn't sure in that.

 

clawson wrote:
That is when pointers are useful. But in your example you are over-complicating and making the code less efficient for no apparent gain.

Tnx.

 

 

Last Edited: Fri. Jan 26, 2018 - 07:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pointers are useful when the address you are writing to can change.

For example:

 

void fill(char *bp, char ch, int len)

{

    while(len--)

        *bp++ = ch;

}

 

In this case the memory pointed to by bp is filled with ch.

 

In an embedded system, it is generally more common to use static allocations for memory and most everything else.

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

Note that all of this is standard, textbook stuff - not specific to AVR or Atmel Studio.

 

gpugelni wrote:
now I must because of job

IF it's for your job, then you really should invest in some proper 'C' training.

Time is money, and is better spent learning the necessary skills in a proper, structured way - rather than randomly picking topics and struggling with them.

 

Trivet wrote:

void fill(char *bp, char ch, int len)
{
    while(len--)
    {
        *bp++ = ch;
    }
}

In this case the memory pointed to by bp is filled with ch.

Indeed, a very common use of pointers is in communication tasks - where you tell the transmit function, "transmit the data from here"; and tell the receive function, "put the received data here".

 

Your programs would soon get very cumbersome if you had to write a separate transmit function for each and every variable that you wanted to send!

 

 

 

 

EDIT

 

Here are some 'C' learning & reference links: http://blog.antronics.co.uk/2011/08/08/so-youre-thinking-of-starting-with-c/

Last Edited: Tue. Jan 30, 2018 - 09:08 AM