驴友花雕
发表于 2021-9-11 07:58:59
本帖最后由 驴友花雕 于 2021-9-11 12:47 编辑
实验场景图动态图
驴友花雕
发表于 2021-9-11 08:41:45
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十二:不断变换的符号图形
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十二:不断变换的符号图形
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include "Grove_LED_Matrix_Driver_HT16K33.h"
Matrix_8x8 matrix;
void setup() {
Wire.begin();
matrix.init();
matrix.setBrightness(0);
matrix.setBlinkRate(BLINK_OFF);
}
void loop() {
for (int i = 0; i < 29; i++) {
// The input range of writeIcon is
matrix.writeIcon(i);
matrix.display();
delay(200);
}
}
驴友花雕
发表于 2021-9-11 08:51:16
实验场景图动态图
驴友花雕
发表于 2021-9-11 09:04:24
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十三:流动的字母"abc","efg"
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十三:流动的字母"abc","efg"
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include "Grove_LED_Matrix_Driver_HT16K33.h"
Matrix_8x8 matrix;
void setup() {
Wire.begin();
matrix.init();
matrix.setBrightness(0);
matrix.setBlinkRate(BLINK_OFF);
}
void loop() {
matrix.writeString("!", 500, ACTION_SHIFT);
matrix.display();
matrix.writeString("abc", 500, ACTION_SHIFT);
matrix.display();
matrix.writeString("efg", 500, ACTION_SCROLLING);
matrix.display();
}
驴友花雕
发表于 2021-9-11 09:09:16
实验场景图动态图
驴友花雕
发表于 2021-9-11 09:15:52
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十四:不断落下的音乐符
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十四:不断落下的音乐符
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include "Grove_LED_Matrix_Driver_HT16K33.h"
Matrix_8x8 matrix;
int temp = -8;
uint8_t orientation = DISPLAY_ROTATE_0;
void setup() {
Wire.begin();
matrix.init();
matrix.setBrightness(0);
matrix.setBlinkRate(BLINK_OFF);
matrix.writeIcon(21);
}
void loop() {
matrix.display();
delay(100);
// Activate after call display()
matrix.setDisplayOffset(temp, temp);
temp++;
if (temp == 9) {
temp = -8;
orientation = orientation + 1;
if (orientation == 4) {
orientation = DISPLAY_ROTATE_0;
}
// Activate after call writeXXX
matrix.setDisplayOrientation(orientation);
matrix.writeIcon(21);
}
}
驴友花雕
发表于 2021-9-11 09:20:31
实验场景图动态图
驴友花雕
发表于 2021-9-11 09:51:08
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十五:不同方向的滚动字符串
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十五:不同方向的滚动字符串
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
void setup() {
Serial.begin(9600);
Serial.println("8x8 LED Matrix Test");
matrix.begin(0x70);// pass in the address
}
static const uint8_t PROGMEM
smile_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10100101,
B10011001,
B01000010,
B00111100
},
neutral_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10111101,
B10000001,
B01000010,
B00111100
},
frown_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10011001,
B10100101,
B01000010,
B00111100
};
void loop() {
matrix.clear();
matrix.drawBitmap(1, 0, smile_bmp, 8, 8, LED_ON);
matrix.writeDisplay();
delay(500);
matrix.clear();
matrix.drawBitmap(1, 0, neutral_bmp, 8, 8, LED_ON);
matrix.writeDisplay();
delay(200);
matrix.clear();
matrix.drawBitmap(1, 0, frown_bmp, 8, 8, LED_ON);
matrix.writeDisplay();
delay(200);
matrix.clear(); // clear display
matrix.drawPixel(1, 0, LED_ON);
matrix.writeDisplay();// write the changes we just made to the display
delay(200);
matrix.clear();
matrix.drawLine(1, 0, 7, 7, LED_ON);
matrix.writeDisplay();// write the changes we just made to the display
delay(200);
matrix.clear();
matrix.drawRect(1, 0, 8, 8, LED_ON);
matrix.fillRect(2, 2, 4, 4, LED_ON);
matrix.writeDisplay();// write the changes we just made to the display
delay(200);
matrix.clear();
matrix.drawCircle(3, 3, 3, LED_ON);
matrix.writeDisplay();// write the changes we just made to the display
delay(200);
matrix.setTextSize(1);
matrix.setTextWrap(false);// we dont want text to wrap so it scrolls nicely
matrix.setTextColor(LED_ON);
for (int8_t x = 0; x >= -36; x--) {
matrix.clear();
matrix.setCursor(x, 0);
matrix.print("Hello");
matrix.writeDisplay();
delay(50);
}
matrix.setRotation(3);
for (int8_t x = 7; x >= -36; x--) {
matrix.clear();
matrix.setCursor(x, 0);
matrix.print("World");
matrix.writeDisplay();
delay(50);
}
matrix.setRotation(0);
}
驴友花雕
发表于 2021-9-11 09:57:26
实验场景图动态图
驴友花雕
发表于 2021-9-11 10:14:15
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十六:滚动的一串数字
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十六:滚动的一串数字
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include "Grove_LED_Matrix_Driver_HT16K33.h"
Matrix_8x8 matrix;
void setup() {
Wire.begin();
matrix.init();
matrix.setBrightness(0);
matrix.setBlinkRate(BLINK_OFF);
}
void loop() {
// 显示数字“0”并延迟 400ns
matrix.writeNumber(0, 400);
matrix.display();
// 显示数字 "-2147483648" 并延迟 (300*11)ns
// writeNumber()的显示范围是int32_t(从-2147483648到2147483647)
matrix.writeNumber(-2147483648, 300);
matrix.display();
}
驴友花雕
发表于 2021-9-11 10:17:03
实验场景图动态图
驴友花雕
发表于 2021-9-11 10:34:25
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十七:变换的笑脸与流淌的字符"Hello","World"
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十七:变换的笑脸与流淌的字符"Hello","World"
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();
void setup() {
Serial.begin(9600);
Serial.println("8x8 LED Matrix Test");
matrix.begin(0x70);// pass in the address
}
static const uint8_t PROGMEM
smile_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10100101,
B10011001,
B01000010,
B00111100
},
neutral_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10111101,
B10000001,
B01000010,
B00111100
},
frown_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10011001,
B10100101,
B01000010,
B00111100
};
void loop() {
matrix.clear();
matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_GREEN);
matrix.writeDisplay();
delay(500);
matrix.clear();
matrix.drawBitmap(0, 0, neutral_bmp, 8, 8, LED_GREEN);
matrix.writeDisplay();
delay(500);
matrix.clear();
matrix.drawBitmap(0, 0, frown_bmp, 8, 8, LED_GREEN);
matrix.writeDisplay();
delay(500);
matrix.clear(); // clear display
matrix.drawPixel(0, 0, LED_GREEN);
matrix.writeDisplay();// write the changes we just made to the display
delay(500);
matrix.clear();
matrix.drawLine(0, 0, 7, 7, LED_GREEN);
matrix.writeDisplay();// write the changes we just made to the display
delay(500);
matrix.clear();
matrix.drawRect(0, 0, 8, 8, LED_GREEN);
matrix.fillRect(2, 2, 4, 4, LED_GREEN);
matrix.writeDisplay();// write the changes we just made to the display
delay(500);
matrix.clear();
matrix.drawCircle(3, 3, 3, LED_GREEN);
matrix.writeDisplay();// write the changes we just made to the display
delay(500);
matrix.setTextWrap(false);// we dont want text to wrap so it scrolls nicely
matrix.setTextSize(1);
matrix.setTextColor(LED_GREEN);
for (int8_t x = 7; x >= -36; x--) {
matrix.clear();
matrix.setCursor(x, 0);
matrix.print("Hello");
matrix.writeDisplay();
delay(50);
}
matrix.setRotation(3);
matrix.setTextColor(LED_GREEN);
for (int8_t x = 7; x >= -36; x--) {
matrix.clear();
matrix.setCursor(x, 0);
matrix.print("World");
matrix.writeDisplay();
delay(50);
}
matrix.setRotation(0);
}
驴友花雕
发表于 2021-9-11 11:01:48
实验场景图动态图
驴友花雕
发表于 2021-9-11 11:07:26
实验场景图动态图之二
驴友花雕
发表于 2021-9-11 11:13:15
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十八:随机的眨眼睛
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十八:随机的眨眼睛
实验接线:
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <WaveHC.h>
#include <WaveUtil.h>
#include "Adafruit_LEDBackpack.h"
// These WAV files should be in the root level of the SD card:
static const char PROGMEM
wav0[] = "beware_i.wav",
wav1[] = "ihunger.wav",
wav2[] = "run_cowd.wav";
static const char * const wavname[] PROGMEM = { wav0, wav1, wav2 };
// PROGMEM makes frequent appearances throughout this code, reason being that
// the SD card library requires gobs of precious RAM (leaving very little to
// our own sketch).PROGMEM lets us put fixed data into program flash memory,
// which is considerably more spacious.String tables are paritcularly nasty.
// See www.arduino.cc/en/Reference/PROGMEM for more info.
SdReadercard; // This object holds the information for the card
FatVolume vol;// This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file for a phrase
WaveHC wave; // A single wave object -- only one sound is played at a time
// Because the two eye matrices share the same address, only four
// matrix objects are needed for the five displays:
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT3
Adafruit_8x8matrix matrix = { // Array of Adafruit_8x8matrix objects
Adafruit_8x8matrix(), Adafruit_8x8matrix(),
Adafruit_8x8matrix(), Adafruit_8x8matrix() };
// Rather than assigning matrix addresses sequentially in a loop, each
// has a spot in this array.This makes it easier if you inadvertently
// install one or more matrices in the wrong physical position --
// re-order the addresses in this table and you can still refer to
// matrices by index above, no other code or wiring needs to change.
static const uint8_t PROGMEM matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 };
static const uint8_t PROGMEM // Bitmaps are stored in program memory
blinkImg[] = { // Eye animation frames
{ B00111100, // Fully open eye
B01111110,
B11111111,
B11111111,
B11111111,
B11111111,
B01111110,
B00111100 },
{ B00000000,
B01111110,
B11111111,
B11111111,
B11111111,
B11111111,
B01111110,
B00111100 },
{ B00000000,
B00000000,
B00111100,
B11111111,
B11111111,
B11111111,
B00111100,
B00000000 },
{ B00000000,
B00000000,
B00000000,
B00111100,
B11111111,
B01111110,
B00011000,
B00000000 },
{ B00000000, // Fully closed eye
B00000000,
B00000000,
B00000000,
B10000001,
B01111110,
B00000000,
B00000000 } },
mouthImg[] = { // Mouth animation frames
{ B00000000, B00000000, B00000000, // Mouth position A
B00000000, B00000000, B00000000,
B01111111, B11111111, B11111110,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position B
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00000111, B00000000, B11100000,
B00000000, B11111111, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position C
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00001000, B00000000, B00010000,
B00000110, B00000000, B01100000,
B00000001, B11000011, B10000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position D
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00100000, B00000000, B00000100,
B00010000, B00000000, B00001000,
B00001100, B00000000, B00110000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position E
B00000000, B00111100, B00000000,
B00011111, B11000011, B11111000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00111100, B00000000, // Mouth position F
B00000000, B11000011, B00000000,
B00001111, B00000000, B11110000,
B00000001, B00000000, B10000000,
B00000000, B11000011, B00000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 } };
// Animation sequences corresponding to each WAV.First number in
// each pair is a mouth bitmap index.Second number is the hold
// time (in frames).255 marks end of list.
// There is no 'magic' here, the software is NOT deriving mouth
// position from the sound...the tables were determined by hand,
// just as animators do it.Further explanation here:
// http://www.idleworm.com/how/anm/03t/talk1.shtml
static const uint8_t PROGMEM
seq1[] = { 0, 2, 2, 5, 5, 3, 3, 7, // "Beware, I live!"
4, 5, 3, 4, 2, 5, 4, 3,
3, 4, 1, 5, 3, 5, 255 },
seq2[] = { 0, 1, 3, 5, 1, 5, 4, 2, // "I hunger!"
3, 2, 1, 2, 4, 4, 1, 3,
4, 2, 255 },
seq3[] = { 0, 1, 1, 2, 3, 6, 2, 5, // "Run, coward!"
0, 1, 4, 4, 5, 2, 1, 5,
3, 6, 1, 4, 255 };
static const uint8_t * const anim[] = { seq1, seq2, seq3 };
const uint8_t
blinkIndex[] PROGMEM = { 1, 2, 3, 4, 3, 2, 1 }; // Blink bitmap sequence
uint8_t
blinkCountdown = 100, // Countdown to next blink (in frames)
gazeCountdown=75, // Countdown to next eye movement
gazeFrames =50, // Duration of eye movement (smaller = faster)
mouthPos = 0, // Current image number for mouth
mouthCountdown =10, // Countdown to next mouth change
newPos = 255, // New mouth position for current frame
*seq, // Animation sequence currently being played back
idx, // Current array index within animation sequence
prevBtn = 99,// Button # pressed on last loop() iteration
btnCount = 0; // Number of iterations same button has been held
int8_t
eyeX = 3, eyeY = 3, // Current eye position
newX = 3, newY = 3, // Next eye position
dX = 0, dY = 0; // Distance from prior to new position
void setup() {
Serial.begin(9600);
Serial.println(F("WAV face"));
if(!card.init()) Serial.println(F("Card init. failed!"));
if(!vol.init(card)) Serial.println(F("No partition!"));
if(!root.openRoot(vol)) Serial.println(F("Couldn't open dir"));
Serial.println(F("Files found:"));
root.ls();
// Seed random number generator from an unused analog input:
randomSeed(analogRead(A0));
// Initialize each matrix object:
for(uint8_t i=0; i<4; i++) {
matrix.begin(pgm_read_byte(&matrixAddr));
// If using 'small' (1.2") displays vs. 'mini' (0.8"), enable this:
// matrix.setRotation(3);
}
// Enable pull-up resistors on three button inputs.
// Other end of each button then connects to GND.
for(uint8_t i=6; i<=8; i++) {
pinMode(i, INPUT);
digitalWrite(i, HIGH); // Enable pullup
}
}
void loop() {
uint8_t i;
// Draw eyeball in current state of blinkyness (no pupil).
matrix.clear();
matrix.drawBitmap(0, 0,
blinkImg[
(blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking?
pgm_read_byte(&blinkIndex) : // Yes, look up bitmap #
0 // No, show bitmap 0
], 8, 8, LED_ON);
// Decrement blink counter.At end, set random time for next blink.
if(--blinkCountdown == 0) blinkCountdown = random(5, 180);
if(--gazeCountdown <= gazeFrames) {
// Eyes are in motion - draw pupil at interim position
matrix.fillRect(
newX - (dX * gazeCountdown / gazeFrames),
newY - (dY * gazeCountdown / gazeFrames),
2, 2, LED_OFF);
if(gazeCountdown == 0) { // Last frame?
eyeX = newX; eyeY = newY; // Yes.What's new is old, then...
do { // Pick random positions until one is within the eye circle
newX = random(7); newY = random(7);
dX = newX - 3;dY = newY - 3;
} while((dX * dX + dY * dY) >= 10); // Thank you Pythagoras
dX = newX - eyeX; // Horizontal distance to move
dY = newY - eyeY; // Vertical distance to move
gazeFrames = random(3, 15); // Duration of eye movement
gazeCountdown = random(gazeFrames, 120); // Count to end of next movement
}
} else {
// Not in motion yet -- draw pupil at current static position
matrix.fillRect(eyeX, eyeY, 2, 2, LED_OFF);
}
// Scan buttons 6, 7, 8 looking for first button pressed...
for(i=0; (i<3) && (digitalRead(i+6) == HIGH); i++);
if(i < 3) { // Anything pressed?Yes!
if(i == prevBtn) { // Same as last time we checked?Good!
if(++btnCount == 3) { // 3 passes to 'debounce' button input
playfile((char *)pgm_read_word(&wavname)); // Start WAV
// Look up animation sequence # corresponding to this WAV...
seq = (uint8_t *)pgm_read_word(&anim);
idx = 0; // Begin at first byte of data
newPos = pgm_read_byte(&seq); // Initial mouth pos
mouthCountdown = pgm_read_byte(&seq); // Hold time for pos
}
} else btnCount = 0; // Different button than before - start count over
prevBtn = i;
} else prevBtn = 99; // No buttons pressed
if(newPos != 255) { // Is the mouth in motion?
if(--mouthCountdown == 0) { // Count down frames to next position
newPos = pgm_read_byte(&seq); // New mouth position
if(newPos == 255) { // End of list?
mouthPos = 0; // Yes, set mouth to neutral position
} else {
mouthPos = newPos; // Set mouth to new position
mouthCountdown = pgm_read_byte(&seq); // Read hold time
}
}
} else mouthPos = 0; // Mouth not in motion -- set to neutral position
drawMouth(mouthImg);
// Refresh all matrices in one quick pass
for(uint8_t i=0; i<4; i++) matrix.writeDisplay();
delay(20);
}
// Draw mouth image across three adjacent displays
void drawMouth(const uint8_t *img) {
for(uint8_t i=0; i<3; i++) {
matrix.clear();
matrix.drawBitmap(i * -8, 0, img, 24, 8, LED_ON);
}
}
// Open and start playing a WAV file
void playfile(const char *name) {
char filename; // 8.3+NUL
if(wave.isplaying) wave.stop(); // Stop any currently-playing WAV
strcpy_P(filename, name); // Copy name out of PROGMEM into RAM
if(!file.open(root, filename)) {
Serial.print(F("Couldn't open file "));
Serial.println(filename);
return;
}
if(!wave.create(file)) {
Serial.println(F("Not a valid WAV"));
return;
}
wave.play();
}
驴友花雕
发表于 2021-9-11 11:26:36
实验场景图动态图
驴友花雕
发表于 2021-9-11 16:18:30
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十九:Arduino 的小型音频可视化
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十九:Arduino 的小型音频可视化
模块接线:
- 3.3V 至麦克风放大器 + 和 Arduino AREF 引脚 <-- 重要!
MAX9814Arduino
VCC 3.3V
GND GND
OUT A0
VK16k33 UNO
VIN 5V
GND GND
SCL A5
SDA A4
*/
// 重要提示:FFT_N 应该在 ffft.h 中 #defined 为 128。
#include <avr/pgmspace.h>
#include <ffft.h>
#include <math.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
// Microphone connects to Analog Pin 0.Corresponding ADC channel number
// varies among boards...it's ADC0 on Uno and Mega, ADC7 on Leonardo.
// Other boards may require different settings; refer to datasheet.
#ifdef __AVR_ATmega32U4__
#define ADC_CHANNEL 7
#else
#define ADC_CHANNEL 0
#endif
int16_t capture; // Audio capture buffer
complex_t bfly_buff;// FFT "butterfly" buffer
uint16_t spectrum; // Spectrum output buffer
volatile byte samplePos = 0; // Buffer position counter
byte
peak, // Peak level of each column; used for falling dots
dotCount = 0, // Frame counter for delaying dot-falling speed
colCount = 0; // Frame counter for storing past column data
int
col, // Column levels for the prior 10 frames
minLvlAvg, // For dynamic adjustment of low & high ends of graph,
maxLvlAvg, // pseudo rolling averages for the prior few frames.
colDiv; // Used when filtering FFT output to 8 columns
/*
These tables were arrived at through testing, modeling and trial and error,
exposing the unit to assorted music and sounds.But there's no One Perfect
EQ Setting to Rule Them All, and the graph may respond better to some
inputs than others.The software works at making the graph interesting,
but some columns will always be less lively than others, especially
comparing live speech against ambient music of varying genres.
*/
static const uint8_t PROGMEM
// This is low-level noise that's subtracted from each FFT output column:
noise = { 8, 6, 6, 5, 3, 4, 4, 4, 3, 4, 4, 3, 2, 3, 3, 4,
2, 1, 2, 1, 3, 2, 3, 2, 1, 2, 3, 1, 2, 3, 4, 4,
3, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4
},
// These are scaling quotients for each FFT output column, sort of a
// graphic EQ in reverse.Most music is pretty heavy at the bass end.
eq = {
255, 175, 218, 225, 220, 198, 147, 99, 68, 47, 33, 22, 14,8,4,2,
0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
},
// When filtering down to 8 columns, these tables contain indexes
// and weightings of the FFT spectrum output values to use.Not all
// buckets are used -- the bottom-most and several at the top are
// either noisy or out of range or generally not good for a graph.
col0data[] = {2,1,// # of spectrum bins to merge, index of first
111, 8
}, // Weights for each bin
col1data[] = {4,1,// 4 bins, starting at index 1
19, 186,38, 2
}, // Weights for 4 bins.Got it now?
col2data[] = {5,2,
11, 156, 118,16, 1
},
col3data[] = {8,3,
5,55, 165, 164,71,18, 4, 1
},
col4data[] = { 11,5,
3,24,89, 169, 178, 118,54,20, 6, 2, 1
},
col5data[] = { 17,7,
2, 9,29,70, 125, 172, 185, 162, 118, 74,
41,21,10, 5, 2, 1, 1
},
col6data[] = { 25, 11,
1, 4,11,25,49,83, 121, 156, 180, 185,
174, 149, 118,87,60,40,25,16,10, 6,
4, 2, 1, 1, 1
},
col7data[] = { 37, 16,
1, 2, 5,10,18,30,46,67,92, 118,
143, 164, 179, 185, 184, 174, 158, 139, 118,97,
77,60,45,34,25,18,13, 9, 7, 5,
3, 2, 2, 1, 1, 1, 1
},
// And then this points to the start of the data for each of the columns:
* const colData[]= {
col0data, col1data, col2data, col3data,
col4data, col5data, col6data, col7data
};
Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();
void setup() {
uint8_t i, j, nBins, binNum, *data;
memset(peak, 0, sizeof(peak));
memset(col , 0, sizeof(col));
for (i = 0; i < 8; i++) {
minLvlAvg = 0;
maxLvlAvg = 512;
data = (uint8_t *)pgm_read_word(&colData);
nBins = pgm_read_byte(&data) + 2;
binNum = pgm_read_byte(&data);
for (colDiv = 0, j = 2; j < nBins; j++)
colDiv += pgm_read_byte(&data);
}
matrix.begin(0x70);
// Init ADC free-run mode; f = ( 16MHz/prescaler ) / 13 cycles/conversion
ADMUX= ADC_CHANNEL; // Channel sel, right-adj, use AREF pin
ADCSRA = _BV(ADEN)| // ADC enable
_BV(ADSC)| // ADC start
_BV(ADATE) | // Auto trigger
_BV(ADIE)| // Interrupt enable
_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz
ADCSRB = 0; // Free run mode, no high MUX bit
DIDR0= 1 << ADC_CHANNEL; // Turn off digital input for ADC pin
TIMSK0 = 0; // Timer0 off
sei(); // Enable interrupts
}
void loop() {
uint8_ti, x, L, *data, nBins, binNum, weighting, c;
uint16_t minLvl, maxLvl;
int level, y, sum;
while (ADCSRA & _BV(ADIE)); // Wait for audio sampling to finish
fft_input(capture, bfly_buff); // Samples -> complex #s
samplePos = 0; // Reset sample counter
ADCSRA |= _BV(ADIE); // Resume sampling interrupt
fft_execute(bfly_buff); // Process complex data
fft_output(bfly_buff, spectrum); // Complex -> spectrum
// Remove noise and apply EQ levels
for (x = 0; x < FFT_N / 2; x++) {
L = pgm_read_byte(&noise);
spectrum = (spectrum <= L) ? 0 :
(((spectrum - L) * (256L - pgm_read_byte(&eq))) >> 8);
}
// Fill background w/colors, then idle parts of columns will erase
matrix.fillRect(0, 0, 8, 3, LED_RED); // Upper section
matrix.fillRect(0, 3, 8, 2, LED_YELLOW); // Mid
matrix.fillRect(0, 5, 8, 3, LED_GREEN);// Lower section
// Downsample spectrum output to 8 columns:
for (x = 0; x < 8; x++) {
data = (uint8_t *)pgm_read_word(&colData);
nBins= pgm_read_byte(&data) + 2;
binNum = pgm_read_byte(&data);
for (sum = 0, i = 2; i < nBins; i++)
sum += spectrum * pgm_read_byte(&data); // Weighted
col = sum / colDiv; // Average
minLvl = maxLvl = col;
for (i = 1; i < 10; i++) { // Get range of prior 10 frames
if (col < minLvl) minLvl = col;
else if (col > maxLvl) maxLvl = col;
}
// minLvl and maxLvl indicate the extents of the FFT output, used
// for vertically scaling the output graph (so it looks interesting
// regardless of volume level).If they're too close together though
// (e.g. at very low volume levels) the graph becomes super coarse
// and 'jumpy'...so keep some minimum distance between them (this
// also lets the graph go to zero when no sound is playing):
if ((maxLvl - minLvl) < 8) maxLvl = minLvl + 8;
minLvlAvg = (minLvlAvg * 7 + minLvl) >> 3; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 7 + maxLvl) >> 3; // (fake rolling average)
// Second fixed-point scale based on dynamic min/max levels:
level = 10L * (col - minLvlAvg) /
(long)(maxLvlAvg - minLvlAvg);
// Clip output and convert to byte:
if (level < 0L) c = 0;
else if (level > 10) c = 10; // Allow dot to go a couple pixels off top
else c = (uint8_t)level;
if (c > peak) peak = c; // Keep dot on top
if (peak <= 0) { // Empty column?
matrix.drawLine(x, 0, x, 7, LED_OFF);
continue;
} else if (c < 8) { // Partial column?
matrix.drawLine(x, 0, x, 7 - c, LED_OFF);
}
// The 'peak' dot color varies, but doesn't necessarily match
// the three screen regions...yellow has a little extra influence.
y = 8 - peak;
if (y < 2) matrix.drawPixel(x, y, LED_RED);
else if (y < 6) matrix.drawPixel(x, y, LED_YELLOW);
else matrix.drawPixel(x, y, LED_GREEN);
}
matrix.writeDisplay();
// Every third frame, make the peak pixels drop by 1:
if (++dotCount >= 3) {
dotCount = 0;
for (x = 0; x < 8; x++) {
if (peak > 0) peak--;
}
}
if (++colCount >= 10) colCount = 0;
}
ISR(ADC_vect) { // Audio-sampling interrupt
static const int16_t noiseThreshold = 4;
int16_t sample = ADC; // 0-1023
capture =
((sample > (512 - noiseThreshold)) &&
(sample < (512 + noiseThreshold))) ? 0 :
sample - 512; // Sign-convert for FFT; -512 to +511
if (++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE); // Buffer full, interrupt off
}
驴友花雕
发表于 2021-9-11 16:22:15
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目十九:Arduino 的小型音频可视化(视频49秒)
https://v.youku.com/v_show/id_XNTgwNTE5NTU0OA==.html?spm=a2hcb.playlsit.page.1
https://v.youku.com/v_show/id_XNTgwNTE5NTU0OA==.html?spm=a2hcb.playlsit.page.1
驴友花雕
发表于 2021-9-11 16:33:19
实验场景图动态图
驴友花雕
发表于 2021-9-14 08:37:52
实验接线示意图