Advertisement
paulogp

ATmega128: Exame final

Jul 18th, 2011
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.95 KB | None | 0 0
  1. /**************************** Resolucao do exame de 6 de Julho de 2011 ***************************/
  2. /* Baseado num ATmega128@1MHz, pretende-se controlar a velocidade e o sentido de rotação de um
  3.   motor DC utilizando um potenciómetro ligado ao canal 3 do ADC. A relação entre o valor lido pelo ADC
  4.   e o valor do PWM (OCR2) e sentido de rotação está representada na figura abaixo (lado esquerdo).
  5.   De notar a existência de uma zona neutra onde o valor de OCR2 deve ser 0. */
  6.  
  7. /* Funcionamento:
  8.   - Após a inicialização do sistema o motor encontra-se parado. Mesmo que o potenciómetro seja
  9.   accionado o motor deve manter-se parado (modo de funcionamento OFF).
  10.  
  11.   - Para colocar o sistema no modo de funcionamento ON é necessário premir S1. Este modo de
  12.   funcionamento só é iniciado se a leitura do ADC estiver na zona neutra (461<Leitura_AD<562). Se isto
  13.   acontecer é activado o LED.
  14.  
  15.   - A partir deste momento, qualquer alteração no potenciómetro vai provocar uma variação da velocidade
  16.   e do sentido de rotação do motor. O valor de OCR2 e o sentido de rotação são dados pelas seguintes
  17.   fórmulas:
  18.   Se Leitura_AD >= 562: OCR2 = (Leitura_AD – 562) * 256 / 462 PA4=1, PA5=0 (sentido directo)
  19.   Se Leitura_AD <= 461: OCR2 = (461 – Leitura_AD) * 256 / 462 PA4=0, PA5=1 (sentido retrógrado)
  20.  
  21.   - O modo de funcionamento ON é desligado se for premido S2. Também neste caso a leitura do ADC
  22.   deverá estar na zona neutra. Se isto acontecer, o LED é desactivado e o sistema entra em modo de
  23.   funcionamento OFF.
  24.  
  25.   - A detecção da tecla STOP (emergência) provoca a paragem imediata do motor e a consequente saída
  26.   do modo de funcionamento ON, desactivando também neste caso o LED.
  27.   - Se o sistema se encontrar em modo de funcionamento ON, de 1 em 1s deve ser enviado pela USART
  28.   o valor actual do sentido de rotação e do OCR2. */
  29.  
  30. /*
  31. Escreva o software necessário à implementação do sistema descrito, de acordo com as
  32. seguintes alíneas:
  33.  
  34. 1. Nesta alínea do exercício serão declaradas todas as variáveis globais que utilizar no
  35.      software e, se necessário, protótipos das funções.
  36.  
  37. 2. Rotina Inic() para a inicialização do sistema:
  38.   a. Inicialização dos portos;
  39.  
  40.   b. Inicialização do TIMER0 de modo a permitir gerar uma interrupção de, aproximadamente,
  41.       100 em 100 ms (@1MHz);
  42.  
  43.   c. Inicialização do TIMER2, em modo Phase Correct PWM, para gerar em OC2 um PWM com
  44.       uma frequência de aproximadamente 250Hz (@1MHz);
  45.  
  46.   d. Inicialização do ADC;
  47.  
  48.   e. Inicialização da USART0 para 4800 bps, 8 bits de dados, s/ paridade, 1 stop bit;
  49.  
  50.   f. Inicialização do sistema de interrupções: TIMER0, ADC e enable global.
  51.  
  52. 3. Rotina de serviço da interrupção do TIMER0 (COMP). Esta rotina deve gerar o “start” da
  53.      conversão do ADC (canal 3) e gerar a temporização de 1s activando a flag_TX no final
  54.      desta temporização. Esta rotina deve ser escrita em linguagem Assembly.
  55.  
  56. 4. Rotina de serviço da interrupção do ADC (fim de conversão) que faz a leitura dos 10 bits
  57.      do ADC e calcula o valor da variável Leitura_AD. Deve também activar a flag Fim_conversao.
  58.  
  59. 5. Função Calcula_PWM() que, de acordo com o valor de Leitura_AD, calcula o valor do PWM
  60.      a aplicar ao motor (OCR2) e o sentido de rotação do motor (PA4 e PA5).
  61.  
  62. 6. Função Print() que envia pela USART uma mensagem com o actual sentido de rotação seguido
  63.      do valor actual de OCR2. Ex: "D128", "R64"
  64.  
  65. 7. Função main(), programa principal que implementa as seguintes tarefas:
  66.   - Inicialização do sistema;
  67.   - Leitura e processamento dos interruptores S1, S2 e S3;
  68.   - Verificar a flag Fim_conversao. Se o sistema estiver ON, deve ser chamada a função
  69.      Calcula_PWM();
  70.   - Verificação de flag_TX. Se o sistema estiver ON, deve ser enviada uma mensagem utilizando a
  71.       função Print().
  72. */
  73.  
  74. // notas:  http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106&start=all&postdays=0&postorder=asc
  75.  
  76. #include <avr/interrupt.h>
  77. #include <stdio.h>
  78.  
  79. #define ON 1
  80. #define OFF 0
  81.  
  82. #define Directo 1
  83. #define Retrogrado 0
  84.  
  85. #define sw_ON 0x06
  86. #define sw_OFF 0x05
  87. #define STOP 0x03
  88.  
  89. // funcao em assembly
  90. extern void tmr0(void);
  91.  
  92. // variaveis globais
  93. unsigned char Flag_Sentido = Directo;
  94. unsigned char Sistema = OFF;
  95. unsigned char Flag_TX = 0;
  96. unsigned char Fim_Conversao = 0;
  97. unsigned int Leitura_AD = 0;
  98. unsigned char cnt_1s = 10;
  99.  
  100. /***********************************************************************************************/
  101. /* alinea 2 */
  102. void Inic()
  103. {
  104.     // ports
  105.     PORTA = 0x07; // activa pull-ups internos para S1, S2, S3
  106.     DDRA = 0x38;
  107.     DDRB = 0x80; // bit 7 como saída (OC2)
  108.    
  109.     // timer0
  110.     OCR0 = 97; // para 100ms @1MHz
  111.     TCCR0 = 0x0F; // CTC, OC0 OFF, prescaler 1024
  112.    
  113.     // PWM
  114.     OCR2 = 0; // motor parado
  115.     TCCR2 = 0b01100010; // PWM Phase Correct, prescaler 8
  116.    
  117.     // ADC
  118.     ADMUX = 0b00000011;
  119.     ADCSRA = 0b10001011; // enable ADC, enable interrupt, prescaler 8
  120.    
  121.     // USART
  122.     UBRR0H = 0; // 4800 bps @1MHz
  123.     UBRR0L = 12;
  124.     UCSR0B |= 0x08; // enable do TX (transmissão)
  125.     UCSR0C |= 0x06; // sem paridade, 1 stop bit, 8 bits de dados
  126.    
  127.     // interrupcoes
  128.     TIMSK = TIMSK|0x2; // enable da interrupção do TC0 (CTC)
  129.     SREG = SREG|0x80; // enable global das interrupções
  130. }
  131.  
  132. /***********************************************************************************************/
  133. /* alinea 3 (mais a file .s em Assembly) */
  134. ISR(TIMER0_COMP_vect)
  135. {
  136.     tmr0(); // rotina em Assembly
  137. }
  138.  
  139. /***********************************************************************************************/
  140. /* alinea 4 */
  141. ISR(ADC_vect)
  142. {
  143.     Leitura_AD = ADCL + (ADCH<<8); // calcula leitura; concactnacao de ADCL com ADCH
  144.     Fim_Conversao = 1;
  145. }
  146.  
  147. /***********************************************************************************************/
  148. /* alinea 5 */
  149. void Calcula_PWM()
  150. {
  151.     unsigned long int calc_tmp;
  152.    
  153.     if (Leitura_AD >= 562)
  154.     {
  155.         PORTA = (PORTA & 0b11001111) | 0b00010000; // sentido directo
  156.         calc_tmp = (long int)(Leitura_AD-562)*256/462;
  157.         OCR2 = (unsigned char)calc_tmp;
  158.         Flag_Sentido = Directo;
  159.     }
  160.     else if (Leitura_AD <= 461)
  161.     {
  162.         PORTA = (PORTA & 0b11001111) | 0b00100000; // sentido retrogrado
  163.         calc_tmp = (long int)(461-Leitura_AD)*256/462;
  164.         OCR2 = (unsigned char)calc_tmp;
  165.         Flag_Sentido = Retrogrado;
  166.     }
  167.     else
  168.     {
  169.         OCR2 = 0;
  170.     }
  171. }
  172.  
  173. /***********************************************************************************************/
  174. /* alinea 6 */
  175. void Print()
  176. {
  177.     unsigned char index = 0;
  178.    
  179.     char buffer[10];
  180.    
  181.     if (Flag_Sentido == Directo)
  182.         sprintf(buffer, "D%d\n\r", OCR2); // mensagem para sentido directo
  183.     else
  184.         sprintf(buffer, "R%d\n\r", OCR2); // mensagem para sentido retrógrado
  185.    
  186.     while(buffer[index] != 0) // envia buffer
  187.     {
  188.         while(!(UCSR0A & (1<<UDRE0)));
  189.         UDR0 = buffer[index];
  190.         index++;
  191.     }
  192. }
  193.  
  194. /***********************************************************************************************/
  195. /* alinea 7 */
  196. int main(void)
  197. {
  198.     unsigned char sw_tmp=0;
  199.    
  200.     Inic();
  201.     Sistema = OFF;
  202.     PORTA &= 0xF7; // Led OFF
  203.    
  204.     while(1)
  205.     {
  206.         sw_tmp = PINA & 0x07; // ler switches
  207.        
  208.         switch (sw_tmp)
  209.         {
  210.             case sw_ON: // se S1 activado
  211.                 if ((Leitura_AD > 461) && (Leitura_AD < 562))
  212.                 {
  213.                     Sistema = ON;
  214.                     PORTA |= 8; // Led ON
  215.                 }
  216.                 break;
  217.                
  218.             case sw_OFF: // se S2 activado
  219.                 if ( (Leitura_AD > 461) && (Leitura_AD < 562))
  220.                 {
  221.                     Sistema = OFF;
  222.                     PORTA &= 0xF7; // LED OFF
  223.                 }
  224.                 break;
  225.                
  226.             case STOP: // se S3 activado
  227.                 OCR2 = 0; // motor OFF
  228.                 Sistema=OFF;
  229.                 PORTA &= 0xF7; // LED OFF
  230.         }
  231.        
  232.         if (Sistema == ON)
  233.         {
  234.             if (Fim_Conversao)
  235.             {
  236.                 Calcula_PWM();
  237.                 Fim_Conversao = 0;
  238.             }
  239.            
  240.             if (Flag_TX == ON)
  241.             {
  242.                 Print();
  243.                 Flag_TX = OFF;
  244.             }
  245.         }
  246.     }
  247. }
  248.  
  249.  
  250. // Assembly
  251. #define __SFR_OFFSET 0
  252.  
  253. #include <interrupt.h>
  254.  
  255. .extern cnt_1s
  256. .extern Flag_TX
  257. .global tmr0
  258.  
  259. tmr0:
  260.     push r16
  261.     push r17
  262.     push r18
  263.     in r17, SREG
  264.  
  265.     sbi ADCSRA, 6 ; start da nova conversão
  266.  
  267.     lds r16, cnt_1s ; temporizacao de 1s
  268.     dec r16
  269.     sts cnt_1s, r16
  270.     brne fim
  271.     ldi r18, 1 ; se passou 1s ...
  272.     sts Flag_TX, r18 ;... activa flag TX ...
  273.     ldi r16, 10 ;... e recarrega contador
  274.     sts cnt_1s, r16
  275.  
  276. fim:
  277.     out SREG, r17
  278.     pop r18
  279.     pop r17
  280.     pop r16
  281.     ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement