And I have to say that my new go to board for my little projects was the Teensy 3.2..but now I LOVE the Adafruit Itsybitsy M4 w/atsam51. This board has a rock solid USB connection on win 11. It processes my cos/sin arc code very quickly, and in doing so, can draw my radius scan lines VERY quickly and fluidly. Tried it on trinket M0, and it failed to display parts of the sweep code.
Also, I found this little SD player: DFRobot SD mini player (https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299) . It is a GREAT little board. Uses micro SD, has a tiny footprint, easy C++ code, and has it's own 3w amp. This is an easy board to use. Just download the DFRobot github code for arduino. the only issue was the 'loop' track does not work. No big deal. I only need a few sounds here and there. It takes 200ms to activate a track, so you have to be patient with your code. Also, be VERY careful the way you close your SD card once files loaded. Always use 'eject' because any tiny bit of corruption, and the DFRobot player will have issues playing your tracks. You do not need a folder, just load your SD tracks as 001.mytrack, etc... Also, be sure to purchase the original version DFRobot player, not the amazon knock-offs (same for Adafruit products!).
for the OLED, I use U8g2lib.h This is an excellent easy to use library. Tons of fonts built in. Branches adafruit gfx code, so you can use many of the same functions...
Short vid at:
https://www.youtube.com/watch?v=C31zMyfmmgQ
Hardware:
Adafruit ItsyBitsy M4
Pololu Mini pushbutton switch 2808
3w 30mm speaker
DFRobot SD mini player
Lighted mini pushbutton TL1265BQSCLR x 3
850mAh lipo battery 45x25x9mm (you can get x4 and charger for only a few $'s)
I2C Display Module 0.91 Inch I2C OLED Display
Here is my code. I don't know what happened to adafruit's pop-out code box, so you will have to scroll through 360 or so lines to find everything. There are a few neat lines. Also, I used an interrupt, a millis timer, and some other things some of you may find useful. Use/modify as you like!
Code: Select all
#include <Adafruit_DotStar.h>
#include <U8g2lib.h>
#include "DFRobotDFPlayerMini.h"
DFRobotDFPlayerMini myDFPlayer;
#define NUMPIXELS 1
//Use these pin definitions for the ItsyBitsy M4
#define DATAPIN 8
#define CLOCKPIN 6
const int widthOLED = 128;
const int heightOLED = 32;
const int rBeam = 50;//radar beam radius
const int ledInterruptPin = A2;
const int ledReset = A3;
const int ledLidar = A4;
const int interruptPin = 9;
volatile int state = LOW;
//timer variables
int milliseconds = 0;
int seconds = 0;
int minutes = 0;
int hours = 0;
const int resetPin = 7;
// global millis variables
unsigned long startMillis;
unsigned long currentMillis;
const int period = 100;
unsigned long decisecond = 0;
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0);
Adafruit_DotStar strip(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_GBR);
uint32_t magenta = strip.Color(255, 255, 0);
void testRects() {//modified from adafruit gfx
int n, i, i2, x, cx = widthOLED / 2, cy = heightOLED / 2;
n = max( widthOLED , heightOLED);
for ( x = 0; x < 1; x++) {
for (i = 2; i < n; i += 12) {
i2 = i / 2;
u8g2.drawFrame(cx - i2, cy - i2, i, i);
u8g2.sendBuffer();
delay(100);
}
u8g2.clearBuffer();
}
}
void drawBigFont() {
myDFPlayer.play(2);
u8g2.setDrawColor(1);// blue
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_logisoso28_tr); // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(8, 29, "LIDAR"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(750);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_logisoso28_tr); // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(10, 29, "ACTIVE"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(750);
myDFPlayer.play(3);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_logisoso28_tr); // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(8, 29, "SHIELD"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(750);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_logisoso28_tr); // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(10, 29, "ACTIVE"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(750);
}
void drawRadarScreen() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_micro_tr);
char loadA[] = " LIDAR ";
for (int p = 0; p < strlen(loadA) ; p++) {
char c = loadA[p];
loadA[p] = '\n';
u8g2.drawStr(2, 5, loadA); // write something to the internal memory
loadA[p] = c;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(10);
}
char loadB[] = "ACTIVE ";
for (int p = 0; p < strlen(loadB) ; p++) {
char c = loadB[p];
loadB[p] = '\n';
u8g2.drawStr(105, 5, loadB); // write something to the internal memory
loadB[p] = c;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(10);
}
for (int j = 0; j < 3; j++) {
myDFPlayer.play(4);
digitalWrite(ledLidar, HIGH);
for ( int i = -180; i > (-360); i = i - 5 ) {//set the degrees according to OLED '0', and for CW or CCW
u8g2.setDrawColor(1);// Blue
u8g2.drawLine(0, 31, widthOLED , 31);
u8g2.drawLine(widthOLED / 2, 0, widthOLED / 2, 31);
u8g2.drawCircle(widthOLED / 2, 30, 10);
u8g2.drawCircle(widthOLED / 2, 30, 20);
u8g2.drawCircle(widthOLED / 2, 30, 30);
u8g2.drawCircle(widthOLED / 2, 30, 40);
u8g2.drawCircle(widthOLED / 2, 30, 50);
u8g2.drawLine( widthOLED / 2, 30, widthOLED / 2 + rBeam * cos( ( 360 - i ) * 3.14 / 180 ), 30 + rBeam * sin( ( 360 - i ) * 3.14 / 180 ) );
u8g2.sendBuffer();
u8g2.setDrawColor(0);// Black
u8g2.drawLine( widthOLED / 2, 30, widthOLED / 2 + rBeam * cos( ( 360 - i ) * 3.14 / 180 ), 30 + rBeam * sin( ( 360 - i ) * 3.14 / 180 ) );
u8g2.sendBuffer();
if (i >= -210) {
digitalWrite(ledLidar, LOW);
}
}
myDFPlayer.play(4);
digitalWrite(ledLidar, HIGH);
for ( int i = -360; i < -180; i = i + 5 ) {
u8g2.setDrawColor(1);// Blue
u8g2.drawLine(0, 31, widthOLED , 31);
u8g2.drawLine(widthOLED / 2, 0, widthOLED / 2, 31);
u8g2.drawCircle(widthOLED / 2, 30, 10);
u8g2.drawCircle(widthOLED / 2, 30, 20);
u8g2.drawCircle(widthOLED / 2, 30, 30);
u8g2.drawCircle(widthOLED / 2, 30, 40);
u8g2.drawCircle(widthOLED / 2, 30, 50);
u8g2.drawLine( widthOLED / 2, 30, widthOLED / 2 + rBeam * cos( ( 360 - i ) * 3.14 / 180 ), 30 + rBeam * sin( ( 360 - i ) * 3.14 / 180 ) );
u8g2.sendBuffer();
u8g2.setDrawColor(0);// Black
u8g2.drawLine( widthOLED / 2, 30, widthOLED / 2 + rBeam * cos( ( 360 - i ) * 3.14 / 180 ), 30 + rBeam * sin( ( 360 - i ) * 3.14 / 180 ) );
u8g2.sendBuffer();
if (i <= -330) {
digitalWrite(ledLidar, LOW);
}
}
}
}
void loadScreen() {//different fonts screen one char at a time
u8g2.setDrawColor(1);// Blue, (0) = black
u8g2.drawFrame(0, 0, 128, 32);
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
char load[] = "LOADING......DONE..";
for (int p = 0; p < strlen(load) ; p++) {
char c = load[p];
load[p] = '\n';
u8g2.drawStr(5, 10, load); // write something to the internal memory
load[p] = c;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(0);
}
u8g2.setFont(u8g2_font_micro_tr);
char load1[] = "SCANNING RANGE: 2000 meters ";
for (int p = 0; p < strlen(load1) ; p++) {
char c = load1[p];
load1[p] = '\n';
u8g2.drawStr(5, 20, load1); // write something to the internal memory
load1[p] = c;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(0);
}
//u8g2.setFont(u8g2_font_u8glib_4_tr); // choose a suitable font
char load2[] = "SHIELD:Random Shield Integer ";
for (int p = 0; p < strlen(load2) ; p++) {
char c = load2[p];
load2[p] = '\n';
u8g2.drawStr(5, 30, load2); // write something to the internal memory
load2[p] = c;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(0);
}
delay(3000);
u8g2.clearBuffer();
}
void randNum() {
myDFPlayer.play(5);
u8g2.setDrawColor(1);// blue
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_logisoso28_tr); // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.setCursor(1, 29);
for (int i = 0; i < 7; i++) {
int a;
a = random(0 - 9);
u8g2.print(a);
delay(35);
u8g2.sendBuffer();
}
delay(1000);
u8g2.clearBuffer();
}
void clockTimer() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_logisoso28_tr);
setClock();
u8g2.setCursor(1, 29);
if (minutes < 10) {
u8g2.print("0");//place holder
u8g2.print(minutes);
u8g2.print(":");
}
else {
u8g2.print(minutes);
u8g2.print(":");
}
if (seconds < 10) {
u8g2.print("0");
u8g2.print(seconds);
u8g2.print(":");
}
else {
u8g2.print(seconds);
u8g2.print(":");
}
if (decisecond < 10) {
u8g2.print("0");
u8g2.print(decisecond);
}
else {
u8g2.print(decisecond);
}
u8g2.sendBuffer();
}
void setClock() {
if (decisecond > 90) { //whenever deciseconds is greater than 90), deciseconds = 0, and add 1 to seconds
decisecond = 0;
seconds++;
}
if (seconds > 59) {
seconds = 0; //whenever seconds is greater than 59, second = 0, and add 1 to minutes
myDFPlayer.play(6);// tick every minute
minutes++;
}
if (minutes > 59) {
u8g2.clearBuffer();
u8g2.drawStr(1, 29, "RESET");
u8g2.sendBuffer();
minutes = 0;
delay(1000);
}
}
void clearClockTimer() {
myDFPlayer.play(6);
digitalWrite(ledReset, HIGH);
u8g2.clearBuffer();
u8g2.drawStr(1, 29, "RESET");
decisecond = 0;
seconds = 0;
minutes = 0;
u8g2.sendBuffer();
delay(1000);
digitalWrite(ledReset, LOW);
}
void blink() {
state = !state;
//Serial.println("button");
if (state) {
digitalWrite(ledInterruptPin, HIGH);
}
if (!state) {
digitalWrite(ledInterruptPin, LOW);
}
}
void setup(void) {
Serial.begin(115200);
Serial1.begin(9600);
u8g2.begin();
myDFPlayer.begin(Serial1);
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);//not sure if this is needed....
//myDFPlayer.EQ(4);//10 selections
myDFPlayer.volume(23);//0-30
randomSeed(analogRead(20));//for randNum generator
pinMode(ledReset, OUTPUT);// reset timer led
pinMode(ledLidar, OUTPUT);//lidar flash led
pinMode(ledInterruptPin, OUTPUT);//turn on when interrupt flagged
pinMode(resetPin, INPUT_PULLUP);
pinMode(interruptPin, INPUT_PULLUP);//interruptPin to ground
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);//works better than CHANGE
//attachInterrupt(interruptPin, blink, CHANGE);//works with M4(samd51)
strip.begin(); // Initialize pins for output
/*
strip.setPixelColor(0, 0xFF0000); // red
strip.show();
delay(1000);
strip.setPixelColor(0, 0x00FF00); // green
strip.show();
delay(1000);
strip.setPixelColor(0, 0x0000FF); // blue
strip.show();
delay(1000);
*/
strip.setBrightness(0);//(80);
strip.fill(0, 0, 0);
strip.show();
delay(250);//df mini sd needs a bit of boot time
myDFPlayer.play(1);
delay(10000); // that's how long boot track is
drawBigFont();
u8g2.clearBuffer();
loadScreen();
u8g2.clearBuffer();
myDFPlayer.play(5);
testRects();
u8g2.clearBuffer();
}
void loop(void) {
if (state) {//non blocking code
int buttonState = digitalRead(resetPin);
if (buttonState == LOW) {
clearClockTimer();
}
else {
currentMillis = millis(); //get the current "time"...the number of milliseconds since boot
if (currentMillis - startMillis >= period) //has period elapsed? do something
{ decisecond = decisecond + 10;//add '1 / 10th' second to timer
clockTimer();
startMillis = currentMillis; //reset start counter
}
}
}
if (!state) { //blocking code
drawRadarScreen();
u8g2.clearBuffer();
randNum();
u8g2.clearBuffer();
}
}