Examen uPuC_Février_2021 & Correction

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 20

École Nationale d’Ingénieurs de Monastir

Département de Génie Électrique


AU : 2020-2021
Classe : GEL 2
Date : Jeudi 4-2-2021 - Durée : 1,5 heures
Documents non autorisés.
Enseignant : M. Lotfi BOUSSAID

Examen de la session principale


Microprocesseur & Microcontrôleur

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

Exercice 2 : Utilisation du TIMER en mode compteur (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.
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.

Exercice 3 : Télécommande SONY à protocole SIRC 12 bits (10 points)


Le protocole SIRC est un des nombreux protocoles de communication binaire développé par la société SONY
et utilisé pour les télécommandes infrarouges pour commander les appareils électroniques notamment ceux
utilisés en audiovisuel.
La trame du protocole est basée sur un codage émis sur une fréquence porteuse de 40 kHz. La composition
de la trame version 12 bits est détaillée à la Figure 2 :
• 1 bit de départ (Start) de 2,4ms suivi d'une pause de 600 us ;
• 7 bits de commande pour l'instruction ;
• 5 bits d'adresses.
Page 1 sur 20
Figure 1. Trame du protocole SONY (version 12 bits)
Le protocole Sony utilise une modulation à largeur d'impulsion (PWM).
Le bit "1" logique est codé avec une rafale de 1,2 ms de porteuse de 40 kHz, tandis que le bit "0" logique est
de 0,6 ms (Figure 3).

Figure 2. Codage des bits logiques


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).

Figure 3. Signal de la porteuse à 40 KHz


Les messages transmis par la télécommande SIRC comprenant la commande et l’adresse de l’appareil est
donnée par la table suivante :
Fonction Commande Appareil Adresse
Touche 0 0 TV 1
Touche 1 1 Magnétoscope 1 2
Touche 2 2 Magnétoscope 2 3
… … … …
Channel + 16 Equaliseur 18
Channel - 17
Volume + 18
Volume - 19
Table 1. Liste des commandes et des adresses des appareils SIRC
Ainsi, pour augmenter le volume sonore d’un téléviseur, le message SIRC comprend le bit de départ, le
code « 18 » (Volume +) et le code « 1 » (TV).
On désire alors réaliser une télécommande SIRC en utilisant une carte électronique à base de
microcontrôleur PIC16F84A doté d’un oscillateur à quartz de 4 MHz. Nous rappelons que toutes les
instructions durent une période d’horloge, soit 1 us, exception faite pour les instructions de branchement
ou de branchement conditionnel qui durent 2µs.
On choisira la broche PA0 pour commander la diode infrarouge (Diode-IR) et les broches RB0, RB1, RB2,
RB3 et RB4 pour contrôler respectivement les touches 0, 1, 2, 3 et 4.

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 :

Commande Adresse appareil


Strat_bit 1 1 0 0 0 0 0 1 0 0 0 0
LSB MSB LSB MSB
7. Écrire le programme principal qui permet d’assurer le fonctionnement de la télécommande SIRC
proposée.

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 :

Figure 1. Liste des registres spéciaux

Figure 2. Schéma bloc du Timer0

Page 4 sur 20
Figure 3. Registre INTCON

Figure 4. Registre OPTION_REG


Page 5 sur 20
Figure 5. Liste des instructions

Page 6 sur 20
Correction de l’Examen

Exercice 1 :

Exercice 1 : (2 points)
1.
; ==================================================

movlw 0x0c ; initialisation pointeur


movwf FSR ; pointeur d'adressage indirect
Init1 clrf INDF ; effacer ram pointée par FSR
incf FSR,f ; pointer sur suivant
btfss FSR,6 ; tester si fin zone atteinte (>=0x40)
goto Init1 ; non, boucler
btfss FSR,4 ; tester si fin zone atteinte (>=0x50)
goto init1 ; non, boucler
….. ; Suite du programme

2. Le programme permet d’insérer des « 0 » à la mémoire RAM à partir de


l’adresse 0x0C jusqu’à l’adresse 0x50.

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

START bsf STATUS, RP0 ; go to bank 1


clrf TRISA ; set PORTA as OUTPUT
clrf TRISB ; set PORTB as OUTPUT
bsf TRISA,4 ; set RA4 as input
movlw B'1010 1000'
movwf OPTION_REG ; PS2 PS1 PS0 = 000 : sans division, PSA=1 : pré-diviseur affecté au WDT,
; TOSE=0 : front montant, T0CS=1 : horloge externe RA4,
bcf STATUS, RP0 ; go to bank 0

movlw b'1010 0000'


movwf INTCON ; GIE = 1 : Global interrupt enabled, TOIE = 1 : enable Timer0 interrupt
goto Main

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

; Main routine ---------------------------------------------------------------------


Main clrf Counter
Loop
goto Loop

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

#define OUTPUT_LED PORTA,0

org 0x00 ; origin vector


goto Init

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
2. Écrire un sous-programme « Delay_ms_600 » qui permet de réaliser une temporisation de 600 us.
Delay_ms_600:
movlw d'198' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; Loop Eq. = 3*197 = 591us (1 us Decfsz and 2 us goto)
goto $-1 ; +2T (last decfsz will skip so 2T)
nop ; 1T
return ; 2T --> Total= 598 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.

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

call Delay_ms_600 ; 598 T


return ; 2T return from subroutine

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 :

Commande Adresse appareil


Strat_bit 1 1 0 0 0 0 0 1 0 0 0 0
LSB MSB LSB MSB
Écrire le programme principal qui permet d’assurer le fonctionnement de la télécommande SIRC
proposée.

Page 11 sur 20
#include <p16f84a.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC

#define OUTPUT_LED PORTA,0 ; Define IR Led


#define Left_BTN PORTB,0 ; Define Inputs
#define Up_BTN PORTB,1
#define Down_BTN PORTB,2
#define Right_BTN PORTB,3
#define Stop_BTN PORTB,4

#define ADDR_TV d'1' ; TV Address


#define ADDR_CD_PLAYER d'17' ; CD PLAYER Address
#define CMD_POWER d'21' ; Sony Command
#define CMD_CHAN_UP d'16' ; Sony Command
#define CMD_CHAN_DOWN d'17' ; Sony Command
#define CMD_VOL_UP d'18' ; Sony Command
#define CMD_VOL_DOWN d'19' ; Sony Command
#define CMD_CHAN_1 d'00' ; Channel 0
#define CMD_CHAN_2 d'01' ; Channel 1
#define CMD_CHAN_3 d'02' ; Channel 2
#define CMD_CHAN_4 d'03' ; Channel 3
#define CMD_CHAN_5 d'04' ; Channel 4

org 0x00 ; origin vector


goto Main

;==================================================================================
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

; Detected the button as pressed. Send keydown code.


; Button's Action Code
; Repeatedly send SIRC transmission while button is held down
Left_BTN_action:

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

; Delay remaining time so that repetitive calls of SendSONY


; occur at 45ms intervals (as per SONY spec)

; Quickly clear the output


bcf OUTPUT_LED ; Set output low for off time

; 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

; Determine number of times to do loop = 47-N


comf BitCounter, F ; Perform "47 - BitCounter"
movlw d'47' ; Result will overflow, but 8-bit
addwf BitCounter, F ; result will be valid.

; Perform variable delay (more 1's reduces num loops)


movfw BitCounter ; Load #times to loop from above
movwf Delay_Count2 ; into outer loop delay counter
call delay_600us
decfsz Delay_Count2, F ; Go through loop
goto $-2 ; if count not 0, keep looping

; This delay is reasonably precise because the overhead for


; setting up the loop only adds a few microseconds to the loop
; time each time. However, compared to a 20-28ms delay between
; packets, the few microseconds are negligible.

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

call Delay_ms_600 ; 598 T


return ; 2T return from subroutine

;============================================================
; 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

; ==================== Delay of 600ms, pause where IR Led = 0 =========================


Delay_ms_600:
movlw d'198' ; 1T
movwf Delay_Count ; 1T
decfsz Delay_Count, F ; Loop Eq. = 3*197 = 591us (1 us Decfsz and 2 us goto)
goto $-1 ; +2T (last decfsz will skip so 2T)
nop ; 1T
return ; 2T --> Total= 598 us

; =================================== Delay = 35 us ================================


DebounceDelay:
Movlw d'10' ; Move 0x0A into w (count, 10) --> 1T
movwf Delay_Count ; Move w -> Delay_Count --> 1T
decfsz Delay_Count, F ; Decrement file skip if 0
goto $-1 ; repeat until 0 --> ((9*3)+2) T= 29T
;
return ; Return program flow --> 2T
; TOTAL DELAY --> 33us (call DebounceDelay: 35us)
;==================================================================================
;==================================================================================
end

Page 20 sur 20

Vous aimerez peut-être aussi