Alors, voilà un premier jet qui combine tes deux programmes avec la librairie YASM. Il n'y a que le compte à rebours que je n'ai pas fait car je n'ai pas compris ce qu'il devait faire
Là en gros tu as : au démarrage, choix du soin
appui sur le bouton = défiler les soins, si plus d'appui pdt 5s --> le soin affiché démarre
pour le moment le soin se limite à afficher >>>> Inspirer
puis <<<<Expirer
Il faut voir chaque machine à états comme une tâche distincte, qui s'execute en // avec les autres
Ici j'execute d'abord "choix", qui va lancer "soin" qui lui même lance "insexp"
"choix" se stoppe elle-même au lancement de "soin", qui va s'executer en // avec "insexp"
dans loop() il y a pourtant l'execution des trois machines, mais seule "choix" a un état initial défini dans setup(). Tant qu'aucun état n'est défini, l'execution de la machine ne fait juste rien, donc au départ seule "choix" est réellement executée, et c'est dans celle-ci que l'état initial de "soin" est défini (quand il y a expiration de la temporisation de validation du choix)
c'est également chaque état initial de "soin" qui lance "insexp" à sa première exécution.
reste à ajouter des états dans les divers soins pour faire ce que tu veux faire dedans (activation des relais, etc etc)
il y a aussi "btn" qui est aussi une machine YASM (de type BTN) un peu particulière puisqu'elle sert uniquement à gérer un bouton, et qui permet d'avoir les actions suivantes sur le bouton : clic, clic long, doubleclic ce qui peut permettre avec un seul bouton une navigation dans un menu. Ici seul le clic simple est employé.
#include <LiquidCrystal.h>
#include <yasm.h>
#include <btn.h>
YASM choix, soin, insexp;
BTN btn;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
const int PIN_BTN = 4;
#define TEMPO_VALIDE 5E3 //temporisation pour valider choix = 5s (5E3=5000ms)
#define TEMPO_INSEXP 600 //tempo d'affichage de chaque > ou <
void setup()
{
lcd.begin(16, 2);
pinMode(PIN_BTN, INPUT_PULLUP);
choix.next(ch_depart); //on définit l'état initial de la machine à états "choix"
}
void loop()
{
//surveillance de l'état du bouton
btn.update(!digitalRead(PIN_BTN)); // ! car le bouton fait contact au GND (actif bas)
//execution des machines à états (tâches)
choix.run();
soin.run();
insexp.run();
}
//////////////////// choix du soin ////////////////////////////////
void ch_depart()
{
if(choix.isFirstRun())
{
//cette partie ne s'execute qu'une fois
lcd.clear();
lcd.print(F(" Choisir soin :")); // F() est une macro pour utiliser facilement progmem pour les chaines et économiser de la ram
lcd.setCursor(0,1);
lcd.print(F("Appuyer pr choix"));
}
if(btn.state(BTN_CLICK)) //clic sur le bouton = on défile dans les choix
choix.next(ch_choix1);
}
void ch_choix1()
{
if(choix.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F("Soin numero 1 "));
}
if(choix.elapsed(TEMPO_VALIDE)) {
soin.next(sn_soin1);
choix.next(ch_depart);
choix.stop();
}
if(btn.state(BTN_CLICK))
choix.next(ch_choix2);
}
void ch_choix2()
{
if(choix.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F("Soin numero 2 "));
}
if(choix.elapsed(TEMPO_VALIDE)) {
soin.next(sn_soin2);
choix.next(ch_depart);
choix.stop();
}
if(btn.state(BTN_CLICK))
choix.next(ch_choix3);
}
void ch_choix3()
{
if(choix.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F("Soin numero 3 "));
}
if(choix.elapsed(TEMPO_VALIDE)) {
soin.next(sn_soin3);
choix.next(ch_depart);
choix.stop();
}
if(btn.state(BTN_CLICK))
choix.next(ch_choix4);
}
void ch_choix4()
{
if(choix.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F("Soin numero 4 "));
}
if(choix.elapsed(TEMPO_VALIDE)) {
soin.next(sn_soin4);
choix.next(ch_depart);
choix.stop();
}
if(btn.state(BTN_CLICK))
choix.next(ch_choix1);
}
///////////////// machine insexp : affichage des > et < ////////////////
byte position;
void ie_inspirer()
{
if(insexp.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F(" Inspirer"));
position=0;
}
if(insexp.periodic(TEMPO_INSEXP)) {
lcd.setCursor(position,0);
lcd.print(F(">"));
position++;
if (position == 8)
insexp.next(ie_expirer);
}
}
void ie_expirer()
{
if(insexp.isFirstRun()) {
lcd.setCursor(0,1);
lcd.print(F(" Expirer "));
position=7;
}
if(insexp.periodic(TEMPO_INSEXP)) {
lcd.setCursor(position,0);
lcd.print(F("<"));
position--;
if (position == 0)
insexp.next(ie_expirer);
}
}
///////////////// programmes de soin //////////////////
void sn_soin1()
{
if (soin.isFirstRun()) {
lcd.clear();
lcd.print(F(" *** SOIN 1 *** "));
insexp.next(ie_inspirer); //lancement de insexp
}
}
void sn_soin2()
{
if (soin.isFirstRun()) {
lcd.clear();
lcd.print(F(" *** SOIN 2 *** "));
insexp.next(ie_inspirer);
}
}
void sn_soin3()
{
if (soin.isFirstRun()) {
lcd.clear();
lcd.print(F(" *** SOIN 3 *** "));
insexp.next(ie_inspirer);
}
}
void sn_soin4()
{
if (soin.isFirstRun()) {
lcd.clear();
lcd.print(F(" *** SOIN 4 *** "));
insexp.next(ie_inspirer);
}
}
Le programme compile, en revanche je ne l'ai pas testé, la flemme de sortir un afficheur et un bouton. Mais ça devrait fonctionner, je suis assez confiant 
Là c'est la version "sale" qui prends plein de lignes de code, il est assez facile de simplifier tout ça car énormément de fonctions sont redondantes : choix du soin, etc. En rangeant les soins dans un tableau, il est assez simple de remplacer autant de fonctions que de choix par une seule, mais pour la clarté de l'exemple ça me semblait bien plus compréhensible ainsi.
Je peux faire la version "propre" demain si besoin.