//-------------------------------------------- // LoRa Annoyatron Base Station // RSP 2021.11.01 // Target: Pro Mini 5V/16M // + SX1278 radio // + MAX7219 display // + dfPlayer //-------------------------------------------- #include // default pins are: cs=10, reset=9, irq=2 #define NETID 0xB4 // ranges from 1-255, default 0x34 #include "DFRobotDFPlayerMini.h" DFRobotDFPlayerMini myDFPlayer; #define DF_INSTALLED #define NUM_MP3S 6 #define BTN1_PIN 4 #define BTN2_PIN 5 #define LED_CS_PIN 8 uint8_t rx_status = 0; uint8_t rx_command; //-------------------------------------------- // 7-segment LED driver #define DISPLAY_BRIGHTNESS 5 // display LED brightness; 0..15 #define NUM_DIGITS 8 // number of digits implemented #define U7219_MODE 0x09 #define U7219_INT 0x0A #define U7219_SCAN 0x0B #define U7219_SHUT 0x0C #define U7219_TEST 0x0F #define LOAD_PIN 8 // 7-segment LED load signal output #define CLK_PIN 13 // SCK 7-segment LED clock output #define DDAT_PIN 11 // MOSI 7-segment LED data output const uint8_t segmentTable[] = // 7 segment LED character set // A // --- // F| G |B // --- // E| D |C // --- // .ABCDEFG { B01111110, // 0 B00110000, // 1 B01101101, // 2 B01111001, // 3 B00110011, // 4 B01011011, // 5 B01011111, // 6 B01110000, // 7 B01111111, // 8 B01111011, // 9 B01110111, // A B00011111, // b B01010110, // C B00111101, // d B01001111, // E B01000111, // F B00000000, // blank B00000001, // - B00110111, // H B00000001, // L B00010101, // n B00011101, // o B01100111, // P B00000101, // r B00111110, // U B10000000 // error indicator }; #define CH_BLANK 16 #define CH_DASH 17 #define CH_H 18 #define CH_L 19 #define CH_n 20 #define CH_o 21 #define CH_P 22 #define CH_r 23 #define CH_U 24 #define CH_WTF 25 // write a LED register void write7segReg( uint8_t addr, uint8_t data ) { digitalWrite(LOAD_PIN, LOW); SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); SPI.transfer(addr); SPI.transfer(data); SPI.endTransaction(); digitalWrite(LOAD_PIN, HIGH); } // write a digit position // 8 7 6 5 4 3 2 1 void write7seg( uint8_t digit, uint8_t extended_binary_code, boolean decimal = false ) { if (extended_binary_code > CH_WTF) extended_binary_code = CH_WTF; write7segReg( digit, segmentTable[extended_binary_code] | (decimal ? 0x80:0) ); } void clearDisplay() { for (uint8_t i=1; i <= 8; i++) write7segReg(i,CH_BLANK); } //-------------------------------------------- void onReceive(int packetSize) { if (packetSize != 1) rx_status = 2; rx_command = LoRa.read(); rx_status = 1; } void paintRandomDigit( uint8_t digit ) { uint8_t n = random(3,4+1); // turn on 3 to 4 segments uint8_t segs = 0; for (uint8_t i=0; i < n; i++) do { uint8_t r = random(0,6+1); if ((segs & (1 << r))==0) { segs |= 1 << r; break; } } while(1); write7segReg( digit, segs ); } void loraError() { write7seg( 8,CH_L ); write7seg( 7,CH_o ); write7seg( 6,CH_r ); write7seg( 5,0x0A ); write7seg( 4,CH_BLANK ); write7seg( 3,0x0E ); write7seg( 2,CH_r ); write7seg( 1,CH_r ); while (1); // hang } void dfError() { write7seg( 8,CH_BLANK ); write7seg( 7,CH_BLANK ); write7seg( 6,0x0D ); write7seg( 5,0x0F ); write7seg( 4,CH_BLANK ); write7seg( 3,0x0E ); write7seg( 2,CH_r ); write7seg( 1,CH_r ); while (1); // hang } //-------------------------------------------- void setup() { Serial.begin(9600); // DFplayer on serial pinMode(BTN1_PIN, INPUT_PULLUP); pinMode(BTN2_PIN, INPUT_PULLUP); pinMode(LED_CS_PIN, OUTPUT); SPI.begin(); // set up display digitalWrite(LOAD_PIN, HIGH); // idle state pinMode(LOAD_PIN, OUTPUT); digitalWrite(CLK_PIN, LOW); // idle state pinMode(CLK_PIN, OUTPUT); pinMode(DDAT_PIN, OUTPUT); delay(100); write7segReg( U7219_MODE, 0x00 ); // set no decode write7segReg( U7219_SCAN, NUM_DIGITS-1 ); // set number of digits write7segReg( U7219_INT, DISPLAY_BRIGHTNESS ); write7segReg( U7219_SHUT, 0x01 ); // normal operation clearDisplay(); // all radios on same network (sync word) if (!LoRa.begin(433E6)) loraError(); LoRa.setSyncWord(NETID); LoRa.onReceive(onReceive); LoRa.receive(); #ifdef DF_INSTALLED if (!myDFPlayer.begin(Serial)) dfError(); //Serial.println("DFplayer ok"); #endif // initial display for (uint8_t i=1; i <= 8; i++) paintRandomDigit(i); // for (uint8_t i=1; i <= 8; i++) write7seg(i,i); } //-------------------------------------------- void loop() { //-- monitor radio switch (rx_status) { case 2: rx_status = 0; break; case 1: uint8_t vol = rx_command >> 4; vol = map(vol,0,15,1,29); uint8_t sel = rx_command & 7; // should be 0..6 rx_status = 0; #ifdef DF_INSTALLED myDFPlayer.stop(); myDFPlayer.volume(vol); //Set volume value. From 0 to 30 myDFPlayer.play(sel+1); //Play the mp3 (0001.mp3) #else Serial.print("Received "); Serial.println(rx_command,HEX); Serial.print("SEL "); Serial.print(sel); Serial.print(" VOL "); Serial.println(vol); #endif } //-- monitor buttons { static uint8_t index = 0; if (!digitalRead(BTN1_PIN)) { //Serial.print("PLAY "); Serial.println(index); #ifdef DF_INSTALLED myDFPlayer.stop(); myDFPlayer.play(index+1); //Play the mp3 (0001.mp3) #else Serial.print("MAN PLAY "); Serial.println(index); #endif index = (index+1) % NUM_MP3S; for (uint8_t i=250; i; i--) if (!digitalRead(BTN1_PIN)) i=250; } } if (!digitalRead(BTN2_PIN)) #ifdef DF_INSTALLED myDFPlayer.stop(); #else Serial.println("STOP"); #endif //-- random display { static uint32_t tm = millis(); if (millis() - tm > 222UL) { tm = millis(); paintRandomDigit( random(1,8+1) ); } } }