-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMFS_ATmega328.h
276 lines (254 loc) · 11.2 KB
/
MFS_ATmega328.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include <Arduino.h>
/* Définition des bits utilisés dans le registre C pour les boutons */
#define BTN_1 0b10 // pinA1
#define BTN_2 0b100 // pinA2
#define BTN_3 0b1000 // pinA3
/* Opérations booléennes pour vérification de l'appui sur les boutons */
#define BTN_1_PRESSED (PINC & BTN_1) == 0
#define BTN_2_PRESSED (PINC & BTN_2) == 0
#define BTN_3_PRESSED (PINC & BTN_3) == 0
/* Définition des bits utilisés dans le registre B */
#define LED_1 0b100000 // pin13
#define LED_2 0b10000 // pin12
#define LED_3 0b1000 // pin11
#define LED_4 0b100 // pin10
#define ALL_LEDS 0b111100
/* ON and OFF */
#define ON 1
#define OFF 0
/* Constantes pour les états des LEDs */
#define LED_OFF 0
#define LED_ON 1
#define LED_BLINKING 2
/* Définition des pins utilisées pour le display 7 segments */
#define LATCH 0b10000 // pin4 (Registre C)
#define CLK 0b10000000 // pin7 (Registre C)
#define DATA 0b1 // pin8 (Registre B)
#define LATCH_PIN 4
#define CLK_PIN 7
#define DATA_PIN 8
/* Définition de caractères spéciaux */
#define __underscore 0b11110111
#define __minus 0b10111111
#define __dot 0b01111111
#define __space 0b11111111
/** DÉPRÉCIÉ ! Utiliser DIGIT[] ou ALPHA[] pour les caractères.
* Définition des symboles à afficher
// 1 = éteint ; 0 = allumé
// SEG = GFEDCBA
// |||||||
#define __g 0b10010000 // === 9
#define __N 0b11001000
#define __o 0b10100011
#define __P 0b10001100
#define __r 0b10101111
#define __U 0b11000001
#define __1 0b11111001 // === I
#define __F 0b10001110
#define __S 0b10010010 // === 5
#define __O 0b11000000 // === 0
*/
/** Pour l'affichage des chiffres */
const byte DIGIT[] = {
// 1 = éteint ; 0 = allumé
// SEG = GFEDCBA
0b11000000, // 0
0b11111001, // 1
0b10100100, // 2
0b10110000, // 3
0b10011001, // 4
0b10010010, // 5
0b10000010, // 6
0b11111000, // 7
0b10000000, // 8
0b10010000 // 9
};
/** Pour l'affichage des lettres ; chaque lettre est à son nombre alphabétique - 1 */
const byte ALPHA[] = {136, 131, 198, 161, 134, 142, 144, 139, 207, 241, 138, 199, 170, 200, 163, 140, 152, 175, 146, 135, 227, 227, 129, 137, 145, 164};
/** Tableau contenant l'accès aux segments */
const byte SEGMENT_SELECT[] = {
0b11110001, // cadran 1 (gauche)
0b11110010, // cadran 2
0b11110100, // cadran 3
0b11111000 // cadran 4 (droite)
};
//----------------------------------------------------------------------------------------------------
// CLASSE PERMETTANT DE CONTRÔLER LES I/O DU MFS
//----------------------------------------------------------------------------------------------------
class MFS_ATmega328
{
public:
//----------------------------------------------------------------------------------------------------
// INITIALISATION DES INPUTS/OUTPUTS
//----------------------------------------------------------------------------------------------------
/**
* @brief Setup des inputs/outputs et extinction des LEDs et du display.
*/
void init()
{
/* Registre D (PORTD) :
pin4 = LATCH <- bit4
pin7 = CLK <- bit7
*/
DDRD |= (LATCH | CLK); // Mise à 1 des bits pour "OUTPUT"
/* Registre B (PORTB) :
pin13 = LED_1 <- bit5
pin12 = LED_2 <- bit4
pin11 = LED_3 <- bit3
pin10 = LED_4 <- bit2
pin8 = DATA <- bit0
*/
DDRB |= (LED_1 | LED_2 | LED_3 | LED_4 | DATA); // Mise à 1 des bits pour "OUTPUT"
setLEDs(ALL_LEDS, OFF);
clear();
/* Registre C (PORTC) === "Groupe 1" :
pinA1 = BTN_1 <- bit1
pinA2 = BTN_2 <- bit2
pinA3 = BTN_3 <- bit3
*/
DDRC &= (byte) ~(BTN_1 | BTN_2 | BTN_3); // Mise à 0 des bits pour "INPUT"
};
//----------------------------------------------------------------------------------------------------
// GESTION DES LEDS
//----------------------------------------------------------------------------------------------------
/**
* @brief Manipule directement le registre PORTB. Utilisez les constantes pour plus de facilité.
*
* @param leds Ex. arg. valides : (ALL_LEDS) (LED_1) (LED_2 | LED_4) (LED_2 + LED_4) ...
* @param state ON or OFF
* @return L'état de PORTB, qui devrait être égal au byte passé
*/
byte setLEDs(byte leds, byte state)
{
if (state)
return PORTB &= (byte)~leds;
else
return PORTB |= leds;
}
//----------------------------------------------------------------------------------------------------
// GESTION DES INTERRUPTIONS
//----------------------------------------------------------------------------------------------------
/**
* @brief Configure les boutons du MFC qui pourront déclencher des interrupts et exécuter ISR(PCINT1_vect){}
* @param button Ex. arg. valides : (BTN_1) (BTN_2 + BTN_3) (BTN_1 | BTN_3) ...
*/
void attachButtonInterrupt(byte button)
{
PCICR |= 0b10; // Active la possibilité d'interruptions pour le registre C (PCINT8 -> PCINT13 = GROUPE 1)
PCMSK1 |= button; // Les pins A1(BTN_1), A2(BTN_2), et A3(BTN_3) peuvent déclencher des interruptions.
}
/**
* @brief Désactive toutes les possibilités d'interruptions avec les boutons du MFS.
*/
void detachButtonInterrupts()
{
PCICR &= (byte) ~(0b10); // Désactive toutes les interruptions
PCMSK1 &= (byte) ~(BTN_1 | BTN_2 | BTN_3);
}
//----------------------------------------------------------------------------------------------------
// AFFICHAGE SUR LE DISPLAY 7 SEGMENTS
//----------------------------------------------------------------------------------------------------
/**
* @brief Affiche les 4 symboles passés en argument. Utilisez DIGIT[] et ALPHA[] au besoin.
*/
void write(byte sym1, byte sym2, byte sym3, byte sym4)
{
byte toPrint[4] = {sym1, sym2, sym3, sym4};
for (unsigned int segment = 0; segment < 4; segment++)
{
PORTD &= (byte)~LATCH; // Prépare à la réception de données === digitalWrite(LATCH_PIN, LOW)
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, toPrint[segment]); // Envoi du caractère à afficher
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, SEGMENT_SELECT[segment]); // Sélection du segment
PORTD |= LATCH; // Fin de la lecture === digitalWrite(LATCH_PIN, HIGH);
delay(5); // Delai pour affichage ~50 Hz
}
}
/**
* @brief Affiche un tableau de 4 bytes passés en argument.
* @param toPrint Un tableau de 4 bytes (pas moins !)
*/
void write(byte toPrint[])
{
for (unsigned int segment = 0; segment < 4; segment++)
{
PORTD &= (byte)~LATCH; // Prépare à la réception de données === digitalWrite(LATCH_PIN, LOW)
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, toPrint[segment]); // Envoi du caractère à afficher
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, SEGMENT_SELECT[segment]); // Sélection du segment
PORTD |= LATCH; // Fin de la lecture === digitalWrite(LATCH_PIN, HIGH);
delay(5); // Delai pour affichage ~50 Hz
}
clear();
}
/**
* @brief Affiche l'entier passé en argument. Attentions, un nombre négatif sera converti en positif.
*/
void write(long value)
{
byte segment = 3;
if (value < 0)
value *= -1; // Un négatif devient positif
if (value > 9999)
value = 9999; // Le max est 9999
while (value && segment >= 0)
{
PORTD &= (byte)~LATCH; // Prépare à la réception de données === digitalWrite(LATCH_PIN, LOW)
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, DIGIT[value % 10]); // %10 pour avoir le dernier chiffre du nombre
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, SEGMENT_SELECT[segment--]); // sélection du segment puis incrémentation
PORTD |= LATCH; // Fin de la lecture === digitalWrite(LATCH_PIN, HIGH);
value /= 10; // On passe au nombre suivant
delay(5); // Delai pour affichage ~50 Hz
}
clear();
}
//----------------------------------------------------------------------------------------------------
// FONCTIONS POUR LOW POWER // Plus d'infos : https://youtu.be/urLSDi7SD8M
//----------------------------------------------------------------------------------------------------
/**
* @brief Arrête l'Analog Digital Converter
*/
void disableADC()
{
ADCSRA &= 0b01111111;
}
/**
* @brief Active l'Analog Digital Converter
*/
void enableADC()
{
// Analog Digital Convert Control and Status (Register A) = ADCSRA
ADCSRA |= 0b10000000;
}
/**
* @brief Passe en "Power-down mode" et arrête l'ADC (Analog-Digital Converter) et BOD (Brown-out Detection)
*/
void deepSleep()
{
disableADC();
SMCR = 0b100; // Sélectionne le "Power-down" mode
SMCR |= 1; // Active la possiblité de recevoir l'instruction "sleep"
// MicroController Unit Control Register (MCUCR)
// La séquence suivante est nécessaire pour arrêter la Brown Out Detection :
MCUCR |= 0b01100000; // BODS à 1, BODSE à 1
MCUCR = ((MCUCR & 0b11011111) | 0b01000000); // BODS à 1, BODSE à 0
__asm__ __volatile__("sleep"); // Exécute l'instruction assembleur "sleep"
SMCR = 0; // RÀZ du mode et du flag après réveil
}
private:
/**
* @brief Utilisé en interne ; éteint tout le display 7-segment.
*/
void clear()
{
for (unsigned int segment = 0; segment < 4; segment++)
{
PORTD &= (byte)~LATCH; // Prépare à la réception de données === digitalWrite(LATCH_PIN, LOW)
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, 0xFF); // Eteint tout
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, SEGMENT_SELECT[segment]); // Sélection du segment
PORTD |= LATCH; // Fin de la lecture === digitalWrite(LATCH_PIN, HIGH);
}
}
};
//----------------------------------------------------------------------------------------------------
// OBJET A UTILISER POUR ACCÈS AUX MÉTHODES DE LA BIBLIOTHÈQUE
//----------------------------------------------------------------------------------------------------
MFS_ATmega328 myMFS;