HØGSKOLEN I SØR-TRØNDELAG Avdeling for teknologi Målform: Norsk Eksamensdato: 13. mai 2014 Varighet/eksamenstid: 0900-1400 Emnekode: Emnenavn: TELE3010 Mikroprosessorsystemer Klasse(r): 2EE 2EI Studiepoeng: 10 Faglærer(e): Rolf Kristian Snilsberg, tlf 920 15 423 Kontaktperson(adm.) Hjelpemidler: Kalkulator (type C), vilkårlig lærebok i C. Oppgavesettet består av: Vedlegg består av: 4 oppgaver og 3 sider 25 dobbeltsidige ark Merknad: Oppgaveteksten kan beholdes av studenter som sitter eksamenstiden ut. NB! Les gjennom hele oppgavesettet før du begynner arbeidet, og disponer tiden. Dersom noe virker uklart i oppgavesettet, skal du gjøre dine egne antagelser og forklare dette i besvarelsen. Lykke til!
Oppgave 1. (20 %) a) Hva menes med at en lysdiode (led) eller knapp er aktiv lav? Svar: Lysdioden lyser ved lavt nivå ut og ikke ved høyt nivå. Knappen gir lavt nivå inn når den trykkes og eventuelt høyt nivå hvis det er pull-up motstand tilkoblet. b) Hva er en bootloader? Svar: En programvare som ligger i boot flash delen av programminnet (flash). Det er beregnet på å oppdatere hovedapplikasjonen på mikrokontrolleren siden kode kan kjøres derfra samtidig som den skriver til applikasjonsdelen av flash (eventuelt. laste programmet). Spørsmålet ble ikke tillagt vekt på eksamen. c) Er AVR en RISC eller CISC mikrokontroller med Harvard eller Von Neuman arkitektur? Svar: RISC og Harvard. d) Er UART-kommunikasjon asynkron eller synkron? Simplex, halv eller full dupleks? Svar: Universal asynchronous receiver/transmitter, asynkron dvs. at klokke ikke overføres mellom sender og mottager. Kan være både simplex (enveis), halv dupleks (en vei av gangen) og full dukpleks (begge veier samtidig). e) Forklar hvordan avbrudd (interrupts) fungerer i ATmega2560 fra avbruddet oppstår til retur fra avbruddet. Stikkord: programteller, stack, prioritet, responstid. Svar: Kjørende instruksjon fullføres, globale avbrudd deaktivert (I-bit et i SREG slettes), returadresse pushes på stack og eventuelt avbruddflagg slettes. Avbruddskode er vanligvis ett hopp (JMP) til avbruddsrutine. Ved retur aktiveres globale avbrudd, returadresse hentes fra stakken og legges inn i programtelleren (PC). Minst en instruksjon utføres etter retur før neste avbrudd kan trigges. Hvis flere avbrudd inntreffer samtidig blir det med lavest adresse kjørt først. Responstid er 5 klokkesykler i ATmega2560 og 4 klokkesykler i ATmega328P. Oppgave 2. (10 %) a) Skriv assembly-instruksjonen som kopierer r16 til r0. Svar: mov r0,r16 b) Finn operasjonskoden for oppgaven over. Svar: mov r0,r16 // Instruction code = 0010 11rd dddd rrrr // r=16=0b10000, d=0=0b00000, // Instruction code = 0b 0010 1110 0000 0000 = 0x 2E 00
Oppgave 3. (20 %) Skriv et assembly-program for ATmega328P i ATmega328P Xplained mini. PB5 er koblet til en gul lysdiode (led) som er aktiv høy og PB7 er koblet til en bryter (switch) som er aktiv lav. Når knappen trykkes skal lysdioden slås på. Hvis knappen holdes inne mer enn ett halvt sekund skal lysdioden slås av. Realiser de delene av koden du får til og skriv pseudokode for resten. Pass på å skrive oversiktlig med god dokumentasjon på hva koden gjør. Svar: // Led connected to PB5 pin active high, switch connected to PB7 active low. sbi DDRB, DDB5 // PB5 output pin (for LED) cbi PORTB,PORTB5 // Make sure led is off. /* Main loop turns on LED if button is pushed and off if it's pushed longer than ~0.5sec Assumes 16MHz clock. main_loop: sbic PINB,PINB7 // check if button is pushed rjmp main_loop // button not pushed, start over sbi PORTB,PORTB5 // button pushed so turn on led /* Loop takes 10 clock cycles. 0.5 second delay @ 16MHz clock is 8 million cycles 8 Million/10 = 800000 #define delay_loops 800000 // loop ldi r16,byte1(delay_loops) // 1 clock cycle ldi r17,byte2(delay_loops) // 1 clock cycle ldi r18,byte3(delay_loops) // 1 clock cycle delay_loop: sbic PINB,PINB7 // Check if button is still pressed. 2 clock cyles since rjmp is 1 word rjmp main_loop // Jump to main loop if button is released while waiting. // rjmp is not executed in the delay loop so not counted on clock cycles subi r16,0x01 // subtract 1. 1 clock cycle sbci r17,0x00 // subtract carry. 1 clock cycle sbci r18,0x00 // subtract carry. 1 clock cycle brne delay_loop // jump if result!= 0, 2 cycles if taken, 1 otherwise cbi PORTB,PORTB5 // button pushed for more than 0.5 sec, turn off led again. release_button: sbis PINB,PINB7 // Check if button is still pressed. rjmp release_button // Button is released so safe to start testing again. rjmp main_loop Oppgave 4. (50 %) Skriv et program i c-kode for ATmega328P for AVRGCC kompilatoren. Programmet skal utføre følgende: Lese en lyssensor som er koblet på ADC2 inngangen. Bruke resultatet fra lysmålingen til å styre en servo som er koblet til OC1A utgangen. Servomotoren skal ha signal med periode 20 millisekunder. Hvis signalet er høyt i 1ms (og lavt resten av perioden) så er motoren i posisjon 0 og hvis det er høyt i 2ms så er motoren i posisjon 180.
1ms=0 20ms 1.5ms=90 20ms 2ms=180 20ms Anta at ATmega328P er konfigurert med ekstern oscillator og systemklokke på 16MHz. Delene kan løses uavhengig av hverandre, så implementer hver delfunksjon for seg og ikke bli låst selv om du ikke får til alt. Programmet bør inneholde funksjonene: main() Timer1_init() ADC_init() Legg vekt på oversiktlig programstruktur og god dokumentasjon med beskrivende kommentarer. Vedlegg: AVR Instruction set side: 1, 95. ATmega328P datablad, sider: 1-26, 75-78, 111-139, 237-252, 612-617, 642-647 Løsning: /* Exam in upsys_2015_c.c Created: 07.05.2015 09:34:03 Author: rolfks Task: Read a light sensor connected to ADC2 input. Use the above result to control a servomotor connected to OC1A output. ADC2 input is PC2 pin. OC1A output is PB1 pin. This code will in addition output the measured ADC value on UART @ 9600 baud, which is for debugging purposes and not required in the task. The code is meant to be run on the ATmega328P Xplained mini. // Defines #define F_CPU 16000000UL // 16MHz system clock #define UART_BAUDRATE 9600UL // Include definition file(s) #include <avr/interrupt.h> #include <util/delay.h> #include <stdio.h> // Prototypes
void usart_putchar( char data ); void USART_init(uint16_t ubrr_value); void ADC_init(void); void TIMER1_init(void); // the following line is required to use printf static FILE uart_str = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE); // for printf to work /* Main int main( void ) TIMER1_init(); USART_init(F_CPU/(16*UART_BAUDRATE)-1); ADC_init(); stdout = &uart_str; // to make printf work do /* The next line uses the ADC value read from the light sensor to control the servo motor. The raw ADC values are 10 bit, i.e. 0-1023. The pwm duty cycle for the servo signal should be in the range 1000-4000, thus using the adc-value * 3 is appropriate. OCR1A=1000+ADC*3; // The next two line are not required as answer to the task. printf("adc data = %d\r",adc); // prints ADC value to USART for debugging. _delay_ms(250); // Delay between each update. Optional. while(1); /* Timer 1 initialisation. Timer 1 is set Fast PWM non-inverting mode with ICR as TOP Prescale 16Mhz by 8 -> 2MHz = 0.5us/timer tick. ICR1 will control how far the timer counts before resetting and thus control the servo signal period which is 20ms = 20000us = 40000 tics. Servo maximum is 2ms = 4000 tics. Servo minimum is 0.5ms = 1000 tics. void TIMER1_init(void) DDRB = (1<<DDB1); // Set OC1A/PB1 as output. ICR1 = 40000; // Servo period TCCR1A = (1<<COM1A1) (0<<COM1A0) (1<<WGM11) (0<<WGM10); TCCR1B = (1<<CS11) (1<<WGM13) (1<<WGM12); OCR1A = (4000+1000)/2; // Manual setting to 90 /* Putchar function for printf to work. Waits for uart data register to be ready for new data before writing provided data (char). void usart_putchar(char data) while ((UCSR0A & (1 << UDRE0)) == 0) ; // Wait for empty transmit buffer UDR0 = data; // Start transmission /* UART initialisation UART is set up with the provided baud rate, in 8 bit mode with 1 stop bit and no parity. Transmission and reception enabled. void USART_init(uint16_t ubrr_value) UBRR0 = ubrr_value; // set baud rate UCSR0C = ((1<<UMSEL01) (3<<UCSZ00)); // 8 bit 1 parity UCSR0B = ((1<<TXEN0) (1<<RXEN0)); // enable transmitter, reciever and interrupt
/* ADC initialisation. ADC is set up with ADC2 as input and result not left shifted. ADC is enabled, ADC converting started, auto trigging enabled, prescaler is 128 which gives 16MHz/128 = 125Kz ADC clock. void ADC_init(void) DDRC &= ~(1<<DDC2); // ADC2 = PC2 input ADMUX = (0<<ADLAR) (0b0010<<MUX0); ADCSRA = ((1<<ADEN) (1<<ADSC) (1<<ADATE) (1<<ADPS0) (1<<ADPS1) (1<<ADPS2)); ADCSRB = 0x00; // Free running mode. Default but explicitly set.