body:
I have a Teensy 3.2 and I am using the Arduino IDE to program it. I am trying to generate 8 pulses with the frequency of 40 kHz and this needs to be repeated every second. I have written 3 different codes and none of them is working quite the way I wanted. The duty cycle of the pulses are not always constant (i.e. the falling edge often shifts in the time axis), indicating an inaccuracy with the delay between the `analogWrite` commands. There seems to be an issue with delays not being consistent and changing within the 8 pulses and between the 8 pulses. **This inaccuracy is different between the 3 different codes, but exists in all of them.** Changing the processor speed between 16 MHz and 120 MHz does not appear to change the problem (except in code 3 where NOP is dependent on it). Is there a way to make the cycles more consistent at 40 kHz? Do I need to use an external timer or oscillator? The two images below display the two problems. The first image shows the differences in time delays and output frequency. The red dashed lines are provided to show the discrepancy in the same pulse at successive iterations of the code. The second image shows a recurring issue where the square wave is not in fact a square, and doesn't seem to be caused by software problems.

**Image 1:**

[![enter image description here][1]][1]

**Image 2:**

[![enter image description here][2]][2]

The codes I have written can be found below:

**Code 1:**

    const uint8_t pin1 = 5;
    const uint8_t pin2 = 6;

    void setup() {
      analogWriteFrequency(pin1, 40000);
      analogWriteFrequency(pin2, 40000);
    }

    void loop() {
      analogWrite(pin1,128);   //for 50% duty cycle
      delayMicroseconds(188);  //It takes 187.5us to generate 8 pulses at the given frequency
      analogWrite(pin1,0);
      delay(1000);
    }

**Code 2:**

    const uint8_t pin1 = 5;
    const uint8_t pin2 = 6;

    void setup() {
      pinMode(pin1, OUTPUT);
      pinMode(pin2, OUTPUT);
    }

    void loop() {
      PWMSignal();
      delay(1000);
    }

    void PWMSignal(){
      for(int i =0; i<=8; i++){
          analogWrite(pin1, 255);
          analogWrite(pin2, 0);
          delayMicroseconds(10);
          analogWrite(pin1, 0);
          analogWrite(pin2, 255);
          delayMicroseconds(10);
          analogWrite(pin2, 0);
      }
    }

**Code 3:**

    const uint8_t pin1 = 5;
    const uint8_t pin2 = 6;

    // Variable N determines the length of the delay.
    // Execution of NOP corresponds to 62.5ns delay
    // when the processor speed is 16 MHz.
    const int N = 50;
    #define NOP __asm__ __volatile__ ("nop\n\t")

    void setup() {
      pinMode(pin1, OUTPUT);
      pinMode(pin2, OUTPUT);
    }

    void loop() {
      PWMSignal();
      delay(1000);
    }

    void PWMSignal(){
      for(int i =0; i<=8; i++){
          analogWrite(pin1, 255);
          analogWrite(pin2, 0);
          delayNOP();
          analogWrite(pin1, 0);
          analogWrite(pin2, 255);
          delayNOP();
          analogWrite(pin2, 0);
      }
    }

    void delayNOP(){
      for(int j =0; j<=N; j++){
        NOP;
      }
    }
  [1]: https://i.stack.imgur.com/RHMK1.jpg
  [2]: https://i.stack.imgur.com/sruwb.jpg

title: Inaccurate PWM Signal Frequency and Timing

Answers: 2

body:
One option is to use the [IntervalTimer](https://www.pjrc.com/teensy/td_timing_IntervalTimer.html) of the Teensy:

    // Set up the variables and objects:
    IntervalTimer myTimer;
    volatile int count = 0;

    // ... later, start it:
    count = 0;
    myTimer.begin(togglePin, 12);

    // ... and:
    void togglePin() {
        GPIOB_PTOR = 1<<8; // Note: find the right register and bit for your chosen pin.
        count++;
        // 16  toggles is 8 pulses.
        if (count == 16) {
            myTimer.end();
        }
    }

Note: this hasn't been tested, and you will need to do some research to get the right register and bit number, and also configure the pin for output and to your default level.

body:
it seems in the first picture that the two pulses have different duty cycles which is why it appears shifted. It looks like the 'on' part stays on for less time than the 'off' so your duty cycle is probably <50 but your frequency might still be 40kHz.

I think the most accurate way of getting 40kHz just with a teensy is to use timer interrupts as Majenko suggested. Check out the documentation for it [here], its pretty straight forward,you set the timer to go off every 12.5us and in the ISR simply toggle a digital pin and keep count of how many times you've toggled it. If your teensy needs to run other interrupts you should change the priority using myTimer.priority(number); to possibly give the 40kHz interrupt a higher priority. One thing, don't use digitalWrite in the ISR as its slow af, either try digitalWriteFast or use assembly language to toggle it as pointed by Majenko.

Alternatively you could use a 555 timer which is easy to setup and I'm pretty sure it's been used to gerate 40kHz at 50% duty cycle, although it might be a bit tricky finding the correct capacitor/resistor values if they're too small/non-standard. Then you would hook up the output of the 555 timer to whatever you're hooking it up to and also to a digital input pin on the micro. Then you would have to set an external interrupt on that pin so whenever the 555 goes high the interrupt on the pin would fire and you would keep track of how many pulses have been generated.

Alternatively, you could use a digital signal synthesizer. I used the ad9837 for one of my projects. It can generate something like 0-3Mhz with a 5Mhz external clock at a resolution of 0.02 which is pretty good. I've got an altium design for it if you don't want to buy the module and an adapted version of the adafruit miniGen library which works with teensy3.5 [link]. Then you'd need to do the same feedback loop as the 555 to keep track of how many pulses have been produced (or your way of waiting X microseconds). The module is actually pretty low power so you could power it from a digital pin and turn that pin on/off every second.

I think you should try the interrupt method first, as it's the easiest. Also, I get that you want 8 pulses evey one second but maybe for debugging purposes have the 40kHz pulse go constantly and change your scope to measure frequency so you can see how far off you are from 40khz.Then once you know you're actually getting 40khz have it run every 1second.

  [here]: https://www.pjrc.com/teensy/td_timing_IntervalTimer.html
  [link]: https://www.sparkfun.com/products/11420


body:
I have a sketch containing the following method:

    // Writes zeros to the complete screen clearing it:
    void clearScreen(uint8_t val) {
      setDrawArea(0x00, 0x7f, 0x00, 0x07); // complete screen
      SSD1306.ssd1306_send_data_start();
      for (int c = 0; c < 128 * 8; c++) {
        SSD1306.ssd1306_send_byte(val);
      }
      SSD1306.ssd1306_send_data_stop();
    }

The whole sketch compiles with a size of 6730 Bytes. While refactoring the code I mistakenly changed "c" to uint8_t. After this I compiled to 4124 Bytes. Does this come from the compiler recognizing that the loop condition will never be reached and cut off all code behind or is this some kind of strange optimization event? I'm asking because I can't test the sketch in the moment.

title: Changing type of one variable dramatically changes compile size

Answers: 1

body:
Without being able to proof it (since I don't have your libraries and you gave only a small part of the sketch), I think this is what happens:

user3629249 is half right. If you change `c` to type `uint8_t` it only has 8 bits (hence the Name), so its maximum value will be 255. When you add 1 to it at this value, the variable will overflow and going back to 0. Thats normal overflow behavior, like used with the Arduinos Timer registers. (No undefined behavior there) So the maximum value `c` can reach is 255.

When compared to a bigger literal the value of `c` gets promoted to the correct type, so that the two values can be compared. But a variable that is at maximum 255 is always lower than 128*8. So you have an infinite loop there. The compiler can see this and doesn't include the functions from the rest of `clearScreen()`, since that is unreachable code.

All in all your code won't work as intended with `uint8_t`. You need a bigger type, that can hold the full range, that you operate. And this optimization is not strange, but very reasonable, since you really don't need the rest of `clearScreen()` in that case.


body:
I want to do on-chip-debugging on an [Arduino Mega](https://store.arduino.cc/arduino-mega-2560-rev3).
According to its [datasheet](http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf), the ATmega2560 chip supports JTAG. (IEEE 1149.1 compliant)

Can I use a generic FT2232H interface to do on-chip-debugging on this?

How would a OpenOCD config file look like for this purpose?

Thanks in advance!

title: OpenOCD with FT2232H on Arduino Mega (ATmega2560)

Answers: 1

body:
The [chip][1] seems to support it:
>Multi-Protocol Synchronous Serial Engine (MPSSE) to simplify synchronous serial protocol (USB to JTAG, I2C, SPI or bit-bang) design.

You'll have to play with the drivers,
and check to see that Arduino brought all the JTAG pins out to header pins.

[1]: http://www.ftdichip.com/Products/ICs/FT232H.htm


body:
I'm using a 2N2222 transistor as a low-side switch to turn a 5V computer fan on and off with an Arduino digital pin, which responds programmatically to a button press - i.e. the relevant digital pin is switched from LOW to HIGH for a determined time in response to a button press recorded on A0.

My circuit looks like this:
[![enter image description here][1]][1]

And here's my code:

    #define btnPin A0
    #define signalPin 6

    void setup() {
      pinMode(btnPin, INPUT_PULLUP);
      pinMode(signalPin, OUTPUT);
      digitalWrite(signalPin, LOW);
    }

    void loop() {
      if(digitalRead(btnPin) == LOW){
      digitalWrite(signalPin, HIGH);
      delay(5000);
      digitalWrite(signalPin, LOW);
      }
    }

For simplicity, I'm showing a separate button component in the diagram, but I'm actually using a button that's wired into an LCD shield.

My expectation is that, when I press the button, the digital pin wired to the transistor's base will cause the transistor to close the circuit and turn the fan (and LED) on for five seconds.

The problem that I have is that the Arduino's digital pin doesn't seem to be able to saturate the base, so not enough current passes through the transistor to power the fan. It does turn the LED on and off as expected, but the fan needs much more current than the LED. If I take a wire directly from VIN or the 5V pin and touch it to base (through a resistor, of course), it does succeed in saturating the base, and the fan turns on. Measuring the current from VIN (or the 5V pin) to base, I get 4mA, so my assumption is that 4mA is sufficient to saturate the base. My understanding is that an Arduino digital pin should easily supply this. But in my case, the current from the relevant digital pin to the transistor's base never goes higher than 1.4mA. I've tried different pins on the board, but always get the same result.

So the question is, why does the circuit work as expected for the LED, but not for the fan? Any help/suggestions will be greatly appreciated!

  [1]: https://i.stack.imgur.com/urEI2.jpg

title: Switching external power supply to 5V cooling fan with an Arduino and 2N2222 transistor

Answers: 4

body:
To fully turn the transistor on you should give the base somewhere around 1/10 to 1/20 of the collector current. If you read the datasheet for the [PN2222][1] (a highly recommended activity) you will see that Vce(sat) is specified with Ic/Ib = 10.

Now, the Microchip ATMega328 MCU chip in many (but not all) Arduinos is capable of sourcing 10mA or 15mA with minimal drop (assuming a 5V supply), again this information is available in the MCU datasheet (Figure 31-71 on page 355).

So it appears you are using an "Arduino" with some other MCU. In which case you can either use another transistor to boost the current or substitute a logic-level MOSFET.

  [1]: https://www.onsemi.com/pub/Collateral/PN2222-D.PDF

body:
Based on the description of your circuit, it sounds like you might not have connected the Arduino's ground to the "negative rail", the same part of the circuit where the transistor's emitter is connected. You must make that connection in order to properly bias the base-emitter junction of the transistor.

I recommend you draw a schematic for this sort of question, that would be helpful.

body: I seem to have solved the problem. As mentioned in the question, I was using a button wired into an LCD shield. As the LCD shield occupies all the header pins on the Arduino, the LCD shield helpfully provides circuit connections for the unused Arduino pins. It seems that the LCD shield I was using has some fault which only allowed limited current to flow from the corresponding Arduino pins. This would explain the anomaly that only the LED lit up as expected, but the fan failed to work: presumably the weak current into the transistor's Base created sufficient gain to power the LED, but not the fan. Eventually, after many attempts at getting the circuit to work, even the LED stopped working and that's when I realised that there must be a continuity problem with the header connections. So, removing the LCD shield and wiring everything directly into the Arduino with a separate push button, everything started working as expected. Many thanks for all the helpful replies. I've got a much better handle on how BJTs work now!

body:
You should also have a diode across the motor, cathode to 5V and anode to the transistor.
When the transistor turns off, the motor will try and keep the 200mA current flowing. The diode lets that current dissipate. Without it, you can get a high voltage spike at the transistor which can damage it.


body:
I'm trying to make my Arduino Uno control the air conditioner by recording the raw IR signal of several of the AC remotes temperatures using AnalysisIR. However these IR codes are quite long (array with 343 items).

Declaring more than one IR code in a variable shows me the error:
"Global variables use 2064 bytes (100%) of dynamic memory, leaving -16 bytes for local variables. Maximum is 2048 bytes."

However, as seen in my code, I have declared the IR codes locally in a separate function to send them to the air conditioner. I don't understand why i get the error saying the global variables are taking up too much dynamic memory.

Isn't the space taken up by the local variable supposed to be freed up from the SRAM once the functions runs because I have declared the variable locally?

Thanks in advance.

Code:

<!-- language-all: c++ -->

    #include <IRremote.h>

    IRsend irsend;

    int khz = 38;

    void send23()
    {

      unsigned int irSignal[]= {9048, 4496, 620, 1636, 620, 1636, 620, 520, 620, 520, 620, 524, 624, 524, 620, 532, 620, 1648, 620, 508, 620, 1640, 620, 1644, 620, 520, 620, 528, 616, 528, 620, 532, 624, 516, 620, 1636, 620, 516, 616, 520, 620, 520, 620, 524, 620, 528, 616, 536, 620, 520, 620, 508, 620, 1640, 620, 520, 620, 520, 620, 1648, 620, 1656, 620, 1656, 616, 524, 620, 508, 620, 516, 616, 520, 620, 520, 624, 520, 620, 528, 620, 532, 620, 520, 620, 508, 624, 508, 624, 516, 616, 520, 624, 524, 620, 524, 620, 532, 620, 504, 620, 7956, 616, 512, 620, 1640, 616, 520, 620, 520, 620, 524, 620, 528, 620, 528, 624, 1644, 620, 1636, 616, 1640, 624, 1640, 620, 1648, 616, 528, 620, 1652, 620, 532, 620, 520, 620, 512, 620, 512, 620, 516, 620, 524, 620, 524, 616, 528, 620, 532, 620, 520, 620, 508, 620, 512, 624, 512, 620, 520, 620, 520, 620, 528, 620, 532, 620, 520, 620, 508, 620, 516, 620, 516, 620, 520, 620, 524, 620, 524, 624, 528, 624, 516, 620, 508, 620, 512, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 620, 520, 624, 504, 624, 512, 620, 516, 624, 516, 620, 524, 620, 524, 624, 528, 620, 520, 624, 504, 624, 1636, 624, 1640, 624, 1640, 624, 1648, 620, 524, 624, 1656, 624, 1624, 624, 7952, 616, 512, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 624, 520, 624, 504, 624, 1636, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 628, 516, 624, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 620, 528, 628, 512, 624, 508, 624, 508, 624, 512, 620, 520, 620, 524, 624, 520, 624, 528, 624, 516, 620, 508, 624, 508, 624, 512, 624, 1640, 624, 520, 624, 524, 624, 528, 624, 512, 628, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 624, 516, 620, 508, 624, 1632, 628, 508, 628, 1640, 624, 520, 624, 524, 620, 528, 624, 500, 608};
      irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); //Note the approach used to automatically calculate the size of the array.
    }

    void send22()
    {

      unsigned int irSignal[]=  {8988, 4548, 572, 1688, 572, 1688, 600, 532, 572, 568, 572, 572, 576, 572, 572, 580, 572, 1724, 544, 556, 576, 1684, 600, 1660, 608, 532, 604, 540, 608, 540, 600, 548, 608, 536, 604, 1652, 608, 520, 616, 524, 608, 532, 612, 532, 612, 532, 620, 532, 616, 524, 620, 512, 616, 1644, 624, 508, 628, 516, 624, 520, 628, 1676, 596, 1648, 632, 508, 632, 500, 632, 500, 632, 504, 636, 504, 636, 512, 628, 516, 632, 524, 628, 508, 636, 496, 632, 504, 628, 508, 632, 508, 632, 512, 632, 516, 632, 516, 632, 496, 628, 7948, 628, 500, 632, 1656, 600, 508, 628, 508, 632, 512, 632, 516, 632, 524, 628, 1636, 632, 496, 632, 504, 632, 504, 632, 508, 632, 1672, 600, 1672, 600, 520, 632, 508, 632, 500, 652, 480, 632, 504, 632, 512, 628, 512, 632, 516, 632, 520, 632, 508, 632, 496, 632, 504, 632, 504, 632, 508, 632, 516, 628, 520, 628, 520, 656, 484, 632, 500, 656, 476, 656, 480, 632, 508, 632, 516, 632, 512, 656, 496, 632, 508, 632, 500, 652, 480, 632, 504, 656, 484, 656, 488, 632, 516, 632, 520, 632, 508, 632, 500, 656, 476, 632, 508, 656, 484, 656, 488, 656, 492, 632, 520, 656, 484, 656, 1632, 624, 476, 632, 508, 656, 484, 656, 1620, 652, 488, 656, 1656, 600, 1648, 604, 7948, 656, 472, 656, 476, 660, 480, 632, 508, 656, 488, 652, 496, 656, 492, 656, 484, 632, 500, 656, 1608, 628, 504, 656, 484, 656, 488, 656, 492, 656, 496, 656, 484, 632, 496, 656, 480, 632, 504, 656, 484, 656, 488, 632, 516, 656, 496, 628, 508, 660, 472, 656, 480, 656, 480, 652, 488, 656, 488, 656, 492, 652, 496, 660, 484, 656, 472, 632, 504, 652, 484, 652, 1644, 624, 488, 656, 492, 656, 492, 632, 512, 628, 500, 664, 468, 656, 480, 656, 488, 652, 488, 656, 492, 656, 492, 632, 512, 652, 476, 656, 1632, 624, 484, 652, 1644, 620, 492, 656, 488, 628, 524, 652, 472, 608};
      irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); //Note the approach used to automatically calculate the size of the array.
    }

    void setup()
    {
      Serial.begin(9600);
      pinMode(13,OUTPUT);
      delay(2000);
      send23();
      delay(2000);
      send22();
    }

    void loop() {

    }

EDIT 05/07:

Here is my new code with the use of PROGMEM.

As you can see, i have initialized the progmem arrays globally at the top of the program. When i do this, my SRAM is not full anymore but sendraw in the functions does not work anymore.

Weirdly however, when i declare the progmem variable INSIDE the send23() function (IN COMMENTS), the sendraw works! But the variable takes up space in the SRAM again and it says that Global variables have used 100% of dynamic memory.

Why does this happen and what can i do to work around it?

PROGMEM updated code:

    #include <IRremote.h>

    const unsigned int irSignal23[] PROGMEM = {9048, 4496, 620, 1636, 620, 1636, 620, 520, 620, 520, 620, 524, 624, 524, 620, 532, 620, 1648, 620, 508, 620, 1640, 620, 1644, 620, 520, 620, 528, 616, 528, 620, 532, 624, 516, 620, 1636, 620, 516, 616, 520, 620, 520, 620, 524, 620, 528, 616, 536, 620, 520, 620, 508, 620, 1640, 620, 520, 620, 520, 620, 1648, 620, 1656, 620, 1656, 616, 524, 620, 508, 620, 516, 616, 520, 620, 520, 624, 520, 620, 528, 620, 532, 620, 520, 620, 508, 624, 508, 624, 516, 616, 520, 624, 524, 620, 524, 620, 532, 620, 504, 620, 7956, 616, 512, 620, 1640, 616, 520, 620, 520, 620, 524, 620, 528, 620, 528, 624, 1644, 620, 1636, 616, 1640, 624, 1640, 620, 1648, 616, 528, 620, 1652, 620, 532, 620, 520, 620, 512, 620, 512, 620, 516, 620, 524, 620, 524, 616, 528, 620, 532, 620, 520, 620, 508, 620, 512, 624, 512, 620, 520, 620, 520, 620, 528, 620, 532, 620, 520, 620, 508, 620, 516, 620, 516, 620, 520, 620, 524, 620, 524, 624, 528, 624, 516, 620, 508, 620, 512, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 620, 520, 624, 504, 624, 512, 620, 516, 624, 516, 620, 524, 620, 524, 624, 528, 620, 520, 624, 504, 624, 1636, 624, 1640, 624, 1640, 624, 1648, 620, 524, 624, 1656, 624, 1624, 624, 7952, 616, 512, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 624, 520, 624, 504, 624, 1636, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 628, 516, 624, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 620, 528, 628, 512, 624, 508, 624, 508, 624, 512, 620, 520, 620, 524, 624, 520, 624, 528, 624, 516, 620, 508, 624, 508, 624, 512, 624, 1640, 624, 520, 624, 524, 624, 528, 624, 512, 628, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 624, 516, 620, 508, 624, 1632, 628, 508, 628, 1640, 624, 520, 624, 524, 620, 528, 624, 500, 608};
    const unsigned int irSignal22[] PROGMEM = {8988, 4548, 572, 1688, 572, 1688, 600, 532, 572, 568, 572, 572, 576, 572, 572, 580, 572, 1724, 544, 556, 576, 1684, 600, 1660, 608, 532, 604, 540, 608, 540, 600, 548, 608, 536, 604, 1652, 608, 520, 616, 524, 608, 532, 612, 532, 612, 532, 620, 532, 616, 524, 620, 512, 616, 1644, 624, 508, 628, 516, 624, 520, 628, 1676, 596, 1648, 632, 508, 632, 500, 632, 500, 632, 504, 636, 504, 636, 512, 628, 516, 632, 524, 628, 508, 636, 496, 632, 504, 628, 508, 632, 508, 632, 512, 632, 516, 632, 516, 632, 496, 628, 7948, 628, 500, 632, 1656, 600, 508, 628, 508, 632, 512, 632, 516, 632, 524, 628, 1636, 632, 496, 632, 504, 632, 504, 632, 508, 632, 1672, 600, 1672, 600, 520, 632, 508, 632, 500, 652, 480, 632, 504, 632, 512, 628, 512, 632, 516, 632, 520, 632, 508, 632, 496, 632, 504, 632, 504, 632, 508, 632, 516, 628, 520, 628, 520, 656, 484, 632, 500, 656, 476, 656, 480, 632, 508, 632, 516, 632, 512, 656, 496, 632, 508, 632, 500, 652, 480, 632, 504, 656, 484, 656, 488, 632, 516, 632, 520, 632, 508, 632, 500, 656, 476, 632, 508, 656, 484, 656, 488, 656, 492, 632, 520, 656, 484, 656, 1632, 624, 476, 632, 508, 656, 484, 656, 1620, 652, 488, 656, 1656, 600, 1648, 604, 7948, 656, 472, 656, 476, 660, 480, 632, 508, 656, 488, 652, 496, 656, 492, 656, 484, 632, 500, 656, 1608, 628, 504, 656, 484, 656, 488, 656, 492, 656, 496, 656, 484, 632, 496, 656, 480, 632, 504, 656, 484, 656, 488, 632, 516, 656, 496, 628, 508, 660, 472, 656, 480, 656, 480, 652, 488, 656, 488, 656, 492, 652, 496, 660, 484, 656, 472, 632, 504, 652, 484, 652, 1644, 624, 488, 656, 492, 656, 492, 632, 512, 628, 500, 664, 468, 656, 480, 656, 488, 652, 488, 656, 492, 656, 492, 632, 512, 652, 476, 656, 1632, 624, 484, 652, 1644, 620, 492, 656, 488, 628, 524, 652, 472, 608};
    const unsigned int irSignal21[] PROGMEM = {9044, 4496, 624, 1628, 628, 1592, 668, 508, 628, 512, 628, 516, 628, 520, 628, 524, 628, 1636, 632, 500, 628, 1632, 624, 1636, 628, 512, 628, 520, 628, 516, 628, 524, 628, 512, 628, 1628, 628, 512, 620, 512, 624, 516, 628, 516, 628, 520, 628, 524, 628, 512, 628, 500, 632, 1628, 628, 512, 628, 512, 628, 1644, 628, 520, 628, 1648, 628, 512, 628, 504, 624, 508, 628, 508, 632, 508, 628, 516, 632, 516, 628, 524, 628, 512, 628, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 500, 624, 7948, 628, 504, 628, 1628, 628, 512, 624, 516, 624, 516, 628, 520, 628, 524, 628, 1636, 628, 504, 624, 1632, 628, 508, 628, 512, 628, 1640, 628, 1648, 628, 520, 628, 512, 628, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 516, 628, 524, 628, 512, 628, 500, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 500, 632, 504, 628, 508, 628, 512, 624, 520, 624, 520, 628, 524, 624, 516, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 504, 628, 504, 628, 508, 624, 516, 628, 512, 628, 520, 628, 524, 624, 516, 628, 1624, 628, 1632, 628, 508, 628, 512, 628, 516, 628, 1644, 628, 1648, 628, 1620, 628, 7944, 628, 500, 628, 504, 628, 512, 624, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 504, 624, 1636, 624, 508, 632, 508, 628, 516, 628, 520, 628, 520, 632, 512, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 516, 628, 500, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 512, 628, 504, 624, 508, 628, 508, 628, 1640, 624, 516, 628, 520, 628, 524, 624, 516, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 512, 628, 504, 628, 1632, 624, 512, 628, 1640, 624, 516, 628, 520, 628, 524, 628, 492, 612};

    IRsend irsend;

    int khz = 38;

    void send23()
    {

    //  const unsigned int irSignal23[] PROGMEM = {9048, 4496, 620, 1636, 620, 1636, 620, 520, 620, 520, 620, 524, 624, 524, 620, 532, 620, 1648, 620, 508, 620, 1640, 620, 1644, 620, 520, 620, 528, 616, 528, 620, 532, 624, 516, 620, 1636, 620, 516, 616, 520, 620, 520, 620, 524, 620, 528, 616, 536, 620, 520, 620, 508, 620, 1640, 620, 520, 620, 520, 620, 1648, 620, 1656, 620, 1656, 616, 524, 620, 508, 620, 516, 616, 520, 620, 520, 624, 520, 620, 528, 620, 532, 620, 520, 620, 508, 624, 508, 624, 516, 616, 520, 624, 524, 620, 524, 620, 532, 620, 504, 620, 7956, 616, 512, 620, 1640, 616, 520, 620, 520, 620, 524, 620, 528, 620, 528, 624, 1644, 620, 1636, 616, 1640, 624, 1640, 620, 1648, 616, 528, 620, 1652, 620, 532, 620, 520, 620, 512, 620, 512, 620, 516, 620, 524, 620, 524, 616, 528, 620, 532, 620, 520, 620, 508, 620, 512, 624, 512, 620, 520, 620, 520, 620, 528, 620, 532, 620, 520, 620, 508, 620, 516, 620, 516, 620, 520, 620, 524, 620, 524, 624, 528, 624, 516, 620, 508, 620, 512, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 620, 520, 624, 504, 624, 512, 620, 516, 624, 516, 620, 524, 620, 524, 624, 528, 620, 520, 624, 504, 624, 1636, 624, 1640, 624, 1640, 624, 1648, 620, 524, 624, 1656, 624, 1624, 624, 7952, 616, 512, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 624, 520, 624, 504, 624, 1636, 624, 512, 624, 516, 624, 520, 624, 524, 624, 524, 628, 516, 624, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 620, 528, 628, 512, 624, 508, 624, 508, 624, 512, 620, 520, 620, 524, 624, 520, 624, 528, 624, 516, 620, 508, 624, 508, 624, 512, 624, 1640, 624, 520, 624, 524, 624, 528, 624, 512, 628, 504, 624, 508, 624, 512, 624, 516, 624, 520, 624, 524, 624, 528, 624, 516, 620, 508, 624, 1632, 628, 508, 628, 1640, 624, 520, 624, 524, 620, 528, 624, 500, 608};
      irsend.sendRaw(irSignal23, sizeof(irSignal23) / sizeof(irSignal23[0]), khz); //Note the approach used to automatically calculate the size of the array.
    }

    void send22()
    {
    //  const unsigned int irSignal22[] PROGMEM = {8988, 4548, 572, 1688, 572, 1688, 600, 532, 572, 568, 572, 572, 576, 572, 572, 580, 572, 1724, 544, 556, 576, 1684, 600, 1660, 608, 532, 604, 540, 608, 540, 600, 548, 608, 536, 604, 1652, 608, 520, 616, 524, 608, 532, 612, 532, 612, 532, 620, 532, 616, 524, 620, 512, 616, 1644, 624, 508, 628, 516, 624, 520, 628, 1676, 596, 1648, 632, 508, 632, 500, 632, 500, 632, 504, 636, 504, 636, 512, 628, 516, 632, 524, 628, 508, 636, 496, 632, 504, 628, 508, 632, 508, 632, 512, 632, 516, 632, 516, 632, 496, 628, 7948, 628, 500, 632, 1656, 600, 508, 628, 508, 632, 512, 632, 516, 632, 524, 628, 1636, 632, 496, 632, 504, 632, 504, 632, 508, 632, 1672, 600, 1672, 600, 520, 632, 508, 632, 500, 652, 480, 632, 504, 632, 512, 628, 512, 632, 516, 632, 520, 632, 508, 632, 496, 632, 504, 632, 504, 632, 508, 632, 516, 628, 520, 628, 520, 656, 484, 632, 500, 656, 476, 656, 480, 632, 508, 632, 516, 632, 512, 656, 496, 632, 508, 632, 500, 652, 480, 632, 504, 656, 484, 656, 488, 632, 516, 632, 520, 632, 508, 632, 500, 656, 476, 632, 508, 656, 484, 656, 488, 656, 492, 632, 520, 656, 484, 656, 1632, 624, 476, 632, 508, 656, 484, 656, 1620, 652, 488, 656, 1656, 600, 1648, 604, 7948, 656, 472, 656, 476, 660, 480, 632, 508, 656, 488, 652, 496, 656, 492, 656, 484, 632, 500, 656, 1608, 628, 504, 656, 484, 656, 488, 656, 492, 656, 496, 656, 484, 632, 496, 656, 480, 632, 504, 656, 484, 656, 488, 632, 516, 656, 496, 628, 508, 660, 472, 656, 480, 656, 480, 652, 488, 656, 488, 656, 492, 652, 496, 660, 484, 656, 472, 632, 504, 652, 484, 652, 1644, 624, 488, 656, 492, 656, 492, 632, 512, 628, 500, 664, 468, 656, 480, 656, 488, 652, 488, 656, 492, 656, 492, 632, 512, 652, 476, 656, 1632, 624, 484, 652, 1644, 620, 492, 656, 488, 628, 524, 652, 472, 608};
      irsend.sendRaw(irSignal22, sizeof(irSignal22) / sizeof(irSignal22[0]), khz); //Note the approach used to automatically calculate the size of the array.
    }

    void send21()
    {
    //  const unsigned int irSignal21[] PROGMEM = {9044, 4496, 624, 1628, 628, 1592, 668, 508, 628, 512, 628, 516, 628, 520, 628, 524, 628, 1636, 632, 500, 628, 1632, 624, 1636, 628, 512, 628, 520, 628, 516, 628, 524, 628, 512, 628, 1628, 628, 512, 620, 512, 624, 516, 628, 516, 628, 520, 628, 524, 628, 512, 628, 500, 632, 1628, 628, 512, 628, 512, 628, 1644, 628, 520, 628, 1648, 628, 512, 628, 504, 624, 508, 628, 508, 632, 508, 628, 516, 632, 516, 628, 524, 628, 512, 628, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 500, 624, 7948, 628, 504, 628, 1628, 628, 512, 624, 516, 624, 516, 628, 520, 628, 524, 628, 1636, 628, 504, 624, 1632, 628, 508, 628, 512, 628, 1640, 628, 1648, 628, 520, 628, 512, 628, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 516, 628, 524, 628, 512, 628, 500, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 500, 632, 504, 628, 508, 628, 512, 624, 520, 624, 520, 628, 524, 624, 516, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 504, 628, 504, 628, 508, 624, 516, 628, 512, 628, 520, 628, 524, 624, 516, 628, 1624, 628, 1632, 628, 508, 628, 512, 628, 516, 628, 1644, 628, 1648, 628, 1620, 628, 7944, 628, 500, 628, 504, 628, 512, 624, 512, 628, 516, 628, 520, 628, 520, 628, 512, 628, 504, 624, 1636, 624, 508, 632, 508, 628, 516, 628, 520, 628, 520, 632, 512, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 516, 628, 500, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 512, 628, 504, 624, 508, 628, 508, 628, 1640, 624, 516, 628, 520, 628, 524, 624, 516, 624, 504, 628, 504, 628, 508, 628, 512, 628, 516, 628, 520, 628, 524, 624, 512, 628, 504, 628, 1632, 624, 512, 628, 1640, 624, 516, 628, 520, 628, 524, 628, 492, 612};
      irsend.sendRaw(irSignal21, sizeof(irSignal21) / sizeof(irSignal21[0]), khz); //Note the approach used to automatically calculate the size of the array.
    }

    void setup()
    {
      Serial.begin(9600);
      pinMode(13, OUTPUT);
      send23();
      Serial.println("done");
      delay(4000);
      send22();
      Serial.println("done");
      delay(4000);
      send21();
      Serial.println("done");
    }

    void loop() {
    }

title: Locally declared variable takes up global variable space in dynamic memory/SRAM

Answers: 2

body:
> Isn't the space taken up by the local variable supposed to be freed up
> from the SRAM once the functions runs because I have declared the
> variable locally?

This is correct. The local arrays you have take up RAM only while the
corresponding function is executing. They do not consume any static RAM
(i.e. .data and .bss, what the Arduino IDE improperly calls “Global
variables”).

The problem is not the arrays themselves, but rather the data used to
initialize them. As an experiment, you can try to change the array
definitions as follows:

<!-- language-all: lang-c++ -->

    unsigned int irSignal[343];

You will see the memory consumption reported by the IDE drop by
4×343 bytes. The local arrays are still there. They use RAM (from
the stack) when the functions execute. Only you have removed the
matching initializers.

I disassembled a slightly modified copy of your program just to see how
the compiler handles it. I will not post the assembly code here, as I
guess not many people here are fluent in AVR assembly. Instead, I will
attempt to translate the assembly back to C in the most straightforward
way. The compiler interpreted the function `send23()` as follows:

    static const unsigned int anonymous_array_1[343] = {9048, ...};

    void send23()
    {
        unsigned int irSignal[343];
        for (int i = 0; i < 343; i++)
            irSignal[i] = anonymous_array_1[i];
        irsend.sendRaw(irSignal, 343, khz);
    }

What is taking up static RAM is not the local arrays, it's the global
anonymous arrays that hold the initialization data. You may notice that
making the arrays local has actually worsened the problem: while
`send23()` executes, you have _two copies_ of the data in RAM.

The solution, as Jot and Juraj said in comments, is to put the arrays in
`PROGMEM`. If it doesn't work, then you have a bug. You should fix the
bug instead of trying to avoid `PROGMEM`.

body:
You must declare the array in global space or `static`, and make sure the function you pass the buffer pointer to knows it is in PROGMEM.

    void send22()
    {

      static unsigned int irSignal[] PROGMEM=  {8988, 4548, 572, 1688, 572, 1688, 600, 532, 572, 568, 572, 572, 576, 572, 572, 580, 572, 1724, 544, 556, 576, 1684, 600, 1660, 608, 532, 604, 540, 608, 540, 600, 548, 608, 536, 604, 1652, 608, 520, 616, 524, 608, 532, 612, 532, 612, 532, 620, 532, 616, 524, 620, 512, 616, 1644, 624, 508, 628, 516, 624, 520, 628, 1676, 596, 1648, 632, 508, 632, 500, 632, 500, 632, 504, 636, 504, 636, 512, 628, 516, 632, 524, 628, 508, 636, 496, 632, 504, 628, 508, 632, 508, 632, 512, 632, 516, 632, 516, 632, 496, 628, 7948, 628, 500, 632, 1656, 600, 508, 628, 508, 632, 512, 632, 516, 632, 524, 628, 1636, 632, 496, 632, 504, 632, 504, 632, 508, 632, 1672, 600, 1672, 600, 520, 632, 508, 632, 500, 652, 480, 632, 504, 632, 512, 628, 512, 632, 516, 632, 520, 632, 508, 632, 496, 632, 504, 632, 504, 632, 508, 632, 516, 628, 520, 628, 520, 656, 484, 632, 500, 656, 476, 656, 480, 632, 508, 632, 516, 632, 512, 656, 496, 632, 508, 632, 500, 652, 480, 632, 504, 656, 484, 656, 488, 632, 516, 632, 520, 632, 508, 632, 500, 656, 476, 632, 508, 656, 484, 656, 488, 656, 492, 632, 520, 656, 484, 656, 1632, 624, 476, 632, 508, 656, 484, 656, 1620, 652, 488, 656, 1656, 600, 1648, 604, 7948, 656, 472, 656, 476, 660, 480, 632, 508, 656, 488, 652, 496, 656, 492, 656, 484, 632, 500, 656, 1608, 628, 504, 656, 484, 656, 488, 656, 492, 656, 496, 656, 484, 632, 496, 656, 480, 632, 504, 656, 484, 656, 488, 632, 516, 656, 496, 628, 508, 660, 472, 656, 480, 656, 480, 652, 488, 656, 488, 656, 492, 652, 496, 660, 484, 656, 472, 632, 504, 652, 484, 652, 1644, 624, 488, 656, 492, 656, 492, 632, 512, 628, 500, 664, 468, 656, 480, 656, 488, 652, 488, 656, 492, 656, 492, 632, 512, 652, 476, 656, 1632, 624, 484, 652, 1644, 620, 492, 656, 488, 628, 524, 652, 472, 608};
      irsend.sendRaw_P(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
      // _P postfix is often used to mark functions taking in PROGMEM pointers
    }

You can adjust the library to allow it to take PROGMEM buffers, with a quick search for the implementation of `IRsend::sendRaw` it gave me:

    void  IRsend::sendRaw (const unsigned int buf[],  unsigned int len,  unsigned int hz)
    {
     // Set IR carrier frequency
     enableIROut(hz);

     for (unsigned int i = 0;  i < len;  i++) {
      if (i & 1)  space(buf[i]) ;
      else        mark (buf[i]) ;
     }

     space(0);  // Always end with the LED off
    }

To make it work with progmem you can create:

    void  IRsend::sendRaw_P (const unsigned int buf[],  unsigned int len,  unsigned int hz)
    {
     // Set IR carrier frequency
     enableIROut(hz);

     for (unsigned int i = 0;  i < len;  i++) {
            unsigned int word = pgm_read_word_near(buf + i);
      if (i & 1)  space(word) ;
      else        mark (word) ;
     }

     space(0);  // Always end with the LED off
    }


body:
I am trying to make a cooler using Peltier Modules, the Peltier Modules and the fans switch on when the Temperature sensor attached to the circuit reads above a certain threshold. But I know that Arduino can only handle a couple of MilliAmps as its functionality, in such a case, how can I control my 480W circuitry (12V/40A) using Arduino?

I'm very new to all this and will appreciate a detailed answer.

**EDIT: To the best of my knowledge, this is not a duplicate of another question as the other question says *I'm currently working on several projects that each require controlling devices ranging from 800mA to 2A from an Arduino Uno.*, whereas my application requires much larger current than that.**

title: Connecting Arduino to a Peltier Module

Answers: 2

body: You are correct the Arduino can only handle a few mA at 5V.  In order to do what you want you need to use the Arduino to switch relays that can handle the current.

body:
There are solid-state relays ([such as this one][1]) capable of switching the currents - 40A - you're talking about and may be a better choice than a mechanical one. Note that it will probably need to be mounted to a heat-sink.

You're Arduino then only needs to drive enough current to switch the relay. The example I gave above is not a recommendation as I've never used it; it's just the first one I found that is spec'd for enough more than 40 Amps to not be operating at its limit. I'm sure there are others as well.

The current it will draw from the Arduino is not specified; this is something you will need to find out about whatever relay you choose, to be sure it won't exceed the Arduino's 20 mA pin-driver spec. It *is* spec'd to require a heat sink.

  [1]: https://www.amazon.com/100A-Solid-State-Relay-SSR/dp/B00KO46YCU/ref=pd_sim_328_5?_encoding=UTF8&pd_rd_i=B00KO46YCU&pd_rd_r=4b333d0d-7f8f-11e8-8042-83a887e2fe6a&pd_rd_w=Fvady&pd_rd_wg=q5eaE&pf_rd_i=desktop-dp-sims&pf_rd_m=ATVPDKIKX0DER&pf_rd_p=7967298517161621930&pf_rd_r=BF7KSJ9443M6RVCHP2QC&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&psc=1&refRID=BF7KSJ9443M6RVCHP2QC


body:
I am trying to make a library for Arduino, which requires an interruption, but the problem is that when I try the `attachInterrupt` function inside my library, there's a problem about attachInterrupt is static. Right now, in the library I have this in the header file:

    #ifndef RegletaCMA_h
    #define RegletaCMA_h

    #include "Arduino.h"

    class DimmerGlider {
    public:
        DimmerGlider(int min, int max, int increase);

        int getMin() { return _min; }

        int getMax() { return _max; }

        int getIncrease() { return _increase; }

        void setMin(int min) { _min = min; }

        void setMax(int max) { _max = max; }

        void setIncrease(int increase) { _increase = increase; }

    private:
        int _min, _max, _increase;
    };

    class Dimmer {

    public:
        Dimmer(DimmerGlider &glider, int outputPin, int t3);

        void Dimmer::begin() {
            pinMode(_outputPin, OUTPUT);
            digitalWrite(_outputPin, false);
        }

        void Dimmer::dim() {
            delayMicroseconds(_DIMMER_counter);
            digitalWrite(_outputPin, true);  // Turn _DIMMER_pinDimmer on
            delayMicroseconds(_t3);
            digitalWrite(_outputPin, false); // Turn _DIMMER_pinDimmer off

            if (_DIMMER_dir) _DIMMER_counter += _glider.getIncrease(); // If dir is negative add _DIMMER_increase
            else _DIMMER_counter -= _glider.getIncrease();                  // If dir is negative substract _DIMMER_increase

            if (_DIMMER_counter > _glider.getMax()) _DIMMER_dir = false; // Change dir if reached bottom
            if (_DIMMER_counter < _glider.getMin()) _DIMMER_dir = true;  // Change dir if reached top

            _DIMMER_lastExecutionTime_micros = micros(); // Reset timer
        }

        void Dimmer::force(bool status) {
            digitalWrite(_outputPin, status);
        }

    private:
        DimmerGlider &_glider;

        int _outputPin;

        int _DIMMER_counter = 1000;
        bool _DIMMER_dir = true;

        unsigned long long _DIMMER_lastExecutionTime_micros = 0;

        int _t3;
    };

    class DimmerImplementor {
    public:
        DimmerImplementor(Dimmer dimmerList[], int optoPin);

        void DimmerImplementor::begin(){
            attachInterrupt(_optoPin, dimAll, RISING);
        }

        void DimmerImplementor::dimAllDimmers() {
            for (int c = 0; c < sizeof(_dimmerList); c++)
                _dimmerList[c].dim();
        }

        void DimmerImplementor::dimAll() {
            DimmerImplementor::dimAllDimmers();
        }

    private:
        int _optoPin;
        Dimmer _dimmerList[];
    };

    #endif

and this in the cpp file:

    #include "Arduino.h"
    #include "RegletaCMA.h"

    DimmerGlider::DimmerGlider(int min, int max, int increase) :
            _min(min),
            _max(max),
            _increase(increase) {
    }

    Dimmer::Dimmer(DimmerGlider &glider, int outputPin, int t3) :
            _glider(glider),
            _outputPin(outputPin),
            _t3(t3) {
    }

    DimmerImplementor::DimmerImplementor(Dimmer *dimmerList, int optoPin) :
            _dimmerList(dimmerList),
            _optoPin(optoPin) {
        for(int c = 0; c < sizeof(dimmerList); c++){
            DimmerImplementor::dimmers[c] = dimmerList[c];
        }

        for (int c = 0; c < sizeof(dimmers); c++) {
            Dimmer dimmer = dimmers[c];

            dimmer.begin();
        }
    }

and when I try to run the library with the Arduino IDE, with this code:

    DimmerGlider dimmer1Glider = DimmerGlider(_DIMMER_1_tempMin, _DIMMER_1_tempMax, _DIMMER_1_increase);
    Dimmer dimmer1 = Dimmer(
                       dimmer1Glider,
                       _DIMMER_1_pin,
                       _DIMMER_t3
                     );
    DimmerGlider dimmer2Glider = DimmerGlider(_DIMMER_2_tempMin, _DIMMER_2_tempMax, _DIMMER_2_increase);
    Dimmer dimmer2 = Dimmer(
                       dimmer2Glider,
                       _DIMMER_2_pin,
                       _DIMMER_t3
                     );
    DimmerGlider dimmer3Glider = DimmerGlider(_DIMMER_3_tempMin, _DIMMER_3_tempMax, _DIMMER_3_increase);
    Dimmer dimmer3 = Dimmer(
                       dimmer3Glider,
                       _DIMMER_3_pin,
                       _DIMMER_t3
                     );

    Dimmer dimmers[] = {
      dimmer1, dimmer2, dimmer3
    };

    DimmerImplementor implementor = DimmerImplementor(dimmers, _DIMMER_pinOpto);

    void Dimmer_Init() {
      implementor.begin();
    }

It throws the following error:

    C:\Users\Arnym\Documents\Arduino\libraries\RegletaCMA/RegletaCMA.h: In member function 'void DimmerImplementor::begin()':

    C:\Users\Arnym\Documents\Arduino\libraries\RegletaCMA/RegletaCMA.h:73:44: error: invalid use of non-static member function

             attachInterrupt(_optoPin, dimAll, 3); // 3 is the same as RISING

                                                ^

I have been messing around with this problem for some days and I can't find an answer, so I would be really pleased if you can help me.
If you need any more info, don't doubt on asking.
Thanks in advance.

title: Attach Interrupt with Library

Answers: 2

body:
The error message says, that in the constructor of `Dimmer` it cannot find a matching constructor of `DimmerGlider`. The problem here is that you pass the parameters by value, which will create a new variable of the given type and content for the function/constructor call. So when you create a new `Dimmer` variable you are calling the constructor of the class. Since the parameters of the constructor contain a `DimmerGlider` instance, it also has to be created for you, which means calling the constructor. When passing variables by value the default constructor (without any parameters) is used. But the `DimmerGlider` doesn't have a default constructor (as you didn't define it). The compiler then tells you, that is needs some parameters for the constructor to create a `DimmerGlider` instance.

I don't know a way to pass these parameters for the `DimmerGlider` constructor directly through the `Dimmer` constructor. Also I don't think this is desirable for you. You are creating the `DimmerGlider` first and sure want the `Dimmer` objects to refer to exactly this instance, not a different (cloned) instance, that was created with the `Dimmer` constructor.

So my suggestion is the following: Pass the `DimmerGlider` by reference, meaning you only pass a pointer to the `DimmerGlider` object. In the constructor definition of `Dimmer` change to the following:

    Dimmer::Dimmer(DimmerGlider *glider, int outputPin, int t3);

The `*` says, that this variable will not hold an instance of the `DimmerGlider` class, but only a pointer to one. A pointer is simple to create, because it is basically an `unsigned int` (a 16 bit memory address).

Then in your sketch you are passing not the variable itself, but only the address in memory (a pointer to the object) by using the `&`:

    Dimmer dimmer1 = Dimmer(
                       &dimmer1Glider,
                       _DIMMER_1_pin,
                       _DIMMER_t3
                     );

Now the constructor of `Dimmer` doesn't have to create an instance of `DimmerGlider`, but only a simple pointer of the type `Dimmerglider`. The `&` retrieves the memory address (the pointer) of an object instance. The constructor now simply writes the pointer, that it got as a parameter, into the `glider` variable of type `DimmerGlider`-pointer.

If you don't understand, how pointers work, please google for a tutorial on this. This isn't something, that can be easily explained in the short question-answer format of this site.

body:
In C++, you need to distinguish between two separate copies of an object, or having a reference to an existing object. @chrisl got it right when he identified that you were trying to create a second copy of `DimmerGlider`, so he suggested using a reference - and then showed using a pointer (`*`) instead.

He was right: `Dimmer` should hold a *reference* to the `DimmerGlider` object, but that is done with `&`. You need to make the following changes to the given code:

In the `.h`:

    class Dimmer {

    public:
        Dimmer(DimmerGlider &glider, int outputPin, int t3);
    .
    .
    .
    private:
        DimmerGlider &_glider;
    .
    .

And in the final `.cpp`:

    DimmerGlider::DimmerGlider(int min, int max, int increase) :
                  _min(min),
                  _max(max),
                  _increase(increase) {
    }

    Dimmer::Dimmer(DimmerGlider &glider, int outputPin, int t3) :
            _glider(glider),
            _outputPin(outputPin),
            _t3(t3) {
    }

The syntax for the `Dimmer` constructor had to change. You were *assigning* the class members the values from the constructor parameters. References need to be ***initialised***, not assigned. This is the syntax you need (note how they’re before the `{`?)

I fixed the `DimmerGlider` constructor code while I was at it...

Also, note the difference between using a reference versus using a pointer. A pointer needs to be dereferenced, so you need to use `*ptr` and `ptr->_min` to refer to the original object. A reference is *already* dereferenced, so you can simply use it like the original object: `ref` and `ref._min`.

----

Edit: If you want to use the function `dimAll()` as an interrupt handler function, then it cannot be a (non-`static`) member of a `class`. All `class` functions have a hidden `this` pointer as the first parameter in the argument list, since it has to know *which* `DimmerImplementor`'s members to modify. Thus you have to declare the function as `static`. And as soon as you do that, you cannot call `dimAllDimmers()`, because that functions accesses an instance of `DimmerImplementor`'s variables. Luckily, you have a global object called `implementor`, so you could use that:

    static void DimmerImplementor::dimAll() {
        implementor.dimAllDimmers();
    }

But it's usual to make that variable a `static` member of the class itself:

    class DimmerImplementor {
        .
        .
    public: // Static variables
        static DimmerImplementor implementor;
        .
        .
    }; // DimmerImplementor

You'd initialise that as follows:

    DimmerImplementor DimmerImplementor::implementor(dimmers, _DIMMER_pinOpto);


body:
So I understand that the USB VBUS circuitry turns off provided there is a high enough vin voltage using the PFET and comparator.

I can see that the DC jack is connected to the Vin pin via a diode.
However, what is to stop someone from plugging a voltage source across the Vin and at the same time putting across a voltage on the DC jack.

If I incorrectly plugged in a voltage source of a low voltage like a coin cell battery across the VIN pin and also powered the device using the 9 V DC jack, wouldn't that then send current through the VIN pin and back to the coin cell battery?

Is that what would happen in this instance? And if so then shouldn't there be a design feature to prevent users from damaging it like that? Fool/fail safe?

title: Different voltage sources across Vin and DC jack

Answers: 1

body:
> wouldnt that then send current through the Vin pin and back to the coin cell battery? Is that what would happen in this instance?

Yep, that's right.

> shouldn't there be a design feature to prevent users from damaging it like that? Fool/fail safe?

No. VIN can also be VOUT. You can use it to power other things that want a higher voltage.


body:
So I've been working on a project over the last few month using homemade boards on a CAN bus. It's working well when using a board as a sender and another one as receiver.
I now have 3 boards and on which there are several sensor.
My purpose here is to be able for every board to share data and use other from another mcu.

An quick overview of the project for a better understanding :
I'm trying to automate a RC plane.

MCU-1 : Potentiometers + GPS

MCU-2 : 1 accelerometer + 1 barometer

MCU-3 : 1 differential pressure transmitter + 1 radio transmitter

I'd like to be able, for MCU-1 to receive and use data from MCU-2 and in the same time to transmit data to MCU-3. (They both have many more components and tasks to achieved, that why I don't have all the sensors on the same board)

I don't think it's important but MCU1 and 3 are ATmega328p (the one from the nano board) and MCU2 is an ATmega2560

My question :
Is it possible ? I mean is it possible to have a MCU running as a Sender and a Receiver at the same time ? and how to do it ? :)

Also is it possible to have a MCU running as a receiver, let's say 90% of the time and sender 10% (or after an update) ? If the first situation isn't possible this one could be a solution for my project.

Thank you

Undeadguy

title: Can Bus to receive and transmit on the same mcu

Answers: 1

body:
Yes, it is possible.

> CAN is a multi-master serial bus standard for connecting Electronic Control Units [ECUs] also known as nodes. Two or more nodes are required on the CAN network to communicate. The complexity of the node can range from a simple I/O device up to an embedded computer with a CAN interface and sophisticated software.
>
> -- *[Wikipedia](https://en.wikipedia.org/wiki/CAN_bus)*

You should understand how collision detection works in a multi-master CAN bus and ensure that you implement it (or it is implemented in your chosen CAN library) to allow reliable operation:

> The CAN specifications use the terms "dominant" bits and "recessive" bits where dominant is a logical 0 (actively driven to a voltage by the transmitter) and recessive is a logical 1 (passively returned to a voltage by a resistor). The idle state is represented by the recessive level (Logical 1). If one node transmits a dominant bit and another node transmits a recessive bit then there is a collision and the dominant bit "wins". This means there is no delay to the higher-priority message, and the node transmitting the lower priority message automatically attempts to re-transmit six bit clocks after the end of the dominant message. This makes CAN very suitable as a real time prioritized communications system.
>
> The exact voltages for a logical 0 or 1 depend on the physical layer used, but the basic principle of CAN requires that each node listens to the data on the CAN network including the transmitting node(s) itself (themselves). If a logical 1 is transmitted by all transmitting nodes at the same time, then a logical 1 is seen by all of the nodes, including both the transmitting node(s) and receiving node(s). If a logical 0 is transmitted by all transmitting node(s) at the same time, then a logical 0 is seen by all nodes. If a logical 0 is being transmitted by one or more nodes, and a logical 1 is being transmitted by one or more nodes, then a logical 0 is seen by all nodes including the node(s) transmitting the logical 1. When a node transmits a logical 1 but sees a logical 0, it realizes that there is a contention and it quits transmitting. By using this process, any node that transmits a logical 1 when another node transmits a logical 0 "drops out" or loses the arbitration. A node that loses arbitration re-queues its message for later transmission and the CAN frame bit-stream continues without error until only one node is left transmitting. This means that the node that transmits the first 1 loses arbitration. Since the 11 (or 29 for CAN 2.0B) bit identifier is transmitted by all nodes at the start of the CAN frame, the node with the lowest identifier transmits more zeros at the start of the frame, and that is the node that wins the arbitration or has the highest priority.
>
> For example, consider an 11-bit ID CAN network, with two nodes with IDs of 15 (binary representation, 00000001111) and 16 (binary representation, 00000010000). If these two nodes transmit at the same time, each will first transmit the start bit then transmit the first six zeros of their ID with no arbitration decision being made.


body:
Im trying to create a circuit so that I can monitor the voltage drop on my battery and send an message when the voltage drop reaches the drop out. But I'm having some problems with my voltage divisions.

I created this circuit to enable a flow so that it does not flow (drain the battery) while not necessary. But as I understand it analog input must not be above 1 volts.

[![enter image description here][1]][1]

The +3.3V represent the MCU (ESP-12, arduino with wifi) turning the circuit on, letting battery flow to the analog input (red circled ground). However, at analog input, the volt is 2,24V, which is more than the 1V it should be. Do I just divide it again? If I divide it again ill be at 1,12 so I need to divide it yet again. I don't think Im doing it right.

The maximum voltage of the analog pin on the ESP-12 is 1V. How can I get there?

  [1]: https://i.stack.imgur.com/xPEb6.png

title: How can I create a battery level circuit

Answers: 1

body:
Firstly, if I understand your schematic right, you're not "dividing" anything there. If the ringed red symbol is where you are connecting the ADC then either you will see near 4V on there (if it's *only* connected to the ADC), or 0V (if it's connected to ground).

You should be connecting the ADC *between* the resistors to get a reading.

Secondly, you should be using a P-channel MOSFET, not a PNP transistor. You *can* use a PNP transistor, but you will have to subtract the voltage drop imposed by the transistor from your calculations to get any meaningful reading. With a P-channel MOSFET, the on-resistance would be (or should be if you choose a sensible one) negligible compared to the resistance of the voltage divider.

You are right that you can't exceed 1V on the ADC, so you will have to size your resistors accordingly. You aren't restricted to just using a pair of 10K resistors - you can choose any values you like that yield the correct result.

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/GMlkS.png)

<!-- End schematic -->

In this example, 10K and 2.2K give you no more than 0.9V from a 5V input. (Tip: choose an input voltage slightly higher than you expect to give a small safety margin).

I calculated those by:

1. Use the voltage divider formula `R2 = R1×(1/((VIN/VOUT)-1))` to calculate the lower resistor (2500Ω).
2. Choose the next lowest "common" resitor (2200Ω)
3. Re-calculate the new output using the chosen resistor values using `VOUT = (R2/(R1+R2))×VIN` (0.9V)


body:
I want to create a system where the servo will make the ultrasonic sensor move and detect the area in front of it. I have made the program but when run the ultrasonic sensor can not detect as usual.

Does anyone have another program or why my program is not running as planned?

This is the source code :

    #include <Servo.h>

    const int trigPin = 10;
    const int echoPin = 9;
    int lampu = 13 ;

    // membuat nama objek servo untuk pengontrolan servo
    Servo myservo;
    // variable untuk menyimpan posisi servo
    int pos = 0;
    long duration, inches, cm;
    void setup() {
      Serial.begin(9600);
      pinMode(lampu, OUTPUT);
      myservo.attach(7);
    }

    void loop() {
      pinMode(trigPin, OUTPUT);
      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);
      pinMode(echoPin, INPUT);
      duration = pulseIn(echoPin, HIGH);
      inches = microsecondsKeInchi(duration);
      cm = microsecondsKeCenti(duration);
      Serial.print(inches);
      Serial.print(" in, ");
      Serial.print(cm);
      Serial.print(" cm");
      Serial.println();

      lampuNyala() ;
      servo();
      delay(10);
    }

    // start dari 0 derajar sampai 180 derajat
    long microsecondsKeInchi(long microseconds)
    {
      return microseconds / 74 / 2;
    }

    long microsecondsKeCenti(long microseconds)
    {
      return microseconds / 29 / 2;
    }

    void servo(){
      for(pos = 0; pos < 180; pos += 1)
      {
        // pada posisi 1 derajat
        // memberitahu servo untuk pergi ke posisi  'pos'
        myservo.write(pos);
        // tunggu 15ms untuk pencapaian  posisi servo
        delay(30);
      }
      // start dari 180 derajat ke 0 derajat
      for(pos = 180; pos>=1; pos-=1)
      {
        // memberitahu servo untuk pergi ke posisi  'pos'
        myservo.write(pos);
        // tunggu 15ms untuk pencapaian  posisi servo
        delay(30);
      }
    }

    void lampuNyala(){
      if(cm > 0 && cm <=30){
        digitalWrite(lampu,HIGH) ;
      }
      else{
        digitalWrite(lampu,LOW) ;
      }
    }

title: Make system with ultrasonic sensor and servo

Answers: 1

body:
Look at your code sequence. An ultrasonic measurement is only taken, when you use `pulseIn()`. At the end of the `loop()` function you call your `servo()` function. In it you tell the Arduino to first go from 0° to 180° and then back to 0°. AFTER THAT (!) the function exits and the `loop()` function continues. This means, that nothing else happens during the servo motion. The measurement only takes place between the motions, meaning about every 10s.

To solve this problem you need to make the servo code non-blocking. It is mostly a bad thing to use `delay()`, since you cannot do anything else during waiting. Think about how you are backing a pizza. You are not sitting in front of the oven the whole time, until the pizza is ready. Instead you are looking at your clock regularily and check, if it is time to take the pizza out of the oven.

You can do the same thing on an Arduino with the `millis()` function. It will return the milliseconds since the last reset/powerup of the Arduino. This has to be used as a clock. To do something after a specific time you first save the current time in a timestamp:

    unsigned long timestamp=0;
    ...
    timestamp = millis();

Then in the `loop()` function you are regularly (on every loop iteration) checking, if the difference between the timestamp and the current time is above your set interval:

    if(millis() - timestamp > 30){
        // do something here, like moving a servo
        timestamp = millis(); //update timestamp for next event
    }

The Arduino will not do the things simultaneously, but will switch between the different code parts so fast, that it will seem simultaneous. Also refer to the `BlinkWithoutDelay` example of the Arduino library.

Note: The current delay between two consecutive servo values is ok. If you want to go way faster with the servo, you have to watch out, that the rest of the code in `loop()` doesn't take to long. If this happens and you cannot make the other code parts non-blocking too, you can also do the servo part in an interrupt routine from a timer.


body:
Modified existing project from this link:  https://arduino.stackexchange.com/questions/47731/problem-trigger-limit-switch-to-stop-dc-motor

I modified this code to control two relays which are wired to motor poles for Forward or Reverse movements until they physically reach a limit switch on either side.

 - Serial input of 'A' turns on one relay. If `Limitswitch1` is pressed, this relay switches off.
 - It detects the current state of the system and awaits the Serial input of 'B' which then turns on the second relay. If `Limitswitch2` is pressed, this relay switches off.

The issues are:

 1. Please help with code - I require option where the two relays switch off on the serial input of letter 'S' and to add the corresponding state machine. Essentially to add a Stop function.

 2. The limit switches work intermittently, sometimes they respond flawlessly, sometimes not at all. I have bought three different brands of switches to test but all have the same behaviour. I have pulled switches up and down with resistors in vain. I have performed button count test using code from this forum and confirm that the switch also behaves erratically. Can changes to code improve switch feedback?

Suggestions will be greatly appreciated.

    const byte RELAY1 = 2;
    const byte RELAY2 = 3;

    const byte LimitSwitch1 = A1;
    const byte LimitSwitch2 = A2;

    const byte State_Idle = 0;
    const byte State_Forward = 1;
    const byte State_Reverse = 2;
    byte currentState;

    void setup(){
    pinMode(RELAY1,OUTPUT);
    pinMode(RELAY2,OUTPUT);

    pinMode(LimitSwitch1, INPUT);
    pinMode(LimitSwitch2, INPUT);

    Serial.begin(9600);
    currentState = 0xFF; // Force a change to enter the idle state
     }

    void loop(){
    // Check if we need to change state
    byte nextState = currentState;
    switch (currentState)
    {
    case State_Idle:
        { // If we received a valid command, start the operation
            if(Serial.available() > 0)
            {
                switch (Serial.read())
                {
                case 'A':
                    nextState = State_Forward;
                    break;
                case 'B':
                    nextState = State_Reverse;
                    break;
                default:
                    break;
                }
            }
        }
        break;
    case State_Forward:
        if(digitalRead(LimitSwitch2))
            nextState = State_Idle;
        break;
    case State_Reverse:
        if(digitalRead(LimitSwitch1))
            nextState = State_Idle;
        break;
    default:
        nextState = State_Idle;
        break;
    }

    // If there was a change, switch state and trigger enter condition
    if (nextState != currentState)
    {
        currentState = nextState; // Move in the new state
        switch (currentState)
        { // Entering the new state
        case State_Idle:
            // Switch both Relays OFF
            digitalWrite(RELAY1, HIGH);
            digitalWrite(RELAY2, HIGH);
            break;
        case State_Forward:
            // Move Forward
            digitalWrite(RELAY1, LOW);
            digitalWrite(RELAY2, HIGH);
            break;
        case State_Reverse:
            // Move Reverse
            digitalWrite(RELAY1, HIGH);
            digitalWrite(RELAY2, LOW);
            break;
        }
    }
    }

  [1]: https://arduino.stackexchange.com/questions/47731/problem-trigger-limit-switch-to-stop-dc-motor#/

title: Arduino Uno Motor control using 2 Relays, 2 Limit switches and Bluetooth. Forward Reverse Stop

Answers: 1

body:
Here I am again for another exciting episode of "Fun with StateMachines".. ;)

Ok, basically you modified the code well, but you thought of the modification in the wrong way.

First of all describe what you want to do in simple words. Let's say you want that

> When I'm moving in one direction and I receive the letter 'S', I immediately stop without waiting for the endstop

Consequently, you know that

 1. you will have to add something when you are moving in one direction
 1. this "something" will top you, which is what the endstop does

So, to implement this, you can do something like this:

    switch (currentState)
    {
    case State_Idle:
        { // If we received a valid command, start the operation
            if(Serial.available() > 0)
            {
                switch (Serial.read())
                {
                case 'A':
                    nextState = State_Forward;
                    break;
                case 'B':
                    nextState = State_Reverse;
                    break;
                default:
                    break;
                }
            }
        }
        break;
    case State_Forward:
        if(digitalRead(LimitSwitch2))
            nextState = State_Idle;
        else  if((Serial.available() > 0) && (Serial.read() == 'S'))
            nextState = State_Idle;
        break;
    case State_Reverse:
        if(digitalRead(LimitSwitch1))
            nextState = State_Idle;
        else  if((Serial.available() > 0) && (Serial.read() == 'S'))
            nextState = State_Idle;
        break;
    default:
        nextState = State_Idle;
        break;
    }

Now, your second problem is a bit harder to understand. When I read it, I immediately thought what chrisl already pointed out, which is switch bounces. But when I was halfway into completing this part of the answer I found out that.. no, the bounces are not what can give problems here, unless you are constantly writing 'A' or 'B' on the serial. So for the second part of the question please post your schematic and/or photos of the setup, so we can see if there is something not normal


body:
I am new to Arduino and I just made my first LED blink. I connected the LED to ground and digital pin 13 without resistance (for only a few seconds). Does this harm my Arduino?

Hilmi

title: Does blinking an LED with no resistor for a few seconds harm my Arduino?

Answers: 1

body: If you try it again with the proper resistor in place, and the pin still works, then no, you probably haven't damaged it. It may have stressed the pin driver some but if it passes the above test, I think you're still good to go.


body:
In my setup I have connected two arduino's Serially. An Arduino Mega is the on that is sending the string and a Arduino Uno is the one receiving it.

- Arduino Mega : RX1(19),TX1(18) - Serial1
- Arduino Uno : RX(10),TX(11)  - using SoftwareSerial
- Gnd is connecetd on both boards

When I send a single string from the mega to Uno multiple times(In void loop)
I receive the string sent infinite number of times on the Uno which is to be expected:

Arduino Mega - Single string sent multiple no. of times

    void setup()
    {
      Serial1.begin(9600);
    }
    void loop()
    {
      Serial1.println("e2e4");
      delay(100);
    }

Now I want to only send the string a single time, so I inserted an exit(0) or an infinite loop after the delay that is always true.

Arduino Mega - Single string sent only one time

    void setup()
    {
      Serial1.begin(9600);
    }
    void loop()
    {
      Serial1.println("e2e4");
      delay(100);
      while(true);
    }

Arduino UNO - code is same for both cases

    #include <SoftwareSerial.h>
    SoftwareSerial s(10, 11);
    void setup()
    {
      delay(200);
      Serial.begin(9600);
      s.begin(9600);
      while (!Serial) ;  // wait for Arduino Serial Monitor
    }
    void loop()
    {
      if(s.available()>0)
      {
         Serial.print("\nrec\n");
         delay(100);
         String b = s.readStringUntil('\n');
         delay(100);
         Serial.print(b);
         delay(40);
      }
   }

Note : Arduino uno is receiving the string using : readStringUntil('\n')

But when I send the string only once I receive nothing on the Arduino Uno, can anyone help me figure out why this is happening

What I want to know is why the uno receives the string only when it's sent an infinite number of times and not when it is sent 1 time.

EDIT (July 8)

Still haven't got a solution that I'm looking for, if anyone needs any extra information to help me out please mention it to me.

EDIT (July 8-9)

Sorry it's my fault for writing Tx1 as 19  and Rx1 as 18 although I did not make the same mistake in the code.
When I pressed the reset button on the mega the string was received on the uno side.How did this happen?  Until now, after I uploaded the code in both the arduino's I opened the serial monitor of the port connected to Uno and I did not receive the string.

Why do I need to reset the mega in order to send the string , shouldn't it work when the serial monitor is opened?

Also I need the mega to send the string automatically without any forced/physical reset is that possible?

I'm asking this because sending a string is part of a larger code where values get updated as time goes by,and a reset will  reset all the values to their original state which I don't want happening.

title: Arduino reads string from another Arduino only if the string is in a loop why?

Answers: 4

body:
exit(0) is not the command to use, it is used to completely stop the program, although I'm not sure what happens exactly for an Arduino sketch.

To stop a loop (and continue, normally a break statement is used. This works inside a while or for loop and the sketch continues after the while or for loop where the break statement is executed.

Note, you also can start at the beginning of the while or for loop with the continue statement.

body: `exit` turns off interrupts which will stop the serial output. I suggest something simpler like `while (true);`

body:
try putting a delay in the arduino mega code to make sure the uno is completely setup before it starts sending the data. I can see some delays in the uno code, so its possible that the arduino uno is not yet ready when the data is sent. Add a large delay, say 2000 to make sure uno is ready. Also there are neater ways to do this instead of just putting an infinite loop, unless the only goal of your program is just to send one string. You can use a flag that to disable sending.

    bool isSent = true;

    void loop()
    {
      if(isSent)
       {
         isSent = false;    // set to false so we will never send again.
         Serial1.println("e2e4");
       }
    }

body:
>  Until now, after I uploaded the code in both the arduino's I opened the serial monitor of the port connected to Uno and I did not receive the string.
>
> Why do I need to reset the mega in order to send the string , shouldn't it work when the serial monitor is opened?

Clearly there is a timing issue. When you open the serial monitor it resets the Arduino (in this case, I assume the Uno). So, the Uno resets, however the Mega doesn't reset because you didn't open the serial monitor there. Manually resetting the Mega forces it to send the data again (it would have sent it earlier when powered on).

In normal operation, of course you don't need to reset the Mega just to force a string "to be sent once". You have already proved that you can send a string many times, and sending a string once is clearly a subset of that situation. Sending n times is just (sending once) times n.

Your test setup, which requires powering both Arduinos at the same time, and then opening the serial monitor which resets one, but not the other, is what is confusing you. It is not that you can't send strings whenever you want, in normal operation.


body:
I have a project that is simply a relay timer. The code is not complete so you will see 'in progress' sections not related to my question in my code.

However, my question is...

I am creating a timer with 4 x 7 segment display using a rotary encoder to set the time. I have 3 'Modes' that allow me to increment the time by 1 second, 10 seconds and minutes. All this is working correctly however when I switch modes I would like to flash the corresponding digit to give a kind of visual feedback showing what mode you are in (the first digit for seconds, the second for 10 seconds etc..). I can manually ground the corresponding common pin to create that effect manually, however, I am having trouble with the code.

I have tried creating for loops that `digitalwrite()` to the specific comPin, however, this is just turning the entire display off and on. The section of code that I am looking at is roughly halfway down.

The Bonus Question: I would like the Dp to illuminate between the second and third digits to show "min:sec". I assume this must be to do with my byte table, however, this is all new to me and I am not sure of what direction to go regarding changes.

    #include <MD_REncoder.h>

    int LightClocksec = 0;
    int LightClockmin = 0;

    int LightClockAdd = 1;
    int Mode = 0;
    boolean LightSW = 5;

    int EncoderSW = 4;
    boolean EncoderSWstate = 0;
    MD_REncoder R1 = MD_REncoder(2, 3);

    int FocusSW = 13;
    boolean FocusSWstate = 0;
    boolean FocusSWstatePRE = 0;
    int FocusSWCounter = 0;

    int MainSW = 14;
    boolean MainSWstate = 0;
    boolean MainSWstatePRE = 0;

    int RelayPIN = 15;
    boolean Relaystate = LOW;

    unsigned long millispre = 0;

    int buttonPushCounter = 0;   // counter for the number of button presses
    int lastButtonState = 0;     // previous state of the button

    int latchPin = 7;          // Pin connected to ST_CP of 74HC595（Pin12）
    int clockPin = 8;          // Pin connected to SH_CP of 74HC595（Pin11）
    int dataPin = 6;           // Pin connected to DS of 74HC595（Pin14）
    int comPin[] = {12, 11, 10, 9};// Common pin (anode) of 4 digit 7-segment
    display

    byte num[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90,
    0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};

    void setup() {
      //  Serial.begin(9600);
      R1.begin();
      pinMode (LightSW, OUTPUT);
      pinMode (RelayPIN, OUTPUT);

      pinMode (EncoderSW, INPUT);
      pinMode (FocusSW, INPUT);

      pinMode(latchPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      pinMode(dataPin, OUTPUT);

    for (int i = 0; i < 4; i++) {
      pinMode(comPin[i], OUTPUT);
      }

    }

    void loop() {

      ///set time, encoder..

      EncoderSWstate = digitalRead(EncoderSW);

      uint8_t z = R1.read();
      if (z) {
        if (EncoderSWstate == 0) {
          if ((Mode == 2) )
          {
            z == DIR_CW ? LightClockmin ++  : LightClockmin --;
          }
          else if (Mode == 1) {
            z == DIR_CW ? LightClocksec = LightClocksec + 10  : LightClocksec = LightClocksec - 10 ;
            if (LightClocksec >= 60) {
              LightClocksec = (LightClocksec - 60);
              LightClockmin ++;
            }
            if ((LightClocksec < 0) && (LightClockmin >= 1 )) {
              LightClocksec = (60 - LightClockAdd) ;
              LightClockmin --;
            }
          }
          else if (Mode == 0) {
            z == DIR_CW ? LightClocksec ++  :  LightClocksec --;
            if (LightClocksec >= 60) {
              LightClocksec = (LightClocksec - 60);
              LightClockmin ++;
            }
            if ((LightClocksec < 0) && (LightClockmin >= 1 )) {
          LightClocksec = (60 - LightClockAdd) ;
          LightClockmin --;
        }
      }
      LightClocksec = constrain(LightClocksec, 0, 59);
      LightClockmin = constrain(LightClockmin, 0, 59);
    }

    if (EncoderSWstate == 1) {
      z == DIR_CW ? Mode -- : Mode ++ ;
      Mode = constrain(Mode, 0, 3);
      if (Mode == 0) {
        ////////STACK EXCHANGE?//// FLASH first digit on and off 5 times
      }

      if (Mode == 1) {
        ////////STACK EXCHANGE?//// FLASH second digit on and off 5 times
      }
      if (Mode == 2) {
       ////////STACK EXCHANGE?////  FLASH 3rd Digit On and of 5 times
      }
       }
     }

      ////switching

      FocusSWstate = digitalRead(FocusSW);
      MainSWstate = digitalRead(MainSW);

      if (FocusSWstate != FocusSWstatePRE ) {
        if (FocusSWstate == HIGH) {
          FocusSWCounter++;
        } else {}
      }

      FocusSWstatePRE  = FocusSWstate;
      if (FocusSWCounter % 2 == 0) {
        digitalWrite(RelayPIN, LOW);
      } else {
        digitalWrite(RelayPIN, HIGH);
      }

      if (MainSWstate != MainSWstatePRE ) {
        if (MainSWstate == HIGH) {
          digitalWrite(RelayPIN, HIGH);
          delay(((LightClockmin * 60) + (LightClocksec)) * 1000);
          digitalWrite(RelayPIN, LOW);
        }
        else {}
      }
      MainSWstatePRE  = MainSWstatePRE;

      //display

      byte bit[4];
      bit[0] = LightClocksec % 10;
      bit[1] = LightClocksec / 10 % 10;
      bit[2] = LightClockmin % 10;
      bit[3] = LightClockmin / 10 % 10;

      for (int i = 0; i < 4; i++) {
        chooseCommon(i);
        writeData(num[bit[3 - i]]);
        writeData(0xff);
      }
     }

    void chooseCommon(byte com) {
      // Close all single 7-segment display
      for (int i = 0; i < 4; i++) {
        digitalWrite(comPin[i], LOW);
      }
      // Open the selected single 7-segment display
      digitalWrite(comPin[com], HIGH);
    }

    void writeData(int evalue) {
      // Make latchPin output low level
      digitalWrite(latchPin, LOW);
      // Send serial data to 74HC595
      shiftOut(dataPin, clockPin, LSBFIRST, evalue);
      // Make latchPin output high level, then 74HC595 will update the data to parallel output
      digitalWrite(latchPin, HIGH);
    }

title: Flashing a specified digit 4x7 segment display and shift register 74HC595N

Answers: 1

body:
When displaying the digits you need to compare the current digit number (`i`) with the digit number you want to flash. If it's a match then either display the number, or don't display the number. How you make that decision is to examine `millis()`.

Take a look at the `BlinkWithoutDelay` example in the IDE to see how to make something flash without using `delay()`, and apply that knowledge to blinking a digit.


body:
I need to obtain 200 kHz from Arduino Uno. I am using `Timer0`. I have configured it to run in normal mode and the Prescaler is set to clk/8 (the clock frequency of Arduino is 16 MHz). `TCNT0` is set to `0xFB` and the code toggles 2 pins of `PORTB` as timer overflow flag is set.

Here is my code (I am using Atmel Studio 7):

    #include <avr/io.h>

    int main(void)
    {
       DDRB = 0x03;
       PORTB |= 0x02;
       while (1)
       {
           TCNT0 = 0xFB;
           TCCR0A = 0X00;
           TCCR0B = 0x02;
           while ( (TIFR0 & 0x01) == 0 );
           PORTB ^= 0x03;
           TCCR1A = 0x00;
           TCCR1B = 0x00;
           TIFR0 = 0X01;
      }
    }

When I check on the oscilloscope, it shows that the pulse is 166 kHz instead of 200 kHz. Although I can use Fast PWM Mode and use interrupts, I am just curious to know why it doesn't work? Did I make any mistake?

title: Generating 200 kHz pulse on Arduino Uno in normal mode

Answers: 1

body:
That's simple enough - you forgot that **everything takes time**.

Your timeline is:

1. Configure timer
2. Set count
3. Wait for count to overflow (33 ticks)
4. Toggle pin
5. Do something with T1 (why...?)
6. Clear overflow bit
7. Go back to 1.

Here's how that looks as assembly:

    90: 3b ef        ldi r19, 0xFB
    92: 42 e0        ldi r20, 0x02
    94: 23 e0        ldi r18, 0x03
    96: 91 e0        ldi r25, 0x01

    while (1) {
    98: 36 bd        out 0x26, r19 ; TCNT0 = 0xFB;
    9a: 14 bc        out 0x24, r1 ; TCCR0A = 0X00;
    9c: 45 bd        out 0x25, r20 ; TCCR0B = 0x02;

    while ( (TIFR0 & 0x01) == 0 );
    9e: a8 9b        sbis 0x15, 0
    a0: fe cf        rjmp .-4       ; 0x9e <setup+0xe>

    PORTB ^= 0x03;
    a2: 85 b1        in r24, 0x05
    a4: 82 27        eor r24, r18
    a6: 85 b9        out 0x05, r24

    a8: 10 92 80 00  sts 0x0080, r1
    ac: 10 92 81 00  sts 0x0081, r1
    b0: 95 bb        out 0x15, r25

    }
    b2: f2 cf        rjmp .-28

So assuming that the waiting for the timer overflow takes 8*4+
1=33 clock cycles, and referencing the datasheet for how long each instruction takes, we can add up everything in the main while loop:

    while (1) {
    98: 36 bd        out 0x26, r19 ; 1
    9a: 14 bc        out 0x24, r1 ; 1
    9c: 45 bd        out 0x25, r20 ; 1

    while ( (TIFR0 & 0x01) == 0 );
    9e: a8 9b        sbis 0x15, 0 ; 2 (at end)
    a0: fe cf        rjmp .-4     ; 33 (while running)

    PORTB ^= 0x03;
    a2: 85 b1        in r24, 0x05 ; 1
    a4: 82 27        eor r24, r18    ; 1
    a6: 85 b9        out 0x05, r24 ; 1

    a8: 10 92 80 00  sts 0x0080, r1  ; 2
    ac: 10 92 81 00  sts 0x0081, r1  ; 2
    b0: 95 bb        out 0x15, r25 ; 1

    }
    b2: f2 cf        rjmp .-28    ; 2

You can see that takes 48 clock cycles (We don't care about what is in the inner `while` except when it comes to finishing, and that's just the `SBIS` instruction). For 200kHz you want 40 clock cycles. You have 48. 16000000/48 = 333333. Divide by two for your pin toggling, and you get 166666Hz.

If you want to use this kind of method you need to ensure that the timer is completely free running and the overflow flag gets set at a regular interval, not just at 32 ticks after you start it.

You should be operating in CTC mode so it counts up from 0 to your target value and then resets back to 0 whilst setting the overflow flag. Your loop then looks like:

    while (1) {
        if ((TIFR0 & 0x01) == 0x01) {
            PORTB ^= 0x03;
        }
    }

All the timer configuration is done before the loop and it just runs and runs until you say otherwise.


body:
For those who use the IDE Platform IO, I have an issue for you. I use to program a home application of sensor reading and use the library "JC_Button.h" to manage buttons. There are other third-party libraries, but this in especial is cumbersome. The project tree is shown below.

[![project-tree][1]][1].

The compile log of the build is [here][2]. I have few notion of what is happening. In my opinion, the project does not find the necessary lib.

Thank you in advance.

  [1]: https://i.stack.imgur.com/moXcM.png
  [2]: http://codepad.org/x3uVz30U

title: Headers linking - PlatformIO

Answers: 1

body:
It looks like you are not telling PlatformIO that you need the JC_Button library. Try adding this to your `platformio.ini` file:

    lib_deps = https://github.com/JChristensen/JC_Button


body:
I'm a newbie in transistor switching.

I have PIR sensors with C and NC onboard. NC is 12 V signal that I need to switch transistor (bipolar?) to emit 3.3 V (collector connected to 3.3 V).

[![Fire and PIR circuit][1]][1]

VCC equals 3.3 V. PIR is pin on ESP32.

 - Can you tell me if this circuit is okay or does it need additional edits?

**Note**: Q3, Q4 transistor number is random, if you can offer me suitable transistor I would be glad.

Next circuit:

ESP32 pin "ALARM" is connected to transistor (MOSFET N channel) base.

[![Alarm circuit][2]][2]

ALARM as device is connected to 12 V, required 300 mA to run and I need transistor to switch circuit. Relay is awful.

 - Is this circuit correct?
 - Do I need any additional edits?
 - Can you suggest me suitable transistor?
 - I don't know much about MOSFET shortcuts.

Third circuit I need is same as this but instead 12 V I need to switch 5 V.

 - I guess just to change MOSFET transistor?
 - Or use same as for 12 V?

Combined circuit schematic:

[![Fire, PIR and Alarm circuit schematic][3]][3]

  [1]: https://i.stack.imgur.com/0gRPV.png "Fire and PIR circuit"
  [2]: https://i.stack.imgur.com/Fw09E.png "Alarm circuit"
  [3]: https://i.stack.imgur.com/IyeXR.png "Fire, PIR and Alarm circuit schematic"

title: Transistor as switch for signal and high current buzzer

Answers: 1

body:
I'll try to answer your post with "just words" and we will see how it goes. If it is not clear to you, i will post small schematic.

I do not recommend the first schematic that you posted.
You will likely reverse bias the BE (base emitter) junction with 12v. Most bipolar transistors have a maximum reverse BE bias of 5 v.

I do recommend using bipolar so that you dont have to study, understand the range of turn on voltages for a MOS transistor.

The bipolar is always 0.6v
and a Darlington bipolar is twice that.

Also, i dont know why you have the 100nF caps in there. They will guarantee a surge, everytime you turn the circuit on and hence put noise on your supply bus.

When I design a driver for a similar application i frequently use a TIP100 (https://www.digikey.com/product-detail/en/on-semiconductor/TIP100G/TIP100GOS-ND/1485300)

So use the basic design of your second circuit but use the TIP100.

ALWAYS have a resistor (10k ohms or so) to keep the leakage current (Icbo) from turning on the transistor when you dont want it on !

I would put all the loads into the Collector circuit in your second schematic, rather than make the uP drive your LED.

If your load is at all inductive (a coil) then ALWAYS put a reverse-biased diode across the load to catch any inductive kick back.

If this is all Greek to you, then just say so and I will draw a simple universal circuit that will work for 3.3v drive or 12v drive.

All the Best to you.
RP


body:
I'm programming an ESP8266 via the Arduino IDE with Arduino libraries.  I explicitly set the WiFi mode to `WIFI_AP`, but then, as described below, I'm still able to use it as both AP and station.  That leaves me unclear what's meant by the three modes available (`WIFI_AP`, `WIFI_STA`, and `WIFI_AP_STA`) since it seems that I've set to `WIFI_AP` explicitly but am getting behavior consistent with `WIFI_AP_STA`.

I have read various documents online about these modes. I think I'm clear on the conceptual difference between them.  What concerns / confuses me is that the actual behavior does not appear to match the specified behavior.

More detail:

Near the beginning of my `setup` function, I have this code

    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid, key);

    server.begin();

where `ssid` and `key` are strings defined with appropriate values, and `server` is a global variable of type `WiFiServer` that has been initialized outside of `setup`.  When run, I see the network with the given name on my phone and can connect to it with the given password.  I can then browse to the IP address assigned by the ESP8266 and set the webpage sent by the server that's been defined in code.  So far so good.

At some point later, inside my `loop`, a condition triggers the ESP8266 to connect to my router.  Specifically, I have this sequence of code that runs once that trigger occurs:

    WiFi.disconnect();
    WiFi.begin(router_ssid, router_key);
    auto status = WiFi.status();
    while ( (status != WL_CONNECTED) && (status != WL_CONNECT_FAILED) ) {
        delay(500);
        status = WiFi.status();
    }

As before, `router_ssid` and `router_key` are variables declared elsewhere with the proper values for my router.  I can verify from subsequent print statements, that the connection succeeds and get the IP address *as assigned by my router*. It is clear that the new IP is assigned by the router because it is on the subnet used by my router, which is different than the subnet the ESP8266 is defining in AP mode.

The ESP8266 is configured to serve a small webpage, as noted above. I can now reach that page using my phone, which is connected directly to the ESP8266 via the IP address assigned initially by the ESP8266 in AP mode, *and* I can also reach the same page from my laptop (connect to my router) using the IP address assigned by my router.  It would seem that I'm effectively in "AP+STA" mode now, despite having explicitly set to "AP" mode at the beginning.

So what's happening here?  Did I automatically switch to "AP+STA" mode when I called `WiFi.begin`?  If yes, what's the point (if any) of calling `WiFi.mode`?  If no, then why am I able to operate as if in "AP+STA" mode given the explicit setting of "AP" mode?

title: ESP8266 working as station while in AP mode

Answers: 1

body:
WiFi.begin() is a function of the ESP8266WiFiSTAClass. It changes the WiFi mode for you to STA or AP+STA based on the current mode.

`begin` functions are in [ESP8266WiFiSTA][1]

`enableSTA` function is in class [ESP8266WiFiGeneric][2]

  [1]: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp
  [2]: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp


body:
I've synced my Uno with the Arduino IDE and I'm using the below code to get the GPS coordinates.

    // Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
    //
    // This code shows how to listen to the GPS module in an interrupt
    // which allows the program to have more 'freedom' - just parse
    // when a new NMEA sentence is available! Then access data when
    // desired.
    //
    // Tested and works great with the Adafruit Ultimate GPS module
    // using MTK33x9 chipset
    //    ------> http://www.adafruit.com/products/746
    // Pick one up today at the Adafruit electronics shop
    // and help support open source hardware & software! -ada

    #include <Adafruit_GPS.h>
    #include <SoftwareSerial.h>

    // If you're using a GPS module:
    // Connect the GPS Power pin to 5V
    // Connect the GPS Ground pin to ground
    // If using software serial (sketch example default):
    //   Connect the GPS TX (transmit) pin to Digital 3
    //   Connect the GPS RX (receive) pin to Digital 2
    // If using hardware serial (e.g. Arduino Mega):
    //   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
    //   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

    // If you're using the Adafruit GPS shield, change
    // SoftwareSerial mySerial(3, 2); -> SoftwareSerial mySerial(8, 7);
    // and make sure the switch is set to SoftSerial

    // If using software serial, keep this line enabled
    // (you can change the pin numbers to match your wiring):
    SoftwareSerial mySerial(3, 2);

    // If using hardware serial (e.g. Arduino Mega), comment out the
    // above SoftwareSerial line, and enable this line instead
    // (you can change the Serial number to match your wiring):

    //HardwareSerial mySerial = Serial1;

    Adafruit_GPS GPS(&mySerial);

    // Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
    // Set to 'true' if you want to debug and listen to the raw GPS sentences.
    #define GPSECHO  true

    // this keeps track of whether we're using the interrupt
    // off by default!
    boolean usingInterrupt = false;
    void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

    void setup()
    {

      // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
      // also spit it out
      Serial.begin(115200);
      Serial.println("Adafruit GPS library basic test!");

      // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
      GPS.begin(9600);

      // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
      GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
      // uncomment this line to turn on only the "minimum recommended" data
      //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
      // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
      // the parser doesn't care about other sentences at this time

      // Set the update rate
      GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
      // For the parsing code to work nicely and have time to sort thru the data, and
      // print it out we don't suggest using anything higher than 1 Hz

      // Request updates on antenna status, comment out to keep quiet
      GPS.sendCommand(PGCMD_ANTENNA);

      // the nice thing about this code is you can have a timer0 interrupt go off
      // every 1 millisecond, and read data from the GPS for you. that makes the
      // loop code a heck of a lot easier!
      useInterrupt(true);

      delay(1000);
      // Ask for firmware version
      mySerial.println(PMTK_Q_RELEASE);
    }

    // Interrupt is called once a millisecond, looks for any new GPS data, and stores it
    SIGNAL(TIMER0_COMPA_vect) {
      char c = GPS.read();
      // if you want to debug, this is a good time to do it!
    #ifdef UDR0
      if (GPSECHO)
        if (c) UDR0 = c;
        // writing direct to UDR0 is much much faster than Serial.print
        // but only one character can be written at a time.
    #endif
    }

    void useInterrupt(boolean v) {
      if (v) {
        // Timer0 is already used for millis() - we'll just interrupt somewhere
        // in the middle and call the "Compare A" function above
        OCR0A = 0xAF;
        TIMSK0 |= _BV(OCIE0A);
        usingInterrupt = true;
      } else {
        // do not call the interrupt function COMPA anymore
        TIMSK0 &= ~_BV(OCIE0A);
        usingInterrupt = false;
      }
    }

    uint32_t timer = millis();
    void loop()                     // run over and over again
    {
      // in case you are not using the interrupt above, you'll
      // need to 'hand query' the GPS, not suggested :(
      if (! usingInterrupt) {
        // read data from the GPS in the 'main loop'
        char c = GPS.read();
        // if you want to debug, this is a good time to do it!
        if (GPSECHO)
          if (c) Serial.print(c);
      }

      // if a sentence is received, we can check the checksum, parse it...
      if (GPS.newNMEAreceived()) {
        // a tricky thing here is if we print the NMEA sentence, or data
        // we end up not listening and catching other sentences!
        // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
        //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false

        if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
          return;  // we can fail to parse a sentence in which case we should just wait for another
      }

      // if millis() or timer wraps around, we'll just reset it
      if (timer > millis())  timer = millis();

      // approximately every 2 seconds or so, print out the current stats
      if (millis() - timer > 2000) {
        timer = millis(); // reset the timer

        Serial.print("\nTime: ");
        Serial.print(GPS.hour, DEC); Serial.print(':');
        Serial.print(GPS.minute, DEC); Serial.print(':');
        Serial.print(GPS.seconds, DEC); Serial.print('.');
        Serial.println(GPS.milliseconds);
        Serial.print("Date: ");
        Serial.print(GPS.day, DEC); Serial.print('/');
        Serial.print(GPS.month, DEC); Serial.print("/20");
        Serial.println(GPS.year, DEC);
        Serial.print("Fix: "); Serial.print((int)GPS.fix);
        Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
        if (GPS.fix) {
          Serial.print("Location: ");
          Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
          Serial.print(", ");
          Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
          Serial.print("Location (in degrees, works with Google Maps): ");
          Serial.print(GPS.latitudeDegrees, 4);
          Serial.print(", ");
          Serial.println(GPS.longitudeDegrees, 4);

          Serial.print("Speed (knots): "); Serial.println(GPS.speed);
          Serial.print("Angle: "); Serial.println(GPS.angle);
          Serial.print("Altitude: "); Serial.println(GPS.altitude);
          Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
        }
      }
    }

When I compile and upload, it successfully does and the serial output displays something like this:

Time: 23:5:8.0
Date: 6/7/2018
Fix: 1 quality: 1
Location: 3855.8869N, 7721.3422W
Location (in degrees, works with Google Maps): 38.9314, -77.3557
Speed (knots): 0.32
Angle: 211.87
Altitude: 177.90
Satellites: 7
$PGTOP,11,2*6E
$GPGGA,230509.000,3855.8869,N,07721.3423,W,1,7,1.10,177.9,M,-33.4,M,,*64
$GPRMC,230509.000,A,3855.8869,N,07721.3423,W,0.28,211.87,060718,,,A*7F
$PGTOP,11,2*6E
$GPGGA,230510.000,3855.8869,N,07721.3424,W,1,7,1.10,177.9,M,-33.4,M,,*6B
$GPRMC,230510.000,A,3855.8869,N,07721.3424,W,0.28,211.87,060718,,,A*70

Everything seems okay except that the time is also offset by 4 hours?

title: Parsing example code in Adafruit GPS library with Ultimate Adafruit GPS

Answers: 1

body: GPS is probably giving you universal time (UTC).  Your profile says that you're in College Park, MD, so that's currently 4 hrs different due to daylight savings time.