//==========================Bibliothèque====================================================
#include "driver/gpio.h"
#include "stdio.h"
#include "driver/ledc.h"
#include "driver/pcnt.h"
#include "soc/pcnt_struct.h"
#include <math.h>
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//=============================================================================================
//====================================Partie Déclaration=======================================
// Configuration de l'afficheur LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define LEDC_HS_CH1_GPIO GPIO_NUM_4 // GPIO 33 comme sortie pour le générateur de pulses (LEDC)
uint32_t RapportCycliqSortie = 0; // Valeur calculée du cycle de travail
uint32_t ResolutionSortie = 0; // Valeur calculée de la résolution
// GPIO pour le clavier matriciel
const byte ROWS = 4; // 4 lignes
const byte COLS = 4; // 4 colonnes
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {5, 18, 19, 12}; // Connexion des lignes du clavier aux GPIO
byte colPins[COLS] = {14, 23, 25, 26}; // Connexion des colonnes du clavier aux GPIO
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
#define LEDC_HS_CH0_GPIO GPIO_NUM_33 // GPIO 33 comme sortie pour le générateur de pulses (LEDC)
#define PCNT_COUNT_UNIT PCNT_UNIT_0 // PCNT Compteur d'impulsions Unité 0
#define PCNT_COUNT_CHANNEL PCNT_CHANNEL_0 // Canal 0 du compteur d'impulsions PCNT de l'ESP32
#define PCNT_INPUT_SIG_IO GPIO_NUM_34 //GPIO 34 entrée du diviseur
#define LEDC_HS_CH0_GPIO GPIO_NUM_33 // GPIO_33 sortie du LEDC
#define PCNT_INPUT_CTRL_IO GPIO_NUM_35 // Pin de contrôle PCNT - HIGH = compte à rebours, LOW = non compte à rebours
#define OUTPUT_CONTROL_GPIO GPIO_NUM_32 // GPIO_32 sortie de la timer
#define PCNT_H_LIM_VAL overflow // Debordement du compteur
#define IN_BOARD_LED GPIO_NUM_2 // GPIO 2
bool flag = true; // le flag de survéllance pour le debordement
uint32_t overflow = 20000;// Valeur max pour que le PCNT deborde
int16_t pulses = 0;// Nombre d'impulsions comptées
uint32_t multPulses = 0; // Nombre de dépassements du compteur PCNT
uint32_t InterValTemps = 1000000;// Intervalle 1S = 1000000µs pour le comptage
uint32_t FreqVoulue = 10000;// Frequence- 10000 Hz
uint32_t RapportCycliq = 0; // Rapport cyclique
uint32_t Resolution = 0; // Resolution de service
float Frequence = 0; // Variable pour calculer la fréquence
String freqInput = ""; // Stocke la fréquence entrée par l'utilisateur
String divInput = ""; // Stocke l'entrée du rapport de division
int inputInt = 1000; // Valeur par défaut de la fréquence
uint32_t n = 2; // Variable du rapprot de division du diviseur
esp_timer_create_args_t create_args; // Arguments de la Timer
esp_timer_handle_t timer_handle; // Instance de Timer
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; // variable portMUX_TYPE pour synchronisation
//===============================================================================================================
//===============================================================================================================
void setup() {
Serial.begin(115200);
Serial.println(" Digite uma frequencia - 1 a 40 MHz");
lcd.init(); // Initialiser l'afficheur
lcd.backlight(); // Activer le rétroéclairage
lcd.clear(); // Effacer l'écran
lcd.setCursor(0, 0); // Placer le curseur à la position (0, 0)
lcd.print("Freq Diviseur"); // Afficher "Freq Diviseur" à l'écran
// Initialiser les broches du clavier
for (int i = 0; i < ROWS; i++) {
pinMode(rowPins[i], OUTPUT);
}
for (int i = 0; i < COLS; i++) {
pinMode(colPins[i], INPUT_PULLUP);
}
GenerateurDeSignaux(); // Initialiser l'oscillateur LEDC
Compteurd1Impulsion(); // Initialisation du PCNT
// Configurer GPIO en mode OUTPUT pour le contrôle de la fréquence
pinMode(OUTPUT_CONTROL_GPIO, OUTPUT);
// Configurer GPIO en mode INPUT pour le signal d'entrée de fréquence
pinMode(PCNT_INPUT_SIG_IO, INPUT);
// Configurer GPIO en mode OUTPUT pour l'LED
pinMode(IN_BOARD_LED, OUTPUT);
// Créer un timer ESP32 pour contrôler la fréquence
create_args.callback = ControleurDeTemps; // Instances du temps de contrôle
esp_timer_create(&create_args, &timer_handle); // Création des paramètres de la minuterie
// Configurer l'LED intégrée pour afficher la fréquence
gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT);
}
//=====================================================================================================
//=====================================================================================================
void loop() {
ClaviMatricielle () ; // Fonction pour le clavier matricielle
FrequenceDeSortie(); // Fonction pour calculer la fréquence divisée
}
//===================================================================================================
//============================Calcul de fréquence de sortie==========================================
void FrequenceDeSortie() {
if (flag == true) // Si le décompte est terminé
{
flag = false; // Empêche la réimpression
Frequence = ((pulses + (multPulses * overflow)) / 2) / n ; // Calcule la somme des impulsions comptées dans le PCNT
Serial.print("Frequencia : ");
Serial.print(Frequence);
Serial.println(" Hz ");
lcd.setCursor(0, 1);
lcd.print("SORTIE: ");
lcd.print(Frequence);
lcd.print(" Hz");
multPulses = 0; // Remise à zéro du compteur de débordement
delay (100); // Délai 100 ms
pcnt_counter_clear(PCNT_COUNT_UNIT); // Remise à zéro du compteur PCNT
esp_timer_start_once(timer_handle, InterValTemps);// Lance le compteur de temps d'une seconde
gpio_set_level(OUTPUT_CONTROL_GPIO, 1);// Porte de contrôle - permet le comptage des impulsions
}
}
//===================================================================================================
//==============================Clavier Matricielle==================================================
void ClaviMatricielle () {
char key = keypad.getKey();
// Si une touche est appuyée
if (key) {
Serial.println(key);
switch (key) {
case '0' ... '9': // Pour les touches numériques
freqInput += key;
Serial.print("Fréquence en entrée: ");
Serial.println(freqInput);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ENTREE: ");
lcd.print(freqInput);
lcd.print(" "); // Effacer les anciens caractères
break;
FreqVoulue = 0;
case '#': // Valider la fréquence entrée
if (freqInput.length() > 0) {
inputInt = freqInput.toInt(); // Convertir l'entrée en entier
//freqInput = "";
FreqVoulue = inputInt; // Mettre à jour la fréquence souhaitée
freqInput = "";
if (FreqVoulue != 0) // Si une valeur a été introduite
{
GenerateurDeSignaux (); // Reconfigure la fréquence de l'oscillateur
}
//GenerateurDeSignaux();
Serial.print("Nouvelle fréquence: ");
Serial.println(FreqVoulue);
// Réinitialiser et appliquer la nouvelle fréquence
}
break;
case 'A': // Valider la modification de rapport de division
if(freqInput.length() > 0) {
n = freqInput.toInt();
FrequenceDeSortie();
freqInput = "";
}
break;
case '*': // Effacer l'entrée actuelle
freqInput = "";
Serial.println("Effacement de l'entrée.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ENTREE: "); // Effacer l'affichage de l'entrée
break;
default:
break;
}
}
}
//================================================================================================================
//===============================LEDC=============================================================================
void GenerateurDeSignaux () // Fonction de l'oscillateur
{
Resolution = (log (80000000 / FreqVoulue) / log(2)) / 2 ; // Calcule de la résolution de service
if (Resolution < 1) Resolution = 1; // Résolution minimale fixée = 1
Serial.println(Resolution);
RapportCycliq = (pow(2, Resolution)) / 2; // Calcul de rapport cyclique
Serial.println(RapportCycliq);
ledc_timer_config_t ledc_timer = {}; // Instance de Configuration du timer de LEDC
ledc_timer.duty_resolution = ledc_timer_bit_t(Resolution); // Configuration de la résolution
ledc_timer.freq_hz = FreqVoulue; // Configuration de la fréquence
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // Mode haute vitesse
ledc_timer.timer_num = LEDC_TIMER_0; // Utilisation du timer0 du LEDC
ledc_timer_config(&ledc_timer); // Configuration du timer de LEDC
ledc_channel_config_t ledc_channel = {}; //Instance de configuration du canal de LEDC
ledc_channel.channel = LEDC_CHANNEL_0; // Configuration canal 0
ledc_channel.duty = RapportCycliq; // Configuration de rapport cyclique
ledc_channel.gpio_num = LEDC_HS_CH0_GPIO; // Configure le GPIO de la sortie LEDC
ledc_channel.intr_type = LEDC_INTR_DISABLE; // Désactive l'interruption LEDC
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; // Mode de fonctionnement du canal à grande vitesse
ledc_channel.timer_sel = LEDC_TIMER_0; // Selecionne de timer 0 de LEDC
ledc_channel_config(&ledc_channel); // Configuration du canal de LEDC
}
//===============================================================================================================
//===============================Fonction d'interruption=========================================================
static void IRAM_ATTR pcnt_intr_handler(void *arg) // Configuration de la timer pour contrôler le debordement
{
portENTER_CRITICAL_ISR(&timerMux); // Bloquer une nouvelle interruption
multPulses++; // Conteneur de débordement incrémentiel
PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT); // Indicateur d'interruption
portEXIT_CRITICAL_ISR(&timerMux); // Nouvelle interruption
}
//==================================================================================================================
//==================================================================================================================
void Compteurd1Impulsion () // Fonction de PCNT
{
pcnt_config_t pcnt_config = { }; // Instance de configuration du PCNT
pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO; // Configuration du GPIO d'entrée du PCNT
pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO; // Configuration du GPIO d'entrée de contrôle
pcnt_config.unit = PCNT_COUNT_UNIT;// Unité 0 de comptage PCNT
pcnt_config.channel = PCNT_COUNT_CHANNEL; // Canal 0 PCNT
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL; // Limite maximale de comptage = 20000
pcnt_config.pos_mode = PCNT_COUNT_INC; // Augmente le comptage lors de la montée de l'impulsion
pcnt_config.neg_mode = PCNT_COUNT_INC; // Augmente le comptage lors de la descente de l'impulsion
pcnt_config.lctrl_mode = PCNT_MODE_DISABLE; // PCNT - mode lctrl désactivé
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; // PCNT - mode hctrl - si HIGH comptage incrémenté
pcnt_unit_config(&pcnt_config); // Configure le compteur PCNT
pcnt_counter_pause(PCNT_COUNT_UNIT);// Mise en pause du compteur PCNT
pcnt_counter_clear(PCNT_COUNT_UNIT); // Remise à zéro du compteur PCNT
pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);// Fixe la limite supérieure de comptage
pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);// Configure la routine d'interruption PCNT
pcnt_intr_enable(PCNT_COUNT_UNIT); // Activer les interruptions PCNT
pcnt_counter_resume(PCNT_COUNT_UNIT);// Remise à zéro du compteur PCNT
}
//=========================================================================================================================
//=========================================================================================================================
void ControleurDeTemps (void*) // Fonction de la fin du temps de lecture de l'impulsion
{
gpio_set_level(OUTPUT_CONTROL_GPIO, 0);// Contrôle du PCNT - pour le comptable
pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses); // Obtient la valeur comptée dans le PCNT
flag = true; // Informe qu'il y a eu une interruption du contrôle
}