Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Radio FM étanche pour douche : Arduino Nano, RDA5807, écran Nokia 5110 et PAM8403

Composants et fournitures

À propos de ce projet

Genèse

Mon ancienne cabine de douche intégrait un système de commande TR028 avec radio. Un jour, il a rendu l'âme, irréparable. J'ai acheté une radio de douche bon marché : elle a duré un an. Ma famille étant habituée à la radio sous la douche, j'ai étudié le TR028 : il contenait un module TEA5767. Mes recherches m'ont mené au RDA5807, très proche mais avec RDS, contrôle de volume et bass boost. C'était mon choix.

Ma vision

Ce que j'ai obtenu

Fonctionnement

Améliorations envisagées

Conclusion

Projet fonctionnel depuis 1 mois, seul le dérèglement de l'horloge est notable. Le code perfectible (premier projet Arduino partagé). Questions bienvenues en commentaires.

Maj 1 : fusible 2 A sur ligne 12 V (sécurité). Ligne 586 ajoutée : menu = 1; pour revenir en mode VOLUME après Power.

Maj 2 : l'écran LCD montre des signes de fin de vie. Recherche d'alternative (1,8" TFT envisagé, mais plus gourmand en ressources).

Code

Sketch principal (Arduino)

// Radio FM douche Arduino Nano - RDA5807M, RTC, EEPROM, LCD5110, Thermistance
#include <LCD5110_Graph.h>
#include <AT24CX.h>
#include <Wire.h>
#include <RDSParser.h>
#include <radio.h>
#include <RTClib.h>
#include <RDA5807M.h>
#include <Keypad.h>

#define MAXmenu 4
#define ledPin 13
#define blPin 7

char keys[7][2] = {
  {'L','P'}, {'I','D'}, {'1','2'}, {'3','4'}, {'5','6'}, {'M','m'}, {'<','>'}
};
byte rowPins[7] = {11,12,10,17,9,16,8};
byte colPins[2] = {15,14};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, 7, 2);

boolean bass = 0, dspl = 0, memdisplay = 0, mempress = 0, adj = 0;
boolean ledPin_state, power_state;
int menu, volume, volumeOld = 5, frequency, frequencyOld;
int txtl = 0, temparray = 0;
int samples[5];
unsigned int status[6];
unsigned long timeprevious = 0, timeprev = 0;

AT24CX mem;
RTC_DS1307 rtc;
LCD5110 lcd(6,5,4,2,3);
RDA5807M radio;
RDSParser rds;

extern unsigned char SmallFont[];
extern uint8_t signal5[]; extern uint8_t signal4[]; extern uint8_t signal3[];
extern uint8_t signal2[]; extern uint8_t signal1[];

void setup() {
  analogReference(EXTERNAL);
  Serial.begin(9600);
  Wire.begin();
  radio.init(); radio.debugEnable();
  lcd.InitLCD(); lcd.clrScr(); lcd.setFont(SmallFont); lcd.enableSleep();
  power_state = 0;
  keypad.addStatedEventListener(keypadEvent);
  keypad.setHoldTime(1500);
  pinMode(ledPin, OUTPUT); pinMode(blPin, OUTPUT);
  digitalWrite(ledPin, LOW); digitalWrite(blPin, LOW);
  ledPin_state = digitalRead(ledPin);

  frequency = mem.readInt(201);
  volume = 2; menu = 1;
  if (volume < 0) volume = 0; if (volume > 15) volume = 15;
  if (frequency < 0) frequency = 0; if (frequency > 210) frequency = 210;

  WriteReg(0x02, 0xC00d);
  radio.attachReceiveRDS(RDS_process);
  rds.attachServicenNameCallback(DisplayServiceName);
  rds.attachTextCallback(DisplayText);
}

void loop() {
  if (frequency != frequencyOld) { frequencyOld = frequency; mem.writeInt(201, frequency); canal(frequency); }
  if (volume != volumeOld) { volumeOld = volume; WriteReg(5, 0x84D0 | volume); }

  char key = keypad.getKey();
  radio.checkRDS();

  // Température (moyenne sur 5 lectures toutes les 0,6 s)
  unsigned long timenow = millis();
  if ((unsigned long)(timenow - timeprevious) > 600) {
    timeprevious = timenow;
    samples[temparray] = analogRead(A7);
    temparray++;
  }
  if (temparray == 5) {
    float average = 0;
    for (int i=0;i<5;i++) average += samples[i];
    printTemp(average);
    temparray = 0;
  }

  // Timeout 4 s pour affichage MEM
  unsigned long dabar = millis();
  if (mempress == 1) { timeprev = dabar; memdisplay = 1; mempress = 0; }
  if (memdisplay == 1) {
    if ((unsigned long)(dabar - timeprev) < 4000) memdisplay = 1; else memdisplay = 0;
  }

  // Ajustement RTC via Serial (hXX, mXX, sXX)
  if (Serial.available() > 0) {
    char t = Serial.read();
    DateTime now = rtc.now();
    switch (t) {
      case 'h': { unsigned int h = Serial.parseInt(); rtc.adjust(DateTime(now.year(),now.month(),now.day(),h,now.minute(),now.second())); Serial.println("Hours"); Serial.println(h); break; }
      case 'm': { unsigned int m = Serial.parseInt(); rtc.adjust(DateTime(now.year(),now.month(),now.day(),now.hour(),m,now.second())); Serial.println("Minutes"); Serial.println(m); break; }
      case 's': { unsigned int s = Serial.parseInt(); rtc.adjust(DateTime(now.year(),now.month(),now.day(),now.hour(),now.minute(),s)); Serial.println("Seconds"); Serial.println(s); break; }
    }
  }

  printSignalStrength(); printLines(); printTime(); printFreq(); printStereo(); printMode(); printMenu(); printDate();
  lcd.update();
}

// --- Fonctions d'affichage ---
void printSignalStrength() {
  unsigned int sig; Readstatus(); sig = status[1] / 1000;
  if (sig <= 12) lcd.drawBitmap(1,1,signal1,17,6);
  else if (sig <= 24) lcd.drawBitmap(1,1,signal2,17,6);
  else if (sig <= 36) lcd.drawBitmap(1,1,signal3,17,6);
  else if (sig <= 48) lcd.drawBitmap(1,1,signal4,17,6);
  else lcd.drawBitmap(1,1,signal5,17,6);
}
void printLines() { lcd.drawLine(0,9,84,9); lcd.drawLine(0,39,84,39); }
void printTemp(float avg) {
  avg /= 5; avg = 1023/avg - 1; avg = 51700/avg;
  float steinhart = avg/50000; steinhart = log(steinhart); steinhart /= 3950;
  steinhart += 1.0/(25+273.15); steinhart = 1.0/steinhart; steinhart -= 273.15;
  int tmp = round(steinhart);
  lcd.printNumI(tmp,60,1,2); lcd.print("~C",72,1);
}
void DisplayServiceName(char *name) { lcd.print(name,18,22); }
void DisplayText(char *text) { lcd.print(text,txtl,30); txtl -= 66; if (txtl == -396) txtl = 0; }
void printTime() { DateTime now = rtc.now(); lcd.printNumI(now.hour(),24,1,2,'0'); lcd.print(":",36,1); lcd.printNumI(now.minute(),42,1,2,'0'); }
void printDate() {
  if (dspl == 1) { ClearRDS(); DateTime now = rtc.now();
    lcd.printNumI(now.year(),12,22,4); lcd.print(".",36,22); lcd.printNumI(now.month(),42,22,2,'0'); lcd.print(".",54,22); lcd.printNumI(now.day(),60,22,2,'0');
    int dw = now.dayOfTheWeek();
    const char* days[] = {"Sekmadienis","Pirmadienis","Antradienis","Treciadienis","Ketvirtadienis","Penktadienis","Sestadienis"};
    lcd.print(days[dw], CENTER, 30); lcd.update(); delay(4000); ClearRDS(); dspl = 0;
  }
}
void printMode() { lcd.print("MODE ",0,41); }
void printMenu() {
  if (menu==1) { lcd.print("VOLUME ",30,41); if (volume<0) lcd.print("XX",72,41); else lcd.printNumI(volume+1,72,41,2,'0'); }
  if (menu==2) lcd.print("AUTO-TUNE",30,41);
  if (menu==3) lcd.print("MAN.-TUNE",30,41);
  if (menu==4) { lcd.print(" BASS ",30,41); if (bass==0) lcd.print("OFF",66,41); else lcd.print(" ON",66,41); }
}
void printFreq() {
  int fr = 870 + frequency; int frH = fr/10; int frD = fr%10;
  lcd.printNumI(frH,30,12,3); lcd.print(".",48,12); lcd.printNumI(frD,54,12,1); lcd.print("MHz",66,12);
}
void printStereo() {
  if (memdisplay) lcd.print("MEM>",0,12);
  else if ((status[0] & 0x0400) == 0) lcd.print("( )",0,12);
  else lcd.print("(ST)",0,12);
}

// --- Radio / RDS ---
void search(byte direc) {
  byte i; if (!direc) WriteReg(0x02,0xC30d); else WriteReg(0x02,0xC10d);
  for (i=0;i<10;i++) { delay(200); Readstatus(); if (status[0] & 0x4000) { frequency = status[0] & 0x03ff; break; } }
}
void canal(int canal) {
  byte nH = canal >> 2; byte nL = ((canal & 3) << 6) | 0x10;
  Wire.beginTransmission(0x11); Wire.write(0x03); Wire.write(nH); Wire.write(nL); Wire.endTransmission();
}
int Readstatus() { Wire.requestFrom(0x10,12); for(int i=0;i<6;i++) status[i]=256*Wire.read()+Wire.read(); Wire.endTransmission(); }
void WriteReg(byte reg, unsigned int valor) { Wire.beginTransmission(0x11); Wire.write(reg); Wire.write(valor>>8); Wire.write(valor&0xFF); Wire.endTransmission(); }
void RDS_process(uint16_t b1,uint16_t b2,uint16_t b3,uint16_t b4) { rds.processData(b1,b2,b3,b4); }
void ClearRDS() { lcd.print(" ",0,22); lcd.print(" ",0,30); }

// --- Gestion clavier ---
void keypadEvent(KeypadEvent key, KeyState kpadState) {
  switch (kpadState) {
    case HOLD: if (key=='D' && power_state) adj=1; break;
    case RELEASED:
      if (key=='D' && adj) {
        DateTime now = rtc.now();
        if (now.minute()>=45 && now.minute()<=59) rtc.adjust(DateTime(now.year(),now.month(),now.day(),now.hour()+1,0,0));
        if (now.minute()>=1 && now.minute()<=15) rtc.adjust(DateTime(now.year(),now.month(),now.day(),now.hour(),0,0));
        adj=0;
      } break;
    case PRESSED:
      if (key=='M' && power_state) { memdisplay=0; menu++; if (menu>MAXmenu) menu=1; }
      if (key=='>' && power_state) { memdisplay=0;
        switch(menu) {
          case 1: if (volume<0) { if(bass==0) WriteReg(0x02,0xD00D); else WriteReg(0x02,0xC00D); volume=0; } else volume++; if (volume>15) volume=15; break;
          case 2: search(0); ClearRDS(); break;
          case 3: frequency++; if (frequency>210) frequency=210; ClearRDS(); break;
          case 4: if (bass==0) { bass=1; WriteReg(0x02,0xD00D); } break;
        }
      }
      if (key=='<' && power_state) { memdisplay=0;
        switch(menu) {
          case 1: volume--; if (volume<0) WriteReg(0x02,0x800D); break;
          case 2: search(1); ClearRDS(); break;
          case 3: frequency--; if (frequency<0) frequency=0; ClearRDS(); break;
          case 4: if (bass==1) { bass=0; WriteReg(0x02,0xC00D); } break;
        }
      }
      if (key=='L' && power_state) { digitalWrite(ledPin, !digitalRead(ledPin)); ledPin_state = digitalRead(ledPin); }
      if (key=='P') { digitalWrite(blPin, !digitalRead(blPin)); power_state = digitalRead(blPin); if (power_state==0) { lcd.enableSleep(); digitalWrite(ledPin,LOW); } else lcd.disableSleep(); volume=2; menu=1; }
      for (int p=1;p<=6;p++) {
        if (key==char('0'+p) && power_state) {
          int addr = 100 + p*10;
          if (!memdisplay) { frequency = mem.readInt(addr); ClearRDS(); }
          else { mem.writeInt(addr, frequency); memdisplay=0; }
        }
      }
      if (key=='m' && power_state) mempress=1; else mempress=0;
      if (key=='I' && power_state) dspl=1;
      break;
  }
}

Symboles de force du signal (C/C++)

#if defined(__AVR__) #include  #define imagedatatype const uint8_t
#elif defined(__PIC32MX__) #define PROGMEM #define imagedatatype const unsigned char
#elif defined(__arm__) #define PROGMEM #define imagedatatype const unsigned char
#endif
imagedatatype signal5[] PROGMEM={0xC1,0xC2,0xC4,0xFF,0xC4,0xC2,0xC1,0xC0,0xE0,0xC0,0xF0,0xC0,0xF8,0xC0,0xFC,0xC0,0xFE};
imagedatatype signal4[] PROGMEM={0xC1,0xC2,0xC4,0xFF,0xC4,0xC2,0xC1,0xC0,0xE0,0xC0,0xF0,0xC0,0xF8,0xC0,0xFC,0xC0,0xC0};
imagedatatype signal3[] PROGMEM={0xC1,0xC2,0xC4,0xFF,0xC4,0xC2,0xC1,0xC0,0xE0,0xC0,0xF0,0xC0,0xF8,0xC0,0xC0,0xC0,0xC0};
imagedatatype signal2[] PROGMEM={0xC1,0xC2,0xC4,0xFF,0xC4,0xC2,0xC1,0xC0,0xE0,0xC0,0xF0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0};
imagedatatype signal1[] PROGMEM={0xC1,0xC2,0xC4,0xFF,0xC4,0xC2,0xC1,0xC0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0};

Schéma

Schéma de câblage complet (image fournie).

Processus de fabrication

  1. L'évolution et l'ingénierie de la technologie radio
  2. Circuits intégrés (CI) : puces compactes et puissantes alimentant l'électronique moderne
  3. JX Wave Generator – Générateur DDS compatible Arduino avec affichage OLED
  4. MotionSense : Détection d'intrusion intelligente avec Arduino et ESP8266
  5. Construire une boîte à énigme IoT sécurisée avec Arduino MKR Bundle – Guide étape par étape
  6. Régulateur de douche intelligent – Électrovanne fiable pour contrôle précis de la température
  7. Scanner IR de température sans fil – Arduino Nano, Bluetooth & MLX90614
  8. Char autonome « WalaBeer » : Walabot, Arduino, Raspberry Pi & Alexa
  9. Kit MOSMusic : MOSFET, Arduino et plus pour éclairage musical