1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
| #include <Adafruit\_NeoPixel.h> #include <math.h>
#define N\_PIXELS 24 // WS2812像素个数 #define MIC\_PIN A0 // 麦克风采样引脚 #define LEFT\_STRIP\_PIN 3 // WS2812引脚 #define RIGHT\_STRIP\_PIN 4 // WS2812引脚 #define SAMPLE\_WINDOW 10 // 平均水平的样本窗口 #define PEAK\_HANG 15 // 峰点下降前暂停时间 #define PEAK\_FALL 6 // 峰点下降率 #define INPUT\_FLOOR 40 // 模拟读取输入的较低范围 建议 40 #define INPUT\_CEILING 400 // analogRead 输入最大量程,值越小越灵敏(1023 = max) 建议 400
byte peak = 20; // 列的峰值水平; 用于下降的点 unsigned int sample;
byte dotCount = 0; // 峰值点帧计数器 byte dotHangCount = 0; // 用于保持峰值点的帧计数器
Adafruit_NeoPixel leftStrip = Adafruit\_NeoPixel(N_PIXELS, LEFT_STRIP_PIN, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel rightStrip = Adafruit\_NeoPixel(N_PIXELS, RIGHT_STRIP_PIN, NEO_GRB + NEO_KHZ800);
volatile int state = LOW;
void setup() { // 初始化灯带 leftStrip.begin(); leftStrip.show();
rightStrip.begin(); rightStrip.show();
}
void loop() {
VUmeter(); }
void VUmeter(){ unsigned long startMillis= millis(); // 样本窗口开始 float peakToPeak = 0;
unsigned int signalMax = 0; unsigned int signalMin = 1023; unsigned int c, y; // 收集样本窗口长度的数据(以 mS 为单位) while (millis() - startMillis < SAMPLE_WINDOW) { sample = analogRead(MIC_PIN); if (sample < 1024) // 剔除虚假读数 { if (sample > signalMax) { signalMax = sample; // 保存最大值 } else if (sample < signalMin) { signalMin = sample; // 保存最小值 } } } peakToPeak = signalMax - signalMin; // max - min = peak-peak 振幅
//用彩虹渐变填充 for (int i=0;i<=rightStrip.numPixels()-1;i++){ leftStrip.setPixelColor(i,Wheel(map(i,0,leftStrip.numPixels()-1,10,200))); rightStrip.setPixelColor(i,Wheel(map(i,0,rightStrip.numPixels()-1,10,200))); }
//以对数方式而不是线性方式缩放输入 c = fscale(INPUT_FLOOR, INPUT_CEILING, leftStrip.numPixels(), 0, peakToPeak, 2); if(c < peak) { peak = c; // 保持点在顶部 dotHangCount = 0; // 让点在落下之前挂起 } if (c <= leftStrip.numPixels()) { // 用关闭像素填充部分列 drawLine(leftStrip.numPixels(), leftStrip.numPixels()-c, leftStrip.Color(0, 0, 0)); }
//设置峰值点以匹配彩虹渐变 y = leftStrip.numPixels() - peak; leftStrip.setPixelColor(y-1,Wheel(map(y,0,leftStrip.numPixels()-1,10,200))); rightStrip.setPixelColor(y-1,Wheel(map(y,0,rightStrip.numPixels()-1,10,200)));
leftStrip.show(); rightStrip.show(); // 基于帧的峰点动画 if(dotHangCount > PEAK_HANG) { //峰值停顿长度 if(++dotCount >= PEAK_FALL) { //跌落率 peak++; dotCount = 0; } } else { dotHangCount++; } }
//用于在给定颜色的两点之间画一条线 void drawLine(uint8\_t from, uint8\_t to, uint32\_t c) { uint8\_t fromTemp; if (from > to) { fromTemp = from; from = to; to = fromTemp; } for(int i=from; i<=to; i++){ leftStrip.setPixelColor(i, c); rightStrip.setPixelColor(i, c); } }
// 缩放输入值 float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve){
float OriginalRange = 0; float NewRange = 0; float zeroRefCurVal = 0; float normalizedCurVal = 0; float rangedValue = 0; boolean invFlag = 0;
// 条件曲线参数限制范围
if (curve > 10) curve = 10; if (curve < -10) curve = -10; // 反转和缩放 - 正数对输出的高端给予更多权重 curve = (curve \* -.1) ; curve = pow(10, curve); // 将线性刻度转换为其他 pow 函数的对数指数
// 检查范围 if (inputValue < originalMin) { inputValue = originalMin; } if (inputValue > originalMax) { inputValue = originalMax; }
OriginalRange = originalMax - originalMin;
if (newEnd > newBegin){ NewRange = newEnd - newBegin; } else { NewRange = newBegin - newEnd; invFlag = 1; }
zeroRefCurVal = inputValue - originalMin; normalizedCurVal = zeroRefCurVal / OriginalRange; // 归一化
if (originalMin > originalMax ) { return 0; }
if (invFlag == 0){ rangedValue = (pow(normalizedCurVal, curve) \* NewRange) + newBegin;
} else // 反转范围 { rangedValue = newBegin - (pow(normalizedCurVal, curve) \* NewRange); }
return rangedValue; } // 转换颜色 uint32\_t Wheel(byte WheelPos) { if(WheelPos < 85) { return leftStrip.Color(WheelPos \* 3, 255 - WheelPos \* 3, 0); } else if(WheelPos < 170) { WheelPos -= 85; return leftStrip.Color(255 - WheelPos \* 3, 0, WheelPos \* 3); } else { WheelPos -= 170; return leftStrip.Color(0, WheelPos \* 3, 255 - WheelPos \* 3); } }
|