Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**************************** Resolucao do exame de 6 de Julho de 2011 ***************************/
- /* Baseado num ATmega128@1MHz, pretende-se controlar a velocidade e o sentido de rotação de um
- motor DC utilizando um potenciómetro ligado ao canal 3 do ADC. A relação entre o valor lido pelo ADC
- e o valor do PWM (OCR2) e sentido de rotação está representada na figura abaixo (lado esquerdo).
- De notar a existência de uma zona neutra onde o valor de OCR2 deve ser 0. */
- /* Funcionamento:
- - Após a inicialização do sistema o motor encontra-se parado. Mesmo que o potenciómetro seja
- accionado o motor deve manter-se parado (modo de funcionamento OFF).
- - Para colocar o sistema no modo de funcionamento ON é necessário premir S1. Este modo de
- funcionamento só é iniciado se a leitura do ADC estiver na zona neutra (461<Leitura_AD<562). Se isto
- acontecer é activado o LED.
- - A partir deste momento, qualquer alteração no potenciómetro vai provocar uma variação da velocidade
- e do sentido de rotação do motor. O valor de OCR2 e o sentido de rotação são dados pelas seguintes
- fórmulas:
- Se Leitura_AD >= 562: OCR2 = (Leitura_AD – 562) * 256 / 462 PA4=1, PA5=0 (sentido directo)
- Se Leitura_AD <= 461: OCR2 = (461 – Leitura_AD) * 256 / 462 PA4=0, PA5=1 (sentido retrógrado)
- - O modo de funcionamento ON é desligado se for premido S2. Também neste caso a leitura do ADC
- deverá estar na zona neutra. Se isto acontecer, o LED é desactivado e o sistema entra em modo de
- funcionamento OFF.
- - A detecção da tecla STOP (emergência) provoca a paragem imediata do motor e a consequente saída
- do modo de funcionamento ON, desactivando também neste caso o LED.
- - Se o sistema se encontrar em modo de funcionamento ON, de 1 em 1s deve ser enviado pela USART
- o valor actual do sentido de rotação e do OCR2. */
- /*
- Escreva o software necessário à implementação do sistema descrito, de acordo com as
- seguintes alíneas:
- 1. Nesta alínea do exercício serão declaradas todas as variáveis globais que utilizar no
- software e, se necessário, protótipos das funções.
- 2. Rotina Inic() para a inicialização do sistema:
- a. Inicialização dos portos;
- b. Inicialização do TIMER0 de modo a permitir gerar uma interrupção de, aproximadamente,
- 100 em 100 ms (@1MHz);
- c. Inicialização do TIMER2, em modo Phase Correct PWM, para gerar em OC2 um PWM com
- uma frequência de aproximadamente 250Hz (@1MHz);
- d. Inicialização do ADC;
- e. Inicialização da USART0 para 4800 bps, 8 bits de dados, s/ paridade, 1 stop bit;
- f. Inicialização do sistema de interrupções: TIMER0, ADC e enable global.
- 3. Rotina de serviço da interrupção do TIMER0 (COMP). Esta rotina deve gerar o “start” da
- conversão do ADC (canal 3) e gerar a temporização de 1s activando a flag_TX no final
- desta temporização. Esta rotina deve ser escrita em linguagem Assembly.
- 4. Rotina de serviço da interrupção do ADC (fim de conversão) que faz a leitura dos 10 bits
- do ADC e calcula o valor da variável Leitura_AD. Deve também activar a flag Fim_conversao.
- 5. Função Calcula_PWM() que, de acordo com o valor de Leitura_AD, calcula o valor do PWM
- a aplicar ao motor (OCR2) e o sentido de rotação do motor (PA4 e PA5).
- 6. Função Print() que envia pela USART uma mensagem com o actual sentido de rotação seguido
- do valor actual de OCR2. Ex: "D128", "R64"
- 7. Função main(), programa principal que implementa as seguintes tarefas:
- - Inicialização do sistema;
- - Leitura e processamento dos interruptores S1, S2 e S3;
- - Verificar a flag Fim_conversao. Se o sistema estiver ON, deve ser chamada a função
- Calcula_PWM();
- - Verificação de flag_TX. Se o sistema estiver ON, deve ser enviada uma mensagem utilizando a
- função Print().
- */
- // notas: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106&start=all&postdays=0&postorder=asc
- #include <avr/interrupt.h>
- #include <stdio.h>
- #define ON 1
- #define OFF 0
- #define Directo 1
- #define Retrogrado 0
- #define sw_ON 0x06
- #define sw_OFF 0x05
- #define STOP 0x03
- // funcao em assembly
- extern void tmr0(void);
- // variaveis globais
- unsigned char Flag_Sentido = Directo;
- unsigned char Sistema = OFF;
- unsigned char Flag_TX = 0;
- unsigned char Fim_Conversao = 0;
- unsigned int Leitura_AD = 0;
- unsigned char cnt_1s = 10;
- /***********************************************************************************************/
- /* alinea 2 */
- void Inic()
- {
- // ports
- PORTA = 0x07; // activa pull-ups internos para S1, S2, S3
- DDRA = 0x38;
- DDRB = 0x80; // bit 7 como saída (OC2)
- // timer0
- OCR0 = 97; // para 100ms @1MHz
- TCCR0 = 0x0F; // CTC, OC0 OFF, prescaler 1024
- // PWM
- OCR2 = 0; // motor parado
- TCCR2 = 0b01100010; // PWM Phase Correct, prescaler 8
- // ADC
- ADMUX = 0b00000011;
- ADCSRA = 0b10001011; // enable ADC, enable interrupt, prescaler 8
- // USART
- UBRR0H = 0; // 4800 bps @1MHz
- UBRR0L = 12;
- UCSR0B |= 0x08; // enable do TX (transmissão)
- UCSR0C |= 0x06; // sem paridade, 1 stop bit, 8 bits de dados
- // interrupcoes
- TIMSK = TIMSK|0x2; // enable da interrupção do TC0 (CTC)
- SREG = SREG|0x80; // enable global das interrupções
- }
- /***********************************************************************************************/
- /* alinea 3 (mais a file .s em Assembly) */
- ISR(TIMER0_COMP_vect)
- {
- tmr0(); // rotina em Assembly
- }
- /***********************************************************************************************/
- /* alinea 4 */
- ISR(ADC_vect)
- {
- Leitura_AD = ADCL + (ADCH<<8); // calcula leitura; concactnacao de ADCL com ADCH
- Fim_Conversao = 1;
- }
- /***********************************************************************************************/
- /* alinea 5 */
- void Calcula_PWM()
- {
- unsigned long int calc_tmp;
- if (Leitura_AD >= 562)
- {
- PORTA = (PORTA & 0b11001111) | 0b00010000; // sentido directo
- calc_tmp = (long int)(Leitura_AD-562)*256/462;
- OCR2 = (unsigned char)calc_tmp;
- Flag_Sentido = Directo;
- }
- else if (Leitura_AD <= 461)
- {
- PORTA = (PORTA & 0b11001111) | 0b00100000; // sentido retrogrado
- calc_tmp = (long int)(461-Leitura_AD)*256/462;
- OCR2 = (unsigned char)calc_tmp;
- Flag_Sentido = Retrogrado;
- }
- else
- {
- OCR2 = 0;
- }
- }
- /***********************************************************************************************/
- /* alinea 6 */
- void Print()
- {
- unsigned char index = 0;
- char buffer[10];
- if (Flag_Sentido == Directo)
- sprintf(buffer, "D%d\n\r", OCR2); // mensagem para sentido directo
- else
- sprintf(buffer, "R%d\n\r", OCR2); // mensagem para sentido retrógrado
- while(buffer[index] != 0) // envia buffer
- {
- while(!(UCSR0A & (1<<UDRE0)));
- UDR0 = buffer[index];
- index++;
- }
- }
- /***********************************************************************************************/
- /* alinea 7 */
- int main(void)
- {
- unsigned char sw_tmp=0;
- Inic();
- Sistema = OFF;
- PORTA &= 0xF7; // Led OFF
- while(1)
- {
- sw_tmp = PINA & 0x07; // ler switches
- switch (sw_tmp)
- {
- case sw_ON: // se S1 activado
- if ((Leitura_AD > 461) && (Leitura_AD < 562))
- {
- Sistema = ON;
- PORTA |= 8; // Led ON
- }
- break;
- case sw_OFF: // se S2 activado
- if ( (Leitura_AD > 461) && (Leitura_AD < 562))
- {
- Sistema = OFF;
- PORTA &= 0xF7; // LED OFF
- }
- break;
- case STOP: // se S3 activado
- OCR2 = 0; // motor OFF
- Sistema=OFF;
- PORTA &= 0xF7; // LED OFF
- }
- if (Sistema == ON)
- {
- if (Fim_Conversao)
- {
- Calcula_PWM();
- Fim_Conversao = 0;
- }
- if (Flag_TX == ON)
- {
- Print();
- Flag_TX = OFF;
- }
- }
- }
- }
- // Assembly
- #define __SFR_OFFSET 0
- #include <interrupt.h>
- .extern cnt_1s
- .extern Flag_TX
- .global tmr0
- tmr0:
- push r16
- push r17
- push r18
- in r17, SREG
- sbi ADCSRA, 6 ; start da nova conversão
- lds r16, cnt_1s ; temporizacao de 1s
- dec r16
- sts cnt_1s, r16
- brne fim
- ldi r18, 1 ; se passou 1s ...
- sts Flag_TX, r18 ;... activa flag TX ...
- ldi r16, 10 ;... e recarrega contador
- sts cnt_1s, r16
- fim:
- out SREG, r17
- pop r18
- pop r17
- pop r16
- ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement