Search code examples
cpointersstructurestm32

RTC value in stm32 Nucleo


I'm trying to print RTC date and time on Tera Term. But I'm getting errors mentioned in code. Also nothing is being printed on Tera term. I have used pointer as the declaration for Setdate and Getdate have mentioned. Also there are few warning such as 1)format '%d' expects a matching 'int' argument [-Wformat=] 2)passing argument 2 of 'HAL_RTC_GetDate' from incompatible pointer type [-Wincompatible-pointer-types] 3)passing argument 2 of 'HAL_RTC_SetDate' from incompatible pointer type [-Wincompatible-pointer-types]

#include "main.h"
#include "stdio.h"

//uint8_t Time[6]="HH:MM:SS";
//uint8_t Date[6]="DD/MM/YY";
int main(void)
{
  /* USER CODE BEGIN 1 */
    typedef struct
    {
      uint8_t Month = 0x03;
      uint8_t Date = 0x24;
      uint8_t Year = 0x21;
    }Date_struct;
  uint8_t *Date;
  Date = &Date_struct;  Error: Expected expression before Date_struct

HAL_RTC_SetDate(&hrtc, &Date, RTC_FORMAT_BCD);
  while (1)
  {
      HAL_RTC_GetDate(&hrtc,&Date, RTC_FORMAT_BCD);
      HAL_Delay(1000);
  }
}

Solution

  • I frankly don't have experience with Tera Term in particular, but I've programmed Atmel MCUs before and there seem to be issues with your general C code, rather than the MCU functions. The C compiler errors can be often hard to read, but I can see you're mixing up the structure definition, declaration and initialization, as well as struggle with pointers.


    Consider the following plain C code and let's go over the differences with yours.

    #include <stdio.h>
    #include <stdint.h>
    
    int main(void)
    {
        struct date_struct
        {
            uint8_t month;
            uint8_t date;
            uint8_t year;
        }; // Define a structure named date_struct
    
        typedef struct date_struct date_struct_type; // make 'struct date_struct' into a new type
    
        date_struct_type date; // Declare a variable of the new type
    
        date.month = 0x03; // Initialize the fields of the variable
        date.date = 0x24;
        date.year = 0x21;
    
        date_struct_type * date_ptr; // Create a new pointer to the struct
    
        date_ptr = &date; // Assign the address of the variable to the pointer
    
        // Use the pointer to adress the structure's values
        printf("Month: %d\nDate: %d\nYear: %d\n", date_ptr->month, date_ptr->date, date_ptr->year);
    
        // ... or pass the pointer into any hypothetical function
        // func(date_ptr);
    
        // ... or pass a reference to the structure, but never a reference to the pointer
        // unless you know that you need it!
        // func(&date);
    
        return 0;
    }
    

    In your code, you first define an anonymous local structure and immediately typedef it to create a new type. That means, from that point on, you work with the structure as if it was just a variable type.

    In my code, I split up the structure definition and the typedef into two individual statements. That code is identical to writing

    typedef struct date_struct
    {
        uint8_t Month;
        uint8_t Date;
        uint8_t Year;
    } date_struct_type; // Define and typedef a structure at the same time
    

    ... or we can even leave the structure's name out and leave it anonymous - like you did in your code - we don't need it named at all since we already have a new type made out of it that we can use.

    typedef struct // <-- leave out the name
    {
        uint8_t Month;
        uint8_t Date;
        uint8_t Year;
    } date_struct_type; // Define and typedef a structure at the same time
    

    However, a structure definition is a "template" that tells the compiler how to allocate and access the structure in memory. The definition itself doesn't store any values and as such, we can't assign to it. We first need to declare a variable of that type*.

    date_struct_type date;
    

    * C is a very wild language, and you can do and use all sorts of shorthands, such as this. However, I strongly recommend against doing this when you're just starting out (and also in the future), as it's really not needed and is harder to read, maintain and debug.

    With the variable in place, we can finally assign our values to the individual elements of the structure. When accessing members of a structure we use the member reference operator - ..

    date.month = 0x03;
    date.date = 0x24;
    date.year = 0x21;
    

    Now we're moving to pointers and the two magical operators - * and & in C, that often cause a lot of headaches.

    In your code, you've successfully declared a pointer with this: uint8_t *Date;. Here, the * is not an operator, it signifies the variable holds a pointer - in other words, the uint8_t *Date; says "There is a variable named Date and it will hold an address of a uint8_t variable somewhere in the memory".

    However, that is not what we intend - we want to point to our new structure, not the uint8_t. Pointers all have the same size (in your case 32 bits on the smt32 platform), so it works, but that's what's setting off the "incompatible pointer type" warnings of your compiler.

    Instead, we should declare a pointer of the same type as the variable we intend to "point at" using this pointer. We'll once again split up the declaration and assignment statements for clarity - we're doing two things, writing them as one statement is just a shorthand.

    date_struct_type * date_ptr;
    

    The assignment is where the & operator comes into play. The & operator takes any variable and returns an address to it - which is exactly the thing we want to store inside our pointer.

    date_ptr = &date;
    

    Now whenever we want to pass a pointer to our new structure, either we use the one we just created - date_ptr, or directly pass a reference to the structure - &date. Both are viable, but be sure to not mistakenly write this: &date_prt. This gives you a pointer to a pointer, which is not something you usually want.

    A few more things. When accessing member of a structure through a pointer to that structure, we have to use a structure dereference operator - ->. That's why the printf statement contains -> operators instead of just ..

    I'm sure with this you can tweak your code to have it work. There shouldn't be any more issues in your function calls and the infinite while loop, just pay attention which pointers are you passing into the HAL_RTC_SetDate and HAL_RTC_GetDate functions. Do ask in the comments if there's still anything unclear or not working!