驴友花雕 发表于 2021-9-9 08:05:42

【Arduino】168种传感器系列实验(207)--- HT16k33 LED8*8点阵I2C

本帖最后由 驴友花雕 于 2021-9-14 08:40 编辑

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手试试多做实验,不管成功与否,都会记录下来——小小的进步或是搞不掂的问题,希望能够抛砖引玉。

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块HT16k33(VK16K33)驱动1088BS树莓派物联网可扩展编程








驴友花雕 发表于 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 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-10 10:51:02

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之八:右向流动显示“SOS Call 9-1-1”

实验开源代码

/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之八:右向流动显示“SOS Call 9-1-1”
实验接线:
VK16k33    UNO
VIN      5V
GND      GND
SCL      A5
SDA      A4
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"   //necessary

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void setup() {
   
matrix.begin(0x70);// pass in the address
}

static const uint8_t PROGMEM    // Setting Static Constants for the LED Matrix
S_bmp[] =                  // Declaring the "S" Shape Bitmap for the Matrix
{ B01111111,                // String of characters dictates each LED position as on or off on 8x8 gird
    B01111111,               // 0 = Off LED 1 = On LED
    B01100000,
    B01111110,
    B01111110,
    B00000110,
    B11111110,
    B11111110 },
   
O_bmp[] =               // Declaring the "O" Shape Bitmap for the Matrix
{ B11111111,
    B11111111,
    B11000011,
    B11000011,
    B11000011,
    B11000011,
    B11111111,
    B11111111 },
   
S2_bmp[] =          // Declaring the second "S" Shape Bitmap for the Matrix

{ B01111111,
    B01111111,
    B01110000,
    B01111110,
    B01111110,
    B00000110,
    B11111110,
    B11111110 };

void loop() {
matrix.clear();                                     // Starting with clear matrix where all LEDs are off
matrix.drawBitmap(1, 0, S_bmp, 8, 8, LED_ON);      // Drawing the "S" Bitmap according to void setup configuration
matrix.writeDisplay();                            // With 2000 milisecond delay
delay(2000);

matrix.clear();                                    // Transitioning with clear matrix where all LEDs are off
matrix.drawBitmap(1, 0, O_bmp, 7, 8, LED_ON);   // Drawing the "O" Bitmap according to void setup configuration
matrix.writeDisplay();                           // With 2000 milisecond delay
delay(2000);

matrix.clear();                                    // Transitioning with clear matrix where all LEDs are off
matrix.drawBitmap(1, 0, S2_bmp, 7, 8, LED_ON);    // Drawing the second "S" Bitmap according to void setup configuration
matrix.writeDisplay();                           // With 2000 milisecond delay
delay(2000);


matrix.setTextSize(1);                        // Setting matrix text size to 1
matrix.setTextWrap(false);                     // Preventing text wrapping to scroll text continuously through matrix
matrix.setTextColor(LED_ON);                  // Turning LED On
for (int8_t x=0; x>=-36; x--) {            // Setting for loop to position letters side by side for the scroll
    matrix.clear();                           // Transitioning with clear matrix where all LEDs are off
    matrix.setCursor(x,0);                   // Defining letter positions to print one at time side by side
    matrix.print(" Call");                   // Printing "Call" on the matrix
    matrix.writeDisplay();               // With 100 milisecond delay
    delay(100);
}
matrix.setRotation(0);                  // Prevent rotation and keep scroll at the same angle
for (int8_t x=7; x>=-36; x--) {      // Setting new for loop to position letters side by side for the scroll
    matrix.clear();                     // Transitioning with clear matrix where all LEDs are off
    matrix.setCursor(x,0);             // Defining letter positions to print one at time side by side
    matrix.print("9-1-1");            // Printing "9-1-1" on the matrix
    matrix.writeDisplay();         // With 100 milisecond delay
    delay(100);
}
}

驴友花雕 发表于 2021-9-9 10:02:48

Arduino 系列传感器和执行器模块实验目录清单:
一块扩展板完成Arduino的10类37项实验(代码+图形+仿真)
https://mc.dfrobot.com.cn/thread-280845-1-1.html
连杆形式的腿机构十一种:盘点机器人行走背后的机械原理
https://mc.dfrobot.com.cn/thread-308097-1-1.html
【花雕动手做】超低成本,尝试五十元的麦克纳姆轮小车!
https://mc.dfrobot.com.cn/thread-307863-1-1.html
【花雕动手做】超迷你哦,用徽商香烟盒做个智能小车!
https://mc.dfrobot.com.cn/thread-307907-1-1.html
【花雕动手做】太搞笑啦,一支胶管制成二只蠕动机器人
https://mc.dfrobot.com.cn/thread-308046-1-1.html
【花雕动手做】快餐盒盖,极低成本搭建机器人实验平台
https://mc.dfrobot.com.cn/thread-308063-1-1.html
【花雕动手做】特别苗条,使用微波传感器控制的纤细小车
https://mc.dfrobot.com.cn/thread-308866-1-1.html
【花雕动手做】脑洞大开、五花八门的简易机器人66种
https://mc.dfrobot.com.cn/thread-307900-1-1.html

实验一百五十八:QMC5883L电子指南针罗盘模块 三轴磁场传感器GY-271
https://mc.dfrobot.com.cn/thread-308195-1-1.html
实验一百六十三:BMI160 6轴惯性运动传感器 16位3轴加速度+超低功耗3轴陀螺仪I2C/SPI 14LGA
https://mc.dfrobot.com.cn/thread-310371-1-1.html
实验一百六十五:2.4 英寸 TFT LCD 触摸屏模块 XPT2046 PCB ILI9341 240x320 像素 8 位 SPI 串口显示器 300mA
https://mc.dfrobot.com.cn/thread-309803-1-1.html
实验一百七十六:6mm大尺寸8x8LED方块方格点阵模块 可级联 红绿蓝白色 可选8级亮度
https://mc.dfrobot.com.cn/thread-309845-1-1.html
实验一百八十三:GY-530 VL53L0X 激光测距 ToF测距 飞行时间测距传感器模块 IIC通信协议
https://mc.dfrobot.com.cn/thread-310273-1-1.html
实验一百八十五:MAX4466声音传感器 驻极体话筒放大器 麦克风可调功放模块 microphone
https://mc.dfrobot.com.cn/thread-310193-1-1.html
实验一百八十九:TDA1308 硅麦克风 数字咪头放大模块 拾音器放大板 楼氏SUNLEPHANT
https://mc.dfrobot.com.cn/thread-310246-1-1.html
实验一百九十三:TCS34725颜色识别传感器 RGB IIC明光感应模块 ColorSensor
https://mc.dfrobot.com.cn/thread-310209-1-1.html
实验二百:RCWL-0515微波雷达感应开关 人体感应 智能感应探测传感器 12-15米远距离2.7G微波检测模块
https://mc.dfrobot.com.cn/thread-310313-1-1.html
实验二百零三:Air724UG合宙 Cat14G模块 DTU物联网UART串口通信数据TCP透传 核心板组合套餐
https://mc.dfrobot.com.cn/thread-310342-1-1.html
实验二百零七:I2C红色8*8LED点阵模块ht16k33驱动1088BS树莓派物联网可扩展编程
https://mc.dfrobot.com.cn/thread-310951-1-1.html
实验二百零九:Gravity: I2C & UART BC20 NB-IoT & GNSS通信模块 NB-IoT广域低功耗无线通信 GPS/北斗精准定位
https://mc.dfrobot.com.cn/thread-310433-1-1.html

驴友花雕 发表于 2021-9-9 11:16:52

查看模块的驱动芯片


驴友花雕 发表于 2021-9-9 11:28:47

本帖最后由 驴友花雕 于 2021-9-9 12:55 编辑



VK16K33
是一款存储器映射和多功能LED控制驱动芯片。该芯片支持更大 128 点的显示模式(16SEGs×8COMs) 以及更大 13×3 的按键矩阵扫描电路。VK16K33 的软件配置特性使其适用于多种 LED 应用,包括 LED 模块和显示子系统。VK16K33 通过双向I2C 接口可与大多数微控制器进行通信。


功能特点1.工作电压:4.5V~5.5V2.内部 RC 振荡器3.I2C 总线接口4.16×8 位 RAM 用于存储显示数据5.更大显示模式为16×8:16SEGs和8COMs6.读 /写地址自动递增7.多达13×3 按键矩阵扫描功能8. 16阶调光电路9.封装类型:20/24/28-pin SOP    VK16K33此系列IC具有低功耗、高抗杂讯及高系统ESD防护能力;VK16K33整合了LED驱动和按键扫描的功能,将控制面板所需要的功能融合于一身,可降低主MCU的负担及需要的I/O数目。采用I2C的介面更可减少控制面板和主板之间的材料成本、进而降低产品整体成本。


VK16K33有28SOP、24SOP和20SOP三种包装,分别对应三种更大显示点数;16x8点LED和13x3个按键、12x8点LED和10x3个按键,以及8x8点LED和8x3个按键。内建显示记忆体及RC振荡电路;工作电压:4.5V~5.5V;VK16K33支持中断信号和轮询两种工作模式。可选择性的提供按键中断信号给MCU,MCU可不须一直检查按键状态。VK16K33与系统控制晶片的传输只需2根信号线,通过VK16K33 侦测按键输入,可减少主版MCU I/O数目及精简主版及面板的布局线路;因此可降低产品整体成本。 VK16K33适用于家电、影音设备、仪表设备、车用装置等LED显示器/面板的控制及驱动。

驴友花雕 发表于 2021-9-9 11:50:33

VK16K33参数特点
工作电压:4.5V-5.5V
集成RC振荡器
I2C总线接口
16×8位RAM用于显示数据存储
最高 16×8模式,16段和8个共同点
读/写地址自动递增
最高 13×3矩阵键扫描
16级调光电路
20/24/28引脚SOP封装类型

VK16K33主要应用
工控指标
数字时钟、温度计、计数器、万用表
组合套装
录像机
仪表读数
其他消费类应用
LED显示屏



驴友花雕 发表于 2021-9-9 12:20:28

VK16K33功能框图


驴友花雕 发表于 2021-9-9 12:26:47

VK16K33近似内部连接图


驴友花雕 发表于 2021-9-9 12:28:28

VK16K33管脚



驴友花雕 发表于 2021-9-9 12:30:14



VK16k33芯片详细资料
https://cdn-shop.adafruit.com/datasheets/ht16K33v110.pdf

驴友花雕 发表于 2021-9-9 13:08:48

1088BS共阳点阵屏





驴友花雕 发表于 2021-9-9 13:10:29


驴友花雕 发表于 2021-9-9 13:17:19



I2C88单色点阵模块,采用HT16K33芯片作为驱动,可以仅仅使用2个IO管脚就能驱动点亮 I2C点阵模块,可以与Arduino或者其他单片机级联使用。

电源要求:+4.5-5.5V
输入类型:数字信号
接口模式:XH2.54×4
引脚定义:G-地V-电源   D(SDA)-串行数据C(SCL)-串行时钟
模块重量:35g

驴友花雕 发表于 2021-9-9 14:55:17

I2C红色8*8LED点阵模块VK16k33驱动,参考电原理图



驴友花雕 发表于 2021-9-9 14:59:34

连线方法:按照传感器模块接口标号与主控制器相连接,标号“G”接主控制器的“地”、“V”接“电源”、“D”接“Arduino UNO R3”SDA,“C”接“Arduino UNO R3”SCL


驴友花雕 发表于 2021-9-9 15:01:25


驴友花雕 发表于 2021-9-9 15:02:33


驴友花雕 发表于 2021-9-9 16:38:05

本帖最后由 驴友花雕 于 2021-9-9 17:46 编辑

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之一:8x8 LED 矩阵测试,显示一个点

实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之一:8x8 LED 矩阵测试,显示一个点
实验接线:
VK16k33    UNO
VIN      5V
GND      GND
SCL      A5
SDA      A4
*/

// For I2C
#include <Wire.h>
// Libraries for Matrix
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void setup() {
Serial.begin(9600);
// Good idea to send data to both
// device and serial as it helps with
// troubleshooting.
Serial.println("8x8 LED 矩阵测试");
// set the address
matrix.begin(0x70);
}

void loop() {
// clear display
matrix.clear();
// set pixel x,y to ON
matrix.drawPixel(0, 0, LED_ON);
// write RAM to matrix
matrix.writeDisplay();
delay(500);
}

驴友花雕 发表于 2021-9-9 16:39:28

本帖最后由 驴友花雕 于 2021-9-9 17:49 编辑

实验串口返回情况

驴友花雕 发表于 2021-9-9 16:41:10

本帖最后由 驴友花雕 于 2021-9-9 17:51 编辑

实验场景图

驴友花雕 发表于 2021-9-9 16:58:55

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之二:流水瀑布,循环显示

实验开源代码

/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百零七:I2C红色8*8LED点阵模块VK16k33驱动1088BS树莓派物联网可扩展编程
项目之二:流水瀑布,循环显示
实验接线:
VK16k33    UNO
VIN      5V
GND      GND
SCL      A5
SDA      A4
*/

// 引用I2C库
#include <Wire.h>

// 引用ht16k33库
#include "ht16k33.h"

// LED Matrix 模块默认地址为:0x70
#define I2C_ADDR 0x70

HT16K33 *led = NULL;// 申明模块变量

void setup() {
// 初始化I2C, 也可以使用TwoWire
Wire.begin();
// 初始化串口
Serial.begin(115200);

while (led == NULL) {
    // 当led没有实例化,就循环检测模块是否连接
    Wire.beginTransmission(I2C_ADDR);
    uint8_t error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("LED Matrix module is found at address 0x");
      Serial.println(I2C_ADDR, HEX);
      led = new HT16K33(I2C_ADDR);
    }
    delay(2000);
}

// 打开模块
led->displayOn();
}

void loop() {
if (led != NULL) {
    // 清除模块所有显示
    led->clear();
    // 每次需要刷新模块显示,都需要调用write方法将数据传递给模块
    led->write();

    // 瀑布demo
    for (int i = 0; i < 8; i++) {
      for (int j = 0; j < 8; j++) {
      led->setPixel(i, j, 1);
      led->write();
      delay(30);
      }
    }
}
delay(2000);
}

驴友花雕 发表于 2021-9-9 17:06:03

实验场景图动态图
页: [1] 2 3
查看完整版本: 【Arduino】168种传感器系列实验(207)--- HT16k33 LED8*8点阵I2C