// Bibliothèque u8g2 pour dessiner sur un écran OLED
#include <U8g2lib.h>
// affichage final, 128x128px [tampon de page, taille = 128 octets], connexion HW I2C
U8G2_SH1107_128X128_1_HW_I2C u8g2(U8G2_R0);
// Connexion I2C de l'écran OLED et de l'Arduino UNO
// +5V > +5V // GND > GND // SCL (horloge série) > A5 ou SCL // SDA (données série) > A4 ou SDA
#include <LiquidCrystal_I2C.h> // Bibliothèque pour l'écran LCD fonctionnant avec I2C.
LiquidCrystal_I2C lcd(0x27, 20, 4); // Définitions des paramètres de lcd 2004 à l'adresse 0x27.
int center_x = 64; // affichage x au centre, 64px pour l'affichage 128x128px
int center_y = 64; // affichage au centre y, 64px pour l'affichage 128x128px
//long TempsEcoule, Milliseconde, Seconde, Minute, Heure, Jour; // Variable de temps.
unsigned long currentTime = 0; // Variable utilisée pour récupérer la valeur de millis()
unsigned long previousTime = 0; // Variable utilisée pour stocker la valeur de millis() pour le prochain "loop"
// valeurs du temps de départ
long TempsEcoule, Milliseconde;
long time_hours = 9;
long time_minutes = 20;
long time_seconds = 10;
const int btnDraw [8] = {7, 6, 5, 4, 3, 2, 1, 0};
const int buzzer = 13; // Buzzer relié à la broche 13
const int btn_StartStop = 8; // START/STOP, BP activé à l'état bas
const int btn_Reset = 9; // RESET, BP activé à l'état bas
bool etat_btn_StartStop, etat_btn_Reset, etat_BoutonAppuyer; // Variable qu'on passe à 1 après avoir presser un bouton afin d'éviter l'effet rebond
bool etat_ChronoOnOFF, etat_btnDraw[8]; // Variable qui détermine l'état de marche du chronomètre et la fonction Mute.
char Chrono[20];
void setup(void) { // Initialisation
u8g2.begin(); // début de la bibliothèque u8g2
lcd.init(); lcd.backlight(); // Initialisation de l'écran LCD, et active le rétroéclairage de l'écran LCD
printCenter("Chronometre", 0); // écran de démarrage
Fn_Display();
pinMode(btn_StartStop, INPUT_PULLUP); // Assigne le mode ENTREE et résistance PULL UP
pinMode(btn_Reset, INPUT_PULLUP); // Assigne le mode ENTREE et résistance PULL UP
pinMode(buzzer, OUTPUT); // Assigne le mode SORTIE à la broche 13.
for (int i = 0; i < 8; i++) {
pinMode(btnDraw[i], INPUT_PULLUP);
// printCenter(String(i) +" : "+String(btnDraw[i]), 3);delay(1000);
}
analogClock();
}
void loop(void) {
Fn_Scan_Buttons(); // Fonction de balayage de l'état de tous les boutons poussoirs
Fn_Chronometre(); // Fonction de gestion du temps qui passe lorsque le chrono est à ON
} // fin de loop()
// fonction perso beep pour Émettre une tonalité de x kHz pendant x ms
void beep() { // Émet une tonalité de 2,5kHz pendant 100 ms
tone(buzzer, 2500, 100); // Plays 2,5kHz tone for 100ms
}
void tick() { // fonction perso pour Émettre une très brèvetonalité de 5kHz pendant 1 ms
tone(buzzer, 5000, 1); // Émet un son de 5 kHz pendant 1 ms
}
void Fn_Scan_Buttons() { //balayage de l'état de tous les boutons poussoirs
etat_btn_StartStop = digitalRead(btn_StartStop); // État Bouton Start/Stop
etat_btn_Reset = digitalRead(btn_Reset); // État Bouton Start/Stop
for (int i = 0; i < 8; i++) {
etat_btnDraw[i] = digitalRead(btnDraw[i]);
}
if (etat_btn_StartStop == LOW && etat_BoutonAppuyer == 0) { // Test pression bouton START/STOP
etat_BoutonAppuyer = 1; beep(); delay(500); // Evite l'effet rebond
etat_ChronoOnOFF = !etat_ChronoOnOFF; // Inverse l'état du chronomètre
while (etat_btn_StartStop)etat_btn_StartStop = digitalRead(btn_StartStop); // fonction anti rebond
}
if (etat_btn_Reset == LOW && etat_ChronoOnOFF == 0 && etat_BoutonAppuyer == 0) { // Test pression bouton RESET
etat_BoutonAppuyer = 1; beep(); // Evite l'effet rebond
time_seconds = 0; time_minutes = 0; time_hours = 0; // Remet toutes les variables de temps à 0.
analogClock(); // Mise à zéro du contenu de l'afficheur oled-sh1107
Fn_Display(); // Mise à zéro du contenu de l'écran LCD
}
}
void Fn_Chronometre() {// Fonction pricipale de la gestion de l'horloge du chrono
// Incrémentation du compteur de chrono en utilisant la fonction millis()
currentTime = millis(); // Le temps courant = l'horloge interne en ms.
TempsEcoule = currentTime - previousTime; // Le temps écoulée = au temps courant - le temps précédant
previousTime = millis(); // nouveau temps précédant = l'horloge interne en ms.
// Fonction compteur d'incrémentation des variables Seconde, Minute, Heure
if (etat_ChronoOnOFF == 1) { // Si Etat_ChronoOnOff = true exécute le code entre {}.
Milliseconde = Milliseconde + TempsEcoule; // Incrémentation des millisecondes
if (Milliseconde > 999) { // Si Milliseconde est supérieure à 999... (1000ms)
Milliseconde = Milliseconde - 1000; // ...Remise à 0 de la variable Milliseconde
time_seconds++; // Incrémentation de 1 seconde toutes les 1000 Millisecondes
Fn_Display(); // Fonction principale d'Affichage en temps réel.
tick(); // Émet un tic toutes les secondes
analogClock(); // Fonction principale d'Affichage en temps réel.
}
if (time_seconds > 59) { // Si Seconde est supérieure à 59... (60sec)
time_seconds = 0; // ...Remise à 0 de la variable Seconde
beep(); // Émet un beep par minute
time_minutes++; // Incrémentation de 1 Minute toutes les 60 Secondes
}
if (time_minutes > 59) { // Si Minute est supérieure à 59... (60 minutes)
time_minutes = 0; // ...Remise à 0 de la variable Minute
time_hours++; // Incrémentation de 1 Heure toutes les 60 Minutes
}
}
if (etat_btn_StartStop == HIGH && etat_btn_Reset == HIGH) {
etat_BoutonAppuyer = 0; // réinitialise la variable "etat_BoutonAppuyer" à "0" cequi évite l'effet rebond
}
}
// fonction perso pour centrer le texte à afficher.
void printCenter(String text, int ligne) {
int len = text.length(); // défini la longeur de la variable text
lcd.setCursor((20 - len) / 2, ligne); // positionne le curseur au centre de la ligne choisie et soustrait la longeur du text à afficher
lcd.print(text); // affiche le text centré
}
void Fn_Display() { // rafraîchi l'Affichage en temps réel toutes les secondes.
sprintf(Chrono, "%02ld:%02ld:%02ld", time_hours, time_minutes, time_seconds ); //Formate l'affichage.
printCenter(Chrono, 1); // Affiche le temps écoulé.
}
void analogClock() {
u8g2.firstPage(); // sélectionnez la première page de l'affichage (la page mesure 128x8px), puisque nous utilisons la méthode de dessin de page de la bibliothèque u8g2
do { // dessiner
// dessinez le cercle central pour couvrir la partie centrale des aiguilles
if( etat_btnDraw[0]== LOW){
u8g2.setColorIndex(0); // couleur noir
u8g2.drawDisc(center_x, center_y, 4);
u8g2.setColorIndex(1); // couleur blanche
u8g2.drawCircle(center_x, center_y, 4);
}
// dessine l'arrière-plan - cercle plein écran, points pour les secondes,
// grandes graduations, nombres
draw_background();
if( etat_btnDraw[5]== LOW){
draw_hand_thin(time_seconds * 6, 56, 24); // aiguille des secondes
}
// dessinez les aiguilles avec des angles basés sur la valeur du temps
if( etat_btnDraw[6]== LOW){
draw_hand_bold(time_minutes * 6, 48, 15, 2); // aiguille des minutes
}
if( etat_btnDraw[7]== LOW){
draw_hand_bold(time_hours * 30 + (time_minutes / 2), 32, 15, 2); // aiguille des heures
}
}
while ( u8g2.nextPage() ); // parcourir toutes les pages jusqu'à ce que l'affichage soit entièrement mis à jour
}
// dessine l'arrière-plan -
// cercle plein écran, points pour les secondes, grandes graduations, nombres
void draw_background() {
float xpos, ypos, xpos2, ypos2; // Variables Flottantes
if( etat_btnDraw[1]== LOW){
u8g2.drawCircle(center_x, center_y, 63, U8G2_DRAW_ALL);// dessiner un cercle en plein écran
}
// dessine 60 points (pixels) autour du cercle, un pour chaque minute/seconde
if( etat_btnDraw[2]== LOW){
for (int i = 0; i < 60; i++) { // dessine 60 pixels autour du cercle
xpos = round(center_x + sin(radians(i * 6)) * 60); // calculer x pos en fonction de l'angle et du rayon
ypos = round(center_y - cos(radians(i * 6)) * 60); // calculer y pos en fonction de l'angle et du rayon
u8g2.drawPixel(xpos, ypos); // dessine un pixel blanc sur la position xpos et ypos
}
}
// dessine de grandes graduations
if( etat_btnDraw[3]== LOW){
for (int i = 0; i < 12; i++) {
// dessiner des graduations uniquement pour certains nombres,
// laisser un espace vide pour 12, 3, 6 et 9
if ((i % 3) != 0) {
xpos = round(center_x + sin(radians(i * 30)) * 54); // calculer x pos en fonction de l'angle et du rayon
ypos = round(center_y - cos(radians(i * 30)) * 54); // calculer y pos en fonction de l'angle et du rayon
xpos2 = round(center_x + sin(radians(i * 30)) * 46); // calculer x pos en fonction de l'angle et du rayon
ypos2 = round(center_y - cos(radians(i * 30)) * 46); // calculer y pos en fonction de l'angle et du rayon
u8g2.drawLine(xpos, ypos, xpos2, ypos2); // tracer une ligne pour une graduation
}
}
}
// dessine les étiquettes 12, 3, 6 et 9
if( etat_btnDraw[4]== LOW){
u8g2.setFont(u8g2_font_8x13B_mn); // définir la police u8g2
u8g2.drawStr(57, 20, "12");
u8g2.drawStr(112, 69, "3");
u8g2.drawStr(61, 120, "6");
u8g2.drawStr(9, 69, "9");
}
}
// dessiner une ligne fine = Aiguille des seconde s
void draw_hand_thin (int hand_angle, int hand_lenght_long, int hand_legth_short) {
float xpos, ypos;
float xpos2, ypos2;
// calculer la position de départ et de fin de l'aiguille seconde
xpos = round(center_x + sin(radians(hand_angle)) * hand_lenght_long); // calculer x pos en fonction de l'angle et du rayon
ypos = round(center_y - cos(radians(hand_angle)) * hand_lenght_long); // calculer y pos en fonction de l'angle et du rayon
xpos2 = round(center_x + sin(radians(hand_angle + 180)) * hand_legth_short); // calculer x pos en fonction de l'angle et du rayon
ypos2 = round(center_y - cos(radians(hand_angle + 180)) * hand_legth_short); // calculer y pos en fonction de l'angle et du rayon
u8g2.drawLine(xpos, ypos, xpos2, ypos2); // dessiner la ligne principale
u8g2.setDrawColor(0); // couleur noire
u8g2.drawDisc(xpos2, ypos2, 3); // dessine un petit cercle noir rempli
u8g2.setDrawColor(1); // couleur blanche
u8g2.drawCircle(xpos2, ypos2, 3, U8G2_DRAW_ALL); // dessine un petit contour de cercle blanc
}
// dessiner une aiguille en gras = aiguille des minutes et aiguille des heures
void draw_hand_bold (int hand_angle, int hand_lenght_long, int hand_legth_short, int hand_dot_size) {
float xpos, ypos;
float xpos2, ypos2;
float tri_xoff, tri_yoff;
// calculer les positions des deux cercles
xpos = round(center_x + sin(radians(hand_angle)) * hand_lenght_long); // calculer x pos en fonction de l'angle et du rayon
ypos = round(center_y - cos(radians(hand_angle)) * hand_lenght_long); // calculer y pos en fonction de l'angle et du rayon
xpos2 = round(center_x + sin(radians(hand_angle)) * hand_legth_short); // calculer x pos en fonction de l'angle et du rayon
ypos2 = round(center_y - cos(radians(hand_angle)) * hand_legth_short); // calculer y pos en fonction de l'angle et du rayon
tri_xoff = round( sin(radians(hand_angle + 90)) * hand_dot_size);
tri_yoff = round(-cos(radians(hand_angle + 90)) * hand_dot_size);
u8g2.drawLine(center_x, center_y, xpos2, ypos2); // tracer la ligne d'un cercle vers le centre
u8g2.drawDisc(xpos, ypos, hand_dot_size); // dessine un cercle blanc rempli
u8g2.drawDisc(xpos2, ypos2, hand_dot_size); // dessine un cercle blanc rempli
// deux triangles remplis sont utilisés pour dessiner un rectangle pivoté entre deux cercles
u8g2.drawTriangle(xpos + tri_xoff, ypos + tri_yoff,
xpos - tri_xoff, ypos - tri_yoff,
xpos2 + tri_xoff, ypos2 + tri_yoff);
u8g2.drawTriangle(xpos2 + tri_xoff, ypos2 + tri_yoff,
xpos2 - tri_xoff, ypos2 - tri_yoff,
xpos - tri_xoff, ypos - tri_yoff);
}
Loading
grove-oled-sh1107
grove-oled-sh1107