Je regarde pour faire une balance pour mon chien (les propriétaires de chien savent qu'il faut un grand plateau sinon le chien refuse de monter sur la balance) et j'ai choisi la bibliothèque HX711 de Rob Tillaart parce que j'ai confiance en la qualité de son travail.
J'ai trouvé cette ligne :
while (digitalRead(_dataPin) == HIGH) yield();
J'ai recherché la signification de yield(), j'ai vu que c'était pour éviter de faire des codes bloquants dans des threads.
Je n'avais pas l'impression qu'avec un microcontrôleur on utilisait des threads ou alors comme M Jourdain on utilise des threads sans le savoir.
Même pas peur : cela peut-il avoir une application dans les fonctions avec des delay(xxx) bloquants pour qu'ils ne soient pas bloquant ?
Code complet de la fonction où se trouve le yield() :
float HX711::read()
{
// this waiting takes most time...
while (digitalRead(_dataPin) == HIGH) yield();
union
{
long value = 0;
uint8_t data[4];
} v;
noInterrupts();
// Pulse the clock pin 24 times to read the data.
v.data[2] = shiftIn(_dataPin, _clockPin, MSBFIRST);
v.data[1] = shiftIn(_dataPin, _clockPin, MSBFIRST);
v.data[0] = shiftIn(_dataPin, _clockPin, MSBFIRST);
// TABLE 3 page 4 datasheet
// only default verified, so other values not supported yet
uint8_t m = 1; // default gain == 128
if (_gain == 64) m = 3;
if (_gain == 32) m = 2;
while (m > 0)
{
digitalWrite(_clockPin, HIGH);
digitalWrite(_clockPin, LOW);
m--;
}
interrupts();
// SIGN extend
if (v.data[2] & 0x80) v.data[3] = 0xFF;
_lastRead = millis();
return 1.0 * v.value;
}
Sa librairie est probablement compatible ESP8266 ESP32.
Sur avr la fonction yield() est appelée par delay().
void delay(unsigned long ms)
{
uint32_t start = micros();
while (ms > 0) {
yield();
while ( ms > 0 && (micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
Mais la fonction yield est weak sur avr. Tu peux écrire la tienne et faire une opération X pendant les appels à delay(), ou comme dans la librairie HX711, pendant la boucle while (digitalRead(_dataPin))
void yield(void) {
// à implémenter
}
Quel intérêt en monotâche ? Lire l'état d'un bouton ou d'un capteur pour le mémoriser et le traiter ensuite ? Pourquoi pas ?
C'est le cas sur ESP.
Sur ESP c'est différent, FreeRTOS est utilisé. delay() appelle vTaskDelay(). vTaskDelay() n'est pas bloquant, sauf pour la tâche qui l'appelle. Une autre tâche peut donc prendre la main pendant les appels à delay().
Sur ESP, il y a forcément deux tâches : loop() et WIFI.
La fonction yield est réellement implémentée, car elle est doit être appelée par tout code bloquant. Et yield() appelle vTaskSwitchContext() qui passe éventuellement la main à une autre tâche.
Cela permet par exemple dans une implémentation du type WebServer de ne pas bloquer la tâche WIFI pendant les appels de handleClient(), qui est appelée en boucle par loop(), ce qui est théoriquement bloquant.
Si handleClient() a une requête à traiter, elle la traite, sinon elle appelle yield(). Si yield() n'était pas appelée, la tâche WIFI n'aurait jamais la main, et handleClient() n'aurait jamais quoi que ce soit à se mettre sous la dent, puisque c'est la tâche WIFI qui lui donne du travail.
Sur ESP32 uniquement non ?
Il me semble que sur l'ESP8266, il n'y a pas FreeRTOS (enfin, en programmation de base avec l'IDE) et donc en mode "coopératif" (alors qu'avec FreeRTOS, on est bien en mode préamptif) et donc qu'il faut donner la main par yield(); aux taches de fonds comme le WiFi, non ?
Il me semble effectivement que pour l'extension ESP8266 c'est le 'non_os_sdk' qui est utilisé
et pourtant de manière empirique yield() est nécessaire pour 'donner de l'air' à la tâche 'network'
Pourquoi ? comment ? ..... il faudrait plonger dans les entrailles du code le délay() spécifique ESP8266 fait aussi l'affaire , il contient un yield() https://arduino-esp8266.readthedocs.io/en/3.0.1/reference.html#timing-and-delays
Oui effectivement, j'ai vérifié. Dans le code de delay() il appelle des fonctions propriétaires.
Donc pas de FreeRTOS. Cela ne change pas grand chose, il y a un scheduler.