├── LED_flora_Mic_setup.jpeg └── 8x8_Mouth_Code.ino /LED_flora_Mic_setup.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lazrhog/Adafruit_Flora_Facemask_8x8_NeoPixel_Grid/HEAD/LED_flora_Mic_setup.jpeg -------------------------------------------------------------------------------- /8x8_Mouth_Code.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef __AVR__ 3 | #include 4 | #endif 5 | 6 | // Which pin on the Flora is connected to the NeoPixels? 7 | #define LED_PIN 6 // NeoPixels attached to pin 6 8 | #define MIC_PIN A9 // Microphone is attached to this analog pin 9 | #define DC_OFFSET 0 // DC offset in mic signal - leave 0 fo the moment 10 | #define NOISE 10 // Noise/hum/interference in mic signal 11 | 12 | #define MIN(a,b) (((a)<(b))?(a):(b)) 13 | #define MAX(a,b) (((a)>(b))?(a):(b)) 14 | 15 | // When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. 16 | Adafruit_NeoPixel pixels = Adafruit_NeoPixel(64, LED_PIN, NEO_GRB + NEO_KHZ800); 17 | 18 | // Arduino Setup function 19 | void setup() { 20 | analogReference(EXTERNAL); 21 | pixels.begin(); 22 | pixels.setBrightness(40); //To reduce power consumption 23 | Serial.begin(9600); 24 | } 25 | 26 | void clear() { 27 | for(int i=0;i<64;i++){ 28 | pixels.setPixelColor(i, pixels.Color(0,0,0)); 29 | } 30 | pixels.show(); 31 | } 32 | 33 | void setPixelForColor(int row, int col, uint32_t color) { 34 | if ((row % 2) == 1){ 35 | pixels.setPixelColor(row*8+(7-col), color); 36 | } else { 37 | pixels.setPixelColor(row*8+col, color); 38 | } 39 | } 40 | 41 | 42 | 43 | /* shape definitions for the mouth movements and the smile (smile comes last) 44 | 45 | when the arrays below are unfolded properly, the shapes look like these on the 8x8 grid ... 46 | 47 | B00000000 B00000000 B00000000 B00111100 B00000000 48 | B00000000 B00000000 B00111100 B01000010 B00000000 49 | B00000000 B01111110 B01000010 B10000001 B10000001 50 | B11111111 B10000001 B10000001 B10000001 B11000011 51 | B11111111 B10000001 B10000001 B10000001 B01111110 52 | B00000000 B01111110 B01000010 B10000001 B00111100 53 | B00000000 B00000000 B00111100 B01000010 B00000000 54 | B00000000 B00000000 B00000000 B00111100 B00000000 55 | 56 | */ 57 | 58 | byte mouth[][8] = {{B00000000,B00000000,B00000000,B11111111,B11111111,B00000000,B00000000,B00000000}, 59 | {B00000000,B00000000,B01111110,B10000001,B10000001,B01111110,B00000000,B00000000}, 60 | {B00000000,B00111100,B01000010,B10000001,B10000001,B01000010,B00111100,B00000000}, 61 | {B00111100,B01000010,B10000001,B10000001,B10000001,B10000001,B01000010,B00111100}, 62 | {B00000000,B00000000,B10000001,B11000011,B01111110,B00111100,B00000000,B00000000}}; 63 | 64 | // define a mask for fast bit detection 65 | byte mask[] = {1,2,4,8,16,32,64,128}; 66 | 67 | // function to draw an 8x8 shape 68 | void drawShape(byte shape[], uint32_t color) { 69 | for(int i=0;i<8;i++) { 70 | for(int j=0; j<8; j++) { 71 | if(shape[i] & mask[j]) { 72 | setPixelForColor(i, j, color); 73 | } 74 | else { 75 | setPixelForColor(i, j, 0); 76 | } 77 | } 78 | } 79 | pixels.show(); // This sends the updated pixel color to the hardware. 80 | } 81 | 82 | 83 | /* definitions */ 84 | #define POP_COUNT_THRESHOLD 30 85 | #define LOW_NOISE_START 150 86 | #define LOW_NOISE_DELAY_AFTER_POP 50 87 | #define SMILE_FOR_A_WHILE 750 88 | #define MAX_POWER_OFF_TIME 500 89 | 90 | // these thresholds will need to be tuned for how close the microphone will be 91 | #define VOL_THRESHOLD_1 25 92 | #define VOL_THRESHOLD_2 40 93 | #define VOL_THRESHOLD_3 60 94 | 95 | // global data declarations 96 | typedef enum {LOW_NOISE_B4_POP=0, COUNT_POP=1, LOW_NOISE_AFTER_POP=2} pop_state_type; // state machine state definitions 97 | int countLowNoise=0,countPop=0; // counters for the pop state machine 98 | int smileTimer=0; // timer for the smile when it appears 99 | pop_state_type popState=LOW_NOISE_B4_POP; // State machine handling 'pop' detection for the smile 100 | int lvl=0; // Current "dampened" audio level 101 | int powerConserveTimer=MAX_POWER_OFF_TIME; 102 | 103 | // State machine function that detects a pop, essentially a period of low noise, a small burst of noise, followed by low noise again 104 | bool handlePopStateChanges(int lvl) 105 | { 106 | // this boolean returns whether to activate the smile or not 107 | bool returnSmile=false; 108 | 109 | // check for state changes 110 | switch(popState) { 111 | case LOW_NOISE_B4_POP: 112 | // whilst in this state, count low noise 113 | if (lvl LOW_NOISE_START) & (lvl > VOL_THRESHOLD_1)) { 119 | popState=COUNT_POP; 120 | countPop=1; // had one count to start 121 | } 122 | 123 | // reset low noise count 124 | countLowNoise=0; 125 | } 126 | break; 127 | 128 | case COUNT_POP: 129 | // whilst in this state, increment pop counts 130 | if (lvl > VOL_THRESHOLD_1) { 131 | countPop++; 132 | } 133 | 134 | // change state to after pop counting, if 0>popCount1) & (countPopLOW_NOISE_DELAY_AFTER_POP) { 153 | returnSmile=true; 154 | countLowNoise=0; 155 | popState=LOW_NOISE_B4_POP; 156 | } 157 | } 158 | else { 159 | // back to start 160 | popState=LOW_NOISE_B4_POP; 161 | countLowNoise=0; 162 | } 163 | break; 164 | } 165 | return(returnSmile); 166 | } 167 | 168 | // Arduino Loop function 169 | void loop() { 170 | int rawMicIn; 171 | 172 | rawMicIn = analogRead(MIC_PIN); // Raw reading from mic 173 | rawMicIn = abs(rawMicIn - 512 - DC_OFFSET); // Center on zero 174 | rawMicIn = (rawMicIn <= NOISE) ? 0 : (rawMicIn - NOISE); // Remove noise/hum 175 | lvl = ((lvl * 7) + rawMicIn) >> 3; // simple dampening of mic input to prevent noise 176 | //Serial.println(lvl, DEC); 177 | 178 | // look for pop count state changes 179 | if (handlePopStateChanges(lvl)) smileTimer = SMILE_FOR_A_WHILE; 180 | 181 | // look for a pop to make a smile 182 | if (smileTimer > 0) { 183 | drawShape(mouth[4], pixels.Color(28,172,247)); 184 | smileTimer = MAX(0, smileTimer-1); 185 | } 186 | else { 187 | // only display a mouth if not conserving power 188 | if (powerConserveTimer > 0) { 189 | // otherwise process talking 190 | if (lvl VOL_THRESHOLD_1) { 221 | powerConserveTimer = MAX_POWER_OFF_TIME; 222 | } 223 | } 224 | } 225 | } 226 | --------------------------------------------------------------------------------