Página 1 de 1

AVR ATmega168 Dúvida Programação

MensagemEnviado: 23 Fev 2011 17:07
por chip_flp
Boa tarde a todos,

Estou tentando desenvolver uma programação no AVR Studio com o ATmega168 e gostaria de atingir o seguinte objetivo:

Ler vários canais ADC e quando dado um click no botão PB0 mostrar resultado no LCD, quando dado um segundo click no mesmo botão enviar essas informações via serial...

No entanto não estou conseguindo nem um nem outro, caso alguém possa ajudar o codigo segue abaixo.

Obs:. O controle de interrupção deve controladar o estado da entrada de um único botão usando um único contador de 8 bits para permitir que vários controles.

Características:

- 2 Segundos apertado;
- 5 Segundos apertado;
- rápida, 10 segundos tempo limite;

    Código: Selecionar todos
    #include <avr/io.h>
    #include <util/delay.h>
    #include <compat/twi.h>
    #include <math.h>
    #include <compat/deprecated.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>                           //Necessary for the function itoa
    #include <avr/pgmspace.h>

    #define F_CPU 11059200UL
    #define BAUD_RATE 19200

    #define    tbi(port, bit)   (port  &   (1 << bit))
    #define      button_press   !tbi(PINB,PB0)
                                           //Button Press State Variable Enumeration
    #define IPRESS 0x01   
    #define RELEASE 0x02
    #define IDLE 0x04

    // Timeouts
    #define TIME_OV 148                         //10 sec timeout
    #define TIME_2S 40                          //2 second hold
    #define TIME_5S 80                          //5 second hold

    volatile uint8_t button_state,hold5, hold2, press;
    volatile uint16_t time; // extended time counter

    //------------------------------------------------------------------------------------------------------------------
    //   Definitions LCD 16x2 (Hitachi HD44780U)
    //------------------------------------------------------------------------------------------------------------------
    #define LCD_HOME      0x02
    #define LCD_NEXT_LINE 0xC0
    #define LCD_CLEAR      0x01
    #define LCD_1CYCLE      0
    #define LCD_2CYCLE      1
    char sdigit[3]={'0','0','\0'};

    //------------------------------------------------------------------------------------------------------------------
    // Handling communication with the LCD
    //------------------------------------------------------------------------------------------------------------------
    //------------------------------------------------------------------------------------------------------------------
    //   Subroutine display single character on the LCD (Send Data)
    //------------------------------------------------------------------------------------------------------------------
    void LCD_putch(unsigned char data)                //Function used to display single character on the LCD
    {
                                            //LCD Upper 4 bits data (DB7,DB6,DB5,DB4)
       PORTD = (1<<PD3)|(1<<PD2)|(data & 0xF0);       //RS = 1, E = 1
                                           // E=0; write data
       PORTD &= ~(1<<PD3);
       _delay_us(1);
                                           //LCD Lower 4 bits data (DB3,DB2,DB1,DB0)
       PORTD = (1<<PD3)|(1<<PD2)|((data & 0x0F) << 4);   //RS = 1, E = 1 (<< shifts 4 bits left)
                                           //E=0; write data
       PORTD &= ~(1<<PD3);
       _delay_ms(5);                             //Wait for busy flag (BF)
    }

    //------------------------------------------------------------------------------------------------------------------
    //   Subroutine sending commands to the LCD (Send Instruction)
    //------------------------------------------------------------------------------------------------------------------
    void LCD_putcmd(unsigned char data,unsigned char cmdtype) //Function used to send LCD command
    {
                                            //LCD Upper 4 bits data (DB7,DB6,DB5,DB4)
       PORTD = (1<<PD3)|(data & 0xF0);                  //RS = 0, E = 1
                                           //E=0; write data
       PORTD &= ~(1<<PD3);
       _delay_us(1);
                                           //cmdtype = 0; One cycle write, cmdtype = 1; Two cycle writes
       if (cmdtype)
       {
                                            //LCD Lower 4 bits data (DB3,DB2,DB1,DB0)
          PORTD = (1<<PD3)|((data & 0x0F) << 4);      //RS = 0, E = 1 (<< shifts 4 bits left)
                                           //E=0; write data
          PORTD &= ~(1<<PD3);
        }
    _delay_ms(5);                                //Wait for busy flag (BF)
    }

    //------------------------------------------------------------------------------------------------------------------
    //   Subroutine initialized the LCD 16x2 mode 4bits
    //------------------------------------------------------------------------------------------------------------------
    void initlcd()                              //Function used to initialized the 16x2 LCD
    {
                                           //Power ON - Stabilization
                                           //Wait for more than 15 ms after VCC rises to 4.5 V
       _delay_ms(30);
                                            //Send Command Instruction 0x30 (1 cycle)
       LCD_putcmd(0x30,LCD_1CYCLE);
       _delay_ms(8);                           //Wait for more than 4.1 ms
                                           //Send Command Instruction 0x30 (1 cycle)
       LCD_putcmd(0x30,LCD_1CYCLE);
       _delay_us(200);                           //Wait for more than 100 us
                                           //Send Command Instruction 0x30 (1 cycle)
       LCD_putcmd(0x30,LCD_1CYCLE);
                                           //Function set: Set interface to be 4 bits data long (only 1 cycle write)
       LCD_putcmd(0x20,LCD_1CYCLE);
                                           //Function set: DL=0;Interface is 4 bits data, N=1; 2 Lines, F=0; 5x8 dots font (2 cycle)
       LCD_putcmd(0x28,LCD_2CYCLE);
                                           //Display Off: D=0; Display off, C=0; Cursor Off, B=0; Blinking Off (2 cycle)
       LCD_putcmd(0x08,LCD_2CYCLE);
                                           //Display Clear (2 cycle)
       LCD_putcmd(0x01,LCD_2CYCLE);
                                           //Entry Mode Set: I/D=1; Increment, S=0; No shift (2 cycle)
         LCD_putcmd(0x06,LCD_2CYCLE);
    }

    //------------------------------------------------------------------------------------------------------------------
    //   Subroutine sends string writes LCD
    //------------------------------------------------------------------------------------------------------------------
    void LCD_puts(char *s)                        //Implementation of C puts() function for the LCD, which display
                                           //a terminated null string to the LCD
    {
        while(*s != 0)                           //While not Null
       {
             if (*s == '\n')
              LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE);     //Goto Second Line
            else
              LCD_putch(*s);
             s++;
          }
    }

    //------------------------------------------------------------------------------------------------------------------
    //   Subroutine implementing integer value from 00 to 99
    //------------------------------------------------------------------------------------------------------------------
    char *num2str(char number)                    //Function is used to convert a numeric value to on the LCD
    {
        unsigned char digit;
       digit = '0';                                   //Start with ASCII '0'
          while(number >= 10)                            //Keep Looping for larger than 10
          {
             digit++;                                 //Increase ASCII character
            number -= 10;                            //Subtract number with 10
        }
       sdigit[0]='0';                                //Default first Digit to '0'
       if (digit != '0')
       sdigit[0]=digit;                            //Put the Second digit
       sdigit[1]='0' + number;
       return sdigit;
    }

    //------------------------------------------------------------------------------------------------------------------
    //   Simple program to read multiple channels AD
    //------------------------------------------------------------------------------------------------------------------
    /*
    MUX3   MUX2   MUX1   MUX0   Pino a ler
    0      0      0      0      PORTC0   Analogic0
    0      0      0      1      PORTC1   Analogic1
    0      0      1      0      PORTC2   Analogic2
    0      0      1      1      PORTC3   Analogic3
    0      1      0      0      PORTC4   Analogic4
    0      1      0      1      PORTC5   Analogic5
    */

    int         adc_value;                           //Variable used to store the value read by the ADC
    void       adc_init      (void);               //Function to initialize / configure the converter
    char       buffer[5],mode;                           //Buffer to the function itoa
    uint16_t    read_adc      (uint8_t channel);      //We function to read an arbitrary channel ADC
    uint8_t    i=0,cont=0;                           //Variable is used in for

    void       USART_init      (void);               //Function to initialize the USART
    void       USART_send      (unsigned char data);   //Function that sends a character by the USART
    void      USART_putstring   (char* StringPtr);      //Function that sends a string by the USART

    void init_IO (void)
    {
       DDRB |= (1<<PB5);
       DDRD  = 0xFF;                                //Set PORTD as Output LCD
         PORTD = 0;   
    }

    int Setup(void)
    {
       for(cont=0; cont<2; cont++)                  
       {                              
          for(i=0; i<4;i++)                     //Number of channels to be read AD's
             {
             USART_send('\r');
             USART_putstring("Leitura do Canal");         
             USART_send('\r');                     //To change the line in the terminal
             USART_send('0' + i);                  //When we send only a number between 0 and 9 can simply add the number to the character '0 '
                USART_putstring(" : ");               //Just the thing to beautify
                adc_value = read_adc(i);              //We read channel of a converter
                itoa(adc_value, buffer, 10);          //We convert the measured value to a string
                USART_putstring(buffer);               //We send the same string
                USART_putstring("  ");                  //Just the thing to beautify
                _delay_ms(500);
             }
       USART_send('\r');                           //To change the line in the terminal
       USART_send('\n');                 
       }
    return 0;
    }

    void adc_init(void)
    {
          ADCSRA |= ((1<<ADPS2) | (1<<ADPS1));         //11059200/64 = 172,8Khz
       ADMUX |= (1<<REFS0);                        //5V Reference
          ADMUX &= ~(1<<REFS1);
          ADCSRA |= ((1<<ADEN) | (1<<ADSC));               //ADC on, makes a first conversion circuit to start and why is the slowest
    }

    uint16_t read_adc(uint8_t channel)
    {
       ADMUX &= 0xF0;                              //Clears the previous channel
          ADMUX |= channel;                           //Sets the new channel to read from ADC
          ADCSRA |= (1<<ADSC);                          //Start a new conversion
          while(ADCSRA & (1<<ADSC));                     //Hopes that the conversion is done
          return (ADCL + (ADCH<<8));                     //Returns the value of ADC
    }

    void USART_init(void)
    {
       UBRR0H = (((F_CPU/BAUD_RATE)/16)-1)>>8;         //Set baud rate >>shifts 8 bits right (Asynchronous Normal mode)
         UBRR0L = (((F_CPU/BAUD_RATE)/16)-1);
     
       UCSR0B = (1<<RXEN0)|(1<<TXEN0);             //(Receiver & Transmitter) Enable Tx & Rx
         UCSR0C=  (1<<UCSZ01)|(1<<UCSZ00);               //(Character Size) Config USART 8N1 (8data 1stop bit)
       //UCSR0C = (3<<UCSZ00);                     //As above
    }

    void USART_send( unsigned char data)
    {
       while(!(UCSR0A & (1<<UDRE0)));
          UDR0 = data;
    }

    void USART_putstring(char* StringPtr)
    {
       while(*StringPtr != 0x00)
       {
             USART_send(*StringPtr);
             StringPtr++;
       }
    }

    void start_timer0(void)
    {
       TCCR0B = _BV(CS02) | _BV(CS00);               //Use maximum prescaller: Clk/1024
    }

    void stop_timer0(void)
    {
       TCCR0B = 0;
    }

    void goto_idle(void) {
       button_state = IDLE;                      //goto idle state
       press= 0;
       TCNT0 = 0;
       time = 0;
    }
                                           //ISR for Pin Change Interrupt
                                           //Change to reflect Input pin for button
                                           //Make sure there is debounce circuit on button
                                           //inorder to eliminate bouncing.
    ISR(PCINT0_vect)
    {
       stop_timer0();                          //stop timer
         switch (button_state)
       {
            case IDLE:                           //IDLE State
          {
              if(bit_is_set(PINB,PB0))            //if pb0 press
             {
                start_timer0();
                   button_state = IPRESS;
              }
           break;
            }
            case IPRESS:                        //Pressed State
          {
              if(bit_is_clear(PINB,PB0))            //release
             {
                   if(press == 0 && time >= TIME_5S)
                {
                   goto_idle();
                   hold5 = 1;                   //must be cleared in main routine
                   }
                else if(press == 0 && time >= TIME_2S)
                {
                   goto_idle();
                   hold2 = 1;                   //must be cleared in main routine
                   }
                else                        //goto release state
                {
                   button_state = RELEASE;
                   press++;                   //Quick press
                   start_timer0();             //continue counter
                   }
              }
             else                           //Pin state is corrupted
             {                               
                   goto_idle();
              }
             break;
            }
          case RELEASE:                        //Released state
          {
              if(bit_is_set(PINB,PB0))            //if pb0 press
             {
                   start_timer0();                //continue counting
                   button_state = IPRESS;
              }
             else
             {
                   goto_idle();
              }
           break;
            }
          default:                           //states are messed up
          {
              goto_idle();
              break;
            }
       }
    }
                                           // ISR for Timer overflow.  using an 8bit timer requires
                                           // software overflow extension.
    ISR(TIMER0_OVF_vect)
    {    
         if(time > TIME_OV)
       {
          stop_timer0();
          goto_idle();
       }
       else
       {
           time++;
       }
    }

    void init_uc(void)
    {
       stop_timer0();
       TCNT0 = 0x94;                               // Start counter from 0x94, overflow at 10 mSec
                                           // Enable Interrupts
       TIMSK0 = _BV(TOIE0);                      // enable overflow interrupt
       PCICR = _BV(PCIE0);                       // enable pcint0
       PCMSK0 = _BV(PCINT0);   
       MCUCR = _BV(PUD);
       hold5 = 0;
       hold2 = 0;
       press = 0;
       time = 0;
       button_state = IDLE;
       sei();
    }

    //void SetupMode_Write (void)
    //{
    //   printf(" ** AVR 168 Printing and Adjust Data ** \n\n");
    //}

    int main(void)
    {
       uint32_t i;
         uint8_t x;
         
       init_IO();
       USART_init();                             //We initialize the USART
       adc_init();                               //We initialize the ADC
       initlcd();                              //Initial LCD using 4 bit data interface

       LCD_putcmd(0x0C,LCD_2CYCLE);                  //Display On, Cursor Off
       LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);             //Clear LCD   
       
       init_uc();
       
       for(;;)                               //Infinite loop
       {
          if(hold5)                           //Take action on 5 second hold
          {                                  
             LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);       //Clear LCD
             LCD_puts("   Setup Mode   ");
             Setup();
             hold5 = 0;
             }
          else if(hold2)                        //Take action on 2 second hold
          {
             //SetupMode_Write();
             hold2 = 0;
             }
          else if(press > 0)                      //take action on multiple quick press
          {}
          else if(press == 0)
          {}
             for(i=0; i<=100; i++)                  //put time into loop
          {
             x = PINC;
             }
        }                                     // endless loop
    return 0;
    }

Obrigado

MensagemEnviado: 23 Fev 2011 18:06
por brasilma
Olá Chip,

Fiz algo bem parecido esses tempinhos, porem para ATmega32 e em Basic (exigência do orientador), me fala se ajuda em alguma coisa, ok?

Abraços.

MensagemEnviado: 23 Fev 2011 19:07
por chip_flp
brasilma,

Agradeço pela colaboração só que o eu não conseguiria entender em Basic, sobre o ATmega32 não seria problema somente muda os registradores.

De uma forma ou outra agreço pela atenção.

Abraço

MensagemEnviado: 24 Fev 2011 17:15
por chip_flp
Pessoal estou com outra dúvida, gostaria como converter o valor de tensão lido no pino AD e enviar para o LCD.

A linha a observar = //LCD_puts(num2str(voltage));

//------------------------------------------------------------------------------------------------------------------
// Subroutine converts value bit to the LCD
//------------------------------------------------------------------------------------------------------------------
void converts_display(unsigned int aux)
{
bit[0]=(( aux/1000)+0x48);
bit[1]=(( aux%1000/100)+0x48);
bit[2]=(((aux%1000)%100/10)+0x48);
bit[3]=(((aux%1000)%100%10)+0x48);
}
//------------------------------------------------------------------------------------------------------------------
// Subroutine implementing integer value from 00 to 99
//------------------------------------------------------------------------------------------------------------------
char *num2str(char number) //Function is used to convert a numeric value to on the LCD
{
unsigned char digit;
digit = '0'; //Start with ASCII '0'
while(number >= 10) //Keep Looping for larger than 10
{
digit++; //Increase ASCII character
number -= 10; //Subtract number with 10
}
sdigit[0]='0'; //Default first Digit to '0'
if (digit != '0')
sdigit[0]=digit; //Put the Second digit
sdigit[1]='0' + number;
return sdigit;
}


Código: Selecionar todos
if(button_press)
   {
            mode = 2;
            LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);    //Clear LCD
            LCD_puts("  Read Mode RMS  ");
            _delay_ms(500);
            USART_send('\r');
            USART_putstring("Read Channel:3");
            USART_putstring(" : ");            
            adc_value = read_adc(3);
            converts_display(voltage);
            
            //itoa(adc_value, buffer, 10);       //We convert the measured value to a string
               LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);    //Clear LCD
            LCD_puts("Tensao: ");
            //LCD_puts(buffer);
            
            //show how this value correctly
            //LCD_puts(num2str(voltage));                        
            
            LCD_puts("V");
            USART_putstring(buffer);            //We send the same string
               USART_putstring("  ");            //Just the thing to beautify
            USART_send('\r');
               _delay_ms(500);
         }


obrigado

MensagemEnviado: 01 Mar 2011 17:24
por ze
bom para converter de ad para v...vejamos:
considerando que já domina a captura dos dados de cada canal do ad...não ainda? então pare de ler
unsigned int ad;
ad=read_adc(channel);
considerando que domina uma função para escrever um caracter asc-ii no display... não ainda? então pare de ler
writelcd(unsigned char b);//ou putlcd() ou etc
use sua função para quebrar o valor do ad em alguns asc´s
void converts_display(unsigned int aux)
{
bit[0]=(( aux/1000)+0x48);
bit[1]=(( aux%1000/100)+0x48);
bit[2]=(((aux%1000)%100/10)+0x48);
bit[3]=(((aux%1000)%100%10)+0x48);
}
converts_display(a)
envie o valor de a para o display (também pode enviar pra um terminal)
for (i=0;i<4;i++) writelcd(bit[i]);
meça com o multimetro o valor em mV do ad (deixe um valor fixo nele tipo com tl431) e veja no display o valor ad que ele dá. Com uma simples conta mental ou calculadoral de divisão, já tem o fator de conversão de ad para V.
f=ad/v
guarde f na memória... na sua cabeça... no futuro na eeprom: poderá ser seu ajuste.
agora para converter de ad para v é só fazer
v=ad/f
e escreva o v (em mV) no display da forma supra mencionada
ad,v,f pode ser int mas dá (+) trabalho pra explicar uma otimização. float dá (+) precisão, (+) trabalho pro MC e (-) trabalho pra explicar

ou algo assim

abç & sucessos