I'm working on a tachometer using an IR sensor. It mostly works but I keep getting some peculiar readings. Here is some serial output showing what I'm talking about...
currTime=1659791008 prevTime=1659664548 interval=126460 spindleRPM=474 rpmd=0
currTime=1659791008 prevTime=1659664548 interval=126460 spindleRPM=474 rpmd=0
currTime=1659917544 prevTime=1659791008 interval=126536 spindleRPM=474 rpmd=0
currTime=1660053264 prevTime=1660044076 interval=9188 spindleRPM=6530 rpmd=6056
currTime=1660053264 prevTime=1660044076 interval=9188 spindleRPM=6530 rpmd=0
currTime=1660170544 prevTime=1660053264 interval=117280 spindleRPM=511 rpmd=-6019
currTime=1660297076 prevTime=1660170544 interval=126532 spindleRPM=474 rpmd=-37
currTime=1660297076 prevTime=1660170544 interval=126532 spindleRPM=474 rpmd=0
currTime=1660423608 prevTime=1660297076 interval=126532 spindleRPM=474 rpmd=0
currTime=1660550084 prevTime=1660423608 interval=126476 spindleRPM=474 rpmd=0
currTime=1660550084 prevTime=1660423608 interval=126476 spindleRPM=474 rpmd=0
If the code helps, here it is...
// Screen dimensions
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 128
// You can use any (4 or) 5 pins
#define SCLK_PIN 13 //clk/sck
#define MOSI_PIN 3 //din
#define DC_PIN 4 //data command
#define CS_PIN 5
#define RST_PIN 6
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define LED_PIN 2
#define LED_COUNT 24
#define BRIGHTNESS 20 //0 to 255
#include <Adafruit_GFX.h>
//#include <Adafruit_SSD1351.h>
#include <Adafruit_SSD1331.h>
#include <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <Fonts/FreeMono9pt7b.h>
//#include <Fonts/FreeMono12pt7b.h>
#include <Fonts/FreeMono18pt7b.h>
//#include <Fonts/FreeMono24pt7b.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
//Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, CS_PIN, DC_PIN, MOSI_PIN, SCLK_PIN, RST_PIN);
Adafruit_SSD1331 tft = Adafruit_SSD1331(CS_PIN, DC_PIN, MOSI_PIN, SCLK_PIN, RST_PIN);
Adafruit_NeoPixel ring(LED_COUNT, LED_PIN, NEO_RGBW + NEO_KHZ800);
int spindleRPM = 0;
int prevRpm = 0;
volatile unsigned long rpmArray[2] = {0,0}; //array to hold the latest microseconds and previous microseconds
unsigned long tempArray[2] = {60000000, 0}; //temporary array for copying the value of rpmArray so it can be worked on after interrupts started again
long interval = 0; //time between IR pulses
int rightDigits = 0; //stores the portion of the rpm value from 0 to 99 for the ring display
int rpmDifference = 0; //difference between the current rpm reading and the previous reading
//long currTime = 0;
//long prevTime = 0;
byte mappedPixel = 0; //the pixel to light up on the ring representing RPM from 0 to 99
int tailSize = 0; //the size of the "tail" trailing the lighted pixel
byte rpmDigits[4] = {0,0,0,0}; //array to hold digits of the RPM. Max RPM 9,999.
byte rpmDigitsPrev[4] = {0,0,0,0}; //array to hold previous value of rpmDigits for comparison purposes
void setup(){
pinMode(21, INPUT_PULLUP);
Serial.begin(9600);
tft.begin();
attachInterrupt(digitalPinToInterrupt(21), isr, FALLING); //Interrupts are called on Rise of Input
ring.begin(); // Initialize NeoPixel ring object
ring.show(); // Turn OFF all pixels ASAP
ring.setBrightness(20); // Set brightness to about 1/5 (max = 255)
tftPrintBackground();
}
void loop(){
noInterrupts();
memcpy(tempArray, rpmArray, sizeof tempArray);
interrupts();
interval = (tempArray[0] - tempArray[1]);
spindleRPM = (60*1000000)/interval;
if (spindleRPM < 0) spindleRPM = 0; //prevent rpm from being negative from dividing by 0, issue on startup
rpmDifference = (spindleRPM - prevRpm);
rightDigits = (spindleRPM % 100);
displayDigits(); //Displays the RPM digits on the display
if (spindleRPM > 0 ) {
tftPrintSpindleRPM();
memcpy(rpmDigitsPrev, rpmDigits, sizeof rpmDigits);
printx100(); //prints "x100" under RPM if the RPM is > 100
displayPixel(ring.Color(255, 0, 0), rightDigits, rpmDifference);
ring.show();
prevRpm = spindleRPM;
Serial.print("currTime=");
Serial.print(tempArray[0]);
Serial.print(" prevTime=");
Serial.print(tempArray[1]);
Serial.print(" interval=");
Serial.print(interval);
Serial.print(" spindleRPM=");
Serial.print(spindleRPM);
Serial.print(" rpmd=");
Serial.println(rpmDifference);
//prevTime = currTime;
}
}
void isr(){
rpmArray[1] = rpmArray[0];
rpmArray[0] = micros();
}
void displayDigits(){ //breaks out the digits of the RPM and puts them in an array for display.
int myRPM = spindleRPM;
if (spindleRPM > 99) myRPM /= 100;
for (byte i = 0; i < 2; i++) {
rpmDigits[i] = myRPM % 10;
myRPM /= 10;
}
}
void printx100(){
if (spindleRPM >= 100 && prevRpm < 100) {
tft.setCursor(5, 20);
tft.setTextColor(RED);
tft.println("x100");
tft.setFont();
}
else if (spindleRPM < 100 && prevRpm >= 100) {
tft.setCursor(5, 20);
tft.setTextColor(BLACK);
tft.println("x100");
tft.setFont();
}
}
void displayPixel(uint32_t color, byte rightDigits, int rpmDifference){
// Serial.print("rpmd= ");
// Serial.print(rpmDifference);
rpmDifference = constrain(rpmDifference, -50, 50); //limiting the acceleration value to 100 or less in either direction
// Serial.print(" rpmdc= ");
// Serial.print(rpmDifference);
mappedPixel = map(rightDigits, 0, 99, 0, 23);
tailSize = map(rpmDifference, -50, 50, -23, 23);
// Serial.print(" tailsize= ");
// Serial.println(tailSize);
ring.clear();
ring.setPixelColor(mappedPixel, color); // Set pixel's color (in RAM)
// Serial.print("Mapped=");
// Serial.println(mappedPixel);
int m = mappedPixel;
int brightness = 50;
int x = 50;
for (int i=mappedPixel-tailSize; i < mappedPixel; i++){
uint32_t rgbcolor = ring.ColorHSV(65000, 255, 255);
x += 10;
m = i;
if (m < 0) {
m=m+24;
}
// Serial.println(m);
ring.setPixelColor(m, rgbcolor);
}
}
void tftPrintSpindleRPM(){
tft.setFont(&FreeMono18pt7b);
tft.setTextSize(1);
//print previous spindleRPM in black to clear it
tft.setCursor(50, 23);
tft.setTextColor(BLACK);
if (rpmDigits[1] != rpmDigitsPrev[1]){
tft.print(rpmDigitsPrev[1]);
}
tft.setCursor(70, 23);
if (rpmDigits[0] != rpmDigitsPrev[0]){
tft.print(rpmDigitsPrev[0]);
}
//print the spindleRPM in white
tft.setCursor(50, 23);
tft.setTextColor(WHITE);
if (rpmDigits[1] > 0 && rpmDigits[1] != rpmDigitsPrev[1]){
tft.print(rpmDigits[1]);
}
tft.setCursor(70, 23);
if (rpmDigits[0] != rpmDigitsPrev[0]){
tft.print(rpmDigits[0]);
}
tft.setFont();
}
void tftPrintBackground() {
tft.fillScreen(BLACK);
tft.drawRect(0, 33, 96, 31, GREEN);
tft.drawLine(31, 33, 31, 64, GREEN);
tft.drawLine(62, 33, 62, 64, GREEN);
tft.setFont(&FreeSans9pt7b);
tft.setCursor(1, 13);
tft.setTextColor(RED);
tft.println("RPM");
tft.setFont();
tft.setCursor(7, 38);
tft.setTextColor(RED);
tft.setTextSize(1);
tft.println("MTR");
tft.setCursor(3, 52);
tft.setTextColor(WHITE);
tft.setTextSize(1);
tft.println("3600");
tft.setCursor(38, 38);
tft.setTextColor(RED);
tft.setTextSize(1);
tft.println("DRV");
tft.setCursor(35, 52);
tft.setTextColor(WHITE);
tft.println("1350");
tft.setFont();
tft.setCursor(71, 38);
tft.setTextColor(RED);
tft.setTextSize(1);
tft.println("FPR");
tft.setCursor(64, 52);
//tft.setCursor(60, 72);
tft.setTextColor(WHITE);
tft.println(".0209");
tft.setFont();
}