I recently bought myself a box full of $5 Arduino Uno's (as you do).
For those of you who don't know what an Arduino is, it's a low cost programmable microprocessor, the original Arduino modules cost around $20 but the Chinese clones are a lot cheaper. The software to program the arduino is free and has been downloaded more than 13 million times. Here is a picture of the ones I bought on eBay, and they work just fine.
I started off making a simple geiger counter and after brief success I set my ambitions higher, and wondered if it would be possible to make some kind of spectrometer from a $5 Arduino. The main component of my project is the Schmitt trigger, this is a circuit with a fast opamp that triggers a logic pulse when the analogue voltage from a PMT detector reaches a threshold. The length of the logic pulse varies with the height of the analogue pulse.
I sell the Schmitt trigger here: https://www.gammaspectacular.com/blue/g ... tt-trigger
The only thing that may need changing are the load resistors, very high for neutron detectors and around 1M for PMT's
For an extra few dollars I got some 8 x 32 pixel LED displays off eBay like these:
https://www.ebay.com/sch/i.html?_from=R ... 6&_sacat=0
And some simple 4 digit LED number displays.
The basic principle of the code is to use the interrupt function on the Arduino which are pins 3 and 3, using digital interrupt you can very accurately record the time in microseconds when a pin goes high or low, The maximum resolution on the Arduino is 4 µs. but over longer periods the error is not cumulative, so at best it is out by 2 µs.
Writing the basic spectrometer code was pretty simple, making it display on the 8x32 pixel display took me a bit longer. All up it was a three day job, but I was learning.
To make my job a little easier I 3D printed a smart enclosure for the hardware and fitted a piece of coloured acrylic which I had laying around. I also added a button for resetting the variables quickly.
To fully demonstrate how this thing works I shot a 2 minute video and uploaded it to YouTube here: https://youtu.be/qcwWh61sAhw
I have a few ideas on how to develop the Arduino into useful products, but it wont be anything like what you see here, this was purely a fun R&D project.
If anyone is interested in the code I am happy to post it below.
Steven
Pushing an Arduino to the limit.
-
Sesselmann
- Posts: 1398
- Joined: 27 Apr 2015, 11:40
Pushing an Arduino to the limit.
You do not have the required permissions to view the files attached to this post.
-
Svilen
- Posts: 191
- Joined: 23 Sep 2016, 04:25
Re: Pushing an Arduino to its limit.
Very nice project, Steven. I also experiment for several days now with Arduino, working on an environmental radiation monitor with two GM tubes and a data logger, maybe I share it later too, in case successful :)
I would be interested to see the code you used.
I would be interested to see the code you used.
-
Sesselmann
- Posts: 1398
- Joined: 27 Apr 2015, 11:40
Re: Pushing an Arduino to its limit.
Svilen,
Here is my code as it currently stands, it's working quite well, but consider it a work in progress.
Arduino MCA by Gammaspectacular (v1.0) October 2019
Here is my code as it currently stands, it's working quite well, but consider it a work in progress.
Arduino MCA by Gammaspectacular (v1.0) October 2019
Code: Select all
/*
Multichannel analyser for arduino written by Steven Sesselmann with help from David Housley
The analogue pulse from a scintillation detector is coupled through a GS-SCMITT trigger and outputs
a square wave pulse with length proportional to the log of the pulse height.
The 3.3V square wave length is a known function of the analogue pulse height.
The actual pulse height can be calculated by the formula pheight = (plength)/e^(plength/tconstant)
The program outputs a histogram in 100 channels to a MAX72XX matrix display with 32x8 pixels.
https://www.gammaspectacular.com/phpBB3/viewtopic.php?f=15&t=658
*/
#include <MD_MAXPanel.h> // Library for matrix display
#include <TM1637.h> // Library for 7 segment displays
TM1637 tm(8, 9); // CLK-Pin 8 DIO-Pin 9 Pinout for TM1637(a)
TM1637 tn(6, 7); // CLK-Pin 6 DIO-Pin 7 Pinout for TM1637(b)
const MD_MAX72XX::moduleType_t HARDWARE_TYPE = MD_MAX72XX::FC16_HW; //Hardware definition
const uint8_t X_DEVICES = 4; //Number of 8x8 segments in x direction
const uint8_t Y_DEVICES = 1; // number of segments in y direction
const uint8_t CLK_PIN = 13; // Pin connections for MAX72xx
const uint8_t DATA_PIN = 11; // Pin connections for MAX72xx
const uint8_t CS_PIN = 10; // Pin connections for MAX72xx
MD_MAXPanel mp = MD_MAXPanel(HARDWARE_TYPE, CS_PIN, X_DEVICES, Y_DEVICES);
const byte ledPin = 13; // pin assigned to led on board
const byte Pin2 = 2; // pin assigned to rising pulse (connect3d to pin 3)
const byte Pin3 = 3; // pin assigned to falling pulse (connected to pin 2)
const byte Pin4 = 4; // pin assigned for reset
volatile byte state = LOW; // pin state for positive pulse
//--------------------- SET UP CONSTANTS HERE --------------------------------------
const float e = 0.5; // This is the plength to pheight exponential
const int firstbin = 20; // Ignore pulses below this firstbin threshold
const int binsize = 8; // sets bin size (min 4 for Arduino uno)
const int bins = 80; // sets the number of channels in array
//---------------------DEFINE VARIABLES HERE------------------------------------
float pheight = 0.00; // define variable
float maxvalue = 0.00; // define variable
int channel[bins]; // define number of channels
int ratio = 0; // define variable
int usec = 0; // define variable
int laptime = 0; // define variable lap time
int seconds = 0; // define variable
int tcounts = 0; // define variable
int plength = 0; // define variable
int i = 0;
int m = 0;
unsigned long b = 0; // define variable for beginning of pulse rising
unsigned long f = 0; // define variable for end of pulse falling
//----------------------------------------------------------------------------------
void setup() {
Serial.begin (57600); // set speed of serial communication
tm.init(); // initialise tm display
tm.setBrightness(5); // set brightness tm display
tn.init(); // initialise tn display
tn.setBrightness(5); // set brightness tn display
mp.begin(); // initialise mp display
mp.setIntensity(2); // set brightness mp display
pinMode(ledPin, OUTPUT); // set function of pin 13
pinMode(Pin2, INPUT_PULLUP); // set function of pin 2
pinMode(Pin3, INPUT); // set function of pin 3
pinMode(Pin4, INPUT); // set function of pin 4
attachInterrupt(digitalPinToInterrupt(Pin2), blink1, RISING); // interrupt all funktions for blink1
attachInterrupt(digitalPinToInterrupt(Pin3), blink2, FALLING); // interrupt all funktions for blink2
}
void blink1() { // subroutine 1
b = micros(); // start time in microseconds
}
void blink2() { // subroutine 2
f = micros(); // finish time in microseconds
plength = (f-b); // calculate pulse length
if (plength < 256) {
pheight = (plength * exp(e)) ;
}
tcounts = tcounts +1 ; // make total counts
// for loop sorts by pulseheight and increases the count in the matching channel
for ( i = 0; i <= bins; i = i+1){
if ( pheight > (firstbin+(binsize *i)) && pheight <= (firstbin+(binsize * (i + 1)))){
(channel[i] = (channel[i]+1));
}
else{}
}
}
void loop() {
delay(100); // wait 100 millisecons
mp.clear(); // clear mp display
for ( i = 0; i <= bins ; i = i+1){ // get max value in array
if (channel[i] >= maxvalue){ maxvalue = channel[i]; } else {}
ratio = ((channel[i]/maxvalue)*8) -1 ; // calculat ratio between counts and max value then convert to 8 bit
mp.setPoint(i-m,ratio -7, true); // print spectrum and fill in dots below
mp.setPoint(i-m,ratio -6, true);
mp.setPoint(i-m,ratio -5, true);
mp.setPoint(i-m,ratio -4, true);
mp.setPoint(i-m,ratio -3, true);
mp.setPoint(i-m,ratio -2, true);
mp.setPoint(i-m,ratio -1, true);
mp.setPoint(i-m,ratio -0, true);
}
if (millis() > seconds * 1000) { seconds++; } else {} // second counter
tm.dispNumber(tcounts/(seconds-laptime)); // display counts per second
tn.dispNumber(seconds-laptime); // display seconds since last reset
m = (m+1)%(bins-firstbin); // moves display one pixel to the left
int val = digitalRead(Pin4); // reset button triggers subroutine
if (val == 1) { // to clear variables and reset spectrum
laptime = seconds;
tcounts = 0;
pheight = 0;
maxvalue = 0;
for ( i = 0; i <= bins ; i = i+1){
channel[i] = 0;
}
} else {}
}
-
gwgw
- Posts: 57
- Joined: 13 May 2019, 08:09
Re: Pushing an Arduino to its limit.
A coincidence counter would be an interesting project with more than one tube I guess. It would be challenging - for me the hardware part would be challenging for sure as I know little about HV supplies for GM tubes and any signal conditioning and amplification (if required). But software side would be complicated too. Arduino's interrupts are not reentrant, interrupts are disabled on the MCU before your ISR is called and reenabled after it finishes. So coincident events would very likely be lost as the MCU has already disabled interrupts when the first event occurs. Of course, inside your interrupt handler you can explicitly enable interrupts - perhaps that may happen fast enough so that the second coincident event triggers the interrupt. Perhaps not. But even if it does, writing reentrant interrupt handlers is a very tricky business.
-
Conor Whyte
- Posts: 126
- Joined: 28 Apr 2019, 15:06
Re: Pushing an Arduino to the limit.
I'd love to try executing this code on a Teensy 3.6 or 4 to see if this program could be further adapted to an LCD screen. --- Also I'd like to try outputting the data onto a WG12864B display.
Getting curious. Thank you for posting the code. If I get this experiment to work on the teensy 3.6, I will post here about it.
Getting curious. Thank you for posting the code. If I get this experiment to work on the teensy 3.6, I will post here about it.
-
sgt_bear
- Posts: 117
- Joined: 16 Jan 2017, 07:06
Re: Pushing an Arduino to the limit.
If you need a more "boosted" arduino, take a look at the new models, they come with ARM Processor which is much more powerfull (48Mhz instead of 16)
-
gwgw
- Posts: 57
- Joined: 13 May 2019, 08:09
Re: Pushing an Arduino to the limit.
I'd recommend ESP32, it's very cheap (you can have it for less than $10), it happily runs arduino sketches plus it's much more powerful and it has wifi/bluetooth and a lightweight tcp/ip stack. And it's surprisingly....well, working without issues. Much cheaper than the Uno yet much more powerful.
-
Conor Whyte
- Posts: 126
- Joined: 28 Apr 2019, 15:06
Re: Pushing an Arduino to the limit.
Yes, why I recommended the Teensy 3.6 or Teensy 4.... These are Cortex ARM M4 (Teesny 3.6) 250Mhz and Cortex ARM M7.. capable of 1Ghz
each are capable of +1Msps A/D