Télécommande lumières extérieurs Bluetooth
- Objectif : Télécommander l'éclairage, le portail, ect en bluetooth.
- Moyen:
ATTINY85-20SU/PU DIP-8 - 1,73€ Arduino Nano ATmega328P - 1,98€
Support CI, DIP-8 - 0,10€
AC-DC Alimentation Commutation 230V à 5V 700mA Convertisseur de Tension Régulée - 1,79€ ou
HLK-5M05, Alimentation 5V, 5W - 2,50€
- HC-06 module esclave Bluetooth - 3,43€
- plaque d'essais double face - Dimensions 30x70mm - Pas 2.54mm - 2,25€
- 5V 4 Canaux Relais avec Bouclier Optocoupleur - 3,30€
ou 5V 1 Canal Relais avec Bouclier Optocoupleur - 1,80€
- Petit matériel - 1€
- 5 résistances 10kΩ
- 1 résistance 1kΩ
- 1 résistance 1.5kΩ
Soit un total maximale de 18.36 €, hors téléphone et boitier, bien entendu.
Le principe
Soit un circuit électrique d'éclairage
A partir de celui-ci je souhaite ajouter une commande Bluetooth (Pour l'instant Android).
La transmission asynchrone
Le choix du protocole série asynchrone.
La vitesse de transmission
Temps de bit : Ce temps est lié au débit binaire en bits par seconde ( bit/s ou bauds )de la transmission.
$Débit~binaire = \dfrac{1}{T}$. Par exemple, si $T = 1~ms$, la transmission se fait à $1000 bit/s$.
Vitesse de transmission “standard” en bauds (bits par secondes) 1200, 2400, 4800, 9600, 19200, 38400, 57600, et 115200.
Un bit de stop, et pas de bit de parité "none"
Je choisirai celui qui correspond au HC-06 soit 9600 bauds
Un bit de "start", un bit de "stop" et pas de parité "none"
bit | Start | b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | Stop |
Valeur | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
Le bit de départ a un niveau logique "0" tandis que le bit d'arrêt est de niveau logique "1".
Le bit de donnée de poids faible est envoyé en premier suivi des autres.
Tout d'abords, je vais déterminer le temps de transmission de chaque bit, et de chaque octet en fonction de la vitesse de mon processeur.
Pour la réception
Pour prendre l'information au plus vraie, je la prend au milieu du bit, soit 1.5bit après le premier front descendant du bit de "start".
Le programme
Solution 6, et dernière
L'ajout de bouton poussoir augmenterai l'utilisation des ports, j'utiliserai donc un Arduino Nano (Sniff, je m'éclate plus en assembleur sur Attiny85).
Le seul inconvénient de ce système est l'obligation de remplacer un interrupteur par un bouton poussoir, et de refaire son câblage en 5V.
Ce pendant, je retiens cette solution!, c’est une installation dans le bâtiment extérieurs de mon ami Nicolas, on verra ensemble, si cette solution lui convient!
Pour l'emission Bluetooth du l'HC-06, l'entrée est sur 3,3V, je calcul un petit diviseur de tension :
$V_s=\dfrac{R_2}{R_1+R_2}\cdot V_{cc}$ avec $V_s=3,3V$ et $V_{cc}=5V$ alors $\dfrac{R_2}{R_1+R_2}=\dfrac{V_s}{V_{cc}}=\dfrac{3,3}{5}$
$5\times R_2=3,3\times(R_1+R2)$ soit $R_2=\dfrac{33}{17}\times R_1$ pour $R_1=1k\Omega$, $R_2=1,94k\Omega$, vue mon stock ce sera $1,7k\Omega$.
Je vérifie la tension :
$V_s=\dfrac{1,7}{1+1,7}\times 5=3,15 V$ pour 3,3V, c'est bon ça!
Synthèse des branchements
Le schéma est un principe, le programme est réalisé avec les consignes suivantes.
Utilisation par ports:
Broche | Désignation | Fonction | Zone |
Pin D2 | PD2/INT0 | Interruption externe, Tx du HC-06, Rx de l'arduino |
Pin D3 | PD3/INT1 | Interruption externe, Tous les Boutons poussoir |
Pin D4 | PD4 | Rx du HC-06, Tx de l'arduino |
Pin D8 | PB0 | Sortie Relay 0 | Portail (1 relais 10A) |
Pin D9 | PB1 | Sortie Relay 1 | Bassin 4 lampes (10A max) |
Pin D10 | PB2 | Sortie Relay 2 | Terasse (10A max) |
Pin D11 | PB4 | Sortie Relay 3 | Entrée 6 lampes (10A max) |
Pin D12 | PB3 | Sortie Relay 4 | Plus (10A max) |
Pin A0 | PC0 | Entrée BP 0 |
Pin A1 | PC1 | Entrée BP 1 |
Pin A2 | PC2 | Entrée BP 2 |
Pin A3 | PC3 | Entrée BP 3 |
Pin A4 | PC4 | Entrée BP 4 |
---|
Attention: pour le portail, une seule impulsion de 200cs paramétrable par l'administrateur
Option du programme
Une option qui me paraît intéressante, si la lumière reste allumé un temps important (comme 2.5h par exemple, paramétrable par l'administrateur), alors la lumière s'éteint toute seule.
Le branchement étant défini, je passe à la programmation.
main.asm +
main.asm
;
; Bluetooth.asm
;
; Created: 07/04/2019 18:55:44
; Author : samuel.dupre
;
; Télécommande Bluetooth Relais
; Matériel : Arduino nano 16MHz 5V
; (c) sammy76.free.fr 07/04/2019 18:55:44
; V1.0 Version validée Attiny85
; V2.0 Ajout: Envoyé état Attiny85
; V3.0 Arduini Nano 18/04/2019
; V3.1 Arduini Nano
; -Ajout d'une tempo de 2h
; -Ajout une impulsion de 1.5s pour portail
; V3.2 Bug portail, contact sec, donc relay
; -Récupération du temps programmé "TP150" pour 150cs forcément 3 caractères "150"
; -Récupération du temps programmé "TP150" pour 150cs
; V3.3 Sauvegarde des paramètres dans l'EEPROM - 21/04/2019
; -"RL"
; -"TP150" -> 150 Temps portail (cs)
; -"VE1800" -> temps avant veille (cycles) 2*60*60/4 ->1800 cycles pour la veille de 2h
; -"M" -> renvoyer état PINB
;
; Principe :
; La récéption d'un signal bluetooth,
; Arduino nano
; +-USB-+
; D13|- -|D12 - PB4 RELAY4
; 3.3V|- -|D11 - PB3 RELAY3
; REF|- -|D10 - PB2 RELAY2
; BP0 - A0|- -|D9 - PB1 RELAY1
; BP1 - A1|- -|D8 - PB0 RELAY0
; BP2 - A2|- -|D7
; BP3 - A3|- -|D6
; BP4 - A4|- -|D5
; A5|- -|D4
; A6|- -|D3 - Tx
; A7|- -|D2 - Rx
; 5v|- -|GND
; RST|- -|RST
; GND|- -|RX0
; VIN|- -|TX1
; +-----+
;_____________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;Segment Begin End Code Data Used Size Use%
;---------------------------------------------------------------
;[.cseg] 0x000000 0x0002f8 760 0 760 32768 2.3%
;[.dseg] 0x000100 0x00016e 0 110 110 2048 5.4%
;[.eseg] 0x000000 0x000035 0 53 53 1024 5.2%
;Forme du message reçu:
;ASCII PORT ETAT
;"RL00" PB0 0
;"RL01" PB0 1
;....
;"RL40" PB4 0
;"RL41" PB4 1
.CSEG
.include "m328pdef.inc"
;.include "m168def.inc"
#define F_CPU 16000000 ;8MHz pour Attiny85
#define BAUD_RATE 9600 ;9600bauds
;#define delayportail 150 ;150centiseconde 1.5s
;#define DEBUG
;#define DEBUGRAM
;#define F_CPU 16500000 ;16.5MHz pour Digispark
.def temp0=R11
.def temp1=R12
.def prt =R13 ;port
;r0 et r1 servent pour la multiplication
;r2 et r3 aussi
.def formult=R4 ;x10
.def loopC =R22 ;loop registers for caracter 9600bps
.def State =R20 ;bit0 texte reçu à traiter 0/1
;bit1
.def DATA =R18 ;temporary registers
.def regAH =r17
.def regA =R16
.def regB =R19
.def zero =r10
.equ Rx =PD2 ;interruption INT0
.equ Tx =PD3
.equ Pportail =PB0
;************************************************
;* Interrupt Vectors *
;************************************************
.org 0000
jmp ON_RESET ; Reset Handler
jmp HC_06 ; IRQ0 Handler PD2 Rx
jmp nothing ; IRQ1 Handler PD3
jmp nothing ; PCINT0 Handler
jmp AllBP ; PCINT1 Handler All PC0..4 soit PCINT8..12 soit A0..4
jmp nothing ; PCINT2 Handler
jmp nothing ; Watchdog Timer Handler
jmp nothing ; Timer2 Compare A Handler
jmp nothing ; Timer2 Compare B Handler
jmp nothing ; Timer2 Overflow Handler
jmp nothing ; Timer1 Capture Handler
jmp nothing ; Timer1 Compare A Handler
jmp nothing ; Timer1 Compare B Handler
jmp compteur ; Timer1 Overflow Handler
jmp nothing ; Timer0 Compare A Handler
jmp nothing ; Timer0 Compare B Handler
jmp nothing ; Timer0 Overflow Handler
jmp nothing ; SPI Transfer Complete Handler
jmp nothing ; USART, RX Complete Handler
jmp nothing ; USART, UDR Empty Handler
jmp nothing ; USART, TX Complete Handler
jmp nothing ; ADC Conversion Complete Handler
jmp nothing ; EEPROM Ready Handler
jmp nothing ; Analog Comparator Handler
jmp nothing ; 2-wire Serial Interface Handler
jmp nothing ; Store Program Memory Ready Handler
nothing:
reti
;______________________________________
; SETUP
;______________________________________
ON_RESET:
clr zero
clr temp0
clr temp1
ldi regA, LOW(RAMEND) ;Setup of stack pointer 0x15F t45/0x25F t85
out SPL, regA
ldi regA, HIGH(RAMEND)
out SPH, regA
;Eteint le CAN
lds regA,ADCSRA
ori regA,(1<<ADEN)
sts ADCSRA,regA
;cbi ADCSRA, ADEN ;switch Analog to Digitalconverter OFF, ADC uses ~320uA
cli
ldi regA,(1<<CLKPCE)
;out CLKPR,regA ;Par logiciel sur 16 MHz, modification de la version de pré-calcule (CLKPR Clock Prescale Register- CLKPCE: Clock Prescaler Change Enable)
sts CLKPR,regA
clr regA
sts CLKPR,regA ;Réglez le précalcul à 1 (000) Clock Division Factor=1
;get data from EEPROM to RAM
ldi YL,low(debutEE)
ldi ZL, low(Relay) ;RAM
ldi ZH, high(Relay)
rjmp foreeprom
Recup:
rcall EEPROM_read
st Z+,DATA
foreeprom:
cpi ZL,low(finEE-debutEE) ; X octets
brne Recup
ldi regA,(1<<PB4|1<<PB3|1<<PB2|1<<PB1|1<<PB0) ;Port 0,1,2,3,4 en sortie
out DDRB,regA
out PORTB,regA ;toute les sorties à '1'
ldi regA,(0<<PC4|0<<PC3|0<<PC2|0<<PC1|0<<PC0) ;Port 0,1,2,3,4 en entrée
out DDRC,regA
ldi regA,(1<<PC4|1<<PC3|1<<PC2|1<<PC1|1<<PC0) ;Port 0,1,2,3,4 en entrée
out PORTC,regA ;toute les entrée à '0' are now inputs with pull-up enabled
;Initialise le changement d'interruption sur PCINT4
ldi regA,(0<<INT1|1<<INT0) ;interruption active INT0 et INT1
out EIMSK,regA
ldi regA,(1<<PC4|1<<PC3|1<<PC2|1<<PC1|1<<PC0)
;PCMSK1 |= (1 << PCINT13)...(1 << PCINT8)
sts PCMSK1,regA ;PCMSK1 Pin Change Mask Register 1
;PCMSK1 Pin Change Mask Register 1
;PCINT8->PCINT13 A0->A5
;PCICR |= (1 << PCIE1); // setPCIE1: Pin Change Interrupt Enable 1 PCMSK1
ldi regA,(1 << PCIE1)
sts PCICR,regA
/*
ISC01 ISC00 Description
0 0 The low level of INT0 generates an interrupt request.
0 1 Any logical change on INT0 generates an interrupt request.
1 0 The falling edge of INT0 generates an interrupt request.
1 1 The rising edge of INT0 generates an interrupt request.
*/
ldi regA,(1<<ISC01 | 0<<ISC00) ;int1 rising int0 falling
sts EICRA,regA ;EICRA External Interrupt Control Register A
;Initialise Timer
clr regA ;Normal
sts TCCR1A,regA ;Mode normal
ldi regA,(1<<CS12|0<<CS11|1<<CS10) ;clk/1024
;ldi regA,(0<<CS12|0<<CS11|1<<CS10) ;clk/1
sts TCCR1B,regA ;
;TIMSK1 Timer/Counter1 Interrupt Mask Register
ldi regA,(1<<TOIE1) ;TOIE1: Timer/Counter1, Overflow Interrupt Enable
sts TIMSK1,regA
;appel la routine tous les 65535 cycles (-periode cli)
;-------------------------------------------------------------------------
;Initialise serial port:
;initialize serial tx pin
sbi DDRD,Tx ;Tx output for serial out
sbi PORTD,Tx ;Tx initially high
;cbi PORTB,Tx ;Tx initially low for manchester
;initialize serial rx pin
cbi DDRD,Rx ;Rx input for serial in
sbi PORTD,Rx ;Rx no internal pullup
;-------------------------------------------------------------------------
sei; // activer les interruptions
loop:
andi State,0xFE ;met le bit0 à 0
ldi ZH,high(Buffer)
ldi ZL,low(Buffer) ;Pointe buffer
ldi regA,(1<<SE) ;SMCR Sleep Mode Control Register
out SMCR,regA
sei ; Interrupt enable
sleep ; On dort et on attend une interruption
; donc si int0 -> nouveau caractère
ldi RegA,20 ;Attend 15 caractères maxi
rcall WaitMiliseconds
st Z+,zero ;fin de la chaine avec des Zero (dans le doute!Pour les DCB)
cli
sbrs State,0 ;bit0 à 1 traiter texte
rjmp loop ;Si non boucle
;-----------------------
;traitement du port concerné via la chaine
traitement:
ldi ZH,high(Buffer)
ldi ZL,low(Buffer) ;Pointe buffer
ldi XL,100
rechercheR:
ld regA,Z+ ;'R' pour relay (RL21), ou 'T' pour temps portail (TP250), ou 'V' pour temps veille(VE3000),
;ou 'Z' si debugRAM (Z), ou 'M' pour recup valeur pins (M)
dec XL
breq loop ;X=0 -> pas dans le buffer
cpi regA,'V'
breq recupTveille
cpi regA,'T'
breq recupTportail
cpi regA,'M'
breq recuppins
cpi regA,'R'
brne rechercheR
ld regA,Z+ ;'L'
ld regA,Z+ ;A port ascii
andi regA,0x0F
;---------------- PORTAIL
;Impulsion 1.5s
tst regA ;'0'
brne noportail
rcall traitementPortail
rjmp finportail
noportail:
ldi YH,high(Relay)
ldi YL,low(Relay)
add YL,regA
ld prt,Y ;Bit du port 0 PB0, 1 PB3, 2 PB4 (pas PB2 int0 rx, pas PB1 tx)
ld RegA,Z+ ;"0" low "1" high
in regB,PORTB ;position actuel des bits dans PORTB
sbrc regA,0 ;skip bit0=0? '0x30
rjmp bithigh
eor regB,prt
rjmp fintraitement
bithigh:
or regB,prt
fintraitement:
out PORTB,regB
ldi RegA,10 ;Attend avant de renvoyer
rcall WaitMiliseconds
finportail:
rcall txchar
clr temp0 ;remet à zero, a chaque interruption
clr temp1
rjmp loop
recuppins:
clr temp0 ;remet à zero, a chaque interruption
clr temp1
rcall txchar
rjmp loop
recupTportail:
clr temp0 ;remet à zero, a chaque interruption
clr temp1
rcall recupDCB
sts delayportail,regA
mov DATA,regA
ldi YL,delayPEE
rcall EEPROM_write
rcall txchar
rjmp loop
recupTveille:
rcall recupDCB
sts delayveille,regA
sts delayveille+1,regAH
mov DATA,regA
ldi YL,delayVEE
rcall EEPROM_write
inc YL
mov DATA,regAH
rcall EEPROM_write
rcall txchar
rjmp loop
recupDCB:
clr regAH
ldi regA,10
mov formult,regA
ld regA,Z+ ;'P' ou "E"
ld regA,Z+ ;"unité"
andi regA,0x0F
bclrecup:
ld DATA,Z
andi DATA,0xF0
cpi DATA,0x30
brne finrecup
;mul8x16=16:
movw r2,regA
mul r2, formult ; al * bl
movw regA, r1:r0
mul r3, formult ; ah * bl
add regAH, r0
ld regB,Z+ ;unité
andi regB,0x0F
add regA,regB ;dizainex10+unité
adc regAH,zero
rjmp bclrecup
finrecup:
ret
traitementPortail:
cbi PORTB,Pportail
rcall txchar
lds regA,delayportail ;en centiseconde
rcall Waitcentiseconds
sbi PORTB,Pportail
ret
.include "wait.inc"
.include "AM_.inc"
.include "eeprom_V5.inc"
;Rising edge
;Un front descendant sur le port serie ->Bit de start
HC_06:
cli
push regA
in regA,SREG
push regA
push XH
push XL
rcall rxchar
st Z+,regA
ori State,1 ;met le bit0 à 1
pop XL
pop XH
pop regA
out SREG,regA
pop regA
sei
reti
AllBP:
;Appuis sur un BP enclenche l'interruption,
; qui scrute à son tour les entrées
; puis connecte le relay correspondant.
cli
push regA
in regA,SREG
push regA
push regB
push XH
push XL
push loopC
ldi RegA,15 ;Attend rebond bouton
rcall WaitMiliseconds
in regA,PINC ;Position du bouton à 1
;Pour portail
sbrc regA,0 ;skip bit0=0 logic pull-up
rjmp traitementPortail2
in regA,PINC ;Position du bouton à 1
in regB,PINB ;position actuel des bits dans PORTB
eor regB,regA
out PORTB,regB
nop
rcall txchar
rjmp finAllBP
traitementPortail2:
rcall traitementPortail
finAllBP:
ldi RegA,150 ;Attend si rebond bouton
rcall WaitMiliseconds
pop loopC
pop XL
pop XH
pop regB
pop regA
out SREG,regA
pop regA
clr temp0 ;remet à zero, a chaque interruption
clr temp1
sei
reti
compteur:
;appel environs toutes les 4s
push regA
in regA,SREG
push regA
push regB
inc temp0
adc temp1,zero
lds regA,delayveille
lds regB,delayveille+1
cp regA,temp0 ;1 cy Compare low byte
cpc regB,temp1 ;1 cy Compare high byte
brlo no2h ;1800cycl<temp0 1800cycl=2h
rjmp fincompteur
no2h:
;clear les sorties
in regA,PINB
ori regA,0b11110 ;Pour éteindre, toute les sorties à 1, pas touche au portail
andi regA,0b11111 ;le bit0, c'est le portail, eteind toute les lampes
out PORTB,regA
cli
rcall txchar
sei
clr temp0 ;clear temp
clr temp1
#ifdef DEBUG
in regA,PINB
ldi regB,(1<<PB5)
eor regA,regB
out PORTB,regA
#endif
fincompteur:
pop regB
pop regA
out SREG,regA
pop regA
reti
;RL2 RL1 RL0
;PB4 PB3 PB2 PB1 PB0 Data
;0 0 0 0 1 1
;0 0 0 1 0 2
;0 0 1 0 0 4
;0 1 0 0 0 8
;1 0 0 0 0 16
.DSEG ; Start data segment
Relay:
.db 0x01,0x2,0x04,0x08,0x10,0 ;PORT PB0,PB1,PB2,PB3,PB4
delayportail:
.db 0x00,0x00 ;L,0
delayveille:
.db 0x00,0x00 ;L,H en cycles
Buffer:
.byte 100
.ESEG ;EPROM
.org 0000
debutEE:
.db 0x01,0x2,0x04,0x08,0x10,0 ;ports
delayPEE:
.db 150,0 ;delayportail 150cs soit 1,50s
delayVEE:
.db low(2250),high(2250) ;delayveille 2h30 2.5*60*60/4=2250
.db 0,0
finEE:
.db "Samuel Dupre "
.db "V3.30:"
.db __DATE__ ,"-", __TIME__," "
AM.inc +
AM.inc
;-----------------------------------------------------------------------------
;AVR routines UART. 8 bits, pas de parité.
;Pilote RS-232 sur les deux signaux. Débits en bauds définis dans Waitonebit et
; Waitonehalfbit. Les bits de port sont spécifiés dans Rx et Tx
; Comme la routine de réception nest pas basée sur une interruption, elle doit être appelée
; par le programme principal assez souvent pour voir quand le bit de début de caractère se produit.
; S'il ne peut pas être appelé assez souvent, le débit en bauds devra être plus faible.
; À 9600 bauds, le timing est proche. La routine de réception convient pour
; entrer un seul caractère avec un intervalle de temps compris, par exemple en tapant
; un programme de terminal. Il ne convient pas pour recevoir un flux de données rapide.
;Les valeurs de synchronisation sont basées sur lutilisation de la source dhorloge
;par défaut de la mémoire interne.
; 16.5MHz et la valeur par défaut du prédiviseur dhorloge système de 1,
; résultant en une horloge système 16.5MHZ. Les valeurs de synchronisation sont également basées sur
; 5 volts de puissance et la température de référence de 20 °C.
; Oscillateur interne de 8MHz: 10% non étalonné, 1% étalonné
; avec une tension de 5 volts, si 8MHZ à 25°C, 8,25MHZ à 85°C, 7,7MHZ à -40°C
; 85°C, 3.1% fast, 8,25MHz
; 45°C, 1.25% fast, 8,1MHz
; 40°C, 1% fast, 8,08MHz
; 35°C, 0.625% fast, 8,05MHz
; 30°C, 0.5% fast, 8,04MHz
; 20°C, reference (8MHz)
; 15°C, 0.5% slow, 7,96MHz
; 10°C, 0.625% slow, 7,95MHz
; 0°C, 1% slow, 7,92MHz
; -3°C, 1.25% slow, 7,9MHz
; -40°C, 3.7% slow, 7,7MHZ
;--------------------
#ifndef F_CPU
#define F_CPU 16000000 ;16MHz
#error "F_CPU must be defined!"
#endif
#ifndef BAUD_RATE
#define BAUD_RATE 9600
#error "BAUD_RATE must be defined!"
#endif
//#define BCL_BIT int((F_CPU*0.98/BAUD_RATE)-16)/4 ;Nombre de boucle 4*X+16 pour 1 bit
#define BCL_BIT int((F_CPU*1/BAUD_RATE)-16)/4 ;Nombre de boucle 4*X+16 pour 1 bit
#define BCL_HBIT int((F_CPU*0.6/(BAUD_RATE))-16)/4 ;Nombre de boucle 4*X+16 pour 0.6 bit
#define BCL_OHBIT int((F_CPU*1.5/(BAUD_RATE))-16)/4 ;Nombre de boucle 4*X+16 pour 1.5 bit
txchar: ;transmit character in regA out the port bit
in regA,PINB
com regA
cbi PORTD,Tx ;begin start bit "0"
rcall Waitonebit ;bit time delay
ldi loopC,8 ;8 data bits, no parity
txc1:
ror regA ;rotate right bit0 into carry
brcs txc2 ;branch if bit right high (carry set)
sbi PORTD,Tx ;clear Tx pin "0"
rjmp txc3
txc2: cbi PORTD,Tx ;Set Tx pin "1"
txc3: rcall Waitonebit ;bit time delay
dec loopC
brne txc1 ;loop until all bits done
sbi PORTD,Tx ;begin the stop bit "1"
rcall Waitonebit ;bit time delay
;wait another bit time before next character
;rcall Waitonebit ;bit time delay (sends 2 stop bits)
ret
;--------------------
; Check for start bit, receive character at port bit if asserted. Exit with
; carry set if character received or carry cleared if no character is ready.
rxchar:
;clc ;carry clear means no character ready
;sbic PINB,Rx ;skip if serial receive pin is low
;ret ;start bit not asserted
;receive character at the port bit into regA
;wait 1.5 bit times (center of first bit)
rcall Waitonehalfbit
ldi loopC,8 ;8 data bits, no parity
rxc3:
clc ;start with carry clear
sbic PIND,Rx ;skip if port bit low
sec ;set carry high to match port bit
ror regA ;rotate carry into bit 7 of regA
rcall Waitonebit ;bit time delay
dec loopC ;do next bit
brne rxc3 ;loop until all bits done
rcall Waitstopbit ;bit time delay
;wait until 1/2 bit time past the stop bit
;before allowing looking for next character
sec ;carry set means character ready
ret
Waitonebit: ;Attendre 1 bit
ldi XH,high(BCL_BIT) ;1+3 (call)
ldi XL,low(BCL_BIT) ;+1
rcall Wait4xCycles ;+4+3
ret ;+4 +X*4 ->16+x*4
Waitstopbit: ;Attendre 0.6 bit
ldi XH,high(BCL_HBIT) ;1+3 (call)
ldi XL,low(BCL_HBIT) ;+1
rcall Wait4xCycles
ret
Waitonehalfbit: ;Attendre 1.5 bit
ldi XH,high(BCL_OHBIT) ;1+3 (call)
ldi XL,low(BCL_OHBIT) ;+1
rcall Wait4xCycles ;+4+3
ret ;+4 +X*4 ->16+x*4
Wait.inc +
wait.inc
;______________________________________
; MODULE Wait
; Matériel : ATtiny 45/85 4MHz à 20Mhz 5V
; (c) sammy76.free.fr
; V1.0 2016/11/06
;______________________________________
#ifndef F_CPU
#define F_CPU 16000000 ;16.5MHz
#error "F_CPU must be defined!"
#endif
#if F_CPU < 4000000
#message "Processeur beaucoup trop lent"
#warning "F_CPU too low, possible wrong delay"
#endif
#define CYCLES_PER_US (F_CPU/1000000) ;Nombre de cycles par us
#define C4PUS (F_CPU/4000000) ;/4 nombre de périodes par us attention aux approximation
#define FOR1MS 1000;us par ms
;.define DVUS(x) (C4PUS*x)
;------------------------------------------------------------------------------
; Input : XH:XL - number of CPU cycles to wait (divided by four)
;------------------------------------------------------------------------------
Wait4xCycles: ;(rcall 3cycle)
sbiw XH:XL, 1 ; x-- (2 cycles)
brne Wait4xCycles ; jump if not zero (2 cycles)
ret ;(4 cycles )
;------------------------------------------------------------------------------
; Input : A - number of milliseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms
;donc avec les répétitions on cumul l'erreur
;
WaitMiliseconds:
ldi XH,HIGH(C4PUS*FOR1MS) ;1000us soit 1ms en fait avec 16.5MHz mettre X=0x10D0 4304d
ldi XL,LOW(C4PUS*FOR1MS) ;à 16Mhz mettre X=0xFA0 4000d
rcall Wait4xCycles
dec regA
brne WaitMiliseconds
ret
;------------------------------------------------------------------------------
; Input : A - number of centiseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms
;donc avec les répétitions on cumul l'erreur
;
Waitcentiseconds:
push regA
push XL
push XH
waitcenti:
push regA
waitcs:
ldi regA,10 ;0,01s soit 1 centisecond
rcall WaitMiliseconds
brne waitcs
pop regA
dec regA
brne waitcenti
pop XH
pop XL
pop regA
ret
eeprom_V5.inc +
eeprom_V5.inc
;______________________________________
; GESTION EEPROM
; ATtiny 25/45/85
; Lecture et écriture EEPROM
; ENTREE YH:YL Donnée R18
; Utilise le registre R16
; (c) sammy76.free.fr
;______________________________________
;.EQU EEPROM slength=256
; Incrémente YL après EEPROM_read
EEPROM_write:
; Entrée adresse : YH:YL; donnée R18
; Wait for completion of previous write
clr YH
sbic EECR,EEPE
rjmp EEPROM_write
; Set Programming mode
ldi regA, (0<<EEPM1)|(0<<EEPM0)
out EECR, regA
; Set up address (YH:YL) in address register
out EEARH, YH
out EEARL, YL
; Write data (R18) to data register
out EEDR, DATA
; Write logical one to EEMPE
sbi EECR,EEMPE
; Start eeprom write by setting EEPE
sbi EECR,EEPE
ret
EEPROM_read:
clr YH
; Entrée adresse : YH:YL; donnée R18
; Wait for completion of previous write
sbic EECR,EEPE
rjmp EEPROM_read
; Set up address (YH:YL) in address register
out EEARH, YH
out EEARL, YL
; Start eeprom read by writing EERE
sbi EECR,EERE
; Read data from data register
in DATA,EEDR
inc YL
ret
;______________________________________
; END OF PROGRAM ;
;______________________________________
Sur Android
Il est possible de paramétrer l'application, attention cependant, il faut penser aux restrictions admin/non admin.
Reste
Il reste effectivement plusieurs choses à voir :
- Les distances entres relais / circuit 230V/éclairage....
- Le boitier, le cablage, ..
- La portée suffisante
Evolution
Un projet peu toujours évoluer, je propose d'ajouter un capteur de lumière (je ne sais pas ou le placer).
Celui-ci permettrai, en cas d'ouverture/fermeture portail, d'enclencher une nouvelle minuterie (3 minutes par exemple), avant d'éteindre la lumière dans le chemin (si celle-ci est allumée)
Cela peut déjà fonctionner sans capteur, si la lumière portail, maison est alumée, l'éteindre au bout de X minutes, pas encore implémenté dans le programme.
On verra, en fonction de Nicolas.
C'est tout pour aujourd'hui!
Information boite aux lettre
- Objectif :Transmission d'un signal quand la boite au lettre contient du courrier.
- Moyen:
- Un micro-contrôleur Attiny 85 <8mA En Stand-by : 5μA
- Carte Digispark Kickstarter <30mA Max - Micro USB Development Board
- Emetteur FS1000A, Stand-by 0mA, en transmission: 28mA
- Capteur de porte/fenetre NO
- AM2320 Capteur d'humidité et de température single-bus
Consommation maxi: 1,5 mA ; En Stand-by : 950μA
- Porte 2 batteries 18650 avec fils Conducteurs
- soit 2 Batteries 18650 3.7V 9800mAh - Taille Ø18,6 × 65,2mm
- 78L05 - Output current of 100mA
- ou un batteries Quadrocopter 3.7V 1200mAh 25C Lipo
- Taille : 52x30x10mm
- Taux de décharge continue : 25C soit 1.200x25=30A
- Masse: environ 30gr
Principe
Ma boite aux lettres est placer à l'ombre, (à peu près) à labrit du vent. Elle vas donc pouvoir me donner la température et l'hygrométrie extérieure.
Mais au départ, je voulais juste savoir si j'avais du courrier, mais c'est un peu trop simple. Elle vas me transmettre plusieurs information
- Présence courrier,
- Hygrométrie
- température
Comme la distance entre la maison et la boite aux lettres est relativement importante (environs 20m), j'opte pour un petit composant pas chère et à faible consommation en RF (Radio Fréquence)
Le FS1000A pour l'émission, avec ces 28mA pour la transmission de données, c'est plutôt pas mal!
En parlant de consommation.
L'énergie
Attention en fonction de l'alimentation, la fréquence de l'horloge diminue, je vais donc faire une petit montage et un petit programme pour vérifier la fréquence réelle de mon processeur à 3,7V, histoire de voir si cette tension est suffisante et fiable pour répondre à mes exigences.
Je profite du watchdog de l'attiny85, avec un temps de 8s, cela me permet de consommer 5μA en mode veille.
Donc les informations sont envoyées dans la nature toutes les 8 secondes. Soit 431 relevés/heure, c'est un peu trop non!
Pour une BAL (boîte aux lettres, je pense qu'une fois par minutes c'est suffisant!
Le watch dog vas se lancer 60/8=7.5 je prendrai 8*8=64secondes.
Durant la partie récupération des informations, le temps de fonctionnement de l'AM2320 est d'environs 350ms.
Xx64+0,35*X=3600
X=$\dfrac{3600}{64,35}=55,94$ cycles de fonctionnement par heure On vas pas chipoter, cela fait 60 cycles par heure.
Composant | Actif | "standby" | Total par heure |
Temps | Courant | Temps | Courant | mAh |
AM2320 | $350ms\times 60$ =21s | 1,5mA | 8s soit $3600-21$ 3579s | 950μA | 0,953 |
FS1000A | $0,4ms\times 60$ =24s | 28mA | $3600-24$ 3576s | 0A | 0,187 |
Attiny85 | $350.4ms\times 60$ =21s | 8mA | $3600-21$ 3579s | 5μA | 0,052 |
78L05 | - | 1mA | 3600s | 1mA | 1,000 |
Un total cumulé de | 2,192mAh |
Si j'utilise une alimentation de 3,7V, alors j'économise l'énergie du 78L05, donc 1mAh. De plus la consommation vas baissée
Récapitulatif
Batteries 3.7V 1200mAh | $1200mAh/1,192mAh=1.006,711$ heures, 42 jours |
2 batteries 18650 3.7V 9800mAh |
$9800mAh/2,192mAh=4.470,803$ heures, 186 jours |
1 batteries 18650 3.7V 9800mAh |
$9800mAh/1,192mAh=8.221,477$ heures, 343 jours |
La transmission asynchrone
Le choix du protocole série asynchrone.
La vitesse de transmission
Temps de bit : Ce temps est lié au débit binaire en bits par seconde ( bit/s ou bauds )de la transmission.
$Débit~binaire = \dfrac{1}{T}$. Par exemple, si $T = 1~ms$, la transmission se fait à $1000 bit/s$.
Vitesse de transmission “standard” en bauds (bits par secondes) 1200, 2400, 4800, 9600, 19200, 38400, 57600, et 115200.
Un bit de stop, et pas de bit de parité "none"
Je choisirai celui qui correspond le mieux au FS1000A au vue de la distance soit 2400 bauds
Un bit de "start", un bit de "stop" et pas de parité "none"
bit | Start | b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | Stop |
Valeur | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
Le bit de départ a un niveau logique "0" tandis que le bit d'arrêt est de niveau logique "1".
Le bit de donnée de poids faible est envoyé en premier suivi des autres.
Tout d'abords, je vais déterminer le temps de transmission de chaque bit, et de chaque octet en fonction de la vitesse de mon processeur.
Pour la réception
Pour prendre l'information au plus vraie, je la prend au milieu du bit, soit 1.5bit après le premier front descendant du bit de "start".
Le programme et sous-programmes d'émission
main.asm
;
; BAL.asm
;
; Created: 26/01/2019 10:26:12
; Author : samuel.dupre
;
; GESTION BAL (Boite aux lettres)
; Matériel : ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 26/01/2019
;V1.0 OK problème de parasite réception
;V2.0 Manchester + niveau batterie
; ATtiny85
; +-\/-+
; PB5 1|- -|8 Vcc
; Tx PB3 2|- -|7 PB2 Capteur BAL ouverte/INT0
; LED(DEBUG) PB4 3|- -|6 PB1 Bouton Reset BAL/PCINT1
; GND 4|- -|5 PB0 DTH22/AM2320 SDA +R
; +----+
;______________________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;ATtinyX5.menu.clock.internal16.bootloader.low_fuses=0xf1
;ATtinyX5.menu.clock.internal16.bootloader.high_fuses=0xdf
;ATtinyX5.menu.clock.internal16.bootloader.extended_fuses=0xff
;Segment Begin End Code Data Used Size Use%
;---------------------------------------------------------------
;[.cseg] 0x000000 0x0002c4 626 82 708 8192 8.6%
;[.dseg] 0x000060 0x0000b2 0 82 82 512 16.0%
;[.eseg] 0x000000 0x000000 0 0 0 512 0.0%
;cd C:\Users\samuel.dupre\Documents\Atmel Studio\7.0\BAL\BAL\
;set AVRDUDECONF="C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"
;avrdude -C %AVRDUDECONF% -c avrisp -P COM7 -b 19200 -p t85 -U eeprom:r:eprom_t85.hex:i
.CSEG
.include "tn85def.inc"
#define F_CPU 16000000 ;8MHz pour Attiny85
#define BAUD_RATE 1200 ;2400bauds
#define DEBUG
;#define F_CPU 16500000 ;16.5MHz pour Digispark
.def loopC =R22 ;delay countdown and loop registers
;.def regB =R17 ;temporary registers
.def regA =R16
.def zero =r10
;.equ Rx =PB4
.equ Tx =PB3
#if defined(DEBUG)
.equ LED=PB4
#endif
;************************************************
;* Interrupt Vectors *
;************************************************
rjmp ON_RESET ;Reset Handler
rjmp MYINT0 ; External Interrupt 0
rjmp INT1 ; Pin change Interrupt Request 0
reti ; Timer/Counter1 Compare Match 1A
reti ; Timer/Counter1 Overflow
reti ; Timer/Counter0 Overflow
reti ; EEPROM Ready
reti ; Analog comparator
reti ; ADC Conversion ready
reti ; Timer/Counter1 Compare Match B
reti ; Timer/Counter0 Compare Match A
reti ; Timer/Counter0 Compare Match B
rjmp WDTinterrupt ; Watchdog Time-out
reti ; USI START
reti ; USI Overflow
;______________________________________
; SETUP
;______________________________________
ON_RESET:
clr zero
ldi regA, LOW(RAMEND) ;Setup of stack pointer 0x15F t45/0x25F t85
out SPL, regA
ldi regA, HIGH(RAMEND)
out SPH, regA
;Eteint le CAN
cbi ADCSRA, ADEN ;switch Analog to Digitalconverter OFF, ADC uses ~320uA
cli
ldi regA,(1<<CLKPCE)
out CLKPR,regA ;Par logiciel sur 16 MHz, modification de la version de pré-calcule (CLKPR Clock Prescale Register- CLKPCE: Clock Prescaler Change Enable)
clr regA
out CLKPR,regA ;Réglez le précalcul à 1 (000) Clock Division Factor=1
;
;Initialise le changement d'interruption sur PCINT4
ldi regA,( 1 << PCIE | 1<<INT0) ;modification de l'interruption active
out GIMSK,regA
ldi regA,( 1 << PCINT1) ;interruption de changement de broche activée pour PCINT1
out PCMSK,regA
/*
ISC01 ISC00 Description
0 0 The low level of INT0 generates an interrupt request.
0 1 Any logical change on INT0 generates an interrupt request.
1 0 The falling edge of INT0 generates an interrupt request.
1 1 The rising edge of INT0 generates an interrupt request.
*/
ldi regA,(1<<ISC01 | 0<<ISC00) ;
out MCUCR, regA
sei; // activer les interruptions
#if defined(DEBUG)
sbi DDRB,LED
cbi PORTB,LED
#endif
;-------------------------------------------------------------------------
;initialize serial tx pin
sbi DDRB,Tx ;Tx output for serial out
;sbi PORTB,Tx ;Tx initially high
cbi PORTB,Tx ;Tx initially low for manchester
;initialize serial rx pin
; cbi DDRB,Rx ;Rx input for serial in
; cbi PORTB,Rx ;Rx no internal pullup
;-------------------------------------------------------------------------
;Get data from FLASH to RAM
ldi ZL, low(AllDataFlash<<1)
ldi ZH, high(AllDataFlash<<1)
ldi XL, low(Message) ;RAM
ldi XH, high(Message)
clr regA
rjmp forflash
;Récupération des informations de la FLASH -> RAM
Recup:
lpm tmp,Z+ ;
st X+,tmp ;
forflash: ; rjmp
cpi XL,low(0x60+((finAlldata-AllDataFlash)<<1)) ; X octets
cpc XH,zero
brne Recup
;-------------------------------------------------------------------------
loop:
ldi YL,low(Capteur)
ldi YH,high(Capteur)
rcall read_single
ldi YL,low(Batterie)
ldi YH,high(Batterie)
rcall readbattery
ldi YL,low(Capteur)
ldi YH,high(Capteur)
ld rBin1H,Y+
ld rBin1L,Y+
ldi ZL,low(Hygro)
ldi ZH,high(Hygro)
rcall Bin2ToAsc5 ; Conversion DCB de 0x1F4 -> 500
; Conversion température de 500 50.0
ld rBin1H,Y+
ld rBin1L,Y+
ldi ZL,low(Tempe)
ldi ZH,high(Tempe)
rcall Bin2ToAsc5 ; Conversion DCB de 250 -> 25.0°C
ldi ZL,low(Bat)
ldi ZH,high(Bat)
ldi YL,low(Batterie)
ldi YH,high(Batterie)
rcall hextodcb
ldi ZL, low(Message)
ldi ZH, high(Message)
rcall txmanchester
/*
transmet:
;Transmission du message
ld regA,Z+
tst regA
breq fin
rcall txchar
rjmp transmet
fin:
*/
; ldi temp,8 ;8x8s=64s
ldi temp,1 ;1x8s=8s for test
blcwait:
;Pause du watchdog (8s)
rcall WDT_on ; Watchdog on
ldi regA,(1<<SE | 0<<ISC01 | 1<<ISC00) ; Enable sleep mode , Any logical change on INT0 generates an interrupt request.
out MCUCR, regA
//sei ; Interrupt enable
sleep ; On dort et on attend le watchdog
//cli ; Interrupt disable
ldi regA,(0<<SE | 0<<ISC01 | 1<<ISC00) ; Disable sleep mode
out MCUCR, regA
dec temp
brne blcwait
rjmp loop
hextodcb:
ld rBin1H,Y+
ld rBin1L,Y+
mov regA,rBin1H ;regA=0xH1L1
swap regA ;regA=0xL1H1
andi regA,0x0F ;regA=0xH1
rcall conv1H ;Sauve Z+, asc(hex H1)
mov regA,rBin1H
andi regA,0x0F ;regA=0xL1
rcall conv1H ;Sauve Z+, asc(hex L1)
mov regA,rBin1L ;regA=0xH2L2
swap regA ;regA=0xL2H2
andi regA,0x0F ;regA=0xH2
rcall conv1H ;Sauve Z+, asc(hex H2)
mov regA,rBin1L
andi regA,0x0F ;regA=0xL2
rcall conv1H ;Sauve Z+, asc(hex L2)
ret
conv1H:
cpi regA,0x0A ;compare RegA avec 10
BRLT numH1 ;regA<0x0A ->numH1
subi regA,0xC9 ;regA+(65-10) RegA+55 ->'A'
rjmp saveH1
numH1:
ori regA,0x30
saveH1:
st Z+,regA
ret
MYINT0:
push regA ;Met le courrier à yes
ldi regA,'Y'
endint:
sts bal,regA
pop regA
reti
INT1:
push regA ;button réinitialise courrier à no
ldi regA,'N'
rjmp endint
;.include "Fakewait.inc"
.include "wait.inc"
.include "manchester.inc"
.include "single_bus.inc"
.include "watchdog.inc"
.include "bintoasc.inc"
.include "batterie.inc"
AllDataFlash:
.db 13,10,"Temperature +--.-°C",13,10,"Hygrometrie --.-%Hg",13,10,"Courrier -",13,10,"Batterie ----",13,10,0,0
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
finAlldata:
.DSEG ; Start data segment
Message:
.db 13,10,"Temperature "
Tempe:
.db "+--.-°C",13,10
.db "Hygrometrie "
Hygro:
.db " --.-%Hg",13,10
.db "Courrier "
Bal:
.db "Y",13,10,"Batterie "
Bat:
.db "----",13,10,0,0
Capteur: ;Les 5 bits
AMHg:
.byte 2 ; AM2320 Humidité
AMtemp:
.byte 2 ; AM2320 Température
AMCRC:
.byte 2 ; AM2320 CRC
Batterie:
.byte 2 ; Batterie
.ESEG
.org 0xc0
buildtime:
.db "sammy76.free.fr "
.db "V2.00:%DAY%.%MONTH%.%YEAR% %HOUR%:%MINUTE%"
manchester.inc
;Transmission avec le protocol Manchester
;
; ATtiny85
; +*\/-+
; PB5 1|- -|8 Vcc
; Tx PB3 2|- -|7 PB2
; PB4 3|- -|6 PB1
; GND 4|- -|5 PB0
;.equ Tx =PB3
;--------------------
;ZH:ZL pointe le message
; .def regA =R16
;.def loopC =R22 ;delay countdown and loop registers
.def regB =R17 ;temporary registers
#ifndef F_CPU
#define F_CPU 16000000 ;16MHz
#error "F_CPU must be defined!"
#endif
#ifndef BAUD_RATE
#define BAUD_RATE 2400 ;57600 bauds maxi OK
#error "BAUD_RATE must be defined!"
#endif
#ifndef BAUD_RATE
#define C4PUS (F_CPU/4000000) ;/4 nombre de périodes par us attention aux approximation
#error "C4PUS must be defined!"
#endif
; Base delay | bauds | factor
#define timebit (921600/BAUD_RATE)*C4PUS ;2400bps 4 cycles pour Wait4xCycles 16MHz
;il est commun de mettre à zéro une chaîne ou de transmettre de petits nombres comportant beaucoup de zéros
;ces zéros peuvent être confondus avec un modèle d'apprentissage, ce qui crée de la confusion chez le récepteur
;et entraîne une perte de paquets importante,
;donc on "xor" les données avec masque de découplage aléatoire
#define DECOUPLING_MASK 0b11001010
txmanchester:
#if defined(DEBUG)
sbi PORTB,LED
#endif
;Transmit RegA
ldi loopC,14 ;send capture pulses
initT:
rcall sendzero ;end of capture pulses 0b10 x14
dec loopC
brne initT
rcall sendone ;start data pulse 0b01
transmetmessage:
;Transmission du message
ld regA,Z+
tst regA
breq finmessage
;regA data
ldi loopC,8 ;8 bits
loopallbit:
;ldi regB,DECOUPLING_MASK
ror regA ;rotate right bit0 into carry
brcs bitatone ;branch if bit right high (carry set)
rcall sendzero
rjmp transmetsuite
bitatone:
rcall sendone
transmetsuite:
dec loopC
brne loopallbit
rjmp transmetmessage
finmessage:
; Send terminating 0 to correctly terminate the previous bit and to turn the transmitter off
rcall sendzero
rcall sendzero
#if defined(DEBUG)
cbi PORTB,LED
#endif
ret
sendzero:
sbi PORTB,Tx ;HIGH
ldi XH,HIGH(timebit)
ldi XL,LOW(timebit)
rcall Wait4xCycles
cbi PORTB,Tx ;LOW
ldi XH,HIGH(timebit)
ldi XL,LOW(timebit)
rcall Wait4xCycles
ret
sendone:
cbi PORTB,Tx ;LOW
ldi XH,HIGH(timebit)
ldi XL,LOW(timebit)
rcall Wait4xCycles
sbi PORTB,Tx ;HIGH
ldi XH,HIGH(timebit)
ldi XL,LOW(timebit)
rcall Wait4xCycles
ret
Wait.inc
;______________________________________
; MODULE Wait
; Matériel : ATtiny 45/85 4MHz à 20Mhz 5V
; (c) sammy76.free.fr
; V1.0 2016/11/06
;______________________________________
#ifndef F_CPU
#define F_CPU 16500000 ;16.5MHz
#error "F_CPU must be defined!"
#endif
#if F_CPU < 4000000
#message "Processeur beaucoup trop lent"
#warning "F_CPU too low, possible wrong delay"
#endif
#define CYCLES_PER_US (F_CPU/1000000) ;Nombre de cycles par us
#define C4PUS (F_CPU/4000000) ;/4 nombre de périodes par us attention aux approximation
#define FOR1MS 1000;us par ms
;.define DVUS(x) (C4PUS*x)
;------------------------------------------------------------------------------
; Input : XH:XL - number of CPU cycles to wait (divided by four)
;------------------------------------------------------------------------------
Wait4xCycles: ;(rcall 3cycle)
sbiw XH:XL, 1 ; x-- (2 cycles)
brne Wait4xCycles ; jump if not zero (2 cycles)
ret ;(4 cycles )
;------------------------------------------------------------------------------
; Input : A - number of milliseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms
;donc avec les répétitions on cumul l'erreur
;
WaitMiliseconds:
push regA
WaitMsLoop:
ldi XH,HIGH(C4PUS*FOR1MS) ;1000us soit 1ms en fait avec 16.5MHz mettre X=0x10D0 4304d
ldi XL,LOW(C4PUS*FOR1MS) ;à 16Mhz mettre X=0xFA0 4000d
rcall Wait4xCycles
dec regA
brne WaitMsLoop
pop regA
ret
/*
;------------------------------------------------------------------------------
; Input : A - number of centiseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms
;donc avec les répétitions on cumul l'erreur
;
Waitcentiseconds:
push regA
push XL
push XH
waitcenti:
push regA
waitcs:
ldi regA,10 ;0,01s soit 1 centisecond
rcall WaitMiliseconds
brne waitcs
pop regA
dec regA
brne waitcenti
pop XH
pop XL
pop regA
ret
;------------------------------------------------------------------------------
;Input : A - number of seconds to wait
;------------------------------------------------------------------------------
waitseconds:
push regA
push YL
push YH
push XL
push XH
waitsec:
ldi YL,10 ;1s
push regA
waitms:
ldi regA,100 ;0,1s
rcall WaitMiliseconds
dec YL
brne waitms
pop regA
dec regA
brne waitsec
pop XH
pop XL
pop YH
pop YL
pop regA
ret
;------------------------------------------------------------------------------
;Input : A - number of minutes to wait
;------------------------------------------------------------------------------
waitminute:
push regA
ldi regA,60
onesecond:
rcall waitseconds
pop regA
dec regA
brne waitminute
ret
*/
single_bus.inc
;
;single_bus.inc
;______________________________________
; GESTION Single-Bus
; Matériel : ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 2018/09/23
;V1.0
;V1.1 Attention aux interruptions, à voir, actuellement cli et sei!
; ATtiny85
; +-\/-+
; PB5 1|- -|8 Vcc
; PB3 2|- -|7 PB2
; PB4 3|- -|6 PB1
; GND 4|- -|5 PB0 DTH22/AM2320 SDA +R
; +----+
;______________________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;.CSEG
;.include "tn85def.inc"
;.def regA =r16 ; GENERAL PURPOSE ACCUMULATOR
.def DATA =r18 ;all DATA
.def tmp =r3 ;pour Single-bus
.def timeL =r8
.def timeH =r9
.equ bSDA = PB0 ;* SDA Port B, PB0 Pin 5
.equ mSDA = (1<<bSDA);Calculate binary value corresponding to I/O port bit for masking
.equ timeout =(F_CPU*1000)/(9000000) ;nombre de cycle pour timeout 9cyl/boucle
; MIN TYP MAX UNIT
.equ Tbe =10 ; 0.8 1 20 ms
.equ Tgo =40 ; 20 30 200 us
read_single:
push YH
push YL
;Go into high impedence state to let pull-up raise data line level and
;start the reading process.
cbi DDRB,bSDA ; SDA en entrée
sbi PORTB,bSDA ; HIGH avec Résistance de pullup
ldi regA,250
rcall WaitMiliseconds ;250ms
;Host the start signal down time
;First set data line low for Tbe milliseconds.
sbi DDRB,bSDA ; SDA en sortie
cbi PORTB,bSDA ; LOW
ldi regA,Tbe
rcall WaitMiliseconds
;cli ;clear interrupt
;Bus master has released time Tgo
sbi PORTB,bSDA ; HIGH
;End the start signal by setting data line high for 40 microseconds.
ldi XH,HIGH(C4PUS*Tgo) ;Tgo
ldi XL,LOW(C4PUS*Tgo)
rcall Wait4xCycles ;Wait Tbe us
cbi DDRB,bSDA ; SDA en entrée,
sbi PORTB,bSDA ; pull-up activé
nop
rcall expectPulseLOW ;4 cy Trel
rcall expectPulseHIGH ;4 cy Treh
ldi regA,5 ;5x8 bits=40 bits ;1 cy
mov tmp,regA ;1 cy
bc_octets:
ldi regA,8 ;8 bits ;1 cy
clr DATA ;1 cy
bc_8bits:
rcall expectPulseLOW ;4 cy
mov timeH,XH ;1 cy
mov timeL,XL ;1 cy
adiw XH:XL,10 ;2 cy Rattrapage du décalage
rcall expectPulseHIGH ;4 cy
lsl DATA ;1 cy
cp XL,timeL ;1 cy Compare low byte
cpc XH,timeH ;1 cy Compare high byte
brlo bitZero ; HIGHT<LOW 1 cy false 2 cy true
ori DATA,1 ;1 cy
bitZero:
dec regA
brne bc_8bits ; < 1 cy false 2 cy true
st Y+,DATA ;1 cy
dec tmp ;1 cy
brne bc_octets ; < 1 cy false 2 cy true
pop YL
pop YH
ret
expectPulseLOW:
;compte le temps ou SDA et à 0
clr XL ;1 cy x=0
clr XH ;count ;1 cy
push timeL
push timeH
push regA
ldi regA,HIGH(timeout)
mov timeH,regA
ldi regA,LOW(timeout)
mov timeL,regA
bc_expectPulseLOW:
sbic PINB,bSDA ; if SDA clear, skip increment
; false (1 cycle)/true (2cycles)
rjmp fin_expectPulseLOW ; 2 cy
adiw XH:XL, 1 ; x++ (2 cycles) 9cycles par boucles
;compare tmp avec 1ms
;si tmp>1ms -> Erreur timeout
;sinon valeur de tmp
cp XL,timeL ;1 cy Compare low byte
cpc XH,timeH ;1 cy Compare high byte
brsh fin_expectPulseLOW ; >=timeout false (1 cycle)/true (2cycles)
rjmp bc_expectPulseLOW ;2 cy jump if not zero
fin_expectPulseLOW:
pop regA
pop timeH
pop timeL
ret ;4 cy
expectPulseHIGH:
;compte le temps ou SDA et à 1
clr XL ;1 cy x=0
clr XH ;count ;1 cy
push timeL
push timeH
push regA
ldi regA,HIGH(timeout)
mov timeH,regA
ldi regA,LOW(timeout)
mov timeL,regA
bc_expectPulseHIGH:
sbis PINB,bSDA ; if SDA set, skip increment
rjmp fin_expectPulseHIGH
adiw XH:XL, 1 ; x++ (2 cycles) 9cycles par boucles
;compare tmp avec 1ms
;si tmp>1ms -> Erreur timeout
;sinon valeur de tmp
cp XL,timeL ; Compare low byte ; 1 cy
cpc XH,timeH ; Compare high byte ; 1 cy
brsh fin_expectPulseHIGH ; >=timeout false (1 cycle)/true (2cycles)
rjmp bc_expectPulseHIGH
fin_expectPulseHIGH:
pop regA
pop timeH
pop timeL
ret
Watchdog.inc
;______________________________________
; GESTION WATCHDOG
; Matériel : ATtiny 45/85 4MHz 5V
;
; (c) sammy76.free.fr
; V1.0 2016/06/01 Juin 2016
;______________________________________
; Enclenche le watchdog
WDT_on:
ldi regA,0b01101001 ;met le timeout a 8 sec et set le wtachdog interrupt
; ldi regA,0b01101000 ;met le timeout a 4 sec et set le wtachdog interrupt
; ldi regA,0b01001111 ;met le timeout a 2 sec et set le wtachdog interrupt
; ldi regA,0b01001110 ;met le timeout a 1 sec et set le wtachdog interrupt
; ldi regA,0b01001101 ;met le timeout a 0,5 sec et set le wtachdog interrupt
; ldi regA,0b01001100 ;met le timeout a 0,25 sec et set le wtachdog interrupt
; ldi regA,0b01001011 ;met le timeout a 0,125 sec et set le wtachdog interrupt
; ldi regA,0b01001010 ;met le timeout a 64 ms et set le wtachdog interrupt
; ldi regA,0b01001001 ;met le timeout a 32 ms et set le wtachdog interrupt
; ldi regA,0b01001000 ;met le timeout a 16 ms et set le wtachdog interrupt
out WDTCR,regA
ret
;______________________________________
; Éteint le watchdog
WDT_off:
WDR
; Clear WDRF in MCUSR
ldi regA, (0<<WDRF)
out MCUSR, regA
; Write logical one to WDCE and WDE
; Keep old prescaler setting to prevent unintentional Watchdog Reset
in regA, WDTCR
ori regA, (1<<WDCE)|(1<<WDE)
out WDTCR, regA
; Turn off WDT
ldi regA, (0<<WDE)
out WDTCR, regA
ret
;______________________________________
; Interruption du timeout du watchdog. On retourne simplement juste après le "sleep" !
WDTinterrupt:
reti
bintoasc.inc
;--------------
;
;
; 2 DIGITS TO ASCII
; Bintoasc.asm
;
; Created: 29/01/21/019
; Author : samuel.dupre
;
; Conversop,
; Matériel : ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 29/01/21/019
;V1.0
;.CSEG
;.include "../includes/tn45def.inc"
.def rBin1L = r4 ;
.def rBin1H = r5 ;
;.def regA = r16 ;
.def temp = r19 ;
; In: 16-bit-binary in rBin1H:L
; Z points to current BCD digit
; Out: Result in Z
Bin2ToAsc5:
mov temp,rBin1H
or temp,temp
brmi dcbneg
ldi regA,' '
rjmp sgndcb
dcbneg:
ldi regA,'-'
ldi temp,0x7F
and rBin1H,temp
sgndcb:
st Z+,regA
ldi temp,100
rcall todcb
cp regA,zero
brne chifdcb
ldi regA,' '
rjmp nochifdcb
chifdcb:
ori regA,0x30
nochifdcb:
st Z+,regA
ldi temp,10
rcall todcb
ori regA,0x30
st Z+,regA
ldi regA,'.'
st Z+,regA
mov regA,rBin1L
ori regA,0x30
st Z+,regA
ret
todcb:
clr regA
todcb1:
sub rBin1L,temp
sbc rBin1H,zero
brmi todcb2
inc regA
rjmp todcb1
todcb2:
add rBin1L,temp
adc rBin1H,zero
ret