Necesita ayuda para mejorar el código de AVR

1

Entonces, hay un código que escribí para un proyecto de Clock en el que estoy trabajando y que utiliza un ATMega328P y un DS1307 RTC.

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

typedef unsigned char   u8;
typedef signed short    s16;


#include "lcd.h"
#include "i2cmaster.h"
#define F_CPU 1000000UL

#define RTC 0xD0
#define KEY_PIN     PINB
#define KEY_PORT    PORTB
#define KEY_DDR     DDRB
#define KEY0        0
#define KEY1        1
#define KEY2        2
#define KEY3        3

u8 key_state;               // debounced and inverted key state:
                            // bit = 1: key pressed
u8 key_press;               // key press detect

ISR(TIMER0_OVF_vect)
{
    static u8 ct0 = 0xFF, ct1 = 0xFF;   // 8 * 2bit counters
    u8 i;

    i = ~KEY_PIN;               // read keys (low active)
    i ^= key_state;             // key changed ?
    ct0 = ~( ct0 & i );         // reset or count ct0
    ct1 = ct0 ^ (ct1 & i);      // reset or count ct1
    i &= ct0 & ct1;             // count until roll over ?
    key_state ^= i;             // then toggle debounced state
    key_press |= key_state & i;     // 0->1: key press detect
}
u8 get_key_press( u8 key_mask )
{
    ATOMIC_BLOCK(ATOMIC_FORCEON){       // read and clear atomic !
        key_mask &= key_press;      // read key(s)
        key_press ^= key_mask;      // clear key(s)
    }
    return key_mask;
}
uint8_t dec_to_bcd(uint8_t dec)
{   
    uint8_t x;
    x = ((dec / 10) << 4) + (dec % 10);
    return(x);
}
uint8_t bcd_to_dec(uint8_t bcd)
{
    return (((0xF0 & bcd)  >> 4)* 10) + (0x0F & bcd);
}
uint8_t set_sec_min()               // Set seconds and minutes.
{
    uint8_t sec_min;
    char buff[4];
    while(1)                        // Set seconds/minutes;
    {
        lcd_gotoxy(0,0);
        itoa(sec_min,buff,10);
        lcd_puts(buff);
        if( get_key_press( 1<<KEY1 ))
        {
            sec_min++;
        }
        if( get_key_press( 1<<KEY2 ))
        {
            sec_min--;
        }
        if( get_key_press( 1<<KEY3 ))
        {
            break;
        }
        if( sec_min > 59)
        {
            sec_min =0;
        }
    }

    return(sec_min);
}                               
void init_timer0()
{
    TCCR0B |= (1 << CS01);  // set /8 prescaler
    TIMSK0 |= (1 << TOIE0); // Enable overflow interrupt.
    sei();
}
void set_time()
{
    uint8_t seconds;
    uint8_t minutes;
    uint8_t hours;
    uint8_t day;
    uint8_t date;
    uint8_t month;
    uint8_t year;
    char buff[5];
    while(1)
    {
        lcd_clrscr();
        seconds = set_sec_min();
        lcd_clrscr();
        minutes = set_sec_min();
        lcd_clrscr();
        while(1)                        // Set hours;
        {
            lcd_gotoxy(0,0);
            itoa(hours,buff,10);
            lcd_puts(buff);
            if( get_key_press( 1<<KEY1 ))
            {
                hours++;
            }
            if( get_key_press( 1<<KEY2 ))
            {
                hours--;
            }
            if( get_key_press( 1<<KEY3 ))
            {
                break;
            }
            if( hours   > 12 | hours < 1)
            {
                hours = 1;
            }
        }
        hours = dec_to_bcd(hours);
        hours |= (1 << 6);              //Set 12 hour mode
        lcd_clrscr();
        while(1)                        // Set AM/PM;
        {
            lcd_gotoxy(0,0);
            if( get_key_press( 1<<KEY1 ) | get_key_press( 1<<KEY2 ) )
            {
                hours ^= (1 << 5);
            }
            if( get_key_press( 1<<KEY3 ))
            {
                break;
            }
            if(hours & (1 << 5))
            {
                lcd_puts("PM");
            }else
            {
                lcd_puts("AM");
            }
        }

        lcd_clrscr();
        while(1)                        // Set day;
        {

            lcd_gotoxy(0,0);
            itoa(day,buff,10);
            lcd_puts(buff);
            if( get_key_press( 1<<KEY1 ))
            {
                day++;
            }
            if( get_key_press( 1<<KEY2 ))
            {
                day--;
            }
            if( get_key_press( 1<<KEY3 ))
            {
                break;
            }
            if( day > 7 | day < 1)
            {
                day =1;
            }
        }

        lcd_clrscr();
        while(1)                        // Set date;
        {

            lcd_gotoxy(0,0);
            itoa(date,buff,10);
            lcd_puts(buff);
            if( get_key_press( 1<<KEY1 ))
            {
                date++;
            }
            if( get_key_press( 1<<KEY2 ))
            {
                date--;
            }
            if( get_key_press( 1<<KEY3 ))
            {
                break;
            }
            if( date > 31 | date < 1)
            {
                date =1;
            }
        }

            lcd_clrscr();
            while(1)                        // Set month;
            {

                lcd_gotoxy(0,0);
                itoa(month,buff,10);
                lcd_puts(buff);
                if( get_key_press( 1<<KEY1 ))
                {
                    month++;
                }
                if( get_key_press( 1<<KEY2 ))
                {
                    month--;
                }
                if( get_key_press( 1<<KEY3 ))
                {
                    break;
                }
                if( month > 12 | month < 1)
                {
                    month =1;
                }
            }
                lcd_clrscr();
                while(1)                        // Set year;
                {

                    lcd_gotoxy(0,0);
                    itoa(year,buff,10);
                    lcd_puts(buff);
                    if( get_key_press( 1<<KEY1 ))
                    {
                        year++;
                    }
                    if( get_key_press( 1<<KEY2 ))
                    {
                        year--;
                    }
                    if( get_key_press( 1<<KEY3 ))
                    {
                        break;
                    }
                    if( year > 99)
                    {
                        year =0;
                    }
                }
                    break;
    }


    i2c_init();
    i2c_start_wait(RTC+I2C_WRITE);
    i2c_write(0x00);                            // First register address; the RTC increments the register pointer after every byte write.

    i2c_write(dec_to_bcd(seconds));             // Write seconds.
    i2c_write(dec_to_bcd(minutes));             // Write minutes.
    i2c_write(hours);                           // Write hours.
    i2c_write(day);                             // Write days.
    i2c_write(dec_to_bcd(date));                // Write date.
    i2c_write(dec_to_bcd(month));               // Write month.
    i2c_write(dec_to_bcd(year));                // Write year.

    i2c_stop();
}
void display_time()
{
        uint8_t ret;
        char buff[4];
        char monthNames[][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
        char dayNames[][4] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};

        i2c_start_wait(RTC+I2C_WRITE);          // Establish communication
        i2c_write(0x00);                        // Write Address of first register.
        i2c_rep_start(RTC+I2C_READ);            // Re-establish comm with READ mode.

    //************** PRINT SECONDS ************************
        ret = i2c_readAck();
        ret = bcd_to_dec(ret);
        itoa(ret,buff,10);
        if(ret > 9)
        {
            lcd_gotoxy(6,0);
            lcd_puts(buff);
        }else if(ret == 0)
        {
            lcd_gotoxy(6,0);
            lcd_puts("00");
        }
        else{   
            lcd_gotoxy(7,0);
            lcd_puts(buff);
        }   
    //***************************************************** 
    //************** PRINT MINUTES ************************
        ret = i2c_readAck();
        ret = bcd_to_dec(ret);
        itoa(ret,buff,10);
        if( ret > 9)
        {
            lcd_gotoxy(3,0);
            lcd_puts(buff);

        }else if(ret == 0)
        {
            lcd_gotoxy(3,0);
            lcd_puts("00");
        }
        else{
            lcd_gotoxy(4,0);
            lcd_puts(buff);
        }
    //*****************************************************
    //************** PRINT HOURS ************************
        ret = i2c_readAck();

            if( ret & (1 << 5))
            {
                lcd_gotoxy(9,0);
                lcd_puts("PM");
            }else
            {
                lcd_gotoxy(9,0);
                lcd_puts("AM");
            }
        ret = (((0x10 & ret)  >> 4)* 10) + (0x0F & ret);
        itoa(ret,buff,10);
        lcd_gotoxy(0,1);

            if( ret > 9)
            {
                lcd_gotoxy(0,0);
                lcd_puts(buff);
            }else
            {
                lcd_gotoxy(0,0);
                lcd_puts("0");
                lcd_gotoxy(1,0);
                lcd_puts(buff);
            }
    //*****************************************************
    //************** PRINT DAY ****************************
        ret = i2c_readAck();
        lcd_gotoxy(0,1);
        ret--;
        lcd_puts(dayNames[ret]);
    //******************************************************
    //************** PRINT DATE ****************************
        ret = i2c_readAck();
        ret = (((0x10 & ret)  >> 4)* 10) + (0x0F & ret);
        itoa(ret,buff,10);
        if(ret > 9)
        {
            lcd_gotoxy(4,1);
            lcd_puts(buff);
        }else
        {
            lcd_gotoxy(4,1);
            lcd_putc('0');
            lcd_gotoxy(5,1);
            lcd_puts(buff);
        }   
    //*******************************************************
    //************** PRINT Month ****************************
        ret = i2c_readAck();
        ret = (((0x10 & ret)  >> 4)* 10) + (0x0F & ret);
        lcd_gotoxy(7,1);
        ret--;
        lcd_puts(monthNames[ret]);
    //*****************************************************
    //************** PRINT Year ****************************
        ret = i2c_readNak();
        i2c_stop();
        ret = bcd_to_dec(ret);
        itoa(ret,buff,10);
        lcd_gotoxy(11,1);
        lcd_puts("20");
        lcd_puts(buff);
    //*****************************************************
}
int main(void)
{
    init_timer0();
    KEY_DDR = 0;                // input
    KEY_PORT = 0xFF;            // pullups on
   lcd_init(LCD_DISP_ON);
   lcd_home();
    while (1) 
    {
        if( get_key_press( 1<<KEY0 ))
        {
            set_time();
        }
        display_time();
    }
}

Lo que pasa es que ahora quiero poder optimizar el código. Como puede ver en la función set_time (), se repite la acción de incremento / decremento. ¿Hay alguna manera de que pueda escribir una función para esto y usarla cuando lo necesite? Tenga en cuenta que cada una de las variables tiene un límite diferente después del cual se restablece / ajusta.

    
pregunta hacker804

2 respuestas

1

Aclaración de términos

  

optimizar el código

Optimización en C es un término específico. Supongo que está utilizando AVR GCC como compilador que tiene indicadores de optimización que apuntarán a minimizar el tamaño del código del ensamblador que genera a partir de su código C. AVR studio establece el nivel de optimización predeterminado en 1. Eche un vistazo a este enlace para obtener una buena explicación de ello.

Solución

Creo que lo que quieres decir es que quieres reducir las líneas de código que estás utilizando para hacer que tu proyecto se vea un poco mejor, así que te he dado una idea de qué hacer para tu función set_time() en el bloque de código en El fondo. Esto funcionará para todos los elementos de fecha y hora, excepto el de 12hr y AM / PM, que se debe volver a escribir para ajustarse a los demás o simplemente se deja como una función separada.

En cada bucle while, reemplace las sentencias if con lo que se encuentra a continuación y luego debe agregar mi función check_action() . La acción de verificación acepta un puntero al elemento de fecha y hora que desea cambiar y sus límites superior e inferior. (*pointer)++ evaluará primero el valor de los datos que se encuentran en la ubicación del puntero y luego incrementará ese valor. La función normalmente devolverá 0 y permanecerá en el bucle while a menos que se presione la tecla 3, luego devolverá 1 y se llamará break.

void set_time(void)
{
    uint8_t hours, *p_hours = &hours;

    .....

    while(1) //set seconds
    {
        //LCD functions

        //Replace if statements with this
        if(check_action(p_hours, 12, 1))
            break;
    }

    .....
}

int check_action(uint8_t *date_time_element,
              uint8_t upper_limit,
              uint8_t lower_limit)
{
    if( get_key_press( 1<<KEY1 ))
    {
        (*date_time_element)++;
    }
    if( get_key_press( 1<<KEY2 ))
    {
        (*date_time_element)--;
    }
    if( get_key_press( 1<<KEY3 ))
    {
        return 1;
    }
    if( (*date_time_element) > upper_limit 
      | (*date_time_element) < lower_limit)
    {
        (*date_time_element) = lower_limit;
    }
    return 0;
}
    
respondido por el pfl
0
  

¿Hay alguna forma de que pueda escribir una función para esto y usarla cuando lo necesite?

puede considerar dividirlo en al menos dos partes:

1) leer los teclados; esto devolverá la tecla presionada; 2) procesar la tecla presionada: probablemente un conjunto de declaraciones de cambio / caso; 3) según el resultado del procesamiento en 2), actualice la pantalla.

lo que tienes ahora, con todos los bucles while, es complicado.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas