text:
Problem with character concatenation algorithm in matrix led
good afternoon, I am making a 7x10 led matrix in which I use a CD4017 to handle the 7 rows and 2 cascaded shift registers to handle the 10 columns.
I first tried a programming to turn on my entire led matrix and it worked fine. Then, I tried to make a character appear statically and it worked fine. Next, I tried to make that character sweep from right to left and it worked fine. But, what I am having a hard time with is sweeping the message from right to left smoothly with a column of character to character spacing.
What I originally thought is that if I wanted to move a character from right to left, I have to shift the column values for all the rows by an appropriate amount (shift step) and once the character has been shifted enough, I start feeding the column values of the next character in the message for which, the formula that would create the right to left shift effect is:
(current_char<scroll) | (next_char>>(8-shift_step)-scroll)
But I don't get the expected result, the message scrolls from right to left but it doesn't do it with a column of separation between character and character and it doesn't do it in a fluid way either. In addition to that at the end of sweeping the message appears something strange that should not be there.
I recorded a video showing what I am saying: https://drive.google.com/file/d/1ebO5zassWY060mvWACPhcSLeOi5JmZAC/view
Code:
/*
 char_data is a two dimensional constant array that holds the 5-bit column values
 of individual rows for ASCII characters that are to be displayed on a 7x10 matrix.
*/
const byte char_data[95][7]={
    {0, 0, 0, 0, 0, 0, 0}, // space
    {0b100, 0b100, 0b100, 0b100, 0b100, 0, 0b100}, // !
    {0b1010, 0b1010, 0b1010, 0, 0, 0, 0}, // "
    {0b1010, 0b1010, 0b11111, 0b1010, 0b11111, 0b1010, 0b1010}, // #
    {0b100, 0b1111, 0b10100, 0b1110, 0b101, 0b11110, 0b100}, // $
    {0b11000, 0b11001, 0b10, 0b100, 0b1000, 0b10011, 0b11}, // %
    {0b1000, 0b10100, 0b10100, 0b1000, 0b10101, 0b10010, 0b1101}, // &
    {0b100, 0b100, 0b100, 0, 0, 0, 0}, // '
    {0b100, 0b1000, 0b10000, 0b10000, 0b10000, 0b1000, 0b100}, // (
    {0b100, 0b10, 0b1, 0b1, 0b1, 0b10, 0b100}, // )
    {0b100, 0b10101, 0b1110, 0b100, 0b1110, 0b10101, 0b100}, // *
    {0, 0b100, 0b100, 0b11111, 0b100, 0b100, 0}, // +
    {0, 0, 0, 0, 0b100, 0b100, 0b1000}, // ,
    {0, 0, 0, 0b11111, 0, 0, 0}, // -
    {0, 0, 0, 0, 0, 0, 0b100}, // .
    {0, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0}, // /
    {0b1110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b1110}, // 0
    {0b110, 0b1100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // 1
    {0b1110, 0b10001, 0b1, 0b110, 0b1000, 0b10000, 0b11111}, // 2
    {0b11111, 0b1, 0b10, 0b110, 0b1, 0b10001, 0b1111}, // 3
    {0b10, 0b110, 0b1010, 0b10010, 0b11111, 0b10, 0b10}, // 4
    {0b11111, 0b10000, 0b11110, 0b1, 0b1, 0b10001, 0b1110}, // 5
    {0b01110, 0b10001, 0b10000, 0b11110, 0b10001, 0b10001, 0b1110}, // 6
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b1000, 0b1000}, // 7
    {0b01110, 0b10001, 0b10001, 0b1110, 0b10001, 0b10001, 0b1110}, // 8
    {0b01110, 0b10001, 0b10001, 0b1111, 0b1, 0b10001, 0b1110}, // 9
    {0, 0, 0b100, 0, 0b100, 0, 0}, // :
    {0, 0, 0b100, 0, 0b100, 0b100, 0b1000}, // ;
    {0b10, 0b100, 0b1000, 0b10000, 0b1000, 0b100, 0b10}, // <
    {0, 0, 0b11111, 0, 0b11111, 0, 0}, // =
    {0b1000, 0b100, 0b10, 0b1, 0b10, 0b100, 0b1000}, // >
    {0b1110, 0b10001, 0b1, 0b10, 0b100, 0, 0b100}, // ?
    {0b1110, 0b10001, 0b10111, 0b10101, 0b10110, 0b10000, 0b1111}, // @
    {0b1110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // A
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110}, // B
    {0b1110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b1110}, // C
    {0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110}, // D
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111}, // E
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000}, // F
    {0b1110, 0b10001, 0b10000, 0b10111, 0b10101, 0b10001, 0b1110}, // G
    {0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // H
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b11111}, // I
    {0b1, 0b1, 0b1, 0b1, 0b1, 0b10001, 0b1110}, // J
    {0b10001, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001, 0b10001}, // K
    {0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111}, // L
    {0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001}, // M
    {0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001}, // N
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // O
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000}, // P
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10011, 0b1111}, // Q
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b10001}, // R
    {0b1111, 0b10000, 0b10000, 0b1110, 0b1, 0b1, 0b11110}, // S
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // T
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // U
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // V
    {0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001}, // W
    {0b10001, 0b10001, 0b1010, 0b100, 0b1010, 0b10001, 0b10001}, // X
    {0b10001, 0b10001, 0b1010, 0b100, 0b100, 0b100, 0b100}, // Y
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b11111}, // Z
    {0b1110, 0b1000, 0b1000, 0b1000, 0b1000, 0b1000, 0b1110}, // [
    {0, 0b10000, 0b1000, 0b100, 0b10, 0b1, 0}, // backward slash
    {0b1110, 0b10, 0b10, 0b10, 0b10, 0b10, 0b1110}, // ]
    {0, 0, 0b100, 0b1010, 0b10001, 0, 0}, // ^
    {0, 0, 0, 0, 0, 0, 0b11111}, // _
    {0b1000, 0b100, 0b10, 0, 0, 0, 0}, // `
    {0, 0, 0b1110, 0b1, 0b1111, 0b10001, 0b1111}, // a
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b11110}, // b
    {0, 0, 0b1110, 0b10001, 0b10000, 0b10001, 0b1110}, // c
    {0b1, 0b1, 0b1, 0b1111, 0b10001, 0b10001, 0b1111}, // d
    {0, 0, 0b1110, 0b10001, 0b11111, 0b10000, 0b1111}, // e
    {0b1110, 0b1001, 0b11100, 0b1000, 0b1000, 0b1000, 0b1000}, // f
    {0, 0, 0b1110, 0b10001, 0b1111, 0b1, 0b1110}, // g
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b10001}, // h
    {0b100, 0, 0b100, 0b100, 0b100, 0b100, 0b1110}, // i
    {0b1, 0, 0b11, 0b1, 0b1, 0b10001, 0b1110}, // j
    {0b10000, 0b10000, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001}, // k
    {0b1100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // l
    {0, 0, 0b11110, 0b10101, 0b10101, 0b10101, 0b10101}, // m
    {0, 0, 0b11110, 0b10001, 0b10001, 0b10001, 0b10001}, // n
    {0, 0, 0b1110, 0b10001, 0b10001, 0b10001, 0b1110}, // o
    {0, 0, 0b1111, 0b1001, 0b1110, 0b1000, 0b1000}, // p
    {0, 0, 0b1111, 0b10001, 0b1111, 0b1, 0b1}, // q
    {0, 0, 0b10111, 0b11000, 0b10000, 0b10000, 0b10000}, // r
    {0, 0, 0b1111, 0b10000, 0b1110, 0b1, 0b11110}, // s
    {0b100, 0b100, 0b1110, 0b100, 0b100, 0b100, 0b11}, // t
    {0, 0, 0b10001, 0b10001, 0b10001, 0b10011, 0b1101}, // u
    {0, 0, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // v
    {0, 0, 0b10001, 0b10001, 0b10101, 0b11111, 0b10101}, // w
    {0, 0, 0b10001, 0b1010, 0b100, 0b1010, 0b10001}, // x
    {0, 0, 0b10001, 0b10001, 0b1111, 0b1, 0b11110}, // y
    {0, 0, 0b11111, 0b10, 0b100, 0b1000, 0b11111}, // z
    {0b10, 0b100, 0b100, 0b1000, 0b100, 0b100, 0b10}, // {
    {0b100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // |
    {0b1000, 0b100, 0b100, 0b10, 0b100, 0b100, 0b1000}, // }
    {0, 0, 0, 0b1010, 0b10101, 0, 0} // ~
};
char message[] = "MATRIX LED 7X10 WITH ATMEGA328p";
int string_length = strlen(message);
byte shift_step = 1;

void setup(){
    // PORTB as output.
    // Pin 13: ClockRegister
    // Pin 12: Latch
    // Pin 11: Data
    // Pin 10: Reset
    // Pin 9: Clock4017
    DDRB = 0b111111;
    // Makes sure the 4017 value is 0.
    PORTB |= (1 << PB2);
    PORTB &= ~(1 << PB2);
    Serial.begin(9600);
}

void send_data(uint16_t data){
    uint16_t mask = 1, flag = 0;
    for (byte i=0; i<10; i++){
        flag = data & mask;
        if (flag) PORTB |= (1 << PB3);
        else PORTB &= ~(1 << PB3);
        PORTB |= (1 << PB5);
        PORTB &= ~(1 << PB5);
        mask <<= 1;
    }
    PORTB |= (1 << PB4);
    PORTB &= ~(1 << PB4);
}

void display_pattern(byte loops){
    for (byte c=0; c<string_length; c++){ // For each character
        for (byte scroll=0; scroll<10; scroll++){ // For each column.
            for (byte t=0; t<loops; t++){ // The delay we get with loops.
                for (byte z=0; z<7; z++){ // For each row.
                    // To obtain the position of the current character in the char_data array, subtract 32 from the ASCII value of the character itself.
                    byte index = message[c];
                    byte temp = char_data[index-32][z];
                    byte index_2 = message[c+1];
                    byte temp_2 = char_data[index_2-32][z];
                    send_data((temp<<scroll) | (temp_2>>(8-shift_step)-scroll));
                    delayMicroseconds(800);
                    // Clear the row so we can go on to the next row without smearing.
                    send_data(0);
                    // On to the next row.
                    PORTB |= (1 << PB1);
                    PORTB &= ~(1 << PB1);
                }
                // Select the first row.
                PORTB |= (1 << PB2);
                PORTB &= ~(1 << PB2);
            }
        }
    }
}

void loop(){
    display_pattern(10);
    delay(100000);
}

I appreciate the help.

For the strange char at the end of the display, I think your index_2 is accessing beyond the strlen(message) toward the end of the message.

Slow down your Youtube video to playback rate of 0.25, you will see why it is not display the char smoothly...

Here are a few issues that I noticed in this code. I think that, if you
manage to address them, you should get a smooth display:

In the expression (temp_2>>(8-shift_step)-scroll), the amount of
shift will be negative when scroll gets larger than 7. A righ
shift by a negative amount is not a left shift: it is undefined
behavior. Judging by the video, it seems the compiler does no shit
at all in this case.

If you want a one pixel space between the characters, you should
move to the next character in the string every six pixels, thus the
scroll variable should count from 0 to 5.

Be aware that there could be up to three characters simultaneously
(partially) displayed on the screen: when one character is centered,
you should be able to see the edges of both its neighbors.

As noted by hcheung in a comment, when you get to the last character
in the string, the expression message[c+1] is reading past the end
of that string.

You are right about the scrolling, I reduced the range of the scroll for to scroll<7 and it doesn't get stuck but the character fades earlier. I can't figure out the correct formula for when the scroll is greater than 6. Video: https://drive.google.com/file/d/1bkDzEiGrz1c6avpHSnl6ox7D34MD-mp9/view?ts=635b02e3

I tried to do this:
if (scroll < 7) send_data((temp<<scroll) + (temp_2 >> 6-scroll));
else send_data((temp<<scroll) + (temp_2 << (scroll-6)));
But it behaves strangely, the first character goes through, then it blinks, goes back and goes on again.

@LucioMazzini: Hard to help debugging without seeing the whole code. That being said, I think the right formula should be send_data(temp<<scroll+6|temp_2<<scroll|temp_3>>6-scroll);.

Where temp would be the current character, temp_2 the next character and temp_3 the character that comes after temp_2 right?

@LucioMazzini: temp_2 is the only character that fits completely in the display (there can only be one). temp is the character (if any) that is partially displayed to the left of temp_2, only visible when scroll≤3. temp_3 is the character (if any) that is partially displayed to the right of temp_2, only visible when scroll≥2. Note that you will have to pad your message with spaces on both ends.

Hello, well, I have been able to give a twist to my programming and the sweeping of the characters is working correctly but I am having a little problem... The characters are displayed in mirror.

Video: https://drive.google.com/file/d/1qM7w7Zx73k8dR_xCpCwLOzvuMJoXU7vZ/view

Code: https://pastebin.com/seL3RTch

Forget it, I already solved it. I started the mask at 0b10000 and scroll the mask to the right and the binary offset is 4-column. It works fine now, thanks.


text:
How to architect streaming data from multiple plant monitors to single Arduino?
Premise:
I'm trying to determine a good way to architect getting data from 4 plant monitors to a single Arduino. For context, that Arduino will have a Wifi connection that will transmit the data from the plant monitors to a web server internally.
Setup
Where I'm struggling to make a decision is how to go about hooking the sensors up.  Here's my plant setup:

Materials
Tools I have at hand:

Many Arudino Micros
Arduino Unos
Arduino Mega
Raspberry Pi 4 B
4x Monk Makes Plant Monitors
Wiring stuff and power supplies, basic electronics prototyping collection.

Solutions?
I would like to place 4 monitors into different plants (doesn't matter which ones at the moment, if it does, I can specify).  What I've considered:

All 4 plant monitors directly wired to the Arduino Mega.  This requires a 1k resistor in line of the data pin, which I'm not sure I have a good solution for that without a breadboard.  Also, I wasn't sure if the length of data line would be a problem.
Each Plant Monitor is hooked up to an Arduino micro and then use the USB of the micro to the RPI.
Like #2 but use I2C to send data to Arduino Mega. I would need to supply power to these minis then.
There are some options without using Arduinos, but since is the Arduino SE, I'm happy to keep it with this.

I'm open to other options as well, as well as possibly needing to purchase/make another part to optimize the solution some.

i would just hook each plant sensor to an ESP01 (programmable in Arduino) so that you only need to run 3.3v+gnd to each sensor, and you can use the Pi for something a little more worthy of it's power. It avoids collisions, signaling, IDing, etc, and makes it trivial to add more sensors or move sensors around without changing code or re-cutting wires. You only need 4 dupont 10cm wires for the ESP+sensor and then give it power with the "BBC" connectors up top. If you hate Wifi. use ESP-NOW to talk to a 4th ESP, connected to the Pi via UART.

for curios about the diamond next to Avogador's name. Avogador works for SE on a position which grands moderator access to all SE sites.

@dandavis I was looking at the ESP8266 board from  Adafruit.  However I noticed that it had a max current on it's serial port of 12mA where the Maximum current
consumption on the plant monitor's data sheet says 15mA.  I would think this could mean I'd have some dead 8266's every now and then?

@Juraj This is correct, and I plan to do 0 moderation because I'm definitely a community member here not a moderator.

there's no real current on the serial port, afaik. the plant monitor probably uses 15ma total, but that doesn't matter as they are both powered by the same 3,3v source. i'm assuming the  large terminals up top have continuity to the pins, but even if not, just make a splitter by splicing dupont cabled together. also not sure what paydafruit charges, but you can get ESP01Ss for under $2/each free shipping on amazon.

@dandavis Thanks for bringing my feet back down to Earth.  Yeah, the serial won't be anything and I'll power it separately from the 3.3v bus.  So that can work.  I don't think there's anything wrong with your solution as an answer if you wanted to write it up.

i'm overbooked the next day or two, but i'll see what i can do later, just glad to help...

The distances between the plants on the shelf are in general too long for TTL level communication and soon you may want to connect more sensors at plants elsewhere in the room or even in other rooms.
In my opinion the solution proposed by dandavis, using esp-01 with WiFi or esp-now is the most simple and universal solution. I see no problems with the implementation. The esp-01 is small and will play nice with the 3.3 V sensor. Maybe it can be even made battery powered and then there are no cables between plants.
If wired solution was required, I would recommend to use RS485 bus. With RS485 modules with AutoDirection control the sensors could be directly connected to the RS485 module without a MCU at every sensor.

couldn't have said it better. +1

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
How do I put a LiquidCrystal_I2C class in a Lcd class?
I want to make my main code cleaner so I was thinking of making a Lcd class which I can use every time I need to print on lcd. So my main code every time I try to print text I need to call :
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Text 1st line");
lcd.setCursor(1,0);
lcd.print("Text 2nd line");

The problem is I need to create a class called Lcd which initialises the LCD display through LiquidCrystal_I2C.h and calls it's functions in order to print as I want.
Below I will post some code which is totally wrong but I guess it can give you the idea of what I am trying to do:
LcdControl.hpp
class LcdControl{
    public:
        LcdControl();
        void printOnLcd(int data,int column,int line);
        void printOnLcd(char data,int column,int line);
};

LcdControl.cpp
#include <LiquidCrystal_I2C.h>
#include <Arduino.h>
#include "LcdControl.hpp"

LcdControl::LcdControl(){
    LiquidCrystal_I2C lcd(0x27,20,4);
    lcd.init();
    lcd.init();
    lcd.backlight();
}

void LcdControl::printOnLcd(int data,int column,int line){
    lcd.clear();
    lcd.setCursor(column,line);
    lcd.print(data);
}

void LcdControl::printOnLcd(char data,int column,int line){
    lcd.clear();
    lcd.setCursor(column,line);
    lcd.print(data);
}

You could also use an inheritance model where the the base class is the original library LiquidCrystal_I2C and you simply create a new derived class, in this case LcdControl. In LcdControl, you simply pack in your additional methods. The only slight complexity is that you have to invoke the constructor of the base class LiquidCrystal_I2C when the constructor of the derived class LcdControl is called.
Here it is in a simulation:  https://wokwi.com/projects/349238619253244498
Code:
#include <LiquidCrystal_I2C.h>

class LcdControl : public LiquidCrystal_I2C {
  public:

    LcdControl( uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows) :
      // base class constructor
      LiquidCrystal_I2C ( lcd_Addr, lcd_cols, lcd_rows ) {
    }

    void printOnLcd(const char * data, int column, int line) {
      LcdControl::clear();
      LcdControl::setCursor(column, line);
      LcdControl::print(data);
    }

} ;

LcdControl lcd(0x27, 20, 4);

void setup() {

  Wire.begin() ;
  lcd.init() ;
  lcd.backlight();

  lcd.printOnLcd( "hello world2", 0 , 0 ) ;
  delay(1000) ;

  lcd.printOnLcd( "hello world3", 1 , 2 ) ;

}

void loop() {

}

Potentially, your lcd local of the constructor becomes member instead:
class LcdControl{
    public:
        LcdControl();
    // ...
    private:
        LiquidCrystal_I2C lcd;

There it is accessible from all of your member functions and (without splitting hairs) exists for the lifetime of LcdControl variable. The way you have it currently the lcd instance is local to the constructor, so inaccessible elsewhere (e.g. inside printOnLcd()) and dies when the constructor returns.
The construction of the lcd member happens in the LcdControl() member initializer list:
LcdControl::LcdControl()
    : lcd(0x27,20,4)
{

Newer standards of C++ allow some forms of initialization to be done where it's declared as member. I'm not going to recheck the standards now. But the above way should work regardless of which Arduino core and version you have.
The call to the lcd's init() may need to be done in an counterpart init()/begin() in your own class. When you do something that can fail in the constructor you have little opportunity to detect/handle this when done in the constructor on an embedded device like an Arduino where your class may be to make a global and where exceptions aren't supported; some Arduino's support exceptions and some don't. For an Arduino fallible part of initialization/contruction of often separated out so you can control how and where/when that failure happen, often in setup() and without reliance on exceptions.
There are a lot of ways to achieve something similar. The above seems closest to what you're attempting in the question. It may not necessarily make the most sense in your particular usage. You can want to have the class have a member pointer or member reference instead of a member instance, but you need to be more careful about their respective lifetimes. It is often a mistake to do initialization in inner layers of your code without providing the user of it any control. E.g. not allowing the user of your LcdControl class to initialize it's own LiquidCrystal_I2C instance and pass that in or to allow passing in the parameters for the LcdControl class to use.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Generate a sine wave with a predefined frequency and amplitude via DAC0 or DAC1 with Arduino Due
Good Morning to everyone,
I am a PhD Student in experimental fluid mechanics at the University of Naples "Federico II", Italy. I am working on Arduino Due card and i am novel in applications using it. First, I need to generate a sine wave with variable frequency and amplitude. I tried to download several codes which are able to generate sine waves with a pre-defined frequency, but I would like to change this value of frequency at the beginning of the execution of the code. How could i do this ?
Second, I would like to change, in real-time, the output voltage of Arduino DAC0 or DAC1 at high speed to generate an arbitrary waveshape.. Is it possible?
Thank you in advance for your answers.
Dr. Alessandro Scala

The formula commonly used to represent a sinusoidal signal is
V = A cos(ωt)
where A is the amplitude and ω is the angular frequency. This formula
should cope well with a variable amplitude. It is, however, not suitable
for a signal with variable frequency, because a discontinuity of the
frequency is not supposed to create a discontinuity in the signal.
The correct formula for a signal where both the amplitude and the
frequency can vary is
V = A(t) cos(φ(t))
where the phase is computed as
φ(t) = ∫ ω(t)dt
In terms of code, this means you need a static variable to keep track of
the current phase, and you have to update it periodically in order to
perform the numerical integration.
Here is a tentative implementation. I have qualified some variables as
extern only to hint that you are responsible for managing them. You
can remove the qualifier if you integrate this into your own code:
// Defined and updated elsewhere.
extern const uint8_t output_channel;
extern float angular_frequency;  // in rad/us
extern float amplitude, offset;  // in ADC steps

// Call this as often as practical.
void update_output()
{
    // Compute the time delta.
    static uint32_t time_of_last_update;
    uint32_t now = micros();
    uint32_t dt = now - time_of_last_update;
    time_of_last_update = now;

    // Update the phase.
    static float phase;
    phase += angular_frequency * dt;
    while (phase >= 2 * M_PI) phase -= 2 * M_PI;  // unwrap

    // Output the signal.
    float output = offset + amplitude * cos(phase);
    analogWrite(output_channel, round(output));
}

Regarding the second part of the question (about arbitrary waveshapes),
it is, of course, feasible. You just have to pass arbitrary values to
analogWrite().

thank you very much for your answer. Regarding the second part of the question, you are stating that i could be able to change the voltage in dependence of an input signal received by other pins ? Such as a measurement performed by a sensor read via Arduino and then change the voltage

@AlessandroScala: I am stating that you can change the output voltage however you like, and make it dependent on whatever you want.


text:
Seeeduino XIAO read PWM duration (period) using timers change Pins freom D2 to D1
I designed a circuitboard and need to proof the function.Therefore i have to modify the code to read from Pins D1 instead of D2.
Unfourtunatly i am not that familar with the high level programming so im not sure if i got all changes.
Basically all PINS on the circuit are used.
Basecode foud here:
Seeeduino XIAO write and read PWM duration (period) using timers
Reading short square waves with Seeeduino XIAO pin D2
// Setup TC4 to capture pulse-width and period on digital pin D2 on Seeeduino Xiao
volatile boolean periodComplete;
volatile uint32_t isrPeriod;
volatile uint32_t isrPulsewidth;
uint32_t period;
uint32_t pulsewidth;

void setup()   {
  SerialUSB.begin(115200);                         // Initialise the native serial port
  while(!SerialUSB);                               // Wait for the console to open

  PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;           // Switch on the event system peripheral

  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz system clock by 1 = 48MHz
                     GCLK_GENDIV_ID(4);            // Set division on Generic Clock Generator (GCLK) 4

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK 4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the clock source to 48MHz
                      GCLK_GENCTRL_ID(4);          // Set clock source on GCLK 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Route GCLK4 to TC4 and TC5
                      GCLK_CLKCTRL_GEN_GCLK4 |
                      GCLK_CLKCTRL_ID_TC4_TC5;

  // Enable the port multiplexer on port pin PA10
  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
  // Set-up the pin as an EIC (interrupt) on port pin PA10
  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;

  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Enable event output on external interrupt 10
  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Set event detecting a HIGH level
  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Disable interrupts on external interrupt 10
  EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Enable EIC peripheral
  while (EIC->STATUS.bit.SYNCBUSY);                                        // Wait for synchronization

  EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) |                                // Attach the event user (receiver) to channel 0 (n + 1)
                    EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU);                // Set the event user (receiver) as timer TC4

  EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // No event edge detection
                       EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Set event path as asynchronous
                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Set event generator (sender) as external interrupt 10
                       EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0

  TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Enable the TC event input
                            //TC_EVCTRL_TCINV |              // Invert the event input
                            TC_EVCTRL_EVACT_PPW;           // Set up the timer for capture: CC0 period, CC1 pulsewidth

  TC4->COUNT32.CTRLC.reg = TC_CTRLC_CPTEN1 |               // Enable capture on CC1
                           TC_CTRLC_CPTEN0;                // Enable capture on CC0
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Wait for synchronization

  NVIC_SetPriority(TC4_IRQn, 0);      // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
  NVIC_EnableIRQ(TC4_IRQn);           // Connect the TC4 timer to the Nested Vector Interrupt Controller (NVIC)

  TC4->COUNT32.INTENSET.reg = TC_INTENSET_MC1 |            // Enable compare channel 1 (CC1) interrupts
                              TC_INTENSET_MC0;             // Enable compare channel 0 (CC0) interrupts

  TC4->COUNT32.CTRLA.reg = //TC_CTRLA_PRESCSYNC_PRESC |      // Overflow on precaler clock, (rather than the GCLK)
                           TC_CTRLA_PRESCALER_DIV1  |      // Set prescaler to 1, 48MHz/1 = 48MHz
                           TC_CTRLA_MODE_COUNT32;          // Set TC4/TC5 to 32-bit timer mode

  TC4->COUNT32.CTRLA.bit.ENABLE = 1;                       // Enable TC4
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Wait for synchronization
}

void loop() {
  if (periodComplete)                             // Check if the period is complete
  {
    noInterrupts();                               // Read the new period and pulse-width
    period = isrPeriod;
    pulsewidth = isrPulsewidth;
    interrupts();
    SerialUSB.print("PW: ");
    SerialUSB.print(pulsewidth);
    SerialUSB.print(F("   "));
    SerialUSB.print("P: ");
    SerialUSB.println(period);
    periodComplete = false;                       // Start a new period
  }
}

void TC4_Handler()                                // Interrupt Service Routine (ISR) for timer TC4
{
  // Check for match counter 0 (MC0) interrupt
  if (TC4->COUNT32.INTFLAG.bit.MC0)
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Enable a read request
                               TC_READREQ_ADDR(0x18);      // Offset address of the CC0 register
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Wait for (read) synchronization
    isrPeriod = TC4->COUNT32.CC[0].reg;                    // Copy the period
    periodComplete = true;                                 // Indicate that the period is complete
  }

  // Check for match counter 1 (MC1) interrupt
  if (TC4->COUNT32.INTFLAG.bit.MC1)
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Enable a read request
                               TC_READREQ_ADDR(0x1A);      // Offset address of the CC1 register
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Wait for (read) synchronization
    isrPulsewidth = TC4->COUNT32.CC[1].reg;                // Copy the pulse-width
  }
}

Do i only have to change the IOs:
from:
PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
to:
PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;
or do i need to mod more code?
Thanks for helping.

In addition to the changes you mentioned, your EIC_EVCTRL_EXTINTEO10, EIC_INTENCLR_EXTINT10, and EVSYS_ID_GEN_EIC_EXTINT_10 usages will need to be changed to EIC_EVCTRL_EXTINTE4, EIC_INTENCLR_EXTINT4 and to EVSYS_ID_GEN_EIC_EXTINT_4, to re-target the event system source, because PORT_PMUX_PMUXE_A on both these pins routes the signal to the EIC, but not to the exact same interrupt number.  The EIC->CONFIG line needs to change to the first group of 8 ([0]) and fourth SENSE within that group (EIC_CONFIG_SENSE4_HIGH) to the change to D1 (PA04) uses EXTINT4.  This is something I'd left out of the first edit before I'd been able to test. I did eventually find a XIAO to test with and these modifications seem to make it work just fine on digital pin 1 now instead of digital pin 2.
EIC->EVCTRL.reg    |= EIC_EVCTRL_EXTINTE4;
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;
EIC->INTENCLR.reg   = EIC_INTENCLR_EXTINT4;
EIC->CTRL.reg      |= EIC_CTRL_ENABLE;
while (EIC->STATUS.bit.SYNCBUSY);

...
EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |
                     EVSYS_CHANNEL_PATH_ASYNCHRONOUS |
                     EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |
                     EVSYS_CHANNEL_CHANNEL(0);

The changes you'd mentioned and those I've said above as diff:
--- original.ino
+++ modified.ino
@@ -24,14 +24,14 @@
                       GCLK_CLKCTRL_GEN_GCLK4 |
                       GCLK_CLKCTRL_ID_TC4_TC5;

-  // Enable the port multiplexer on port pin PA10
-  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
-  // Set-up the pin as an EIC (interrupt) on port pin PA10
-  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
+  // Enable the port multiplexer on port pin PA04
+  PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
+  // Set-up the pin as an EIC (interrupt) on port pin PA04
+  PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;

-  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Enable event output on external interrupt 10
-  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Set event detecting a HIGH level
-  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Disable interrupts on external interrupt 10
+  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4;                                 // Enable event output on external interrupt 4
+  EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;                            // Set event detecting a HIGH level
+  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4;                                // Disable interrupts on external interrupt 4
   EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Enable EIC peripheral
   while (EIC->STATUS.bit.SYNCBUSY);                                        // Wait for synchronization

@@ -40,7 +40,7 @@

   EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // No event edge detection
                        EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Set event path as asynchronous
-                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Set event generator (sender) as external interrupt 10
+                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |    // Set event generator (sender) as external interrupt 4
                        EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0

   TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Enable the TC event input


text:
ATTiny85(Digispark) not connected/recognized
I have 1xDigispark(ATTiny85) from Amazon https://www.amazon.pl/gp/product/B076KS2QDS/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&th=1.
When i connect it into USB port nothing happen i didn't get windows sound alert.
And Arduino IDE not detecting it(Not displayed as a port).

I have this link to the drivers in settings and drivers installed.
When I try to upload a code with "COM1" port nothing relly happens.
Regards,
Wiktor Wołos

You have the wrong board selected in your IDE
This

Is a "Digispark (Default 16.5 mhz)" (sic) not a "Digispark Pro". The latter is based on an ATtiny167 not an ATtiny85.
I have bought the exact same item from the same seller.

Thanks, but for me i not working... :(

And I have message sending completed before i see "Plug in device now... (will timeout in 60 seconds)" isn't it weird?

@asdads this information does not belong in a comment to an answer ... it belongs in the question at the top of this page, so that everyone will see it


text:
DS18B20 temperature sensor crashes MbedOS on Arduino Nano RP2040?
I'm trying to use the DS18B20 sensor with Arduino Nano RP2040.
No matter which library I use, it seems to crash MbedOS as soon as the driver is initialized. I get 4 short and 4 long flashes of the orange LED, which as I found somewhere indicates a crash.
I was trying with DS18B20 library (https://github.com/matmunk/DS18B20) as well as the DallasTemperature one (https://github.com/milesburton/Arduino-Temperature-Control-Library).
At first I suspected that the issue is in my code as it interfaces with multiple different devices (EEPROM, SHT30, etc.) and this may interfere with 1-wire interface, but if I upload just the examples from these libraries the effect is the same.
I know that the Arduino is OK, as it can run other code absolutely fine, and the sensor is OK as well since I can read it with RaspberryPi.
Does anyone have similar problems? Is there some workaround?

It's difficult to say much without being able to recreate the problem or at least inspect the code and potentially wiring as well. For certain values of "similar" you may get responses that aren't not exactly answers as they may not have anything to do with the problem you're actually having. You can edit your question to include more details.

@timemage As I said, the problem emerges even with example code from linked libraries. The wiring is not particularly interesting, just a 4.7k resistor between Vcc and data lines. I know that wiring is OK since I can connect RPi instead of Arduino and have readouts. I also suspect that incorrect wiring would prevent communication with the sensor but not outright crash the OS.

Yeah, sorry, I did miss that. If I stumble cross a DS18B20 I'll at least try it with an RPI pico (the closest thing I have to what you're using). But, I don't know how likely I am to find one or when. I can at least cancel out the -1. Hopefully someone will recreate the problem and have something useful to say about it long before I'm able to.

add a lot of debugging code to your program ...determine where it hangs

@jsotola I found out it hangs in DS18B20 constructor for the DS18B20 library and in begin() method for DallasTemperature.

Test Setup
I have wired an DS18B20+ to an RPI Pico and used a 4.7K pullup. The RPI Pico is a stand-in for your board. It uses the  arduino:mbed_rp2040:pico core rather than the arduino:mbed_nano:nanorp2040connect that yours does. However, I'm guessing they're similar enough.
Test result
When I attempt the to use the matmonk DS18B20 library you mention, I see similar pattern on the RPI Pico's onboard LED. Just the attempt to construct the object was sufficient to crash. Construction fairly directly defers to the OneWire library. So, I tried the OneWire library's own example for reading the DS18B20 (with some appropriate modification) and it crashes in the same manner. This lead to searching for and finding issues for the RP2040 on the OneWire github page resulting in (among others) this find. The answer mentions OneWireNG.
The OneWireNG DallasTemperature example works
Or rather, it's the library that works. But, this is the relevant example for it that works for me. I made the following modifications.

All Serial usages were replaced with SerialUSB because I am using the USB connection for the Serial Monitor (well, a terminal emulator).

I changed the one wire object to use GPIO28 because it was conveniently close to the pins where I was picking up 3.3V and GND: OneWire  ds(28);

It seems plausible that you could change the #include <DS18B20.h> usages in the two libraries you cited to #include "OneWireNg_CurrentPlatform.h" and find that they then work fine. I have not tried this yet. If that's of particular interest to you I will try it and update(Update below). However, this stock example from the OneWireNG library is not crashing and is printing temperatures that rise and fall expected when I manipulate the temperature of the sensor.
OneWireNg with Matmunk and DallasTemperature libraries
In general
It turns out that it is unnecessary to modify libraries that were using the original OneWire, not even just changing the #include. Despite the OneWireNg example using "OneWireNg_CurrentPlatform.h" it also provides a OneWire.h header. It is sufficient to have OneWireNg installed but the original OneWire library must uninstalled (or moved out of the libraries directory) so as not to confuse the build process into selecting the original library based on the header name over the OneWireNg library. The OneWireNg authors may have used the OneWireNg specific header in the examples to avoid this problem wit their examples when both libraries were installed. They've gone out of their way to make it compatible with the original, but below are reports of specific tests with the two libraries mentioned anyway.
Matmunk library with OneWireNg
With OneWireNg installed and the original OneWire not installed, the Multiple example form the matmunk library worked with the same minor modifications mentioned before (I used pin 28 rather than 2 and SerialUSB rather than Serial). In case your wondering the only reason why I switched from testing Single to Multiple is the latter didn't require that I first find and enter my part's address. That example is printing temperatures that rise and fall in accordance with manipulation of the sensor.
DallasTemperature with OneWireNg
Likewise I tested with the Multiple example from the DallasTemperature library. Same kind of modifications to the example. I changed ONE_WIRE_BUS to 28 for my setup. I changed Serial to SerialUSB. And runs normally and prints expected temperatures under manipulation of the sensor.

Thanks so much! Using OneWireNg instead of OneWire indeed solves the problem. I looked for problems in DallasTemperature and DS18B20 libraries, but somehow it did not occur to me to look into the OneWire itself.

It didn't work for me.
I removed the OneWire library and installed OneWireNg.
I installed Mathias Munk Hanson's DS18B20 library and loaded the sketch found at this address: https://github.com/matmunk/DS18B20/blob/1.0.0/examples/Multiple/Multiple.ino Arduino Nano RP2040 crashes as soon as the sketch is loaded.

@MauroPagano, I see your comment was converted from an answer. I point that out mostly for the benefit for everyone (most people) that can't see that. It seems like it's the same content that I'd put under the "Matmunk library with OneWireNg" header. So maybe that's why it was converted to a comment. If you were trying to address that part of my answer, then I'm not entirely sure what to say except perhaps if you found a difference it was in the version of OneWireNg, which for me was almost certainly the 0.12.2 I'd linked.


text:
Wire.write invalid conversion from ‘char*’ to ‘const uint8_t*
I have written this code:
char message[4];
memcpy(message, &delta, 4);

Wire.write(message, 4);

When I try to compile I get this warning:
warning: invalid conversion from ‘char*’ to ‘const uint8_t* {aka const unsigned char*}’ [-fpermissive]
   Wire.write(message, 4);
                        ^

Also followed by this note:
In file included from main.ino:5:0:
/usr/share/arduino/libraries/Wire/Wire.h:61:20: note:   initializing argument 1 of ‘virtual size_t TwoWire::write(const uint8_t*, size_t)’
     virtual size_t write(const uint8_t *, size_t);
                    ^

I do not understand what is wrong?

Try
Wire.write((const uint8_t*) message, 4);

I.e., cast it to the correct type, uint8_t and char are the same (at least on Arduino and for this example, as you do not char about unsigned/signed values).
(see also the comment of the busybee below, for using the cleaner C++ cast).

But if they are the same, why is it complaining?

@user88434 Because C++ is a language with a kind of stronger type system, and by purpose the warning is enabled during compilation. You as the programmer need to make clear that you change the interpretation of the bytes. -- BTW, the clean solution would not use a C cast, but a C++ cast, for example Wire.write(reinterpret_cast<uint8_t*>(message), 4);.


text:
Changing SPI ports on an Arduino
My end goal is to read information from an nRF24l01 module connected to my Arduino UNO R3, and generate an interrupt whenever a message is sent to the Arduino.
Now, I have read that for Hardware interrupts, only pins D2 and D3 can be used to generate interrupts. However, while connecting the MISO line, I saw that here it was mentioned that

On some Arduino boards (see table above), pins MOSI, MISO and SCK are the same pins as digital pin 11, 12 and 13, respectively. That is why many tutorials instruct you to hook up the target to these pins.

On every website I have searched, MISO is always connected to 12. Is there any way to change the MISO line from 12 to 3, or will I have to resort to using Pin change interrupts? Another way I can think of to bypass this is to connect D12 to D3, but I'm afraid this may cause complications in the circuit.

SPI (and all the none-GPIO peripherals) has its own interrupt that you can enable it by setting the SPE bit of the SPI Control Register, and when a data is received an interrupt would be triggered. Search for SPI Slave example or read my blog for the section of SPI Slave .

If you are using Arduino Uno (based on ATMega328 chip), it does not support alternative pin for SPI port. On your assumption that " MISO is always connected to 12", this is only true for Arduino board based on ATMega328. For other Arduino Core (e.g. ESP or STM32), or even different MCU(e.g. Arduino Leonardo which is based on ATMega32U4) using the same Arduino AVR Core, this will not be the case.

Thanks!That works for me

The NRF24L01 itself can optionally generate an interrupt on receiving a message. The pin on the NRF24L01 is marked IRQ where it is broken out on most modules. You can connect this to an external interrupt pin on a Uno or use any pin which configured for a pin change interrupt. I am not sure how far you will get attempting to use MISO for the same purpose.  See here for an example: https://howtomechatronics.com/tutorials/arduino/arduino-wireless-communication-nrf24l01-tutorial/

@6v6gt the IRQ line, in idle state, is HIGH or LOW? I am asking because I want to fill in the last parameter of attachInterrupt(digitalPintoInterrupt(3), func_name, ________) correctly.

The IRQ pin is active LOW according to this: https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf . I'd use the input pin pullup resistor and look for a falling edge. The pins should be 5v tolerant. You may have to explicitly enable the IRQ pin using the NRF24L01 library: https://nrf24.github.io/RF24/classRF24.html#abf68b9b0c9cd17179e9e144c3e7f9c45

Thanks @6v6gt for the help

If it works as you want, then add an additional answer in the thread saying what you did, It may help someone else.

@6v6gt Look, this is why answers are supposed to go in answer boxes. Grrr. I scanned the answers to see if anyone had answered the question about the IRQ pin and saw no such answer. So I typed my own. Then I see your comment above answering the question and mentioning the IRQ pin. And now we have, forum-style, more comments querying how your "answer" works. Please, please use the answer "feature" to answer questions. Then comments under the answer make sense. This isn't a forum.

@nickgammon Yes. Sorry. It was a special case. As you have seen, the OP's question had nothing to do with what he wanted to achieve so an answer would not have matched the question. I had tried to get him to sort it out by adding his own answer based on his own experience of the suggested IRQ method but, alas, that never happened.

I have read that for Hardware interrupts, only pins D2 and D3 can be used to generate interrupts

The pin-change interrupts, available on all pins of the Arduino Uno, are almost as good. I say "almost" because the only thing you have to do is work out which pin caused the interrupt, which can be trivial if you only set up one pin to generate interrupts.

Is there any way to change the MISO line from 12 to 3,

Not if you used the hardware SPI on the chip. If you use bit-banged SPI you can use any pins.
I did a project for a temperature and humidity sensor, which logs to a SD card (using SPI), and also displays on a 8-digit display (using SPI). For the latter case I used bit-banged SPI, as described there.
I have a page about SPI and also a similar one on Stack Exchange.
My bit-banged SPI code is available here.

I'm not clear about why you don't just use the hardware SPI pins. Is that you want an interrupt when a SPI message arrives? There is a hardware interrupt for just that. See my posts about SPI for more details about that.

"Is that you want an interrupt when a SPI message arrives?" :My end goal is to read information from an nRF24l01 module connected to my Arduino UNO R3, and generate an interrupt whenever a message is sent to the Arduino. So yeah, that's exactly what I'm looking for.

Actually I've never used bit-banging before, so I will just dive a bit more into the topic. Thanks for the resources.

An SPI interrupt would seem to meet your requirements, no need to muck around trying to generate a different sort of interrupt.

Thanks, Nick, for the help.

Nick, a SPI slave can only send data if requested by the master. so if polling SPI in master is not good enough, there must be some other way for the slave to signal to master that it should do a request.

@Juraj OK, but in that case the slave won't be doing an unsolicited send. So therefore the slave would be sending a signal using some other pin (eg. "data ready"?) which could be connected to pin 2 or pin 3 for an interrupt.

In the example on the linked page the receiver just polls for a message to appear.

@Juraj Ach, I see we have an XY problem here. I made another answer. This answer is still "good" in the sense that it answers the question in bold asked by the OP. My other answer deals with the Y part of the problem.

My second answer ...
Your question, in bold, is a good example of an XY Problem. You asked:

Is there any way to change the MISO line from 12 to 3, or will I have to resort to using Pin change interrupts?

This is the X question. However the Y question is your goal:

My end goal is to read information from an nRF24l01 module connected to my Arduino UNO ...

I answered, in another answer, first about changing the MISO line from pin 12, and also pointed out that SPI transactions can generate interrupts.
However, as Juraj pointed out in a comment, the Arduino in this case is the master and the nRF24l01 is the slave (from the SPI point of view).
There is no way that a slave can burst into life and generate a message, and hence cause an interrupt. That is the master's job.
As I read on this page about the module it has an IRQ pin described thus:

IRQ is an interrupt pin that can notify the master when there is new data to process.

So, your job is simplified, really. You don't need to detect when an SPI transaction starts (the Arduino will start the transaction), you need to connect the IRQ pin to an Arduino pin and detect that data is ready. Simple! Then you can easily use pin 2 or pin 3 if you want to use the "hardware" interrupts rather than the pin-change interrupts. (The pin-change interrupts are hardware interrupts too, though).

I would say Y is the pseudo-problem which doesn't need a solution (move MISO to interrupt pin). the real problem X is the right use of the IRQ pin


text:
Arudino receiving interrupt command BEFORE entering sleep mode causing it not to receive any interrupt commands in order to wake up
I've written code for an Arduino Nano that when a button is pressed, it sends an IR command. It is set so that if no button press has been received for a period of 10 seconds, it will enter sleep mode until a button press is received. The button to send the IR command is the same button being used to send the wake up interrupt (button connected to pin D2). When testing the code the Arduino is able to go to sleep and wake up from the interrupt 1-3 times before it will suddenly receive an interrupt signal just before entering sleep mode. When this happens it gets stuck in sleep mode and will no longer accept the wake up interrupt. I am currently using Serial Monitor outputs and the built-in LED to determine when the Arduino is in sleep mode or not.
#include <IRLib.h>
#include <avr/sleep.h>
#define interruptPin 2

IRsend My_Sender;

const int button = 2;
int buttonState = 0;
int timeSinceCommand = 0;
const unsigned long eventInterval = 1000;
unsigned long previousTime = 0;

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);         //delete once code finalized and working
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);      //delete once code finalized and working
  Serial.println("---------------------------New Run---------------------------");
}

void loop() {
  while (timeSinceCommand < 10) {
    unsigned long currentTime = millis();
    buttonState = digitalRead(button);
    if (buttonState == HIGH) {
      My_Sender.send(SONY, 0xC90, 12);
      timeSinceCommand = 0;
      previousTime = currentTime;
    }
    if (currentTime - previousTime >= eventInterval) {
      timeSinceCommand++;
      previousTime = currentTime;
    }
  }
  if (timeSinceCommand >= 10) {
    Going_To_Sleep();
    timeSinceCommand = 0;
  }
}

void Going_To_Sleep() {
  sleep_enable();
  attachInterrupt(0, wakeUp, RISING);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  digitalWrite(LED_BUILTIN, LOW);             //delete once code finalized and working
  Serial.println("Arudino going to sleep!");  //delete once code finalized and working
  delay(1000);                                //delete once code finalized and working
  sleep_cpu();
  Serial.println("Arudino has waken up!");    //delete once code finalized and working
  digitalWrite(LED_BUILTIN, HIGH);            //delete once code finalized and working
}

void wakeUp() {
  Serial.println("Interrupt received!");      //delete once code finalized and working
  sleep_disable();
  detachInterrupt(0);
}

Here is the Serial Monitor output from a couple of tests:
---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!
---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!

Try clearing the interrupt flag before executing attachInterrupt(). For the pin 2 external interrupt on a Uno class board it will be something like: EIFR = bit (INTF0);

I copied that line of code and put it right before attachInterrupt() and it seems to have fixed my issue. Everything is working properly now. Thanks!

There are a couple of tricky things going on here... First, you should
be aware of a few facts:

Buttons are prone to mechanical bounce. You press a button once, and
quite often the microcontroller senses multiple transitions on the
input pin.

When INT0 is configured to sense rising edges, any rising edge on the
pin will set the INTF0 interrupt flag, whether the interrupt is
enabled or not. Once the flag is set, it will fire an interrupt
request as soon as the interrupt is enabled.

When the CPU receives an interrupt request, it finishes executing the
current instruction before servicing the request.

With that in mind, here is an explanation of what goes on:
When you wake up the Arduino with the push button, it often triggers
multiple signal transitions. The first rising edge wakes up the Arduino
and triggers the interrupt. The second rising edge only sets the INTF0
interrupt flag: the interrupt is “on hold”, because interrupts are not
themselves interruptible. However, before exiting, wakeUp() disables
servicing that interrupt, which means the flags just stays set. It is a
pending interrupt of sorts.
Some time later, Going_To_Sleep() is called again. attachInterrupt()
enables the interrupt and, since the flag is still set, the (pending)
interrupt fires immediately. That's when you see the message “Interrupt
received!” printed right before the Arduino goes to sleep. The problem
is that the interrupt is disabled by wakeUp(). One second later,
sleep_cpu() puts the CPU to sleep, and now our wake-up source is
disabled, so the Arduino is just locked into its dreams.
There is still one issue with this scenario. The interrupt handler
supposedly disabled sleeping, so how come the Arduino went to sleep
anyway? The answer is that sleeping was accidentally re-enabled by
set_sleep_mode() because of a data-race. Here is a disassembly of
set_sleep_mode():
in   r24, 0x33 ; read SMCR (Sleep Mode Control Register) into r24
andi r24, 0xF1 ; clear the Sleep Mode Select bits
ori  r24, 0x04 ; select the Power Down mode
out  0x33, r24 ; write back SMCR

The first instruction in this sequence comes right after the instruction
in attachInterrupt() that enables the INT0 interrupt. When that
instruction generates an interrupt request (because the interrupt flag
was already set), the interrupt request reaches the CPU while it is
already executing the in instruction above, and this instruction is
completed before servicing the interrupt request. This means that we
have now in register r24 a copy of the Sleep Mode Control Register from
before the interrupt is serviced. In this copy, the SE bit (Sleep
Enable) is set. Even though wakeUp() clears that bit in the actual
SMCR register, it stays set in our copy in r24. Then, the out
instruction re-enables sleeping. I experimented putting a single nop
instruction right before set_sleep_mode() and that was enough to
prevent the data race.
So here you have an explanation of the observed behavior. I may come
up with some suggestions for fixing the problem, but it need
to take some sleep before that (do not worry, I will make double sure I
have one interrupt source enabled before executing sleep).

Nice explanation especially about the data race risk which I hadn't thought about. When I use sleep mode, with wakeup on either external or pin change interrupt, I usually, if compatible with the application, (a) have an empty interrupt service routine and (b) don't detach the interrupt which is anyway attached in setup(). The sleep_disable() command immediately follows the sleep_cpu() command then any other code to respond to the wake up.

I'm taking this opportunity to include a simple basic sleep sketch which eliminates the possible race condition risk that Edgar Bonet identified in the standard approach to using the sleep mode for AVR class MCUs. See the reference in the sketch to further optimise, if required, to switch off the ADC, Brown out detection etc.
/*
   Sleep mode demonstration (Uno/Nano ATmega328P)
   based on https://www.gammon.com.au/power Sketch J
   but stripped down for demonstration purposes to exclude some optimisation (BOD and ADC etc.)
   See also: https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html

   Connect a button switch between pin 2 and ground
   Press the button. It wakes, blinks the led and then sleeps.

*/

#include <avr/sleep.h>

const byte LED = 13;  // built in led

void wake()
{
  // nothing here. All done in the loop
}

void setup()
{
  Serial.begin( 115200 ) ;
  pinMode( LED, OUTPUT );
  pinMode( 2, INPUT_PULLUP ) ;
  attachInterrupt ( digitalPinToInterrupt(2), wake, FALLING);
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
}

void loop()
{
  Serial.println( "waking . . . ") ;

  // your own code could go here instead

  for ( int i = 0; i < 4; i++ ) {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
  }
  delay(3000) ;

  Serial.println( "Sleeping. . . " ) ;
  Serial.flush() ;
  delay(20) ; // allow message to be written

  sleep_mode();
  // *** we wake here ***
}

Note that the calls to sleep_enable(), sleep_cpu() and sleep_disable() can be replaced by a single call to sleep_mode(). The three functions you used are most useful when you want to atomically test some condition before going to sleep.

@EdgarBonet. Good point. I've updated to include these because the objective was to provide a "simple as possible" but working example.


text:
Button Matrix / Wiring Schematics
I am just beginning my journey into the Arduino world - plenty of development experience, but basically nothing with electronics outside of building computers.
The question I have involves wiring schematics - specifically for a button matrix, but it does apply more broadly. Using this diagram and Fritzing mapping, I see numerous buttons connected to each other - presumably via soldering:

My question is, can you use wire nuts (or, more specifically multi-slot lever connectors) such as these to simplify the connection process?

I apologize in advance if this seems obvious, but I get lost trying to understand how to connect this stuff because I'm so new to it all.
Thanks in advance!

that keypad can only detect one button press at a time ... if you press two buttons at once, then up to four button presses can be detected ... a diode at each switch can be used to prevent "ghost" button presses

Woah - good to know @jstola! I'm going to start looking into diodes now. So much to learn, but luckily this first project is mainly for a button/busy box for my 18-month old kid, so he's going to smash all the buttons and not care as much on whether they do everything individually or not. Definitely an excellent tip though!

if you are expecting to press only one button at a time, then you can use a resistor array ... the input to the arduino would be a single wire connected to an analog input pin

Yet another thing I didn't know existed! This would make wiring SO much easier by not having to deal with so many individual resistors. If I could give you points on here, I totally would. Thank you!!

Assuming that "multi-slot lever connectors" is shorting the inserted wires together I see no reason why you could not use them.
If you are adverse to soldering consider using switches and cables commonly found in arcade machines instead.
Previously crimped cables ...

And arcade style micro switches ...

Can be combined / connected to form the switch matrix your designed above.

Fantastic - I didn't even know these existed. Thank you!


text:
Interfacing 8 ohm speaker ouput with ESP32
I'm trying to use an ISD1820 recording module with the ESP32, except I want to store the recordings and send them over Wifi rather than playing them back. The ISD1820 has an output for an 8-ohm speaker, which can be used in feedthrough mode (meaning the mic input goes directly to the output). I want to connect the 8-ohm speaker output to the ESP32 analog input, then store the recordings. How can I do that?
Please don't mention any other chips or modules. (e.g. saying "just buy a sparkfun recording module, etc.)
Thanks

why are you using the ISD1820?

You probably need to offset the voltage to 1.65V (half of 3.3V) to accommodate the symmetric speaker output (using a voltage divider between 0V and 3.3V would be the easiest). Also you need to make sure, that the voltage stays in the range between 0V and 3.3V, so that it doesn't destroy the ESP (maybe by using a Zener diode?). So probably possible, though this being not a good choice of chip for it.

Connect the output of the ISD1820 (which is connected to the 8-ohm speaker) to one of the analog input pins of the ESP32.Set up the ESP32's analog-to-digital converter (ADC) to sample the audio input from the ISD1820. Write code on the ESP32 to continuously sample the audio input from the ISD1820 using the ADC. You'll need to buffer the audio samples in memory to store them temporarily before transmission.
Here is a tutorial that you may find useful:https://www.instructables.com/NodeMcu-Speak-With-ISD1820-Module/


text:
OpenCV on ESP32 Arduino Nano
I am implementing a program on Arduino Nano ESP32: the KY-037 microphone is connected to the board and collects five seconds of analog signal. Then, an algorithm is applied to create a 128 x 128 matrix from the five-second signal. Now, I would like to apply the HOGDescriptor function from OpenCV.
Are there any possibilities to do so? How can OpenCV be installed on Arduino?

I vote to reopen. The question that is marked as duplicate only talks about the classic AVR based Arduinos. OpenCV on an ESP32 is possible, though in a reduced form. One seems to need the ESP32-DOWDQ6 chip for it. A quick search gave me this github project with OpenCV for ESP32 cross-compiled and this article on hackaday and the associated video about the ESP32-CAM.

@chrisl I seen that library. Another way to solve this limitation is to run the arduino code until before the OpenCV library, which will run on a Python script on PC. Not perfect but I will try


text:
Slow I2C communication
To collect temperature and BPM, I connected a max30101 in my Heltec WiFi kit V3 with ESP32. The data collected are stored in arrays to extract statistical features from signals which an algorithm will process to predict anxiety or baseline (with two other additional libraries).
The problem is that I see a very slow communication on the serial which increase if I add u8x8 library to print values on my builtin OLED. Thus, BPM are always very slow reaching a maximum of 20 BPM.
This is my code:
#include <PlaquetteLib.h> // --> Smoothing and scaling operations [https://sofapirate.github.io/Plaquette/]
using namespace pq; // --> use plaquette library as "pq"
Smoother smoother3(3.0f); // --> third moving mean of 3 seconds for ST values
Smoother smoother2(3.0f); // --> second moving mean of 3 seconds for HR values
#include <Wire.h> // --> I2C connection
#include "MAX30105.h" // --> Sparkfun library for MAX30101 sensor [https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library]
MAX30105 particleSensor; // --> used for BPM and ST
#include "Scaler.h" // --> Feature extraction library [https://github.com/eloquentarduino/everywhereml]
#include "Classifier.h" // --> Classification library containing Logistic Regression algorithm [https://github.com/eloquentarduino/micromlgen]
Eloquent::ML::Port::LogisticRegression clf; // --> declare classifier library
#include "heartRate.h" // --> Optical Heart Rate Detection (PBA Algorithm) [https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/master/src/heartRate.h]
#include <Arduino.h>
#include <U8x8lib.h>
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(18, 17, 21);

//____________________________________________________________________________________________________________________________________________________________________________
//DEFINING GLOBAL VARIABLES
//hr
const byte RATE_SIZE = 3; //Averaging
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
//st
float degree; // --> raw peripheral skin temperature in °C
float st; // averaged peripheral skin temperature in °C
unsigned long time_printing = 0; // --> variables for millis delay (1Hz)
const byte WINDOW_SIZE = 60;
byte signal1[WINDOW_SIZE];
byte signal2[WINDOW_SIZE];
byte signal1Index = 0;
byte signal2Index = 0;

//_________________________________________________________________________________________________________________________________________________________________________
void setup() {

  //instrumental initialization
  //Serial.begin(9600);
  Plaquette.begin();
  Wire.begin(41, 42);
  u8x8.begin();

  //hr sensor
  particleSensor.begin(Wire, I2C_SPEED_FAST);
  byte ledBrightness = 0x1F;
  byte sampleAverage = 1;
  byte ledMode = 3;
  byte sampleRate = 100;
  int pulseWidth = 411;
  int adcRange = 4096;
  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
  particleSensor.setPulseAmplitudeRed(0); //0 mA
  particleSensor.setPulseAmplitudeIR(0);  // 0 mA
  particleSensor.setPulseAmplitudeGreen(0x19); // 1 mA

  //st sensor
  particleSensor.enableDIETEMPRDY();

  //u8x8.setFont(u8x8_font_8x13B_1x2_r);
  //u8x8.drawString(0, 4, "Initializing...");
  //delay(2000);
  //u8x8.clearDisplay();
  //u8x8.setFont(u8x8_font_open_iconic_check_4x4);
  //u8x8.drawGlyph(6, 2, 0x40);
  //delay(2000);
  //u8x8.clearDisplay();

  }

//_________________________________________________________________________________________________________________________________________________________________________
// BPM values with MAX30101 sensor 1Hz
void hrCollection() {
/**
* The particle sensor capture the green led emission from the inner wrist. When a blood pulse happen, the photodiode capture a pulse of light which corresponds to a heart beat.
* In order to be able to capture peaks throw the wrist, the green led has been accurately set up in the setup() section, following the instructions published by the authors
* on page 22 of the paper. [https://pdfserv.maximintegrated.com/en/an/AN6409.pdf]
* The peaks, corresponding to the BPM, are computed throw a PBA algorithm, then, they are averaged with a moving window of size 3.
*/
  long irValue = particleSensor.getGreen();

  if (checkForBeat(irValue) == true)
  {
    //We sensed a beat!
    long delta = millis() - lastBeat;
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);

    if (beatsPerMinute < 255 && beatsPerMinute > 20)
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
      rateSpot %= RATE_SIZE; //Wrap variable

      //Take average of readings
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;

    }
  }

  // Add beatAvg to signal1
  signal1[signal1Index] = beatAvg;
  signal1Index = (signal1Index + 1) % WINDOW_SIZE;

}

//_________________________________________________________________________________________________________________________________________________________________-
// ST values with the particle sensor 1Hz.
void stCollection() {
/**
* Peripheral skin Temperature has been measured in degree Celsius thanks to an InfraRed thermophile that capture the emissivity of the human skin.
*/

  degree = particleSensor.readTemperature();

  st = degree >> smoother3;

  // Add st to signal2
  signal2[signal2Index] = st;
  signal2Index = (signal2Index + 1) % WINDOW_SIZE;

}
//____________________________________________________________________________________________________________________________________________________________________________
// Feature Extraction
void extraction(float* features) {
  // Calculate minimum, maximum, mean, median, standard deviation, variance, skewness, and kurtosis for signal1 (beatAvg)
  int beatMin = INT_MAX;
  int beatMax = INT_MIN;
  float beatSum = 0.0;
  float beatSumSquares = 0.0;
  float beatSkewness = 0.0;
  float beatKurtosis = 0.0;
  byte sortedSignal1[WINDOW_SIZE];

  for (byte i = 0; i < WINDOW_SIZE; i++) {
    if (signal1[i] < beatMin) {
      beatMin = signal1[i];
    }
    if (signal1[i] > beatMax) {
      beatMax = signal1[i];
    }
    beatSum += signal1[i];
    beatSumSquares += pow(signal1[i], 2);
    sortedSignal1[i] = signal1[i];
  }

  float beatMean = beatSum / WINDOW_SIZE;

  std::sort(sortedSignal1, sortedSignal1 + WINDOW_SIZE);

  byte middle = WINDOW_SIZE / 2;
  byte beatMedian;
  if (WINDOW_SIZE % 2 == 0) {
    beatMedian = (sortedSignal1[middle - 1] + sortedSignal1[middle]) / 2;
  } else {
    beatMedian = sortedSignal1[middle];
  }

  float beatStdDeviation = sqrt((beatSumSquares / WINDOW_SIZE) - pow(beatMean, 2));
  float beatVariance = pow(beatStdDeviation, 2);

  for (byte i = 0; i < WINDOW_SIZE; i++) {
    float deviation = signal1[i] - beatMean;
    beatSkewness += pow(deviation, 3);
    beatKurtosis += pow(deviation, 4);
  }
  beatSkewness /= (WINDOW_SIZE * pow(beatStdDeviation, 3));
  beatKurtosis /= (WINDOW_SIZE * pow(beatStdDeviation, 4));

  // Calculate minimum, maximum, mean, median, standard deviation, variance, skewness, and kurtosis for signal2 (st)
  float stMin = FLT_MAX;
  float stMax = FLT_MIN;
  float stSum = 0.0;
  float stSumSquares = 0.0;
  float stSkewness = 0.0;
  float stKurtosis = 0.0;
  float sortedSignal2[WINDOW_SIZE];

  for (byte i = 0; i < WINDOW_SIZE; i++) {
    if (signal2[i] < stMin) {
      stMin = signal2[i];
    }
    if (signal2[i] > stMax) {
      stMax = signal2[i];
    }
    stSum += signal2[i];
    stSumSquares += pow(signal2[i], 2);
    sortedSignal2[i] = signal2[i];
  }

  float stMean = stSum / WINDOW_SIZE;

  std::sort(sortedSignal2, sortedSignal2 + WINDOW_SIZE);

  middle = WINDOW_SIZE / 2;
  byte stMedian;
  if (WINDOW_SIZE % 2 == 0) {
    stMedian = (sortedSignal2[middle - 1] + sortedSignal2[middle]) / 2;
  } else {
    stMedian = sortedSignal2[middle];
  }

  float stStdDeviation = sqrt((stSumSquares / WINDOW_SIZE) - pow(stMean, 2));
  float stVariance = pow(stStdDeviation, 2);

  for (byte i = 0; i < WINDOW_SIZE; i++) {
    float deviation = signal2[i] - stMean;
    stSkewness += pow(deviation, 3);
    stKurtosis += pow(deviation, 4);
  }
  stSkewness /= (WINDOW_SIZE * pow(stStdDeviation, 3));
  stKurtosis /= (WINDOW_SIZE * pow(stStdDeviation, 4));

  // Store the calculated features in the features array
  features[0] = beatMin;
  features[1] = beatMax;
  features[2] = beatMean;
  features[3] = beatMedian;
  features[4] = beatStdDeviation;
  features[5] = beatVariance;
  features[6] = beatSkewness;
  features[7] = beatKurtosis;
  features[8] = stMin;
  features[9] = stMax;
  features[10] = stMean;
  features[11] = stMedian;
  features[12] = stStdDeviation;
  features[13] = stVariance;
  features[14] = stSkewness;
  features[15] = stKurtosis;
}
//_____________________________________________________________________________________________________________________________________________________________________________

//_____________________________________________________________________________________________________________________________________________________________________________
void loop() {

  Plaquette.step();

  hrCollection();
  stCollection();

  float features[16]; // Create the features array
  extraction(features);

  if (!processor.transform(features))
  return;

  //Serial.print(beatsPerMinute); Serial.print(","); Serial.print(st); Serial.print(","); Serial.println(clf.predictLabel(processor.X));

  char heart[3];
  char temperature[2];
  u8x8.setFont(u8x8_font_open_iconic_embedded_2x2);
  u8x8.drawGlyph(4, 1, 0x46);
  u8x8.setFont(u8x8_font_lucasarts_scumm_subtitle_r_2x2_f);
  itoa(beatsPerMinute, heart, 10);
  u8x8.drawString(7, 1, heart);
  itoa(st, temperature, 10);
  u8x8.drawString(7, 3, temperature);
  u8x8.drawString(0, 5, clf.predictLabel(processor.X));
}

When I print on 9600 without u8x8 the printing is normal even if the problem with BPM persists, when I add u8x8 I see on the serial a very slow printing. 115200 baud rate doesn't show anything but empty squares. I am wondering if the problem could be the bad quality wires or I am making some mistake inside the code.

Discovered that esp32, Heltec in my case, have some conflicts problem when using the builtin OLED. The conflicts depend on the I2C communication: by applying an I2C scanner with on the OLED bus only, I noticed that the address changes randomly, and I didn't understand the reason why. As not having the possibility to test another esp32 board, everything worked with a Wemos esp8266 D1 mini pro.


text:
Esp-now reacting like bloating in Many-to-one setup
I have project which 3 esp01 controller and 1 nodemcu 12-E receiver which gives scores.
Trying to read all input freely from controllers but when i use 3 at same time or pressing button too quickly nodemcu seems to halts and doesn't react or get messages.
Is my simple if algorithm is flawed or did i hit a hardware barrier.
I used working button library for single click event in ESP-01
For fundamental setup i used tutorial.
Esp01 Sender
#include <Button2.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
#define RED 2
#define BLUE 0

// REPLACE WITH RECEIVER MAC Address
//Esp8266 80:7D:3A:37:C5:66
uint8_t broadcastAddress[] = {0x80, 0x7D, 0x3A, 0x37, 0xC5, 0x66};

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID  1

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
    int id;
    int x;
    int y;
} struct_message;

// Create a struct_message called test to store variables to be sent
struct_message myData;

  // Init ESP-NOW
Button2 buttonA, buttonB;

unsigned long lastTime = 0;
unsigned long timerDelay = 5000;

// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  Serial.print("\r\nLast Packet Send Status: ");
  if (sendStatus == 0){
    Serial.println("Delivery success");
  }
  else{
    Serial.println("Delivery fail");
  }
}

//void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow  = true);

void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
  //pinMode(2,INPUT_PULLUP);
  //pinMode(0,INPUT_PULLUP);

  buttonA.begin(RED);
  buttonA.setClickHandler(click);

  buttonB.begin(BLUE);
  buttonB.setClickHandler(click);
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  // Set ESP-NOW role
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);

  // Once ESPNow is successfully init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);

  // Register peer
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

}

void loop() {
  buttonA.loop();
  buttonB.loop();
}
void click(Button2& btn) {
    if (btn == buttonA) {
      myData.id = BOARD_ID;
      myData.x = 1;
      myData.y = 0;
      esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
      Serial.println("A clicked");
    } else if (btn == buttonB) {
      myData.id = BOARD_ID;
      myData.x = 0;
      myData.y = 1;
      esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
      Serial.println("B clicked");
    }
}

NodeMCU 12-E Receiver
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <Arduino.h>

#define  LED0 D0
#define  LED1 D1
#define  LED2 D2
#define  LED3 D3
#define  LED4 D4
#define  LED5 D5
#define  LED6 D6
#define  LED8 D8
#define  LED7 D7

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
    int id;
    int x;
    int y;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Create a structure to hold the readings from each board
struct_message board1;
struct_message board2;
struct_message board3;

// Create an array with all the structures
struct_message boardsStruct[3] = {board1, board2, board3};

// refree
/*
void ref1(int x, int y){

  if (x == 1 ){
      digitalWrite(LED7, HIGH);
      delay(5);
      digitalWrite(LED7, LOW);
    }
  else  if (y == 1 ){

      digitalWrite(LED8, HIGH);
      delay(5);
      digitalWrite(LED8, LOW);
    }

}

void ref2(int x, int y){

  if (x == 1 ){
      digitalWrite(LED6, HIGH);
      delay(5);
      digitalWrite(LED6, LOW);
    }

  else if (y == 1 ){

      digitalWrite(LED2, HIGH);
      delay(5);
      digitalWrite(LED2, LOW);
    }

}

void ref3(int x, int y){

  if (x == 1){
      digitalWrite(LED0, HIGH);
      delay(5);
      digitalWrite(LED0, LOW);
    }

  else if (y == 1){

      digitalWrite(LED1, HIGH);
      delay(5);
      digitalWrite(LED1, LOW);
    }

}
  */

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) {
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.printf("Board ID %u: %u bytes\n", myData.id, len);
  Serial.println(myData.id);

  if (myData.id==1 ){
    ref1(myData.x, myData.y);
  }
  if (myData.id==2 ){
    ref2(myData.x, myData.y);
  }
  if (myData.id==3 ){
    ref3(myData.x, myData.y);
  }

  // Update the structures with the new incoming data
  boardsStruct[myData.id-1].x = myData.x;
  boardsStruct[myData.id-1].y = myData.y;
  boardsStruct[myData.id-1].id = myData.id;
  Serial.printf("x value: %d \n", boardsStruct[myData.id-1].x);
  Serial.printf("y value: %d \n", boardsStruct[myData.id-1].y);
  Serial.printf("id value: %d \n", boardsStruct[myData.id-1].id);
  Serial.println();

}

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED0, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
  pinMode(LED8, OUTPUT);

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);

}

void loop(){

}

don't print inside ISRs ... set a flag instead ... move message printing to inside loop() ...print a message if flag is set

what it the meaning of ISR ? and can you give and example snip of pseudocode.

I set it up with flags but no hope. Still stuck now trying to RingBuffer.

ISR - interrupt service routine ... it is the callback function

take out the delay() and print() lines, and see if it works then.


text:
RMS Voltage Value
it has been a week that I'm struggling with the arduino to measure the RMS Voltage value. By OSC I can see that the RMS voltage value changes around 3V. But I can't see it by serial port. I think my sampling or conversion has problem and I can't find it. I really appreciate it if anyone can take a look at my codes and suggest anything.
float readRMS_new(int pin, int vref) {
  int numReadings[100];
  const unsigned long samplingInterval = 2;  // Interval between RMS calculations in milliseconds
  unsigned int readingsSum = 0;   // Sum of squared readings
  unsigned int readingsCount = 0; // Number of readings taken
  unsigned long lastSamplingTime = 0;  // Time of the last RMS calculation
  float rmsVoltage = 0;
  float finalVoltage = 0;
  float circuitGain = 4.31;  // Gain of the circuit

  unsigned long currentTime = millis();  // Current time

  // Check if it's time to perform an RMS calculation
  if (currentTime - lastSamplingTime >= samplingInterval) {
    lastSamplingTime = currentTime;  // Update the last sampling time

    // Perform RMS calculation
    for (int i = 0; i < 100; i++) {
      numReadings[i] = analogRead(pin);
      readingsSum += pow(numReadings[i] - vref, 2);
      readingsCount++;
    }

    // Calculate RMS voltage
    float rms = sqrt(readingsSum / readingsCount);
    rmsVoltage = rms * 0.0048;
    finalVoltage = rmsVoltage * circuitGain;

    if (finalVoltage > 0.0f) {
      // Print RMS voltage
      Serial.print("RMS Voltage: ");
      Serial.println(finalVoltage, 3);  // Print with 3 decimal places
    }

    // Reset variables for the next RMS calculation
    readingsSum = 0;
    readingsCount = 0;

    return finalVoltage;
  }

  return 0.0f;  // Return 0 if it's not time to perform an RMS calculation
}

Regards
Farzaneh

What calls  readRMS_new() ? An Interrupt Service Routine or from the loop() ? But, whatever, it is going to be slow with all those maths functions.

please describe the signal that is being sampled ... add the description to your question ... do not add a comment

There are multiple issues with this piece of code:

Local variables, i.e. variables defined inside functions or braced
blocks, are created each time the execution enters the function or
block, and destroyed when it leaves it. Thus, lastSamplingTime will
always be zero when it is checked. If you want the variable to
preserve its value across invocations of the function, you have to
either make it global or qualify it as static.

There is no point in storing the readings in an array, as you never
read back any element of the array other than the one you just
stored. The array is then eating memory for no good reason.

The Arduino will not be able to take more than one reading every
112 µs, or 100 readings in 11.2 ms. There is no point
in trying to ensure a 2 ms interval between RMS calculations.

There is no point in counting the readings: you know you are taking
100 of them.

You should avoid using pow() for squaring an integer: this is a
floating-point function which is prone to rounding errors.

Maybe the most serious issue: on the Mega, an unsigned int is
16-bits, and cannot store numbers larger than 65,535. readingsSum
is very likely going to overflow and give you a meaningless result.

Returning zero to mean “no data available” is probably not a very
good choice, as zero is also a perfectly valid result. You should
consider returning an impossible value, like -1 (an RMS reading
cannot be negative).

Here is how I would write the computation of the RMS value:
long readingsSum = 0;
for (int i =0; i < 100; i++) {
    long reading = analogRead(pin) - vref;
    readingsSum += reading * reading;
}
float rms = sqrt(readingsSum / 100);

Note that reading is of type long in order to avoid the squaring to
overflow.

Thank you all for your time dedication. Finally increasing the sampling and optimize the same codes I could achieve my goals. I will post the functioning code for those who might need it.
float readRMS(int pin, int vref) {

  int lecturas[200]; // declaring the matrix

  float suma = 0; // sum of the squares

  float rms = 0;  // squares mean

  float volt = 0;  //

  float Volt_Final = 0;

  for (int cont = 0; cont < 200; cont++) {

    lecturas[cont] = analogRead(pin);

    delayMicroseconds(200);
  }
  for (int j = 0; j < 200; j++) {

    //Serial.println(lecturas[j]);

    suma = suma + pow((lecturas[j] - vref), 2);

    //Serial.println(suma);
  }
  rms = sqrt((suma / 200));

  volt = (rms / 1024) * 5;

  //Serial.println(volt);

  //suma=0;

  // Reset variables for the next RMS calculation

  rms = 0;

  lecturas[200] = 0;

  //Volt_Final = (volt * 4.31); //real voltage with circuit gain

  return volt;
}

lecturas[200] = 0; is out of bounds. Array indices are 0 to 199


text:
Code not displaying/working DFRobot SIM808 shield data on Adafruit 1.69" ST7789 rounded screen
I have been having trouble with the code below not display and possibly not working and or looping. Before making changes to my code I had a problem where the Serial monitor would print up to "longitude" and occasionally print the first number of this value, however, it would pause stop and the whole code would pause/not continue. I had printed data to the Serial Monitor constantly but was told that the problem could be that the serial monitor is full. With this, I have deleted most of the code for the serial monitor as it is not needed for my project. Now I cant tell at what stage my code is not working. The code for the screen is formatted this way as I have found it is the best way to reduce flickering, however I know there is a fast display library but was unable to implement it.
Could it be battery issue? I am using a 9V battery to power all of the components.
Any help would be much appreciated and the code is provided below.
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <DFRobot_SIM808.h>
#include <SPI.h>
#include <Wire.h>

#define TFT_CS        10
#define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
#define TFT_DC         8

#define date_x    20
#define date_y    17
#define time_x    20
#define time_y    35
#define v_x       17
#define v_y       70

float la;
float lo;

char DateGPS[10];
char TimeGPS[5];

String prevDate = "99/99/9999";
String Date = "00/00/0000";
String prevTime = "99:99";
String Time = "00:00";
String prevV = "999:99";
String V = "000:00";

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

DFRobot_SIM808 sim808(&Serial);

void setup()
{
  Serial.begin(9600);

  tft.init(240, 280);
  tft.fillScreen(ST77XX_BLACK);

  //******** Initialize sim808 module *************
  while(!sim808.init())
  {
      delay(1000);
      Serial.print("Sim808 init error\r\n");
  }

  //************* Turn on the GPS power************
  if( sim808.attachGPS())
      ;
  else
      ;

}

void loop()
{
   //************** Get GPS data *******************
   if (sim808.getGPS())
   {
    sprintf(DateGPS, "%02d-%02d-%04d", sim808.GPSdata.day, sim808.GPSdata.month, sim808.GPSdata.year);
    Date = String(DateGPS);
    if(prevDate != Date)
    {
      deletePrevDate();
      printDate();
    }
    prevDate = Date;

    sprintf(TimeGPS, "%02d:%02d", sim808.GPSdata.hour, sim808.GPSdata.minute);
    Time = String(TimeGPS);
    if(prevTime != Time)
    {
      deletePrevTime();
      printTime();
    }
    prevTime = Time;

    Serial.println(sim808.GPSdata.lat, 6);

    Serial.println(sim808.GPSdata.lon, 6);

    V = String(sim808.GPSdata.speed_kph);
    if(prevV != V)
    {
      deletePrevV();
      printV();
    }
    prevV = V;

    //************* Turn off the GPS power ************
    sim808.detachGPS();
  }

}

void deletePrevDate()
{
  tft.setCursor(date_x, date_y);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_BLACK);
  tft.println(prevDate);
  return;
}

void printDate()
{
  tft.setCursor(date_x, date_y);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_WHITE);
  tft.println(Date);
  return;
}

void deletePrevTime()
{
  tft.setCursor(time_x, time_y);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_BLACK);
  tft.println(prevTime);
  return;
}

void printTime()
{
  tft.setCursor(time_x, time_y);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_WHITE);
  tft.println(Time);
  return;
}

void deletePrevV()
{
  tft.setCursor(v_x, v_y);
  tft.setTextSize(6);
  tft.setTextColor(ST77XX_BLACK);
  tft.println(prevV);
  return;
}

void printV()
{
  tft.setCursor(v_x, v_y);
  tft.setTextSize(6);
  tft.setTextColor(ST77XX_WHITE);
  tft.println(V);
  return;
}

serial monitor is full is nonsense ... you can test that with a sketch that sends a lot of data

please roll back your code to the previous version with lots of serial.print ... copy the content of the serial monitor and paste it into your question ... format it as code for readability ... please, no screenshots of text


text:
LIS3DH not working with arduino
I am new to LIS3DH and tried to interface it with Arduino Uno. I have made the circuit as follows-
LIS3DH    :    Arduino Uno
SCL       :    SCL (GPIO18)
SDA       :    SDA (GPIO19)
3.3v      :    3.3v
Gnd       :    Gnd
I used the example code from below link -
sparkfun LIS3DH hookup guide
Even though I tried to change the scl/sda pins to A4 and A5, I am not getting any results. All the time I am getting same values for all orientations.
Let me know if anyone can help me.
Thanks

Try https://playground.arduino.cc/Main/I2cScanner/ if it finds any address in the bus

Hi, just to update, deleting the header file "SPI.h" makes it work. I don't know why but it is working. Also, same thing happened in esp8266 nodemcu.


text:
4x TPIC6B595 + 4x 7 segment display
I am going to use 4x TPIC6B595 and 4x 7 segment display with common anode.
Below You Can find vendor site of this display.
https://sklep.avt.pl/wyswietlacz-led-2-30-57mm-zielony-wa.html
Here is my diagram:

I want to display 4 digit number. Will it work? Or do i need also MIC2981 chip to supply more current?
I didn't use shift registers like TPIC before. Could You show me a basic code to make display show 4 digit number?
Thanks in advance.

In this case you don't need the MIC2981 to switch the anodes because the anodes can be continuously powered. In your previous attempt, which used a single shift register and multiplexing, it was necessary to switch the anodes. Check that 9 volts is enough before proceeding too far. 12volts is probably better with that display.
You may find this project helpful as a code example: https://github.com/HeikkiHietala/large-7-segment-led-display/blob/master/Arduino-bigdigit03-clock.ino

Thank You for Your big support! That's what I need.


text:
Running a 5V, 4pin pwm fan with Mega2560
I have a Mega2560 and would like to use it to power a single fan and display. The fan is a 5V fan that draws 260mA and I can't find power specs for this display. I can't find a clear answer for how much current I can safely draw off of the 5V pins on this board. Does anyone know if I'll be able to run these devices off of my Mega2560?
Board: https://www.amazon.ca/dp/B01H4ZLZLQ
Display: https://www.amazon.ca/gp/product/B085NHM5TC/
Fan: https://www.amazon.ca/dp/B07DXR1Y73/

yes, the manufacturer knows ... read their datasheet

Your board has an AMS1117 voltage regulator, google the part number for its datasheet. For display, even you can't find the data, you can measure it easily by turning on all the display segments.

Your board has an AMS1117 voltage regulator, google the part number for its datasheet. For display, even you can't find the data, you can measure it easily by turning on all the display segments.


text:
If I reduce ADC sample rate, do I get an average over the time period?
I am working with a ESP32-C3 devkit. I am using the internal ADC on that chip to read from an analog microphone. I initialize the ADC like this:
adc_continuous_config_t dig_cfg = {
    .sample_freq_hz = 20000,
    // ...
};
ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg));

If I reduce the sample frequency to, say 1000 Hz, then will each sample represent, roughly, an average of 20 samples from my previous stream (where the sample frequency was 20,000 Hz)? Or is it more like I will get just one out of every 20 samples from the original stream?
The reason I ask is that I'm hoping to perform a kind of low-pass filter by changing the ADC sampling frequency and I'm wondering what's going on inside the ADC hardware when I change the sampling frequency.

This really depends on the hardware inside the processor.  Some chip makers like NXP have configurable ADC circuits where the hardware can average several samples for every reported value.  Others may not.  You really have to dive into the processor's specifications / configuration.  Also investigate the number of significant bits.  Just because an ADC has 8 bits does not necessarily mean it has 8 bits of resolution.

Most people would rather do the filtering in the digital domain: you have so much flexibility for the filter design…

Possibly not. The ADC on the Arduino Uno (a different processor, I know) uses the "sample and hold" technique. This means that the ADC samples the input voltage at a point in time, copying it into a sample-and-hold capacitor. It then successively compares it to be above or below threshold voltages to generate the individual bits of the resulting number. I have some details about the Uno ADC here.
It probably does this so that, when sampling a rapidly changing signal (like audio) it samples a moment in time, rather than having the comparison be of a signal that is changing over time.
I can't find technical details for the ESP32 ADC sampling method, but it seems likely that a lower sample rate will simply sample less data points, not take an average. This  could lead to wildly inaccurate results.
You might want to check out the Nyquist Frequency to see the reasons for choosing a certain sample rate.
If you want an average, feeding the signal into a suitably-sized RC filter might be a good way of finding an average voltage.