Пример #1
0
int main(void)
{
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); 
    init_DACs();
    init_ADC1();
    init_Timers();
    init_USART();
    state = STATE_IDLE;
    EOL = 0;
    EOS = 0;

    DAC1.start	= 0x0000;
    DAC1.step	= 0x0020;
    DAC1.stop	= 0x1000;
    DAC1Value	= 0x0000;

    DAC2.start	= 0x0000;
    DAC2.step	= 0x0200;
    DAC2.stop	= 0x1000;
    DAC2Value	= 0x0000;

    ADCBuffer	= malloc(128 * sizeof(uint16_t));

    while(1)
    {
	if(state == STATE_FORCE)
	{
	    TIM_Cmd(TIM2, ENABLE);
	    state = STATE_START;
	}
    }
}
Пример #2
0
int main(void)
{
    DDRA  = 0xFF; // Port A output
    PORTA = 0xFF; // Port A all pins 1

    DDRB  = 0xFF; // Port B output
    PORTB = 0xFF; // Port B all pins 1

    DDRC  = 0xFF; // Port C output
    PORTC = 0xFE; // Port C all pins 1, except PC0

    DDRD  = 0xFF; // Port D output
    PORTD = 0xFF; // Port D all pins 1

    cli(); // deactivate interrupts
        init_USART(); // activate USART global
        sei(); // activate interrupts global

    while(1){
        uart_sendstring("I'm still up.\n");
        _delay_ms(5000);
    }

    return 0;
}
Пример #3
0
void soc_family_init(void)
{
  init_sysclk();
  init_exception_prio();

  /* Enable peripheral clocks. */
  init_peripheral_clocks();

  /* Set up IO pin direction and mode registers. */
  init_io();

#ifdef SYSTEM_SOC_CORTEXM3_STM32_GPIO_USED
  /* Set up GPIO. */
  init_GPIO();
#endif

#ifdef SYSTEM_SOC_CORTEXM3_STM32_USART_USED
  /* Set up USART. */
  init_USART();
#endif

#ifdef SYSTEM_SOC_CORTEXM3_STM32_SPI_USED
  /* Set up SPI. */
  init_SPI();
#endif
}
Пример #4
0
int main(void)
{
	SysTick_Config(SystemCoreClock/1000); // Every 1 ms

	init_GPIO();
	init_USART();

	while(1)
    {
		GPIO_ToggleBits(GPIOA, GPIO_Pin_5);
		USART_SendData(USART2, 'a');
		delay_ms(500);
    }
}
Пример #5
0
int main(void) {
	
	init_PORT();
	init_EX_INTERRUPT();
	init_TIMER();
	init_ADC();
	init_USART();

	sei();
		
	while(1) {

	}
	
	return 0;
}
Пример #6
0
int
main(void)
{
	init_USART();
	write_string("serial init\r\n");

	init_timer();
	write_string("timer init\r\n");

	sei();

	while (1) {
		_delay_ms(1000);
		write_string("tock\r\n");
	}
}
Пример #7
0
int main(void) {

	init_PORT();
	init_TIMER0();
	init_TIMER();
	init_EX_INTERRUPT();
	init_ADC();
	init_USART();
	init_PWM();
	
	sei();
	
	while(1) {
		if(state>3) state = 3;
	}
	
	return 0;
}
Пример #8
0
int main(void)
{
	//lprintf("%d", 4);
	init_ADC();
	init_timer3();
	init_timer();
	init_USART(calcUBRR(BAUD));
	char * str = "Degrees\tIR Distance (cm)\tSonar Distance (cm)\n\n\r";
	move_servo(0);
	char degrees = 0;
    while(1)
    {
        //send_pulse();
		Transmit_String(str);
		sprintf(str, "%d\t%d\t%d\n\r", degrees, ir_distance(), time2dist(ping_read()));
		move_servo(degrees);
		degrees += 2;
		if(degrees > 180)
			break;
    }
}
Пример #9
0
void sleep_stat_hendler( )
{
//  if ( last_sw_stat != SLEEP )
//    {
//      printf( "\n\rTO SLEEP MODE" );
//      last_sw_stat = SLEEP;
//      normal_charging = 0;
//      trickl_charging = 0;
//      red_led = 0;
//      green_led = 0;
//      main_led_stat = 0;
//    }
//  else
//    {
    printf( "\n\r\n\r\n\r sw_stat = SLEEP" );
      //      TRISD = TRISD_MASK_AT_SLEEP;
      //      TRISE = TRISE_MASK_AT_SLEEP;
      FVRCONbits.FVREN = 0; //disnable the FVR

      WDT_cnter = 156; //set counter for WDT evrey 32msec so 156*32=5 sec
      blink_GREEN_LED_and_RED_LED_and_BUZZER( 6, 40 );
      //wait here making shure the user relese the SW
      while  ( !TEST_SW )//continue incation system go to sleep after the user relese the sw
        //  blink_GREEN_LED_and_RED_LED_and_BUZZER( 1, 40 );
        DelayMs( 255 );
      DelayMs( 255 ); //to avoid noise on the SW
      while  ( !TEST_SW )//continue incation system go to sleep after the user relese the sw
        blink_GREEN_LED_and_RED_LED_and_BUZZER( 1, 40 );
      //~~~~~~~time base for 50Ms~~~~~~~~~~~~~~~~
      //do WDT*3 so the timing will be 17Ms*3=49Ms ~50Ms
      //                      pulse_send_interval=my_eeprom_read(PULSE_SENDING_INTERVAL_EE_ADD);//##$$
      //                      WDT_cnter = WDT_MULTIPLYER_FOR_50Ms;

      TRISA = TRISA_MASK_AT_SLEEP;
      TRISB = TRISB_MASK_AT_SLEEP;
      TRISC = TRISC_MASK_AT_SLEEP;
      LATA = 0x00;
      LATB = 0x00;
      LATC = 0x00;

      exit_sleep_count = 0;
      while ( sw_stat == SLEEP )                   //enter to sleep as mutch as needed//##$$
        {
          /////////////////////////////
#ifdef  debeg
          T0CON = 0b11000101;    //1:64 PRESCALER GIVING 16.3ms full range inTMR0
          TMR0 = 0;
          TMR0IE = 0;
          TMR0IF = 0;
          while ( !TMR0IF );
#else
          SLEEP( );
#endif

          //GREEN_LED = 1 - GREEN_LED;

          if ( GREEN_LED )
            GREEN_LED = 0;
          WDT_cnter--;
          if ( !WDT_cnter )
            {
              FVRCONbits.FVRS = 2; //so FVR is 2.048V
              FVRCONbits.FVREN = 1; //enable the FVR
              GREEN_LED = 1;
              WDT_cnter = 156;
                            
              GRID_Voltage_ADC_val = readA2D( ADC_CHANNEL_VIN );
              if ( GRID_Voltage_ADC_val > grid_power_low_voltage ) //grid power is to low
                {
                  DelayMs(30);
                  GRID_Voltage_ADC_val = readA2D( ADC_CHANNEL_VIN );
              
                  if ( GRID_Voltage_ADC_val > grid_power_low_voltage ) //grid power is to low
                    {
                      DelayMs(30);
                      GRID_Voltage_ADC_val = readA2D( ADC_CHANNEL_VIN );

                      if ( GRID_Voltage_ADC_val > grid_power_low_voltage ) //grid power is to low
                        {
                        init_system( ); // Initialize System Function and Variables
                        init_USART( );
                        printf( "\n\r Vin ADC = %d", GRID_Voltage_ADC_val );
                        printf( " GRID POWER DETECTED so WAKING UP" );
                        sw_stat = ST_BY;
                        }
                    }
                }
              if (sw_stat == SLEEP)
              FVRCONbits.FVREN = 0; //disnable the FVR
            }
          
          
          if( !TEST_SW )//press detected
            {
              exit_sleep_count++;
              if ( exit_sleep_count >= exit_sleep_press )
                {
                 
                  init_system( ); // Initialize System Function and Variables
                  init_USART( );
                   printf( "\n\rTEST_SW press detected so" );
                   printf( "WAKING UP" );
                  sw_stat = ST_BY;
                }
            }
          else
            exit_sleep_count = 0;
        }
//    }
}
Пример #10
0
/*---------------------------------------------------------------------------
  Main program start here
 *---------------------------------------------------------------------------*/
int main() 
{
  GPIO_InitTypeDef pa0;
  
  RCC_RTC_Configuration();
  LCD_GLASS_Init();
  LCD_GLASS_Configure_GPIO();
  
  init_USART();
  
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
  
  GPIO_StructInit(&pa0);
  pa0.GPIO_Mode = GPIO_Mode_IN;
  pa0.GPIO_Pin = GPIO_Pin_0;
  GPIO_Init(GPIOA,&pa0);

    while(1) {
    if( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1 && state == 0)
    {
      count++;
      sprintf(DataSendToServer,"GET /cpe312/index.php?Name=TESTING_%d HTTP/1.1\r\nHost: markdang.lnw.mn\r\n\r\n",count);
      
      // Test AT startup
      send_data("AT\r\n");
      wait_data("OK");
      
      // Restart module
      send_data("AT+RST\r\n");
      wait_data("ready");

      display("OK RST");
   
      // Set Station & softAP Mode
      send_data("AT+CWMODE_CUR=3\r\n");
      wait_data("OK");
      display("STA+AP");
      
      // Set Station & softAP Mode
      send_data("AT+CWJAP_CUR=\"CPE312\",\"25033333\"\r\n");
      wait_data("OK");
      display("SET AP");
      
      // Set TCP , Address & Port : Check data http://markdang.lnw.mn/cpe312/show_data.php
      send_data("AT+CIPSTART=\"TCP\",\"markdang.lnw.mn\",80\r\n");
      wait_data("CONNECT");
      display("SETTCP");
      
      length = strlen(DataSendToServer);  // find length of data
      sprintf(nbr_DataSendToServer, "AT+CIPSEND=%d\r\n", length); // Set data size
      
      // Send length of data to server
      send_data(nbr_DataSendToServer);
      wait_data(">");
      display("SetLEN");
      
      // Send data to server
      send_data(DataSendToServer);
      wait_data("SEND OK");
      display("SENDOK");
      
      // Close AP
      send_data("AT+CWQAP\r\n");
      wait_data("OK");
      display("Close");
      
      state = 1;
    }
    else if ( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0 && state == 1)
    {
      state = 0;
    }
    display("ready ");
    }
}
Пример #11
0
/*
 * Tx:PC10 , Rx:PB11
 */
void init_USART(int buadrate)
{
	//RCC Initialization
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

	//GPIO Initialization
	GPIO_InitTypeDef GPIO_InitStruct = {
		.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11,
		.GPIO_Mode = GPIO_Mode_AF,
		.GPIO_Speed = GPIO_Speed_50MHz,
		.GPIO_OType = GPIO_OType_PP,
		.GPIO_PuPd = GPIO_PuPd_UP
	};

	GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);

	GPIO_Init(GPIOC, &GPIO_InitStruct);

	//USART Initialization
	USART_InitTypeDef USART_InitStruct = {
		.USART_BaudRate = buadrate,
		.USART_Mode = USART_Mode_Rx | USART_Mode_Tx,
		.USART_WordLength = USART_WordLength_8b,
		.USART_StopBits = USART_StopBits_1,
		.USART_Parity = USART_Parity_No
	};

	USART_Init(USART3, &USART_InitStruct);

	USART_Cmd(USART3, ENABLE);
}


void send_data(char *string)
{
	while(*string != '\0') {
		USART_SendData(USART3, (uint16_t)(*string));
		string++;
		while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
	}
}


void init_ADC()
{
	//RCC Initialization
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

	DMA_InitTypeDef DMA_InitStruct = {
		.DMA_Channel = DMA_Channel_2,
		.DMA_PeripheralBaseAddr = ADC3_DR_ADDRESS,
		.DMA_Memory0BaseAddr = (unsigned int) &ADC_Value,
		.DMA_DIR = DMA_DIR_PeripheralToMemory,
		.DMA_BufferSize = 1,
		.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
		.DMA_MemoryInc = DMA_MemoryInc_Disable,
		.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord,
		.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord,
		.DMA_Mode = DMA_Mode_Circular,
		.DMA_Priority = DMA_Priority_High,
		.DMA_FIFOMode = DMA_FIFOMode_Disable,
		.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull,
		.DMA_MemoryBurst = DMA_MemoryBurst_Single,
		.DMA_PeripheralBurst = DMA_PeripheralBurst_Single		
	};

	DMA_Init(DMA2_Stream0, &DMA_InitStruct);
	DMA_Cmd(DMA_Stream0, ENABLE);	

	//GPIO Initialization
	GPIO_InitTypeDef GPIO_InitStruct = {
		.GPIO_Pin = GPIO_Pin_3,
		.GPIO_Mode = GPIO_Mode_AN,
		.GPIO_PuPd = GPIO_PuPd_NOPULL
	};

	GPIO_Init(GPIOA, &GPIO_InitStruct);

	//ADC Common Initialization
	ADC_CommonInitTypeDef ADC_CommonInitStruct = {
		.ADC_Mode = ADC_Mode_Independent,
		.ADC_Prescaler = ADC_Prescaler_Div2,
		.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled,
		.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles
	};

	ADC_CommonInit(&ADC_CommonInitStruct);

	//ADC Initialization
	ADC_InitTypeDef ADC_InitStruct = {
		.ADC_Resolution = ADC_Resolution_12b,
		.ADC_ScanConvMode = DISABLE,
		.ADC_ContinuousConvMode = ENABLE,
		.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None,
		.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1,
		.ADC_DataAlign = ADC_DataAlign_Right,
		.ADC_NbrOfConversion = 1
	};

	//Set ADC to channel 3
	ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 1, ADC_SampleTime_3Cycles);

	ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

	ADC_DMACmd(ADC3, ENABLE);

	ADC_SoftwareStartConv(ADC3);
}


int main()
{
	init_USART(9600);
	init_ADC();

	char ADC_Prompt[100] = {'\0'};

	while(1) {
		sprintf(ADC_Prompt, "ADC Value = %d\n\r", ADC_Value);

		send_data(ADC_Prompt);
		delay(1000000L);		
	}

	return 0;
}
Пример #12
0
int main()
{
    // LCD Keypad Shield de 16 colunas por 2 linhas

    // PINOS
    /*
       VSS -> GND (está ligado ao GND do Arduino para que ambos tenham massas comuns)
       VDD -> +5v (está ligado à porta de 5V do Arduino)
       V0 -> ???? (ver datasheet)
       RS -> PB0
       RW -> GND (este pino está diretamente ligado à massa uma vez que é desnecessário pois apenas queremos escrever no LCD e não queremos ler nada dele)
       E  -> PB1
       D0 -> no ar
       D1 -> no ar
       D2 -> no ar
       D3 -> no ar
       D4 -> PD4
       D5 -> PD5
       D6 -> PD6
       D7 -> PD7
       A  -> +5V (está ligado à porta de 5V do Arduino)
       K  -> ???? (ver datasheet)
       BOTÕES -> PC0 (os botões são detetados através de um ADC -> ver datasheet)
    */

    // Coordenadas do display do LCD
    /*
          Y
          |
         _________________________________
      	/								  \
    X - | 0 1 2 3 4 5 6 7 8 9 A B C D E F |  Posição inicial do cursor (x,y) = (0,0)
    	| 1	 							  |
    	\_________________________________/

    */

    // Descrição dos pinos

    /* O controlador usado neste LCD é o HD44780 que é controlado por uma comunicação em paralelo de 4 ou 8 bits. Neste caso usam-se 4 bits pois é o que
       o LCD permite devido à sua estrutura física, isto é, os pinos D0, D1, D2 e D3 estão ligados ao ar, logo não estão ligados diretamente às portas
       do shield (que por sua vez estão diretamente ligadas às correspondentes portas do Arduino). As restantes portas D4, D5, D6 e D7 estão, logo
       enviam-se os 4 bits por estas portas, sendo que D4 corresponde à porta do LSB e D7 À porta do MSB. Para além destas portas, também interessa a
       porta RS pela qual vão ser enviados dados ou comandos para o controlador e a porta E que é o "enable" do controlador. A porta RW significa
       R/(/W), isto é caso tenha nível lógico 1 significa que vamos ler alguma coisa do LCD. Isto pode ser útil caso se queira enviar alguma informação
       (dados ou comandos) para o LCD. Podemos verificar uma flag que sinaliza o final da escrita, portanto, para ler esta flag é necessário que este
       pino esteja a 1! Outro modo de fazer isto é simplesmente esperar um determinado tempo em que é garantido que a informação já foi enviada para o
       LCD e neste modo não necessitamos do modo R. Quando assim é, ligamos este pino à massa pois /W é ativo com nível lógico 0. Neste LCD o pino RW
       está ligado diretamente à massa, logo apenas se pode fazer operações de escrita no LCD esperando um tempo predefinido que garante que a
       informação já foi enviada.
     */

    // Descrição dos botões

    /* Este shield possui 5 botões que, através de vários divisores resistivos (ver datasheet), estão ligados a uma porta do shield ligada diretamente à
       porta PC0 do Arduino. Quando um dos botões é pressionado, fecha-se um circuito que faz com que na entrada PC0 esteja um valor de tensão
       que varia com o divisor resistivo. Como a cada botão está associado um divisor resistivo, então o valor disponível na entrada PC0 varia de
       botão para botão, o que faz com que seja possível reconhecer cada botão através da leitura do valor do divisor resistivo a ele associado!
       Esta leitura é obviamente feita através do ADC associado ao pino PC0, o ADC0. Através das leituras do ADC podemos distinguir qual botão está a
       ser pressionado. Os valores das leituras para cada botão são:

       Botões   | 	 Leitura

       (nenhum) | 	ADC > 1000
       RIGHT	|	ADC < 50
       UP		|	ADC < 250
       DOWN		|	ADC < 450
       LEFT		|	ADC < 650
       SELECT	|	ADC < 850

       O código que permite implementar tudo isto está escrita no programa principal. Para além disto o shied ainda possui um botão de RESET que está
       eletricamente ligado ao botão de RESET do Arduino
     */

    // Biblioteca HD44780.h

    /* De várias bibliotecas AVR disponíveis para realizar operações com o controlador deste LCD - HD44780 - esta é mais completa que encontrei pois
       permite fazer o controlo de mais de um LCDs ao mesmo tempo (suporta 4 [AINDA NÃO TESTADO]) e para além disso permite também trabalhar com o
       pino RW ligado à massa ou não. Este último ponto é bastante útil pois permite trabalhar com uma vasta gama de LCD incluindo os integrados em
       shields (como é o caso) pois alguns tem o pino RW ligado à massa, o que os limita bastante em relação ao uso de bibliotecas pois a maior parte
       usa o pino RW.
       Esta biblioteca é bastante fácil de utilizar e de configurar. Ela possui um ficheiro chamado "hd44780_settings_example.h" que é o ficheiro de
       configurações da biblioteca em função do LCD utilizado. Ela permite definir as portas que estão a ser utilizadas, bem como o modo em que o pino
       RW está a ser utilizado, o número de linhas do LCD, etc. e está muito bem explicado como configurar este ficheiro no próprio ficheiro. Depois de
       configurado o nome do ficheiro deve ser mudado para "hd44780_settings.h".
       Outra funcionalidade desta biblioteca é possuir uma função chamada lcd_command que permite alterar o valor lógico dos bits RS, RW e D0
       até D7, o que é bastante útil pois dá-nos a possibilidade de escrever novas funções (como fiz na versão que fiz desta biblioteca). Para se criar
       esta novas funções é necessário ver a datasheet deste controlador para perceber como se fazem. Uma vez que eu próprio alterei esta biblioteca,
       acrescentei algumas funções (através da função lcd_command()) às que já estavam disponíveis, que se encontram descritas de seguida. POR ISSO,
       A BIBLIOTECA INCLUÍDA NESTE PROGRAMA DEVE SER A QUE SE ENCONTRA NA PASTA "Biblioteca HD77480" -> "HD44780 v1.12 - José Brito" ! PORTANTO DEVEM
       SER COPIADOS OS FICHEIROS "hd44780.c", "hd44780.h" e "hd44780_settings.h" PARA A PASTA DO PROJETO

     */

    // Funções da biblioteca Biblioteca HD44780.h alterada por mim

    /* lcd_init(); // inicializa o display do LCD, o cursor (inicialmente invisível) e as portas I/O. Esta é a primeira função a ser chamada em qualquer programa que use esta biblioteca
       lcd_command(uint8_t cmd); // função que altera bits específicos no registo RS (comandos ou dados) que vai ser enviado para o controlador do LCD. Esta função pode ser usada para escrever novas funções
       lcd_clrscr(); // apaga tudo o que foi escrito no display do LCD e coloca o cursor na posição (x,y) = (0,0) sem alterar as suas definições (se estava a piscar, sublinhado ou ambos)
       lcd_home(); // coloca o cursor na posição (x,y) = (0,0) sem alterar as suas definições (se estava a piscar, sublinhado ou ambos)
       lcd_goto(uint8_t pos); // coloca o cursor na posição especificada: (0x00) -> (x,y) = (0,0) ||| (0x0F) -> (x,y) = (15,0) ||| (0x40) -> (x,y) = (0,1) ||| (0x4F) -> (x,y) = (15,1)
       lcd_putc(char c); // escreve o parâmetro de entrada c (um carater) na posição onde o cursor se encontra
       lcd_puts(const char *s); // escreve o parâmetro de entrada s (uma string de carateres) na posição onde o cursor se encontra
       lcd_puts_P(const char *progmem_s); // ??? (escreve a string [constant char] s na memória flash do controlador HD44780 ???)
       lcd_blink_cursor(); // põe o cursor a piscar
       lcd_underline_cursor(); // sublinha o cursor
       lcd_underline_blink_cursor(); // sublinha o cursor e põem-o a piscar
       lcd_no_cursor(); // desliga o cursor (deixa de estar sublinhado e/ou a piscar)
       lcd_shift_cursor_right(); // faz um shift right do cursor, isto é, move-o uma coordenada em x para a direita
       lcd_shift_cursor_left(); // faz um shift left do cursor, isto é, move-o uma coordenada em x para a esquerda
       lcd_shift_display_right(); // faz um shift right do display do LCD (ambas as linhas), isto é, move tudo o que foi escrito uma coordenada em x para a direita
       lcd_shift_display_left();  // faz um shift left do display do LCD (ambas as linhas), isto é, move tudo o que foi escrito uma coordenada em x para a esquerda
       lcd_write_backwards(); // escreve futuras strings e chars de trás para a frente e da esquerda para a direita em vez de escrever normalmente e da direita para a esquerda
       lcd_write_normally(); //  escreve futuras strings e chars normalmente e da direita para a esquerda. Apenas chamar esta função se anteriormente chamou a função lcd_write_backwards()
       lcd_write_speed_slow(); // escreve futuras string e chars mais lentamente (para ser visível o que está realmente a ser escrito no display do lcd). Esta velocidade pode ser alterada, mudando o valor do delay na linha 397 do ficheiro "hd44780.c"
       lcd_write_speed_normal(); // escreve futuras strings e chars instantaneamente (predefinição). Apenas chamar esta função se anteriormente chamou a função lcd_write_speed_slow()
    */

    // ----------------------------------------------------------

    // CONFIGURAÇÃO DA LEITURA DOS BOTÕES ATRAVÉS DO ADC0

    sei(); // habilitação das interrupções globais

    ADMUX = 0b01000000; // ADC escolhido é o ADC0 que se encontra no pino PC0
    ADCSRA = 0b10001111; // estão ativadas as interrupções quando o ADC0 acabar de fazer uma conversão. A conversão é manual

    DIDR0 = 0b00000001; // este registo desativa a função digital do pino correspondente ao bit especificado por ele (neste caso desativamos a função digital do pino PC0)

    /* Nota: A conversão do ADC deve ser manual uma vez que todos os timers 0 e 1 que podiam ser usados para fazer a conversão automática estão
       indiretamente associados aos pinos que estão a ser usados para fazer a comunicação com o LCD. Apesar destes pinos não estarem a ser usados como
       saídas de PWM (obviamente), o LCD parece não reagir muito bem a que se mexa nestes pinos fora das configurações feitas na biblioteca hd44780.h.
       Por essa razão, a conversão deve ser feita manualmente, como está exemplificado no programa a seguir
    */
    // INÍCIO DO PROGRAMA

    init_USART();
    lcd_init();
    lcd_putc('A'); // o primeiro caracter do programa escrito com as funções lcd_putc ou lcd_puts é muitas vezes aleatório (por razões que desconheço). Para resolver este problema
    lcd_clrscr(); // escreve-se um primeiro carater (neste caso o "A") e em seguida volta-se a apagá-lo. Mais nenhum carater deverá ser aleatório após este procedimento

    // ESCREVA O PROGRAMA A PARTIR DAQUI

    lcd_write_speed_slow();
    lcd_puts("Botao:");

    while(1)
    {
        lcd_goto(0x40); // coloca o cursor na posição (0,1) -> segunda linha, primeira coluna
        ADCSRA = ADCSRA | 0b01000000; // iniciar a conversão do ADC do pino PC0 através da ativação manual do bit ADSC
        while(ADCSRA & (1<<ADSC)); // o programa entra num ciclo infinito até acabar a conversão do ADC
        lcd_write_speed_normal();
        lcd_puts(botao); // escreve o nome do botão pressionado
        lcd_puts("    "); // escreve "    " para não aparecerem carates a mais
    }
}