Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Sound_man
Aug 25, 2004
Rocking to the 80s

Forseti posted:

You could try a pair of ESP8266 microcontrollers as well. Clones of the Wemos D1 Mini are dirt cheap: eBay. Probably cheaper than 50' of cable.

When I outlined my needs for this project I looked at bluetooth and using an app/web interface to control the scoreboard. Like this guy did but I opted away from that to keep it simple. I don't want to have to worry about any batteries and I want real buttons. I did think about using two Arduinos and have them talk over serial but that seemed excessive for a couple of buttons.

Adbot
ADBOT LOVES YOU

mobby_6kl
Aug 9, 2009

by Fluffdaddy

Forseti posted:

You could try a pair of ESP8266 microcontrollers as well. Clones of the Wemos D1 Mini are dirt cheap: eBay. Probably cheaper than 50' of cable.

You can put an Arduino firmware on them if that's what you're used to programming, although my experience is with NodeMCU. Power can be supplied with a USB battery pack. You could even just do use only one on the scoreboard itself and control with smartphones via a simple web page interface and skip the control pad completely if you wanted to.

Edit: fixed the link
I see that's not how Sound_man wants to do it but in case anyone's curious, I've made a scoreboard/timer for our weekly football games with an ESP32 and a chinese 64x32 LED panel. I had it run a web server so you could change the settings (teams, maximum score, timer) through the web interface. It worked pretty well for a hacked-together prototype, although having the powerbank attached by a usb cable and needing an unlocked phone wasn't ideal. I bought a little BTLE remote control thing to make it easier to add goals but there hasn't been a single game sine then :v:

babyeatingpsychopath posted:

If you're going to go that route, then mount the probe on a servo and just have the micro dip the sensor in before measurement, then pull it back out when done and eject it behind the bookshelf.
Yeah that would be even easier if the sample doesn't have to be specifically in that little cap thing. Which I've no idea if it does. I suppose they aren't that expensive so I could just try and see what it does.

Forseti
May 26, 2001
To the lovenasium!
Fair enough, I'm a developer by trade so I'm at home with REST APIs and hacking together simple HTML interfaces but I know it's not the easiest thing to get started with.

Watch out for inductive kickback on long wires like that, if it gets disconnected suddenly (which is exactly what a switch does) while there's power going it can damage whatever it's connected to with a voltage spike. Basically, you'll probably want to have some flyback diodes in your circuit.

https://www.mouser.com/pdfdocs/EAO-TA-HMI-Inductive-loads-and-flyback-voltages-EN.pdf

Coax cables are also a good option for long connections like that but it sounds like you have a parallel type interface in mind and you'd need to convert it to serial to use a single coax cable. Also Cat5 is probably cheaper than coax anyway these days. I'm not sure how Ethernet cables handle long runs if you're not using them the way Ethernet does, which is a differential signal on each twisted pair.

For de-bouncing you want capacitors near the switches I think. Just throw a small capacitor (probably a few pF is fine? Been a while since I've done this to be honest, can't remember what I used) on the switch's output to ground so that the rapid oscillations when the contacts are closing don't show on the signal.

Sagebrush
Feb 26, 2012

Sound_man posted:

I will stuff with WS2812B LED tape. I’ve got a beefy 5V PSU and a 5V 16mhz Mini Arduino Pro

I’m trying to use four total inputs for this project. One reset button located on the scoreboard that will start a new game after being held down for 5 seconds. There will be three buttons on a remote control

does it mater where the ‘debounce resistor’ is located? My gut says, if it matters, it would be better on the Arduino side of the cable.

I’ve got a rough idea of how I think I’m going to code this but if there are any improvements, I’m all ears.

I'm gonna go against the other thread opinions and say that wireless connectivity is a needless complication for something like this, and that a long cable is perfectly adequate if you're fine with running it where it needs to go. I would get some female ethernet jacks to install at both ends so you can set up and store the thing more easily.

I don't know what a "debounce resistor" is; I assume you mean a capacitor/resistor RC debouncing circuit. I would say don't bother with that and just do it in software. The PolymorphicButtons library (available in the Arduino library manager) handles everything you've mentioned -- debouncing, long-pressing, etc -- and doesn't require any external circuitry. Just set the inputs as INPUT_PULLUP and you're done.

I do not believe you need flyback diodes if you're using the internal pull-ups and pulling the buttons to ground when pressed; they're like 25kΩ or something so you'll only have 0.2mA in the circuit and I doubt 50 feet of wire is enough to create a damaging spike with that amount of current. It wouldn't hurt anything to put them in, though.

If you do want to do wireless stuff, the ESP8266 in WeMos D1 carrier board is a great choice. I haven't tried setting up mesh networking between two of them, but for basic IoT stuff like talking to an MQTT server they are great and you can't beat the price.

Sagebrush fucked around with this message at 20:48 on May 2, 2020

Sound_man
Aug 25, 2004
Rocking to the 80s

Sagebrush posted:

I would get some female ethernet jacks to install at both ends so you can set up and store the thing more easily.

One step ahead of you I've got a few of these kicking around so I'm covered on that front.

Sagebrush posted:

I don't know what a "debounce resistor" is; I assume you mean a capacitor/resistor RC debouncing circuit. I would say don't bother with that and just do it in software. The PolymorphicButtons library (available in the Arduino library manager) handles everything you've mentioned -- debouncing, long-pressing, etc -- and doesn't require any external circuitry. Just set the inputs as INPUT_PULLUP and you're done.
I think I was after "pull down resistor". My last project was a bunch of buttons that got read by an Arduino which outputted them as Modbus coils so I could read them with some entertainment automation software. Reading the buttons got alot more accurate when I added a pull down resistor. I should be able to get something wired up on a bread board soon and I'll try using the PolymorphicButtons Library and see how I get on.

Sagebrush
Feb 26, 2012

Okay, yeah, any digital switch is going to need a pullup or pulldown resistor to work correctly. I suggest just using the internal pullups in the Arduino, which can be enabled by setting pinMode(pin, INPUT_PULLUP) for whatever pin you're using. That will make the switch default to a HIGH (1), and you connect it to ground through the button, so pressing the button will drop it to a LOW. It's easy and effective and doesn't require any other parts.

ickna
May 19, 2004

Sound_man posted:

One step ahead of you I've got a few of these kicking around so I'm covered on that front.

I think I was after "pull down resistor". My last project was a bunch of buttons that got read by an Arduino which outputted them as Modbus coils so I could read them with some entertainment automation software. Reading the buttons got alot more accurate when I added a pull down resistor. I should be able to get something wired up on a bread board soon and I'll try using the PolymorphicButtons Library and see how I get on.

Now do buzzer and bell sounds over Dante, and a Streamdeck/Companion timer setup to complete Entertainment Industry Tech Bingo. What automation software were you using in the other project?

Your project sounds great though and you shouldn’t have much trouble with using UTP cable at those distances even without a differential signal. Like Sagebrush mentioned, do the pulldown internally on the arduino side and use a software debounce and it should work just fine.

Fanged Lawn Wormy
Jan 4, 2008

SQUEAK! SQUEAK! SQUEAK!
Speaking of resistors and in proximity to WS2812Bs....

The Adafruit NeoPixel Uberguide recommends putting a 300-400 ohm resistor between the arduino output pin and the input of the WS2812B pixel. I'm not entirely sure of the electrical rule behind why, I'm assuming some kind of current limitation. They say it is best if it is closer to the LED end of the wire, and not the Microcontroller end. Again, not sure why, as I would think it would serve the same purpose either way.

Anyways, I always do it with my builds, Following the recommendation of having it on the pixel end whenever possible. I've found that if I don't, there is a tendency to damage the first pixel in the chain occasionally... the data still passes to all the other pixels, and I get light, but that first one is dead for all intents and purposes. If I'm doing multiple pixel-output pins, and I don't do the resistor, at least one of them will get damaged 100% of the time.

shame on an IGA
Apr 8, 2005

Spec sheet says the maximum allowable current on that input pin is 1 microamp.

Sound_man
Aug 25, 2004
Rocking to the 80s

ickna posted:

Now do buzzer and bell sounds over Dante, and a Streamdeck/Companion timer setup to complete Entertainment Industry Tech Bingo. What automation software were you using in the other project?

Tait Towers Navigator software, it will talk to almost anything so it is really easy to bring I/O into the system and then you can do anything you want with it.

When I have to do jobs with other software and get asked to do something I really have to think and search around a little before I commit to it.

porksmash
Sep 30, 2008
I'm looking for a specific electrical thing for a project but I can't find the right words to search for to find the correct product. What I want is to be able to drop my project into a dock, and have electrical connections make when it lands. I need it to do 5V and serial so at least 4 pins required. I think it's kinda like pogo pins, but I'm not looking for literally individual spring loaded pins. ideally I'd be able to find some sort of breakout-board like product with both the pin and contact side ready to go. Anyone know of something like that?

EDIT: Turns out pogo pins are exactly what I am looking for, and are not all pogo pins are extremely long, thin, with huge amount of travel. This one and it's mate are going to suit my needs quite nicely.

porksmash fucked around with this message at 05:37 on May 7, 2020

Sound_man
Aug 25, 2004
Rocking to the 80s
Here is an update.


I've got two of the 7 segment displays wired up. I was able to fit 4 pixels in each segment. I need to look at some diffusion to get rid of the point source, my buddy offered to reprint the covers with a different fill on top but I might try and find someone local so we can experiment a little easier. Even with some pretty terrible soldering both digits powered up and worked first try. I'm really happy with how the buttons are working. I might tweak the code slightly but part of me wants to wait until someone else gives it a whirl to get their feedback.

If anyone else is looking to do a 7 segment display with ws2812 tape this Library was perfect.

My next hurdle is to figure out how to mount this and enclosures for the controller and ardunio.

stinch
Nov 21, 2013

porksmash posted:

I'm looking for a specific electrical thing for a project but I can't find the right words to search for to find the correct product. What I want is to be able to drop my project into a dock, and have electrical connections make when it lands. I need it to do 5V and serial so at least 4 pins required. I think it's kinda like pogo pins, but I'm not looking for literally individual spring loaded pins. ideally I'd be able to find some sort of breakout-board like product with both the pin and contact side ready to go. Anyone know of something like that?

EDIT: Turns out pogo pins are exactly what I am looking for, and are not all pogo pins are extremely long, thin, with huge amount of travel. This one and it's mate are going to suit my needs quite nicely.

https://www.hirose.com/product/series/QR__P8

connectors for racks and the like can also be used. sometimes a better option as the contracts wipe and the pressure between pins is provided by the connector.

Sir Bobert Fishbone
Jan 16, 2006

Beebort

stinch posted:

https://www.hirose.com/product/series/QR__P8

connectors for racks and the like can also be used. sometimes a better option as the contracts wipe and the pressure between pins is provided by the connector.

A 1000-cycle rating seems kinda low though for a docking application, no?

sharkytm
Oct 9, 2003

Ba

By

Sharkytm doot doo do doot do doo


Fallen Rib

Sir Bobert Fishbone posted:

A 1000-cycle rating seems kinda low though for a docking application, no?

That's three times a day for a year. And those cycle ratings are what's guaranteed, not when they'll fail.

Nikon rates their camera shutters at 100k on consumer cameras, and I've got a d7000 that too 400k shots and still works.

I mean, it's a consideration, but I don't think 1k is crazy low.

ante
Apr 9, 2005

SUNSHINE AND RAINBOWS
Connectors are (usually) rated very conservatively

https://hackaday.io/project/3339/log/50102-tedious-testing-suggests-the-connector-selection-is-sound

Doggles
Apr 22, 2007

Sound_man posted:

I need to look at some diffusion to get rid of the point source, my buddy offered to reprint the covers with a different fill on top but I might try and find someone local so we can experiment a little easier.

I've started using 1/8 inch thick white HDPE sheets for diffusion. Literally a generic plastic sheet. Once your light sources are 3-4 inches away you don't see individual points anymore.

During my time in isolation I've been hosting games of Codenames for my friends over Twitch. Because we were playing so often, I decided to make an Arduino-powered Codenames board my next project. The latest version of which was played for the first time last night!

The front panel is a basic 24x24x1/8 white HDPE sheet. All the lights are mounted about 4 inches away from the sheet. 2 "bullet" style LEDs are behind each of the word panels, and each side of the border has a strip of 30 LEDs behind it.

A short clip of the end of our men vs women round:
https://clips.twitch.tv/IntelligentEnjoyableChinchillaLeeroyJenkins

shame on an IGA
Apr 8, 2005

The top of the line crazy overbuilt Harting modular connectors we use in industry are only rated to 500 cycles on the spec sheet even though they're basically giant D-sub connectors with 4mm pins. "conservative" doesn't begin to describe it.

Sound_man
Aug 25, 2004
Rocking to the 80s

Doggles posted:

I've started using 1/8 inch thick white HDPE sheets for diffusion. Literally a generic plastic sheet. Once your light sources are 3-4 inches away you don't see individual points anymore.

I wish I had that kind of depth to work with. I am trying to keep this thing fairly compact so I am staying under 2 inches. I have glued down the LED ribbon to the frame and pulled the covers out about 1/4 to a 1/2" inch before hot gluing them. The point source is still a little viable but I'm learning to be ok with that.

JawnV6
Jul 4, 2004

So hot ...

porksmash posted:

I'm looking for a specific electrical thing for a project but I can't find the right words to search for to find the correct product. What I want is to be able to drop my project into a dock, and have electrical connections make when it lands. I need it to do 5V and serial so at least 4 pins required. I think it's kinda like pogo pins, but I'm not looking for literally individual spring loaded pins. ideally I'd be able to find some sort of breakout-board like product with both the pin and contact side ready to go. Anyone know of something like that?

EDIT: Turns out pogo pins are exactly what I am looking for, and are not all pogo pins are extremely long, thin, with huge amount of travel. This one and it's mate are going to suit my needs quite nicely.

When I was working with ME's, I was able to quickly build test jigs by getting them to laser-cut acrylic layers, one to hold the pogo pins, one to hold the board, etc. It wasn't a perfect process, but after a few tries we dialed it in and I could drop-in test boards.

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

There are some connectors rated for really low numbers like 10 connection cycles, molex picoblade is one iirc. They are designed to be plugged in once at assembly and maybe once or twice more for rework. They are pretty much dead after 100 cycles, which isn't too hard to hit doing development.

sharkytm
Oct 9, 2003

Ba

By

Sharkytm doot doo do doot do doo


Fallen Rib

taqueso posted:

There are some connectors rated for really low numbers like 10 connection cycles, molex picoblade is one iirc. They are designed to be plugged in once at assembly and maybe once or twice more for rework. They are pretty much dead after 100 cycles, which isn't too hard to hit doing development.
I use Picoblades for programming headers on some of my products. They get 1 plug/unplug cycle. Plug in, program the MCU, unplug, send to customer. They're rated for 30 cycles, though: http://www.literature.molex.com/SQLImages/kelmscott/Molex/PDF_Images/987651-3691.PDF

FFC cables too. If you're lucky, you can release the latch and disconnect/reconnect 2-3 times before the latch loses tension and the pins don't apply enough pressure for connection. They're the bane of all cell phone/laptop repair folks existences.

::edit:: The Pico EZ-Mate is rated for 10: http://www.literature.molex.com/SQLImages/kelmscott/Molex/PDF_Images/987651-7111.PDF

sharkytm fucked around with this message at 19:26 on May 11, 2020

porksmash
Sep 30, 2008

stinch posted:

https://www.hirose.com/product/series/QR__P8

connectors for racks and the like can also be used. sometimes a better option as the contracts wipe and the pressure between pins is provided by the connector.

That's a good suggestion. I'll look into those style connectors if the contact pressure does turn out to be an issue.

Are there any newer devices in the hobby market that replace the HC-05 bluetooth module? I specifically need the capability for bluetooth master mode, as I have a slave HC-06 module on the other end to create a wireless serial bridge. I've seen these JDY-30/31 modules advertised as drop in replacements, but they don't actually support master mode. A controller like the ESP32 with bluetooth integrated is a little overkill, since I just need a serial bridge.

FetusPorn
Jul 7, 2003

WUGT: Creatures attack and block as normal, but none deal any damage during combat. All attacking creatures are still tapped. Use this ability any time
I've got a question I'm sure one of you fine folk should be able to answer.

I'm working on using an ATTINY84 to replace an obsolete quadrature encoder counter IC (HCTL-2017-A00) for a hand operated jog-wheel on a motion control system I'm trying to restore.

I've got the project working on a breadboard (programming through Arduino IDE and UNO as ISP) and I have a little PCB designed that'll breakout the TINY pins to the pinout of the HCTL. Since it's a hand-jog I'm not too worried about it not being able to operate as fast as the original chip (32Mhz), but I'm still trying to optimize things as much as possible for an accurate count. So, I turned to port manipulation:

I can post the entire code if needed, but I'm just stuck on this bit in the loop().
code:
  //if (count>255) count = count-256;
  //if (count<0) count = count+256;
  
  //PORTA=count;

  for (byte i = 0; i < numPins; i++) { // this loop outputs the binary equivalent of 'count' to the output pins.
    byte state = bitRead(count, i);
    digitalWrite(pins[i], state);

The uncommented part works great, but still uses digitalWrite() which I guess can be a little slow for these kinds of things. If it could operate faster, I'd be happy.
But, generally, no issues with this code; count may go above 256, but the output just rolls over to 0 as I would expect (ignoring higher bits). NO errors on the rollover regardless of rotation speed.

So I found the delightfully simple (currently commented) "PORTA=count;" line to work quite well because all of my output pins are on the A channel of the TINY84. I, of course comment out the for loop when using this. HOWEVER, when the count rolls over and I keep turning the encoder in the same direction I sometimes get one or more bounces between 256 and zero before continuing up from 0 as normal. The faster I turn the encoder, the more likely this is to happen.

Thinking there was some issue with this line's translation of numbers outside of 0-255, I created the other 2 commented lines to clamp the count, but the issue still occurs.

Any idea how I can tame this beast? When it comes to this lower level coding, I'm a bit out of my depth.

poeticoddity
Jan 14, 2007
"How nice - to feel nothing and still get full credit for being alive." - Kurt Vonnegut Jr. - Slaughterhouse Five

FetusPorn posted:

I've got a question I'm sure one of you fine folk should be able to answer.

I'm working on using an ATTINY84 to replace an obsolete quadrature encoder counter IC (HCTL-2017-A00) for a hand operated jog-wheel on a motion control system I'm trying to restore.

I've got the project working on a breadboard (programming through Arduino IDE and UNO as ISP) and I have a little PCB designed that'll breakout the TINY pins to the pinout of the HCTL. Since it's a hand-jog I'm not too worried about it not being able to operate as fast as the original chip (32Mhz), but I'm still trying to optimize things as much as possible for an accurate count. So, I turned to port manipulation:

I can post the entire code if needed, but I'm just stuck on this bit in the loop().
code:
  //if (count>255) count = count-256;
  //if (count<0) count = count+256;
  
  //PORTA=count;

  for (byte i = 0; i < numPins; i++) { // this loop outputs the binary equivalent of 'count' to the output pins.
    byte state = bitRead(count, i);
    digitalWrite(pins[i], state);

The uncommented part works great, but still uses digitalWrite() which I guess can be a little slow for these kinds of things. If it could operate faster, I'd be happy.
But, generally, no issues with this code; count may go above 256, but the output just rolls over to 0 as I would expect (ignoring higher bits). NO errors on the rollover regardless of rotation speed.

So I found the delightfully simple (currently commented) "PORTA=count;" line to work quite well because all of my output pins are on the A channel of the TINY84. I, of course comment out the for loop when using this. HOWEVER, when the count rolls over and I keep turning the encoder in the same direction I sometimes get one or more bounces between 256 and zero before continuing up from 0 as normal. The faster I turn the encoder, the more likely this is to happen.

Thinking there was some issue with this line's translation of numbers outside of 0-255, I created the other 2 commented lines to clamp the count, but the issue still occurs.

Any idea how I can tame this beast? When it comes to this lower level coding, I'm a bit out of my depth.

I don't know if it's fast enough for your needs, but I think the modulus operator solves your looping issue: count = count%255

Sockser
Jun 28, 2007

This world only remembers the results!




Sound_man posted:

Here is an update.


I've got two of the 7 segment displays wired up. I was able to fit 4 pixels in each segment. I need to look at some diffusion to get rid of the point source, my buddy offered to reprint the covers with a different fill on top but I might try and find someone local so we can experiment a little easier. Even with some pretty terrible soldering both digits powered up and worked first try. I'm really happy with how the buttons are working. I might tweak the code slightly but part of me wants to wait until someone else gives it a whirl to get their feedback.

If anyone else is looking to do a 7 segment display with ws2812 tape this Library was perfect.

My next hurdle is to figure out how to mount this and enclosures for the controller and ardunio.

I'm way late on this but I built an 8-digit 7 segment display last year using this model and making some new connectors so I could get around the : separator--
https://www.thingiverse.com/thing:3014572
It diffuses a lot better than your model because the LEDs all face sideways instead of straight into the front panel

And here's my lovely modification of the code-
https://github.com/KyleMagocs/PushyKawaii

And then my dumb little not-game art piece ended up at GDQ getting speed runs
https://twitter.com/FrostedGH/status/1215051737981161474?s=20

ante
Apr 9, 2005

SUNSHINE AND RAINBOWS

FetusPorn posted:

I've got a question I'm sure one of you fine folk should be able to answer.

I'm working on using an ATTINY84 to replace an obsolete quadrature encoder counter IC (HCTL-2017-A00) for a hand operated jog-wheel on a motion control system I'm trying to restore.

I've got the project working on a breadboard (programming through Arduino IDE and UNO as ISP) and I have a little PCB designed that'll breakout the TINY pins to the pinout of the HCTL. Since it's a hand-jog I'm not too worried about it not being able to operate as fast as the original chip (32Mhz), but I'm still trying to optimize things as much as possible for an accurate count. So, I turned to port manipulation:

I can post the entire code if needed, but I'm just stuck on this bit in the loop().
code:
  //if (count>255) count = count-256;
  //if (count<0) count = count+256;
  
  //PORTA=count;

  for (byte i = 0; i < numPins; i++) { // this loop outputs the binary equivalent of 'count' to the output pins.
    byte state = bitRead(count, i);
    digitalWrite(pins[i], state);

The uncommented part works great, but still uses digitalWrite() which I guess can be a little slow for these kinds of things. If it could operate faster, I'd be happy.
But, generally, no issues with this code; count may go above 256, but the output just rolls over to 0 as I would expect (ignoring higher bits). NO errors on the rollover regardless of rotation speed.

So I found the delightfully simple (currently commented) "PORTA=count;" line to work quite well because all of my output pins are on the A channel of the TINY84. I, of course comment out the for loop when using this. HOWEVER, when the count rolls over and I keep turning the encoder in the same direction I sometimes get one or more bounces between 256 and zero before continuing up from 0 as normal. The faster I turn the encoder, the more likely this is to happen.

Thinking there was some issue with this line's translation of numbers outside of 0-255, I created the other 2 commented lines to clamp the count, but the issue still occurs.

Any idea how I can tame this beast? When it comes to this lower level coding, I'm a bit out of my depth.

code:
  count = count & 0xFF;
  PORTA=count;
That said, are you sure you're not prematurely optimising? For just reading back an encoder value, I feel like you could do it the least efficient way imaginable, and it would still be fine.

FetusPorn
Jul 7, 2003

WUGT: Creatures attack and block as normal, but none deal any damage during combat. All attacking creatures are still tapped. Use this ability any time

poeticoddity posted:

I don't know if it's fast enough for your needs, but I think the modulus operator solves your looping issue: count = count%255

Yeah, that seems to almost completely kill it... it must be a slow function. Thank you though!

Regardless of the rollover being constrained to 0-255 (with or without the clamping code I posted), I still get that strange output only with the port manipulation code, and not the for-loop.

The error appears to be something like ...253, 254, 255, 0, 255, 0, 1, 2... as the count goes up. It doesn't happen when going the other direction.

Here's the whole shebang:
code:
#include "PinChangeInterrupt.h" // MANDATORY: enable interrupts on pins 9-10 by changing line 228 to "#define PCINT_ENABLE_PORT1" in PinChangeInterruptSettings.h

const byte numPins = 8;// number of pins to output binary number on.
byte pins[] = {0, 1, 2, 3, 4, 5, 6, 7}; //array of which pins to use for those bits.
int encoderPinA = 9; // Quadrature encoder leg A pin location
int encoderPinB = 10; // Quadrature encoder leg B pin location
volatile unsigned int count = 0; // Holds encoder count.
static boolean rotating = false; // debounce management
boolean A_set = false;
boolean B_set = false;

void setup() {

  DDRA = 0b11111111; // set all output pins.
  DDRB = 0b00000000; // set the interrupt inputs (last 2 bytes are all we need for Pin9-10).
  attachPCINT(digitalPinToPCINT(encoderPinA), encodedA, CHANGE);
  attachPCINT(digitalPinToPCINT(encoderPinB), encodedB, CHANGE);
}

void loop() {
  rotating = true;  // reset the debouncer when interrupt code is not running.
  //if (count>255) count = count-256;
  //if (count<0) count = count+256;
  PORTA=count;
/*  for (byte i = 0; i < numPins; i++) { // this loop outputs the binary equivalent of 'count' to the output pins.
    byte state = bitRead(count, i);
    digitalWrite(pins[i], state);
  }*/
}

void encodedA() {
  if (rotating) delayMicroseconds(250);  // small delay to debounce.
  if (PINB & 0b00000001) { // Low to High transition?
    A_set = true;
    count = (B_set) ? count - 1 : count + 1;
  } else { // High to Low transition
    A_set = false;
    count = (B_set) ? count + 1 : count - 1;
  }
  rotating = false;
}

void encodedB() {
  if (rotating) delayMicroseconds(250);  // small delay to debounce.
  if (PINB & 0b00000010) { // Low to High transition?
    B_set = true;
    count = (A_set) ? count + 1 : count - 1;
  } else { // High to Low transition
    B_set = false;
    count = (A_set) ? count - 1 : count + 1;
  }
  rotating = false;
}

ante
Apr 9, 2005

SUNSHINE AND RAINBOWS

FetusPorn posted:

Yeah, that seems to almost completely kill it... it must be a slow function. Thank you though!

Regardless of the rollover being constrained to 0-255 (with or without the clamping code I posted), I still get that strange output only with the port manipulation code, and not the for-loop.

The error appears to be something like ...253, 254, 255, 0, 255, 0, 1, 2... as the count goes up. It doesn't happen when going the other direction.

Here's the whole shebang:
code:
#include "PinChangeInterrupt.h" // MANDATORY: enable interrupts on pins 9-10 by changing line 228 to "#define PCINT_ENABLE_PORT1" in PinChangeInterruptSettings.h

const byte numPins = 8;// number of pins to output binary number on.
byte pins[] = {0, 1, 2, 3, 4, 5, 6, 7}; //array of which pins to use for those bits.
int encoderPinA = 9; // Quadrature encoder leg A pin location
int encoderPinB = 10; // Quadrature encoder leg B pin location
volatile unsigned int count = 0; // Holds encoder count.
static boolean rotating = false; // debounce management
boolean A_set = false;
boolean B_set = false;

void setup() {

  DDRA = 0b11111111; // set all output pins.
  DDRB = 0b00000000; // set the interrupt inputs (last 2 bytes are all we need for Pin9-10).
  attachPCINT(digitalPinToPCINT(encoderPinA), encodedA, CHANGE);
  attachPCINT(digitalPinToPCINT(encoderPinB), encodedB, CHANGE);
}

void loop() {
  rotating = true;  // reset the debouncer when interrupt code is not running.
  //if (count>255) count = count-256;
  //if (count<0) count = count+256;
  PORTA=count;
/*  for (byte i = 0; i < numPins; i++) { // this loop outputs the binary equivalent of 'count' to the output pins.
    byte state = bitRead(count, i);
    digitalWrite(pins[i], state);
  }*/
}

void encodedA() {
  if (rotating) delayMicroseconds(250);  // small delay to debounce.
  if (PINB & 0b00000001) { // Low to High transition?
    A_set = true;
    count = (B_set) ? count - 1 : count + 1;
  } else { // High to Low transition
    A_set = false;
    count = (B_set) ? count + 1 : count - 1;
  }
  rotating = false;
}

void encodedB() {
  if (rotating) delayMicroseconds(250);  // small delay to debounce.
  if (PINB & 0b00000010) { // Low to High transition?
    B_set = true;
    count = (A_set) ? count + 1 : count - 1;
  } else { // High to Low transition
    B_set = false;
    count = (A_set) ? count - 1 : count + 1;
  }
  rotating = false;
}

You're probably hitting interrupt encodedB(), and then it delays, and gets interrupted by encodedA()


Usuuuually you'd never ever want to put a delay in your interrupt for that reason, but considering your code is doing nothing else, you should be able to get away with just disabling the interrupt while it's running (also good practice generally)

code:
void encodedB() {
  disablePinChangeInterrupt(digitalPinToPCINT(encoderPinA));
  disablePinChangeInterrupt(digitalPinToPCINT(encoderPinB));
  if (rotating) delayMicroseconds(250);  // small delay to debounce.
  if (PINB & 0b00000010) { // Low to High transition?
    B_set = true;
    count = (A_set) ? count + 1 : count - 1;
  } else { // High to Low transition
    B_set = false;
    count = (A_set) ? count - 1 : count + 1;
  }
  rotating = false;
  enablePinChangeInterrupt(digitalPinToPCINT(encoderPinA));
  enablePinChangeInterrupt(digitalPinToPCINT(encoderPinB));
}

Sagebrush
Feb 26, 2012

If your goal is just to have the thing work, I would just the PJRC encoder library.

https://www.pjrc.com/teensy/td_libs_Encoder.html

I have used it on a number of rotary and linear encoders, including a linear encoder with 720 line pairs per inch that slides at several inches per second, and it's completely rock solid and reliable.

FetusPorn
Jul 7, 2003

WUGT: Creatures attack and block as normal, but none deal any damage during combat. All attacking creatures are still tapped. Use this ability any time

ante posted:

You're probably hitting interrupt encodedB(), and then it delays, and gets interrupted by encodedA()


Usuuuually you'd never ever want to put a delay in your interrupt for that reason, but considering your code is doing nothing else, you should be able to get away with just disabling the interrupt while it's running (also good practice generally)

code:
posted code

Thanks, Ante. I had looked into interrupts interrupting interrupt functions for this very reason and it seems that the consensus is that you can't have one interrupt function get interrupted by another (unless you do some tricky stuff, which I'm not). Regardless, I wrapped both of my interrupt functions in the dis/enable commands as you suggested, and the problem still exists.

As far as the delay, I've tried various values up to 2 millis and even removing it entirely. Surprisingly with no debounce, my encoder seems to be pretty stable, but the rollover issue persists in all instances.

SageBrush, I'll give this a shot. I'm not sure if it'll play nice with the TINY84, but this will be something to try tomorrow. Thank you!

To be clear though, it does work perfectly with the for-loop. Probably even fast enough for this application. I'm mostly just curious why the port manip. method is giving this error. Maybe someone who understands the low level stuff better can provide some insight.

FetusPorn fucked around with this message at 01:16 on Jun 3, 2020

Fanged Lawn Wormy
Jan 4, 2008

SQUEAK! SQUEAK! SQUEAK!
Here's something I've been meaning to write up for a while but have never gotten around to.

I write a lot of lighting animations, typically outputting via DMX or Pixel LED strips. For adaptability, I often wish I could come up with a lazier way to handle timing of these things.

For example, let's use the simplest example: a light that pulses. I typically use the [url="https:////https://github.com/FastLED/FastLED/wiki/High-performance-math"]FastLED[/url] "lerp" library. I typically prefer to use the 8by8 or 16by8 options, so I can keep my "fraction" that tracks speed of the animation as an 8 bit variable to save time. So, to determine how long an animation takes, I usually pick what I think will be a reasonable time, and then do the math to work out what would be best (ie; if I want it to take 1/4 of a second, I know that that's roughly 1 increment of the fract variable every 4-5 millis.) I can adjust the timing clock or the increment/decrement accordingly.

Only problem with this is that it's pretty rough and it can be annoying to re-calculate every time I do one of these.

So, I'm thinking the better solution is to come up with something that works more on human time, where I just tell my function the number of milliseconds (or seconds if it is a big one) I want a full animation to take. I figure there are a few ways to do this.

The best way I can figure mentally right now is to use a scale operation. let say I want it to take 1 second. I use a few 16 bit variables, something like this:
code:
dotheanimation(1000 ms, red)
{
findcurrentms()
frac16=scale(currentMS, MS, 0, 65535)
brightness = lerp16by16(a, b, frac16)
}
Is this the most efficient (without going into more-base level coding) kind of way to do this? I generally am working with 8 bit Arduinos, but I sometimes mess around with 32bit. I figure for my needs, most of the time an 8 bit is going to handle something like this fast enough to be fine, but I always have a lingering fear that something I'm doing (let's say calculating 200 values, all requiring stepping through essentially 2 scaling operations) is going to get slowness problems.


Ugh, I'm a bit burnt out from thinking on this to the point I'm not sure I'm communicating well.

mod sassinator
Dec 13, 2006
I came here to Kick Ass and Chew Bubblegum,
and I'm All out of Ass
I like to do animations with sine waves, like generating a signal. So like if I want a smooth glowing pulse up and down I use the current time in seconds (computed from a millisecond tick count / 1000) as an input to a simple sine wave function like:

amplitude * sin(2*pi*frequency*time + phase) + offset

You can play with the values to start getting an intuition about how they respond, but basically:

- Amplitude, use a value of 1 and by definition you'll only ever get an output between -1 and +1 from the sine wave. You can scale this value up and down with different amplitude values.

- Frequency, this is how many times the sine wave will do a complete up and down cycle within a second. Use low fractional values like 1/4 to stretch this out longer than a second, or small values like 2-3 for 'faster' cycling.

- Time, feed this in in seconds. Or if you scale all the other constants appropriate you could directly use millisecond ticks--the sine wave equation doesn't really care about the scale or absolute value of this value.

- Phase, use this to control where in the wave cycle the sine wave starts. You can just keep this zero and it's fine, when I usually use it is if I have multiple things animating and I don't want them all 'stuck' at the same cycle going up and down in lock step. I've done fun things like set the phase randomly for a bunch of independent sine wave animations to get neat organic looking flashes.

- Offset, you'll get a value from the sine function that goes from negative to positive values so add an offset if you need the values to be all positive. Or I usually just throw the output of the sine function right into a linear interpolation function that expects a negative to positive range and scales to a linear output value within the range I'm trying to set (like 0-255 color component values for LEDs).

The possibilities here are pretty limitless and if you structure your code and dev environment in a way to quickly iterate you can play with the values to find something that gets an effect you're after. And thinking again like a signal processing problem, you can go absolutely wild with more complexity by driving those constants above with sine wave functions themselves--like changing the frequency, amplitude, etc. over time with a sine wave. Or a cosine wave, tanget, etc.--there are a world of possibilities and wild things to explore. Exponential growth and decay functions are other fun ones for heartbeats and fast pulses.

Making animations procedural mathematical functions like that makes things so much easier I've found. I don't have to worry about any state other than a monotonically increasing tick count so the animation functions are simple and fast, just computing a bunch of math. It's all about finding the right knobs to give yourself to tweak and adjust the animations.

Forseti
May 26, 2001
To the lovenasium!
I think you may have been born in the wrong decade:

https://www.youtube.com/watch?v=0wxc3mKqKTk

(Good advice though)

(Also I want to play with a Scanimate so bad, it looks awesome)

mod sassinator
Dec 13, 2006
I came here to Kick Ass and Chew Bubblegum,
and I'm All out of Ass
Yep! That's exactly how I think of animations in my head--it's all just an analog synth. Someday I'll get around to doing a project to make a moog like console that drives neopixels.

FetusPorn
Jul 7, 2003

WUGT: Creatures attack and block as normal, but none deal any damage during combat. All attacking creatures are still tapped. Use this ability any time
UPDATE:

I gotta thank SageBrush. I still don't know why my thing wasn't working, but with the encoder library I was able to get an even faster, and completely accurate result with this beautifully simple code:

code:
#include "Encoder.h"
Encoder myEnc(8, 9); // Start encoder. Only pin 8 is an ext interrupt, but this library handles it very nicely.
volatile unsigned int count = 0; // Holds encoder count.

void setup() {
  DDRA = 0b11111111; // set all output pins.
}

void loop() {
  count=myEnc.read(); // Read encoder value
  PORTA=count; // Output binary value to output pins.
}
Yeah, I know all the dirty business is hidden in the #include, but I'm gonna have to dig into that to see how they got it to be so optimized.

The only caveat was that the encoder library doesn't work with the ATTINY84 out of the box. To enable it, I had to add these 4 lines to the interrupt_pins.h file

code:
// ATtiny44 ATtiny84
#elif defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#define CORE_NUM_INTERRUPT  1
#define CORE_INT0_PIN   8
Thanks again!

Fanged Lawn Wormy
Jan 4, 2008

SQUEAK! SQUEAK! SQUEAK!

mod sassinator posted:

I like to do animations with sine waves, like generating a signal. So like if I want a smooth glowing pulse up and down I use the current time in seconds (computed from a millisecond tick count / 1000) as an input to a simple sine wave function like:

amplitude * sin(2*pi*frequency*time + phase) + offset

You can play with the values to start getting an intuition about how they respond, but basically:

- Amplitude, use a value of 1 and by definition you'll only ever get an output between -1 and +1 from the sine wave. You can scale this value up and down with different amplitude values.

- Frequency, this is how many times the sine wave will do a complete up and down cycle within a second. Use low fractional values like 1/4 to stretch this out longer than a second, or small values like 2-3 for 'faster' cycling.

- Time, feed this in in seconds. Or if you scale all the other constants appropriate you could directly use millisecond ticks--the sine wave equation doesn't really care about the scale or absolute value of this value.

- Phase, use this to control where in the wave cycle the sine wave starts. You can just keep this zero and it's fine, when I usually use it is if I have multiple things animating and I don't want them all 'stuck' at the same cycle going up and down in lock step. I've done fun things like set the phase randomly for a bunch of independent sine wave animations to get neat organic looking flashes.

- Offset, you'll get a value from the sine function that goes from negative to positive values so add an offset if you need the values to be all positive. Or I usually just throw the output of the sine function right into a linear interpolation function that expects a negative to positive range and scales to a linear output value within the range I'm trying to set (like 0-255 color component values for LEDs).

The possibilities here are pretty limitless and if you structure your code and dev environment in a way to quickly iterate you can play with the values to find something that gets an effect you're after. And thinking again like a signal processing problem, you can go absolutely wild with more complexity by driving those constants above with sine wave functions themselves--like changing the frequency, amplitude, etc. over time with a sine wave. Or a cosine wave, tanget, etc.--there are a world of possibilities and wild things to explore. Exponential growth and decay functions are other fun ones for heartbeats and fast pulses.

Making animations procedural mathematical functions like that makes things so much easier I've found. I don't have to worry about any state other than a monotonically increasing tick count so the animation functions are simple and fast, just computing a bunch of math. It's all about finding the right knobs to give yourself to tweak and adjust the animations.

This is way more helpful than you might expect - part of the reason I'm struggling w/ this is that I am working with some prototype code from another developer, and it literally is a sine wave function of the same construction. I took Trig back in high school, but it's been years, and I recall very little of it. I had de-constructed through some online graphing calculator work - offset, phase, etc.

I'm thinking a little more about it now, and I'm beginning to understand better. I usually think of things only in 0-255, but yeah, signed variables would allow negative values, and that's okay if I just scale it to what I want.

My only concern is that bit about what you have about frequency - I've always strictly avoided floating point to keep things moving quickly. FastLED has some 8 and 16bit sine/cosine functions. They take an unsigned int for "angle" and then output a signed int of the same type. Would manipulating something like this work better for me processor-speed wise than dealing with floating points? Or, if i'm working with a 32bit controller (as I increasingly am), is it moot?

I really gotta test out the DMX library I found for a 32bit stuff. I have a shield built for it, but haven't had the time to test it.

Sagebrush
Feb 26, 2012

FetusPorn posted:

UPDATE:

I gotta thank SageBrush. I still don't know why my thing wasn't working, but with the encoder library I was able to get an even faster, and completely accurate result with this beautifully simple code:

Yeah, I know all the dirty business is hidden in the #include, but I'm gonna have to dig into that to see how they got it to be so optimized.

Thanks again!

:cheers: yeah, I mean, while I do write my own libraries and (sometimes) have fun doing it, when you just want something to work, sometimes there isn't any point in duplicating effort. In some cases it's actually a really bad idea to try to write it yourself (e.g. cryptography). Paul Stoffregen of PJRC is a really talented guy and I trust all of his libraries to generally be faster and cleaner than anything I could come up with on my own.

(when you dig into it you'll probably find a lot of assembly and bitwise operations)

Fanged Lawn Wormy
Jan 4, 2008

SQUEAK! SQUEAK! SQUEAK!
Paul's a turbonerd and I am thankful he exists.

Adbot
ADBOT LOVES YOU

Forseti
May 26, 2001
To the lovenasium!
I doubt you'd notice it either way unless you have other stuff going on that's already pushing the limits of the processor but unless you have an FPU int is probably quite a bit faster. Without knowing the specifics though if FastLED is general purpose it probably doesn't make a difference what size integers you're using (in terms of execution speed, it should still save you memory), they all probably use a 32-bit instruction when they get to the processor.

Plenty of 32-bit MCUs do have an FPU though (eg STM32F3) which should be more or less the same speed as the integer instructions.

If you really want to go down the rabbit hole, you can look at the DSP instructions :v: This gives you things like instructions that operate on multiple smaller ints at a time (eg two 16-bit ints in one instruction). I don't know if the compiler will do it for you with the right flags or if you actually need to write some assembly chunks though. My guess would be there are libraries somewhere that make use of them for their math functions.

Really though, your best bet is probably to write it in a way that's easy to understand and only worry about optimizing it if it's too slow when you test it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply