Bonjour,
voilà la problématique:
Je fabrique des parties électroniques pour du modélisme bateau. Variateurs switch etc ...
Pour cela il faut décoder le signal PWM du récepteur pour commander un pont en H ou divers relais.
J'ai donc un signal de ce type.
et je dois mesurer avec la meilleure précision un temps qui varie de 1000 microsecondes à 2000 microsecondes.
Quand j'ai un arduino avec un quartz cela ne pose pas vraiment de problème.
Pour un Attiny 85 sur horloge interne la précision c'est plus du tout ça.
Ou on a du bol ...ou (et c'est plus souvent le cas ) on a un décalage en plus ou en moins insupportable pour le neutre (1500) ce qui fait que a zéro on entends le moteur couiner.
Alors on peut toujours décaler le zéro de la radiocommande .... mais bon.
La solution : Régler la fréquence de l'attiny avec OSCCAL.
J'ai lu relu et rerelu un tas de site avec des solutions plus ou moins exotiques, qui vont du réglage par tâtonnement a carrément concevoir et réaliser un appareil qui ne fait que ça (mais qui n'évite pas le chargement d'un programme dans l'attiny).
Chargement d'un programme de réglage dans l'attiny ! soit il faut en passer par là.
Mais moi je fais çà avec une platine arduinoISP (voir un autre post)
pourquoi ne pas l'utiliser pour le réglage ??
Aussitôt dis presque aussitôt fait.
Écriture du programme attiny.
// Réglage de la frequence interne de l'attiny 85.
// Ce programme nécessite l'utilisation de l'ArduinoISP modifié.
#include <EEPROM.h>
byte EEpOsc;
// Timer/Counter0 Compare Match A interrupt handler
ISR (TIMER0_COMPA_vect) {
PORTB ^= 1 << PINB4; // Invert pin PB4
}
void setup() {
pinMode(4, OUTPUT); // Sortie 10kHz
pinMode(2, INPUT); // entrée --
pinMode(0, INPUT); // entrée ++
pinMode(1, INPUT); // entrée validation
EEPROM.get(0, EEpOsc); // Récupération de la valeur sauvegardée
if (EEpOsc != 0xFF) {
OSCCAL = EEpOsc;
} else {EEpOsc = OSCCAL;}
TCNT0 = 0; // Count up from 0
TCCR0A = 2 << WGM00; // CTC mode
if (CLKPR == 3) // If clock set to 1MHz
TCCR0B = (1 << CS00); // Set prescaler to /1 (1uS at 1Mhz)
else // Otherwise clock set to 8MHz
TCCR0B = (2 << CS00); // Set prescaler to /8 (1uS at 8Mhz)
GTCCR |= 1 << PSR0; // Reset prescaler
OCR0A = 49; // 49 + 1 = 50 microseconds (10KHz)
TIFR = 1 << OCF0A; // Clear output compare interrupt flag
TIMSK |= 1 << OCIE0A; // Enable output compare interrupt
}
void loop() {
if (digitalRead(1) == HIGH) { // uniquement si validation
if ((digitalRead(0) == HIGH) & ( digitalRead(2) == HIGH)) {
// sauvegarde OSCCAL
EEPROM.put(0, EEpOsc);
} else if ((digitalRead(2) == HIGH) & ( digitalRead(0) == LOW)) {
EEpOsc --;
} else if ((digitalRead(2) == LOW) & ( digitalRead(0) == HIGH)) {
EEpOsc ++;
}
while (digitalRead(1) == HIGH) {}; // attendre fin de validation
OSCCAL = EEpOsc;
}
}
Reste plus qu'a modifier le programme arduino ISP
void Optimisation() {
SERIAL.println();
SERIAL.println("Procédure d'optimisation Osccal");
SERIAL.println("--------------------------------------");
SERIAL.println();
SERIAL.println("X sortie mode optimisation");
SERIAL.println("W sauvegarde optimisation");
SERIAL.println("+ Augmenter OSCCAL");
SERIAL.println("- Diminuer OSCCAL");
SERIAL.println();
digitalWrite(PIN_SCK, LOW);
digitalWrite(PIN_MOSI, LOW);
pinMode(PIN_SCK, OUTPUT);
pinMode(PIN_MOSI, OUTPUT);
pinMode(PIN_MISO, OUTPUT);
uint8_t ch = 0;
while (ch != 'X')
{
ch = getch();
switch (ch) {
case '+':
SERIAL.println("+ Augmenter OSCCAL");
digitalWrite(PIN_MISO,HIGH);
digitalWrite(PIN_MOSI,HIGH);
delay(200);
digitalWrite(PIN_MOSI,LOW);
digitalWrite(PIN_MISO,LOW);
delay(200);
break;
case '-':
SERIAL.println("- Diminuer OSCCAL");
digitalWrite(PIN_MISO,HIGH);
digitalWrite(PIN_SCK,HIGH);
delay(200);
digitalWrite(PIN_SCK,LOW);
digitalWrite(PIN_MISO,LOW);
delay(200);
break;
case 'W':
SERIAL.println("W sauvegarde optimisation");
digitalWrite(PIN_MISO,HIGH);
digitalWrite(PIN_MOSI,HIGH);
digitalWrite(PIN_SCK,HIGH);
delay(200);
digitalWrite(PIN_MOSI,LOW);
digitalWrite(PIN_SCK,LOW);
digitalWrite(PIN_MISO,LOW);
delay(200);
break;
}
}
pinMode(PIN_MISO, INPUT);
SERIAL.println();
SERIAL.println("Sortie procédure d'optimisation Osccal");
SERIAL.println("--------------------------------------");
SERIAL.println();
}
ajout dans le setup:
SERIAL.begin(BAUDRATE);
SERIAL.println("--------------------------------------");
SERIAL.println();
SERIAL.println("Arduino ISP Opti_OSCCAL ATTINY");
SERIAL.println("Tapez O pour modifier l'OSCCAL");
SERIAL.println();
SERIAL.println("--------------------------------------");
SERIAL.println();
ajout dans avrisp()
case 'O': // Mode d'optimisation osccal ATTiny
Optimisation();
empty_reply();
break;
et voila
il suffit de regler pour avoir un signal a 10 kHz sur l'attiny (fréquencemètre, oscillo) puis de faire une sauvegarde.
dans le programme d’utilisation recharger la valeur OSCCAL stockée en EEprom.
EEPROM.get(0, EEpOsc); // Récupération de la valeur sauvegardée
if (EEpOsc != 0xFF) {
OSCCAL = EEpOsc;
} else {EEpOsc = OSCCAL;}
PS ne pas oublier de déclarer la variable. Moi je flash mes attiny a 8 mHz donc j'ai fais tous les essais a 8 mHz ... mais ça marche surement a 1 mHz.
PS2: pour reflasher un arduinoISP câblé ne pas oublier de débrancher le condo.