Examen uPuC_Février_2021 & Correction
Examen uPuC_Février_2021 & Correction
Examen uPuC_Février_2021 & Correction
Exercice 1 : (4 points)
Soit le code du programme assembleur ci-dessous.
1. Commenter chacune des lignes du programme et expliquer l’utilité de chaque bloc de code.
2. À partir des différentes instructions, expliquer ce que fait ce programme.
; ==================================================
movlw 0x0c ;
movwf FSR ;
Init1 clrf INDF ;
incf FSR,f ;
btfss FSR,6 ;
goto Init1 ;
btfss FSR,4 ;
goto Init1 ;
; Suite du programme
Page 2 sur 20
Figure 4. Schéma de câblage de la télécommande SIRC
1. Écrire un sous-programme « Init » qui permet de configurer le port A en sortie et le port B en entrée.
2. Écrire un sous-programme « Delay_ms_600 » qui permet de réaliser une temporisation de 600 us.
3. Écrire un sous-programme « Start_bit » qui permet de générer un signal modulé sur la broche PA0
comme indiqué à la figure 2. Une rafale de 96 impulsions pendant 2,4 ms suivie d’une pause de 600 us.
La rafale est un signal PWM de période 25 us et de largeur d’impulsion 7 us (Figure 4). Ainsi, il faut
générer 96 fois le signal PWM pour obtenir le start_bit de 2,4 ms suivie d’une pause de 600 us.
4. Écrire un sous-programme « Send_IR_Zero » qui permet de générer une rafale de 24 impulsions qui
représentent 600 us du temps haut de "0" logique suivie d’une pause de 600 us.
5. Écrire un sous-programme « Send_IR_One » qui permet de générer une rafale de 48 impulsions qui
représentent 1200 us du temps haut de "1" logique suivie d’une pause de 600 us.
6. En supposant que les messages SIRC à transmettre sont destinés pour un appareil TV (code = 1), écrire
un sous-programme qui permet de scruter les cinq touches 0,1, 2, 3 et 4 et de générer la trame
correspondante à la touche enfoncée comme suit :
Start bit + Code de la touche (7 bits) + Code de l’appareil (5 bits)
Exemple :
Quand la touche 3 est enfoncée le message transmis est le suivant :
Rappelons que pour les microcontrôleurs RISC, toutes les instructions durent 1 cycle machine, les sauts
conditionnels durent 2 cycles machines en cas de saut sinon un seul cycle et enfin les sauts inconditionnels
(goto) durent toujours 2 cycles machine.
Page 3 sur 20
Annexe :
Page 4 sur 20
Figure 3. Registre INTCON
Page 6 sur 20
Correction de l’Examen
Exercice 1 :
Exercice 1 : (2 points)
1.
; ==================================================
Exercice 2 : (6 points)
On désire réaliser un compteur modulo 100 en utilisant le Timer 0 en mode compteur et l’entrée RA4 reliée
à un capteur Infrarouge qui permet de détecter les pièces usinées dans une chaîne de production industrielle.
Ainsi, le compteur est incrémenté à chaque front montant arrivant sur la broche RA4.
1. Écrire le sous-programme « Init » permettant d’assurer les configurations nécessaires.
#include <p16f84a.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
Counter EQU 0x0C ; Define variable Counter
org 0x00 ; origin vector
goto START
org 0x04 ; interrupt vector
goto ISR
Page 7 sur 20
2. À chaque passage d’une pièce usinée, le compteur du Timer0 est incrémenté. Écrire le programme
« Main » permettant d’incrémenter une variable « Counter » à chaque passage de 100 pièces.
On utilise le registre TMR0 (adresse 01h) du Timer0 qui se trouve à la banque 0 (voir tableaux en
annexes) qui indique l’état du compteur.
; Interrupt service routine--------------------------------------------------------
ISR
bcf INTCON, GIE ; Disable all interrupts inside interrupt service routine
movlw 0x9C ; TMR0 initialized by 156 to overflow after 100 pulses
movwf TMR0
bcf INTCON, TOIF ; Clear Timer 0 interrupt flag bit
incf Counter ; Counter incremented each overflow after 100 pulses
bsf INTCON, GIE ; Enable all interrupts on exit
end
Page 8 sur 20
Exercice 3 : (12 points)
La porteuse étant de 40 KHz, ce qui équivaut 24 impulsions pendant le temps haut de "0" (600 us) et 48
impulsions pendant le temps haut de "1" (1200 us).
1. Écrire un sous-programme « Init » qui permet de configurer le port A en sortie et le port B en entrée.
#include <p16f84a.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
Start_bit:
; HIGH PORTION (2.4 ms = 2400 us)
movlw d'96' ;
movwf Delay_Count2 ; num pulses counter
CarrierLoopOne:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (delayed 7us completed)
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; 1T / 2T
goto $-1 ; 2T
; Total 1 + 1 + 3*2 +2 = 10
goto $+1 ; 2T
goto $+1 ; 2T
Page 9 sur 20
decfsz Delay_Count2, F ; 1T
goto CarrierLoopOne ; 2T
; 10 + 2 + 2 + 3 + 1 (bsf output_led) = 18 T
; DONE Sending a one
call Delay_ms_600 ; pause of 598 us
return ; + 2T ➔ Total = 600 us
4. Écrire un sous-programme « Send_IR_Zero » qui permet de générer une rafale de 24 impulsions qui
représentent 600 us du temps haut de "0" logique suivie d’une pause de 600 us.
;------------------------------------------------------------------
; Send IR Zero in FORMAT: Sony SIRC
; fc = 40kHz
; Tc = 1/fc = 25us
; DC = 25%-33% for carrier
; (Use 7us/25us = 28% duty cycle)
; hitime=600us - lowtime = 600us
;------------------------------------------------------------------
Send_IR_Zero:
; HIGH PORTION (1.2ms = 1200 instructions)
; Toggle 7us on, 18us off, for: fc = 40kHz, DC = 28%
movlw d'24' ;
movwf Delay_Count2 ; num pulses counter
CarrierLoopZero:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T, Start counting
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (End of 7 us)
;=======================================================
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count,F ;
goto $-1 ; Loop time : ((3*2)+2)T = 8T
goto $+1 ; 2T
goto $+1 ; 2T
decfsz Delay_Count2, F ; 1T
goto CarrierLoopZero ; 2T ➔ Time = (1 + 1 + 8 + 2 + 2 + 1 + 2 + 1 (bsf output_led) = 18 T
goto $+1 ; Last iteration: 1+1+8+2+2+2+2 = 18 us
5. Écrire un sous-programme « Send_IR_One » qui permet de générer une rafale de 48 impulsions qui
représentent 1200 us du temps haut de "1" logique suivie d’une pause de 600 us.
Page 10 sur 20
;============================================================
; Send IR One in FORMAT Sony SIRC:
; Fc = 40kHz
; Tc = 1/Fc = 25us
; DC = 25%-33% for carrier
; (Use 7us/25us = 28% duty cycle)
; low_time = 600us, hi_time=1200us
;============================================================
Send_IR_One:
; HIGH PORTION (1.2ms = 1200 instr)
; Toggle 7us on, 18us off, for: Fc = 40kHz, DC = 28%
movlw d'48' ;
movwf Delay_Count2 ; num pulses counter
CarrierLoopOne:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (delayed 7us completed)
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; 1T / 2T
goto $-1 ; 2T
; Total 1 + 1 + 3*2 +2 = 10
goto $+1 ; 2T
goto $+1 ; 2T
decfsz Delay_Count2, F ; 1T
goto CarrierLoopOne ; 2T
; 10 + 2 + 2 + 3 + 1 (bsf output_led) = 18 T
; DONE Sending a one
call Delay_ms_600 ; pause of 598 us
return ; + 2T ➔ Total = 600 us
6. En supposant que les messages SIRC à transmettre sont destinés pour un appareil TV (code = 1), écrire
un sous-programme qui permet de scruter les cinq touches 0,1, 2, 3 et 4 et de générer la trame
correspondante à la touche enfoncée comme suit :
Start bit + Code de la touche (7 bits) + Code de l’appareil (5 bits)
Exemple :
Quand la touche 3 est enfoncée le message transmis est le suivant :
Page 11 sur 20
#include <p16f84a.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
;==================================================================================
Init: bsf STATUS, RP0 ; go to bank 1
clrf TRISA ; set PORTA as OUTPUT
movlw 0xFF ;
movwf TRISB ; set PORTB as INTPUT
bcf STATUS, RP0 ; go to bank 0
return
;==================================================================================
Main:
goto Init
Mainloop:
;==================================================================================
; Left_BTN test --- CHANNEL_1
; Check if button is pushed down
;==================================================================================
btfss Left_BTN
goto skip_Left_BTN ;
call DebounceDelay ; Short debounce delay
btfss Left_BTN ; check if button is up (false indicator)
goto skip_Left_BTN ; bttn is up, skip action code
Page 12 sur 20
movlw ADDR_TV
movwf AddrByte ; Load Device Address
movlw CMD_CHAN_1
movwf DataByte ; Load Data byte with command
call SendSONY
btfsc Left_BTN
goto Left_BTN_action ; Keep sending code while bttn down
;==================================================================================
; End test Left BTN .. Test next button
;==================================================================================
;==================================================================================
; Up_BTN test --- CHANNEL_2
; Check if button is pushed down
;==================================================================================
skip_Left_BTN:
btfss Up_BTN
goto skip_Up_BTN ; button is up, skip play code
call DebounceDelay ; Short debounce delay
btfss Up_BTN ; check if button is still down
goto skip_Up_BTN ; bttn is up, skip action code (false indicator)
Up_BTN_action:
movlw ADDR_TV
movwf AddrByte ; Load Device Address
movlw CMD_CHAN_2
movwf DataByte ; Load Data byte with command
call SendSONY
btfsc Up_BTN
goto Up_BTN_action ; Keep sending code while bttn down
;==================================================================================
; Down_BTN test --- CHANNEL_3
; Check if button is pushed down
;==================================================================================
skip_Up_BTN:
btfss Down_BTN
goto skip_Down_BTN ; button is up, skip play code
call DebounceDelay ; Short debounce delay
btfss Down_BTN ; check if button is still down
goto skip_Down_BTN ; bttn is up, skip action code (false indicator)
Down_BTN_action:
movlw ADDR_TV
movwf AddrByte ; Load Device Address
movlw CMD_CHAN_3
movwf DataByte ; Load Data byte with command
call SendSONY
btfsc Down_BTN
goto Down_BTN_action ; Keep sending code while bttn down
;==================================================================================
Page 13 sur 20
; Right_BTN test --- CHANNEL_4
; Check if button is pushed down
;==================================================================================
skip_Down_BTN:
btfss Right_BTN
goto skip_Right_BTN ; button is up, skip play code
call DebounceDelay ; Short debounce delay
btfss Right_BTN ; check if button is still down
goto skip_Right_BTN ; bttn is up, skip action code (false indicator)
Right_BTN_action:
movlw ADDR_TV
movwf AddrByte ; Load Device Address
movlw CMD_CHAN_4
movwf DataByte ; Load Data byte with command
call SendSONY
btfsc Right_BTN
goto Right_BTN_action ; Keep sending code while bttn down
;==================================================================================
; Stop_BTN test --- CHANNEL_5
; Check if button is pushed down
;==================================================================================
skip_Right_BTN:
btfss Stop_BTN
goto skip_Stop_BTN ; button is up, skip play code
call DebounceDelay ; Short debounce delay
btfss Stop_BTN ; check if button is still down
goto skip_Stop_BTN ; bttn is up, skip action code (false indicator)
Stop_BTN_action:
movlw ADDR_TV
movwf AddrByte ; Load Device Address
movlw CMD_CHAN_5
movwf DataByte ; Load Data byte with command
call SendSONY
btfsc Stop_BTN
goto Stop_BTN_action ; Keep sending code while bttn down
skip_Stop_BTN:
goto MainLoop
Page 14 sur 20
;==================================================================================
; SendSONY: Send the Sony SIRC protocol. Designed to be called over
; and over in a loop while a button is held down.
; Inputs:
; DataByte = 7 bits of data to send in LSBs (data = command)
; AddrByte = 5 bits of device address to send in LSBs
;==================================================================================
SendSONY:
; bit 0
movlw 0
movwf BitCounter ; Clear bit counter to count ones
call Start_bit
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C ; NOTE!!
call SendOne ; bit is 1, send a one
btfsc STATUS, C ; NOTE!!
incf BitCounter, F
; NOTE!! testing carry after subroutine
; works ONLY if subroutine does NOT contain
; any add/subtract/rotate commands. These
; commands augment C flag.
; bit 1
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 2
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 3
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 4
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
Page 15 sur 20
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 5
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 6
rrf DataByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; SEND ADDRESS
; Begin shifting out address
; bit 0
rrf AddrByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 1
rrf AddrByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 2
rrf AddrByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
Page 16 sur 20
; bit 3
rrf AddrByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; bit 4
rrf AddrByte, F ; Shift out LSB ➔ C = LSB
btfss STATUS, C ; if bit is 1, skip next instr.
call SendZero ; bit is 0, send a zero
btfsc STATUS, C
call SendOne ; bit is 1, send a one
btfsc STATUS, C
incf BitCounter, F
; Decide how many ones were sent, and compute time to delay
; Delay time remaining = 45 -2.4 -12*1.2 - N*0.6 where N=#ones
; [every time] [Tx dependant]
; 45 - 16.8ms - N*0.6ms
; Td = 28.2 - N*0.6ms = (47-N)*600us
return
;------------------------------------------------------------------
Page 17 sur 20
;------------------------------------------------------------------
; Send IR Zero in FORMAT: Sony SIRC
; fc = 40kHz
; Tc = 1/fc = 25us
; DC = 25%-33% for carrier
; (Use 7us/25us = 28% duty cycle)
; hitime=600us - lowtime = 600us
;------------------------------------------------------------------
Send_IR_Zero:
; HIGH PORTION (1.2ms = 1200 instructions)
; Toggle 7us on, 18us off, for: fc = 40kHz, DC = 28%
movlw d'24' ;
movwf Delay_Count2 ; num pulses counter
CarrierLoopZero:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T, Start counting
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (End of 7 us)
;=======================================================
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count,F ;
goto $-1 ; Loop time : ((3*2)+2)T = 8T
goto $+1 ; 2T
goto $+1 ; 2T
decfsz Delay_Count2, F ; 1T
goto CarrierLoopZero ; 2T ➔ Time = (1 + 1 + 8 + 2 + 2 + 1 + 2 + 1 (bsf output_led) = 18 T
goto $+1 ; Last iteration: 1+1+8+2+2+2+2 = 18 us
;============================================================
; Send IR One in FORMAT Sony SIRC:
; Fc = 40kHz
; Tc = 1/Fc = 25us
; DC = 25%-33% for carrier
; (Use 7us/25us = 28% duty cycle)
; low_time = 600us, hi_time=1200us
;============================================================
Send_IR_One:
; HIGH PORTION (1.2ms = 1200 instr)
; Toggle 7us on, 18us off, for: Fc = 40kHz, DC = 28%
movlw d'48' ;
movwf Delay_Count2 ; num pulses counter
Page 18 sur 20
CarrierLoopOne:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (delayed 7us completed)
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; 1T / 2T
goto $-1 ; 2T
; Total 1 + 1 + 3*2 +2 = 10
goto $+1 ; 2T
goto $+1 ; 2T
decfsz Delay_Count2, F ; 1T
goto CarrierLoopOne ; 2T
; 10 + 2 + 2 + 3 + 1 (bsf output_led) = 18 T
; DONE Sending a one
call Delay_ms_600 ; pause of 598 us
return ; + 2T ➔ Total = 600 us
Page 19 sur 20
; ================= Start bit (HIGH PORTION: 2.4ms with modulation and 600us pause =======
Start_bit:
movlw d'96' ;
movwf Delay_Count2 ; num pulses counter
CarrierLoopOne:
bsf OUTPUT_LED ; 1T, Led IR = 1 after 1T
;=======================================================
goto $+1 ; 2T
goto $+1 ; 2T
goto $+1 ; 2T
bcf OUTPUT_LED ; 1T (delayed 7us completed)
movlw d'3' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; 1T / 2T
goto $-1 ; 2T
; Total 1 + 1 + 3*2 +2 = 10
goto $+1 ; 2T
goto $+1 ; 2T
decfsz Delay_Count2, F ; 1T
goto CarrierLoopOne ; 2T
; 10 + 2 + 2 + 3 + 1 (bsf output_led) = 18 T
; DONE Sending a one
call Delay_ms_600 ; pause of 598 us
return ; + 2T ➔ Total = 600 us
Page 20 sur 20