250 views|0 replies

20

Posts

8

Resources
The OP
 

【Follow me Season 2 Episode 1】Multiple apps scheduling all tasks in Arduino environment [Copy link]

 This post was last edited by eew_dy9f48 on 2024-8-8 18:40


Source code: https://download.eeworld.com.cn/detail/eew_dy9f48/633952

I am very happy to participate in the follow me event. I bought an Adafruit Circuit Playground Express development board and a raspberry pi zero 2w development board in this event.

In order to complete the task, I also prepared a 9g servo and an ADS1115 module myself.

I used Arduino as the development environment because there are a lot of routines on Arduino, including routines for switching between multiple apps, which is just right for this activity. Each task is written as an independent app, and then switching between apps is done by pressing buttons.

First we need to download the corresponding board and library in Arduino:

Then connect the development board and start programming. The program is modified based on the mega_demo routine in the library.

Getting Started Tasks

The development environment has been configured above, and turning on the light is very simple. Just add the following two lines to the setup function.

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

Before completing other tasks, let's take a look at the main program structure to see how to implement multi-app switching. Then we will complete the following series of tasks in each app.

Here is the main program code:

#include <Adafruit_CircuitPlayground.h>
#include <Wire.h>
#include <SPI.h>
#include "Adafruit_SleepyDog.h"

// Include all the demos, note that each demo is defined in a separate class to keep the sketch
// code below clean and simple.
#include "Demo.h"
#include "RainbowCycleDemo.h"
#include "VUMeterDemo.h"
#include "CapTouchDemo.h"
#include "TiltDemo.h"
#include "SensorDemo.h"
#include "ProximityDemo.h"

// Create an instance of each demo class.
RainbowCycleDemo rainbowCycleDemo;
VUMeterDemo vuMeterDemo;
CapTouchDemo capTouchDemo;
TiltDemo tiltDemo;
SensorDemo sensorDemo;
ProximityDemo proximityDemo;

// Make a list of all demo class instances and keep track of the currently selected one.
int currentDemo = 0;
Demo* demos[] = {
  &rainbowCycleDemo,
  &sensorDemo,
  &proximityDemo,
  &tiltDemo,
  &capTouchDemo,
  &vuMeterDemo
};

void setup() {
  // Initialize serial port and circuit playground library.
  Serial.begin(115200);
  Serial.println("Circuit Playground MEGA Demo!");
  CircuitPlayground.begin();
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
}

void loop() {
  // Check if slide switch is on the left (false) and go to sleep.
  while (!CircuitPlayground.slideSwitch()) {
    // Turn off the pixels, then go into deep sleep for a second.
    CircuitPlayground.clearPixels();
    Watchdog.sleep(1000);
  }

  // Check for any button presses by checking their state twice with
  // a delay inbetween.  If the first press state is different from the
  // second press state then something was pressed/released!
  bool leftFirst = CircuitPlayground.leftButton();
  bool rightFirst = CircuitPlayground.rightButton();
  delay(10);

  // Run current demo's main loop.
  demos[currentDemo]->loop();

  // Now check for buttons that were released.
  bool leftSecond = CircuitPlayground.leftButton();
  bool rightSecond = CircuitPlayground.rightButton();

  // Left button will change the current demo.
  if (leftFirst && !leftSecond) {
    // Turn off all the pixels when entering new mode.
    CircuitPlayground.clearPixels();
    // Increment the current demo (looping back to zero if at end).
    currentDemo += 1;
    if (currentDemo >= (sizeof(demos)/sizeof(Demo*))) {
      currentDemo = 0;
    }
    Serial.print("Changed to demo: "); Serial.println(currentDemo, DEC);
  }

  // Right button will change the mode of the current demo.
  if (rightFirst && !rightSecond) {
    demos[currentDemo]->modePress();
  }
}

From the above code, we can see that we can write each different task in a class in a separate h file, then create instances of these classes in the main program, and then load these instances into a list. Then read the key reading in the main loop. If the key is pressed once, the index is increased by one. The app to be run is selected through this index, and then the loop function in the app is run after entering the app. It can be understood here that we only need to define a class in each separate app file, and define a constructor in this class, which is equivalent to the standard Arduino setup function and only runs once; in addition, define a member function called loop, which will be loaded in the loop of the main program, which is equivalent to the standard Arduino loop function. The other button is used as a mode change function to trigger the modePress function in the app.

In addition, we also need to write a Demo.h, which contains the parent class of all apps to ensure that the methods in all app classes are consistent; at the same time, a linear extrapolation function is defined, which will be used in multiple apps, so there is no need to define it repeatedly:

#ifndef DEMO_H
#define DEMO_H

// Define each mode with the following interface for a loop and modePress
// function that will be called during the main loop and if the mode button
// was pressed respectively.  It's up to each mode implementation to fill
// these in and add their logic.
class Demo {
public:
  virtual ~Demo() {}

  virtual void loop() = 0;
  virtual void modePress() = 0;
};

// Linear interpolation function is handy for all the modes to use.
float lerp(float x, float xmin, float xmax, float ymin, float ymax) {
  if (x >= xmax) {
    return ymax;
  }
  if (x <= xmin) {
    return ymin;
  }
  return ymin + (ymax-ymin)*((x-xmin)/(xmax-xmin));
}

#endif

Basic Task 1

The marquee can directly use the CircuitPlayground.colorWheel function in the library to calculate the color. A speed selection function can be added to the code, and when another button is triggered, the next speed in the speed list is switched.

Create a new file RainbowCycleDemo.h and write the following content.

#ifndef RAINBOWCYCLEDEMO_H
#define RAINBOWCYCLEDEMO_H

#include "Demo.h"

// Animation speeds to loop through with mode presses.  The current milliseconds 
// are divided by this value so the smaller the value the faster the animation.
static int speeds[] = { 5, 10, 50, 100 };

class RainbowCycleDemo: public Demo {
public:
  RainbowCycleDemo() { currentSpeed = 0; }
  ~RainbowCycleDemo() {}

  virtual void loop() {
    // Make an offset based on the current millisecond count scaled by the current speed.
    uint32_t offset = millis() / speeds[currentSpeed];
    // Loop through each pixel and set it to an incremental color wheel value.
    for(int i=0; i<10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, CircuitPlayground.colorWheel(((i * 256 / 10) + offset) & 255));
    }
    // Show all the pixels.
    CircuitPlayground.strip.show();
  }

  virtual void modePress() {
    // Increment through the available speeds.
    currentSpeed += 1;
    if (currentSpeed >= sizeof(speeds)/sizeof(int)) {
      currentSpeed = 0;
    }
  }

private:
  int currentSpeed;
  
};


#endif

Basic Task 2

In this task, we use the CircuitPlayground library to directly read the light intensity and temperature, and then divide the onboard LED into two parts, blue for temperature and red for light intensity, and use the number of LEDs that light up to represent the value of temperature and light intensity. The mode button can be used to switch the indicated range.

#ifndef SENSORDEMO_H
#define SENSORDEMO_H

#include "Demo.h"

// Define small, medium, large range of light sensor values.
static int minLight[] = { 0, 0, 0 };
static int maxLight[] = { 50, 255, 1023 };

// Define small, medium, large range of temp sensor values (in Fahrenheit).
static float mintempC[] = { 30.0, 25.0, 20.0 };
static float maxtempC[] = { 35.0, 38.0, 40.0 };

// Define color for light sensor pixels.
#define LIGHT_RED 0xFF
#define LIGHT_GREEN 0x00
#define LIGHT_BLUE 0x00

// Define color for temp sensor pixels.
#define TEMP_RED 0x00
#define TEMP_GREEN 0x00
#define TEMP_BLUE 0xFF

class SensorDemo : public Demo {
public:
  SensorDemo() {
    mode = 0;
  }
  ~SensorDemo() {}

  virtual void loop() {
    // Reset all lights to off.
    for (int i = 0; i < 10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, 0);
    }

    // Measure the light level and use it to light up its LEDs (right half).
    uint16_t light = CircuitPlayground.lightSensor();
    int level = (int)lerp(light, minLight[mode], maxLight[mode], 0.0, 5.0);
    for (int i = 9; i > 9 - level; --i) {
      CircuitPlayground.strip.setPixelColor(i, LIGHT_RED, LIGHT_GREEN, LIGHT_BLUE);
    }

    // Measure the temperatue and use it to light up its LEDs (left half).
    float tempC = CircuitPlayground.temperature();
    level = (int)lerp(tempC, mintempC[mode], maxtempC[mode], 0.0, 5.0);
    for (int i = 0; i < level; ++i) {
      CircuitPlayground.strip.setPixelColor(i, TEMP_RED, TEMP_GREEN, TEMP_BLUE);
    }

    // Light up the pixels!
    CircuitPlayground.strip.show();

    Serial.print("Light: ");
    Serial.print(light);
    Serial.print("; ");
    Serial.print("Temperature: ");
    Serial.println(tempC);
  }

  virtual void modePress() {
    // Switch to one of three modes for small, medium, big ranges of measurements.
    mode += 1;
    if (mode > 2) {
      mode = 0;
    }
  }

private:
  int mode;
};

#endif

When I cover the brightness sensor with my finger, I can see the red indicator light change:

I adjusted the power of the hot air blower to minimum, blew gently on the thermistor, and I could also see the blue temperature indicator light change.

Basic Task 3

In this task, we use the onboard IR transmitter to send a pulse, and then use the IR receiver to detect the infrared intensity. When there is an obstacle, the reflected infrared light will be observed by the IR receiver, so an analog quantity can be measured. We also use the number of LED lights to show the proximity sensor position, and drive the buzzer to sound an alarm when the threshold is exceeded.

#ifndef PROXIMITYDEMO_H
#define PROXIMITYDEMO_H

#include "Demo.h"

class ProximityDemo : public Demo {
public:
  ProximityDemo() {
    mode = 0;
    pinMode(CPLAY_IR_EMITTER, OUTPUT);
    pinMode(CPLAY_IR_EMITTER, LOW);
    pinMode(A10, INPUT);
  }
  ~ProximityDemo() {}

  virtual void loop() {
    // Reset all lights to off.
    for (int i = 0; i < 10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, 0);
    }

    // Measure the proximity level and use it to light up its LEDs.
    digitalWrite(CPLAY_IR_EMITTER, HIGH);
    delay(1);
    digitalWrite(CPLAY_IR_EMITTER, LOW);
    int prox = analogRead(A10);
    int level = (int)lerp(prox, 300, 500, 0.0, 10.0);
    for (int i = 0; i < level; ++i) {
      CircuitPlayground.strip.setPixelColor(i, 0, 0, 255);
    }

    // Light up the pixels!
    CircuitPlayground.strip.show();

    if (level > 5) {
      CircuitPlayground.playTone(330, 100);
    }

    Serial.print("Proximity: ");
    Serial.println(prox);
  }

  virtual void modePress() {
  }

private:
  int mode;
};

#endif

It can be seen that when the finger approaches, the blue light shows the degree of the finger's proximity by the number of lights. The blue light is chosen here mainly to avoid the possible interference of red light with infrared light.

Advanced Tasks

If the board is placed horizontally inside the tumbler, the Z-axis of the onboard accelerometer is pointing vertically downward, and the theoretical acceleration read on the Z-axis should be 9.8, which is the acceleration of gravity. When the board tilts, the z-axis is no longer directly opposite the center of the earth, so the acceleration value will decrease. Using this principle, you can indirectly observe the degree of the tumbler's tipping by observing the value of the z-axis acceleration. When it is completely horizontal, the onboard LED displays blue; if it tips to the maximum, here I set it to turn red when the z-axis acceleration decreases to 8. The LED will change linearly between red and blue. By pressing the mode button, you can also switch the observation of the x-axis and y-axis acceleration.

#ifndef TILTDEMO_H
#define TILTDEMO_H

#include "Demo.h"

// Define range of possible acceleration values.
#define MIN_ACCEL 8.0
#define MAX_ACCEL 10.0

// Define range of colors (min color and max color) using their red, green, blue components.
// First the min color:
#define MIN_COLOR_RED   0xFF
#define MIN_COLOR_GREEN 0x00
#define MIN_COLOR_BLUE  0x00

// Then the max color:
#define MAX_COLOR_RED   0x00
#define MAX_COLOR_GREEN 0x00
#define MAX_COLOR_BLUE  0xFF


class TiltDemo: public Demo {
public:
  TiltDemo() { mode = 2; }
  ~TiltDemo() {}

  virtual void loop() {
    // Grab the acceleration for the current mode's axis.
    float accel = 0;
    switch (mode) {
      case 0:
        accel = CircuitPlayground.motionX();
        break;
      case 1:
        accel = CircuitPlayground.motionY();
        break;
      case 2:
        accel = CircuitPlayground.motionZ();
        break;
    }

    // Now interpolate the acceleration into a color for the pixels.
    uint8_t red = (uint8_t)lerp(accel, MIN_ACCEL, MAX_ACCEL, MIN_COLOR_RED, MAX_COLOR_RED);
    uint8_t green = (uint8_t)lerp(accel, MIN_ACCEL, MAX_ACCEL, MIN_COLOR_GREEN, MAX_COLOR_GREEN);
    uint8_t blue = (uint8_t)lerp(accel, MIN_ACCEL, MAX_ACCEL, MIN_COLOR_BLUE, MAX_COLOR_BLUE);

    // Gamma correction makes LED brightness appear more linear
    red   = CircuitPlayground.gamma8(red);
    green = CircuitPlayground.gamma8(green);
    blue  = CircuitPlayground.gamma8(blue);

    // Light up all the pixels the interpolated color.
    for (int i=0; i<10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, red, green, blue);
    }
    CircuitPlayground.strip.show();
  }

  virtual void modePress() {
    // Change the mode (axis being displayed) to a value inside 0-2 for X, Y, Z.
    mode += 1;
    if (mode > 2) {
      mode = 0;
    }
  }

private:
  int mode;
};

#endif

When perfectly horizontal, the light is blue.

As the tilt occurs, the light gradually turns red:

Creative Task 2

This task is a little more complicated. The board reads the volume of the microphone to drive the LED light to indicate the volume change. At the same time, it drives the servo to operate the change of Squidward's tentacles. But in this task, I did not use the development board directly to drive the servo, but used the only DAC interface A0 on the board. I sent the recognized volume through the DAC as an analog quantity, which was received by the 16-bit ADC module ADS1115 connected to the Raspberry Pi, and then the Raspberry Pi drove the servo to rotate according to the received analog quantity.

Development board app code:

// This demo is based on the vumeter demo in the Adafruit Circuit Playground library.
#ifndef VUMETERDEMO_H
#define VUMETERDEMO_H

#include <math.h>
#include "Demo.h"

#define SAMPLE_WINDOW 10   // Sample window for average level
#define PEAK_HANG 24       // Time of pause before peak dot falls
#define PEAK_FALL 4        // Rate of falling peak dot
#define INPUT_FLOOR 56     // Lower range of mic sensitivity in dB SPL
#define INPUT_CEILING 110  // Upper range of mic sensitivity in db SPL

static byte peak = 16;  // Peak level of column; used for falling dots
static unsigned int sample;
static byte dotCount = 0;      //Frame counter for peak dot
static byte dotHangCount = 0;  //Frame counter for holding peak dot

static float mapf(float x, float in_min, float in_max, float out_min, float out_max);
static void drawLine(uint8_t from, uint8_t to, uint32_t c);

class VUMeterDemo : public Demo {
public:
  VUMeterDemo() {
    currentCeiling = 0;
  }
  ~VUMeterDemo() {}

  virtual void loop() {
    int numPixels = CircuitPlayground.strip.numPixels();
    float peakToPeak = 0;  // peak-to-peak level
    unsigned int c, y;

    //get peak sound pressure level over the sample window
    peakToPeak = CircuitPlayground.mic.soundPressureLevel(SAMPLE_WINDOW);

    //limit to the floor value
    peakToPeak = max(INPUT_FLOOR, peakToPeak);

    // Serial.println(peakToPeak);

    //Fill the strip with rainbow gradient
    for (int i = 0; i <= numPixels - 1; i++) {
      CircuitPlayground.strip.setPixelColor(i, CircuitPlayground.colorWheel(map(i, 0, numPixels - 1, 30, 150)));
    }

    c = mapf(peakToPeak, INPUT_FLOOR, INPUT_CEILING, numPixels, 0);

    // Turn off pixels that are below volume threshold.
    if (c < peak) {
      peak = c;          // Keep dot on top
      dotHangCount = 0;  // make the dot hang before falling
    }
    if (c <= numPixels) {  // Fill partial column with off pixels
      drawLine(numPixels, numPixels - c, CircuitPlayground.strip.Color(0, 0, 0));
    }

    // Set the peak dot to match the rainbow gradient
    y = numPixels - peak;
    CircuitPlayground.strip.setPixelColor(y - 1, CircuitPlayground.colorWheel(map(y, 0, numPixels - 1, 30, 150)));
    CircuitPlayground.strip.show();

    // Frame based peak dot animation
    if (dotHangCount > PEAK_HANG) {   //Peak pause length
      if (++dotCount >= PEAK_FALL) {  //Fall rate
        peak++;
        dotCount = 0;
      }
    } else {
      dotHangCount++;
    }


    analogWrite(A0, mapf(peakToPeak, INPUT_FLOOR, INPUT_CEILING, 0, 255));
  }

  virtual void modePress() {
  }

private:
  int currentCeiling;
};



static float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//Used to draw a line between two points of a given color
static 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++) {
    CircuitPlayground.strip.setPixelColor(i, c);
  }
}

#endif

The following is the Raspberry Pi part. We also use Adafruit's blinka to drive the ADS1115 and servos. First install and configure the blinka and DAS1115 libraries:

sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get install python3-pip
sudo apt install --upgrade python3-setuptools

cd ~
sudo apt install python3-venv
python3 -m venv env --system-site-packages
source env/bin/activate

pip3 install --upgrade adafruit-python-shell
wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py
sudo -E env PATH=$PATH python3 raspi-blinka.py

pip3 install adafruit-circuitpython-ads1x15

After completing the above steps, you can create a main.py file in the Raspberry Pi and start writing code. After the code reads the value of ADS1115, it converts it into a pulse width between 500-2500 and sends it out through pin 18.

import time
import board
import pwmio
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

# Create the I2C bus
i2c = busio.I2C(board.SCL, board.SDA)

# Create the ADC object using the I2C bus
ads = ADS.ADS1115(i2c)

# Create single-ended input on channel 0
A0 = AnalogIn(ads, ADS.P0)

# Initialize PWM output for the servo (on pin BCM18):
servo = pwmio.PWMOut(board.D18, frequency=50)

# Create a function to simplify setting PWM duty cycle for the servo:
def servo_duty_cycle(pulse_us, frequency=50):
    period_us = 1.0 / frequency * 1000000.0
    duty_cycle = int(pulse_us / (period_us / 65535.0))
    return duty_cycle

print("{:>5}\t{:>5}".format('raw', 'volt'))
while True:
    try:
        value = A0.value
        voltage = A0.voltage
        print("{:>5}\t{:>5.3f}".format(value, voltage))

        dc = value / 16000.0 * 2000.0 + 500.0
        print(dc)
        servo.duty_cycle = servo_duty_cycle(dc)

    except:
        pass

    finally:
        time.sleep(0.1)

When wiring, first connect the playground development board, Raspberry Pi, ADS1115 module and servo to the same ground. The Raspberry Pi 40pin interface has multiple GNDs, which can be used at this time. Then connect SDA and SCL to BCM2 and BCM3 respectively, and connect the servo to BCM18. The servo is powered by the Raspberry Pi 5V pin, and the ADS1115 module is powered by the 3.3V pin.

Just blow air into the board to make noise at the microphone, and the servos and LEDs will react accordingly:

Creative Task 3

The fruit piano is realized by using the principle that the capacitance of the board pins changes after being touched. As long as the pins on the board support capacitance measurement, they can be used as the keyboard of the fruit piano. Since I don't have an extra wiring clip here, I don't connect the fruit, but touch the pins directly. When a pin is triggered, the corresponding LED lights up and plays the corresponding sound, and the piano effect can be achieved.

#ifndef CAPTOUCHDEMO_H
#define CAPTOUCHDEMO_H

#include "Demo.h"


#define CAP_SAMPLES      20   // Number of samples to take for a capacitive touch read.
#define TONE_DURATION_MS 100  // Duration in milliseconds to play a tone when touched.

class CapTouchDemo: public Demo {
public:
  uint16_t CAP_THRESHOLD = 200;  // Threshold for a capacitive touch (higher = less sensitive).

  CapTouchDemo() { 
    playSound = true; 
    if (CircuitPlayground.isExpress()) {
      CAP_THRESHOLD = 800;
    } else {
      CAP_THRESHOLD = 200;
    }
  }
  ~CapTouchDemo() {}

  
  virtual void loop() {
    // Clear all the neopixels.
    for (int i=0; i<10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, 0);
    }
    
    // Check if any of the cap touch inputs are pressed and turn on those pixels.
    // Also play a tone if in tone playback mode.
    if (CircuitPlayground.readCap(0, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(3, CircuitPlayground.colorWheel(256/10*3));
      if (playSound) {
        CircuitPlayground.playTone(330, TONE_DURATION_MS);  // 330hz = E4
      }
    }
    if (CircuitPlayground.readCap(1, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(4, CircuitPlayground.colorWheel(256/10*4));
      if (playSound) {
        CircuitPlayground.playTone(349, TONE_DURATION_MS);  // 349hz = F4
      }
    }
    if (CircuitPlayground.readCap(2, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(1, CircuitPlayground.colorWheel(256/10));
      if (playSound) {
        CircuitPlayground.playTone(294, TONE_DURATION_MS);  // 294hz = D4
      }
    }
    if (CircuitPlayground.readCap(3, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(0, CircuitPlayground.colorWheel(0));
      if (playSound) {
        CircuitPlayground.playTone(262, TONE_DURATION_MS);  // 262hz = C4
      }
    }
    if (CircuitPlayground.readCap(6, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(6, CircuitPlayground.colorWheel(256/10*6));
      if (playSound) {
        CircuitPlayground.playTone(440, TONE_DURATION_MS);  // 440hz = A4
      }
    }
    if (CircuitPlayground.readCap(9, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(8, CircuitPlayground.colorWheel(256/10*8));
      if (playSound) {
        CircuitPlayground.playTone(494, TONE_DURATION_MS);  // 494hz = B4
      }
    }
    if (CircuitPlayground.readCap(10, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(9, CircuitPlayground.colorWheel(256/10*9));
      if (playSound) {
        CircuitPlayground.playTone(523, TONE_DURATION_MS);  // 523hz = C5
      }
    }
    if (CircuitPlayground.readCap(12, CAP_SAMPLES) >= CAP_THRESHOLD) {
      CircuitPlayground.strip.setPixelColor(5, CircuitPlayground.colorWheel(256/10*5));
      if (playSound) {
        CircuitPlayground.playTone(392, TONE_DURATION_MS);  // 392hz = G4
      }
    }

    // Light up the pixels.
    CircuitPlayground.strip.show();
  }

  virtual void modePress() {
    // Turn sound on/off.
    playSound = !playSound;
  }

private:
  bool playSound;
};

#endif

At this point, all the tasks are completed. In the main program file at the beginning, we have included the files of these tasks in the main program, so that the tasks can be switched in sequence through the onboard D4 button.

This event taught me how to manage and schedule multiple apps. I feel that I gained a lot from it. I hope I can continue to participate in the next event and gain more.

This post is from DigiKey Technology Zone
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews

Room 1530, Zhongguancun MOOC Times Building, Block B, 18 Zhongguancun Street, Haidian District, Beijing 100190, China Tel:(010)82350740 Postcode:100190

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list