How to delay a output about 15 minutes after pressing a button? - c++

I am learning micro controller programming. I need help to complete my program at WinAVR with Atmega8L-8PU.
i have added 3 buttons, when the buttons pressed: first button will supply output for 15 minutes, 2nd one will 30 minutes and the last 3rd one will 45 minutes. after elapsing each time that should auto reset for the next press.
Here is my codes i have wrote but i cant added time duration. if anybody can make it it will be very helpful for me. Advance Thanks :).
#define numberofButtons 3
#include <avr/io.h>
#include"buttonpress.h"
int main(void)
{
DDRB = 0b00000000;
DDRD = 0b00000111;
PORTB = (1<<PINB0)|(1<<PINB1)|(1<<PINB2);
while(1)
{
if (buttonpressed(0, PINB, 0, 100))
{
PORTD ^= (1<<PIND0);
}
if (buttonpressed(1, PINB, 1, 100))
{
PORTD ^= (1<<PIND1);
}
if (buttonpressed(2, PINB, 2, 100))
{
PORTD ^= (1<<PIND2);
}
}
}
i have tried this way but it also not working........ :(
#define numberofButtons 3
#include"buttonpress.h"
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned char seconds =0;
int minutes;
int main ()
{
DDRB = 0b00000000;
DDRD = 0b00000111;
PORTB = (1<<PINB0)|(1<<PINB1)|(1<<PINB2);
volatile int seconds;
DDRD |= (1<<PIND0)|(1<<PIND1)|(1<<PIND2);
TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
TIMSK |= (1 << OCIE1A); // Enable CTC interrupt
sei(); // Enable global interrupts
OCR1A = 15624; // Set CTC compare value to 1Hz at 8MHz AVR clock, with a prescaler of 64
TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
while (1)
{
if(seconds==60)
{
minutes++;
seconds=0;
}
{
if (buttonpressed(0, PINB, 0, 100))
{
PORTD ^= (1<<PIND0);
int total_seconds=900;
while(total_seconds-seconds!=0)
{
//Delay of 15 min
}
}
} return 0;
}
}
ISR (TIMER1_COMPA_vect)
{
seconds++;
}

You can setup Timer0 to call interrupt each second for example. During each interrupt you have to increment internal counter. After elapsing required time (15, 30, 45 min) implement your own logic (Like shutdown desired port).

It very simple if you have functions to get a counter from the CPU, a counter that increases with a specific interval that can be calculated.
Then when the button is pressed, you set a variable to the current value of the counter plus the amount that corresponds to 15 minutes. And in the loop, you check the current value of the counter to the variable you set on key-press. When the current counter is equal or larger than the variable, then 15 minutes have passed.
Some pseudo-code
int main(void)
{
int eventHapening = 0;
while (1)
{
if (keypress)
{
eventHappening = currentCounter + 15 minutes;
}
// Check that eventHappening is non-zero to prevent false positives
if (eventHappening != 0 && currentCounter >= eventHappening)
{
// Do something
eventHappening = 0; // Reset, and disable event
}
}
}

If you have access to the header file time.h, then the following could be a solution:
#define numberofButtons 3
#include <avr/io.h>
#include<time.h>
#include"buttonpress.h"
void wait(double x)
{
clock_t begin, end;
double time_spent, limit=1000*60*x;
begin = clock();
while(time_spent<= limit)
{
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
}
}
int main(void)
{
DDRB = 0b00000000;
DDRD = 0b00000111;
PORTB = (1<<PINB0)|(1<<PINB1)|(1<<PINB2);
while(1)
{
if (buttonpressed(0, PINB, 0, 100))
{
PORTD ^= (1<<PIND0);
wait(15);
}
if (buttonpressed(1, PINB, 1, 100))
{
PORTD ^= (1<<PIND1);
wait(15);
}
if (buttonpressed(2, PINB, 2, 100))
{
PORTD ^= (1<<PIND2);
wait(15);
}
}
}
Most probably the above code would not get any error. As the code have some dependencies I could successfully compile a similar program which is given below.
#define numberofButtons 3
#include <stdio.h>
#include<time.h>
void wait(double x)
{
clock_t begin, end;
double time_spent, limit=1000*60*x;
begin = clock();
while(time_spent<= limit)
{
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
}
}
int main(void)
{
char c;
while((c = getchar())!='e')
{
if (c == 'a')
{
printf("I am in a! Come after 15 min!\n");
wait(15);
printf("WOW! How could you pass 15 min!!\n");
}
if (c == 'b')
{
printf("I am in b! Come after 15 min!\n");
wait(15);
printf("WOW! How could you pass 15 min!!\n");
}
if (c == 'c')
{
printf("I am in c! Come after 15 min!\n");
wait(15);
printf("WOW! How could you pass 15 min!!\n");
}
}
}
You can see here that it has no compilation error while compiling with c.

You didn't tag your question as AVR, which is why the existing answers are ignoring the fact that you have actual AVR timers.
More accurately, those timers are CPU cycle counters. TIMER1 in particular is a 16 bit counter. If you set the TCCR1 clock select bits to 101, this will count one tick every 1024 CPU cycles. Let's assume a 16 Mhz clock, that means 16000000 CPU cycles per second = 15625 ticks per second.
As TIMER1 is a 16 bit value, it overflows every 4.2 seconds. You can use this overflow to generate an interrupt. 900 seconds is just 214.6 interrupts - can you get away with 898 seconds? Of course, you could also count overflows of TIMER0. Since that's only 8 bits, you have 256 times as many overflows: 54931 in 900 seconds.

Related

How to read motor encoder values with interrupts in FreeRTOS?

I am working on a project where I need to obtain precise angular velocity from four motor encoders. I am using ESP32 DEVKIT-V1 module, and would like to use four interrupts, which will fire when each motor encoder switches state. This produces a square signal of around 700 Hz (period of 1,42 ms). This needs to be done on one core due to timing restrictions, as the processor must not miss any ticks. This is why I decided to use FreeRTOS. As the tick rate of the ESP32 is 1 ms, it cannot read higher frequencies than 500 Hz (period of 2 ms).
I would like to call getEncoderTickNumber() function every time one of the four interrupts fires, however, I only get the ESP32 to continually reset. I also wish to pass the number of ticks (encoderValueA1 - A4) from function getEncoderTickNumber() to getEncoderRPM() by queues.
I am still a beginner in C/C++, so I would be very grateful if you could point out some beginner mistakes that I am making. Thank you for your time.
#include <Arduino.h>
// Motor encoder output pulse per rotation (AndyMark Neverest 60)
int ENC_COUNT_REV = 420;
// Pulse count from encoder
long encoderValueA1 = 0;
long encoderValueA2 = 0;
long encoderValueA3 = 0;
long encoderValueA4 = 0;
int currentStateMotorEncoderA1;
int currentStateMotorEncoderA2;
int currentStateMotorEncoderA3;
int currentStateMotorEncoderA4;
int previousStateMotorEncoderA1;
int previousStateMotorEncoderA2;
int previousStateMotorEncoderA3;
int previousStateMotorEncoderA4;
// Variable for RPM measuerment
int rpm1 = 0;
int rpm2 = 0;
int rpm3 = 0;
int rpm4 = 0;
#define INT_PIN1 17
#define INT_PIN2 18
#define INT_PIN3 19
#define INT_PIN4 16
#define PRIORITY_LOW 0
#define PRIORITY_HIGH 1
QueueHandle_t encoderQueueHandle;
#define QUEUE_LENGTH 4 //four rpm readings
long* pdata = &encoderValueA1;
void io_expander_interrupt()
{
xQueueSendToBackFromISR(&encoderQueueHandle, &pdata, NULL);
}
///////////
// TASKS //
///////////
void getEncoderTickNumber(void *parameter)
{
while (1)
{
if (xQueueReceiveFromISR(&encoderQueueHandle, &pdata, NULL) == pdTRUE)
{
currentStateMotorEncoderA1 = digitalRead(INT_PIN1);
currentStateMotorEncoderA2 = digitalRead(INT_PIN2);
currentStateMotorEncoderA3 = digitalRead(INT_PIN3);
currentStateMotorEncoderA4 = digitalRead(INT_PIN4);
if (currentStateMotorEncoderA1 != previousStateMotorEncoderA1)
{
encoderValueA1++;
}
if (currentStateMotorEncoderA2 != previousStateMotorEncoderA2)
{
encoderValueA2++;
}
if (currentStateMotorEncoderA3 != previousStateMotorEncoderA3)
{
encoderValueA3++;
}
if (currentStateMotorEncoderA4 != previousStateMotorEncoderA4)
{
encoderValueA4++;
}
previousStateMotorEncoderA1 = currentStateMotorEncoderA1;
previousStateMotorEncoderA2 = currentStateMotorEncoderA2;
previousStateMotorEncoderA3 = currentStateMotorEncoderA3;
previousStateMotorEncoderA4 = currentStateMotorEncoderA4;
}
}
}
void getEncoderRPM(void *parameter)
{
while (1)
{
rpm1 = (encoderValueA1 * 60) / ENC_COUNT_REV;
rpm2 = (encoderValueA2 * 60) / ENC_COUNT_REV;
rpm3 = (encoderValueA3 * 60) / ENC_COUNT_REV;
rpm4 = (encoderValueA4 * 60) / ENC_COUNT_REV;
encoderValueA1 = 0;
encoderValueA2 = 0;
encoderValueA3 = 0;
encoderValueA4 = 0;
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
void printData(void *parameter)
{
while (1)
{
Serial.print("1:");
Serial.print(rpm1);
Serial.print(" 2:");
Serial.print(rpm2);
Serial.print(" 3:");
Serial.print(rpm3);
Serial.print(" 4:");
Serial.println(rpm4);
vTaskDelay(500 / portTICK_RATE_MS);
}
}
void setup()
{
Serial.begin(115200);
pinMode(INT_PIN1, INPUT);
attachInterrupt(INT_PIN1, getEncoderTickNumber, RISING);
pinMode(INT_PIN2, INPUT);
attachInterrupt(INT_PIN2, getEncoderTickNumber, RISING);
pinMode(INT_PIN3, INPUT);
attachInterrupt(INT_PIN3, getEncoderTickNumber, RISING);
pinMode(INT_PIN4, INPUT);
attachInterrupt(INT_PIN4, getEncoderTickNumber, RISING);
// Create the queue
encoderQueueHandle = xQueueCreate(QUEUE_LENGTH, sizeof(uint32_t));
xTaskCreatePinnedToCore( // Use xTaskCreate() in vanilla FreeRTOS
getEncoderTickNumber, // Function to be called
"getEncoderTickNumber", // Name of task
1024, // Stack size (bytes in ESP32, words in FreeRTOS) inside the heap
NULL, // Parameter to pass to function
PRIORITY_LOW, // Task priority (0 to configMAX_PRIORITIES - 1)
NULL, // Task handle
1); // Run on one core for demo purposes (ESP32 only)
xTaskCreatePinnedToCore( // Use xTaskCreate() in vanilla FreeRTOS
printData, // Function to be called
"printData", // Name of task
1024, // Stack size (bytes in ESP32, words in FreeRTOS) inside the heap
NULL, // Parameter to pass to function
PRIORITY_LOW, // Task priority (0 to configMAX_PRIORITIES - 1)
NULL, // Task handle
0); // Run on one core for demo purposes (ESP32 only)
xTaskCreatePinnedToCore( // Use xTaskCreate() in vanilla FreeRTOS
getEncoderRPM, // Function to be called
"getEncoderRPM", // Name of task
1024, // Stack size (bytes in ESP32, words in FreeRTOS)
NULL, // Parameter to pass to function
PRIORITY_HIGH, // Task priority (0 to configMAX_PRIORITIES - 1)
NULL, // Task handle
0); // Run on one core for demo purposes (ESP32 only)
vTaskDelete(NULL); // Deletes the setup/loop task now that we are finished setting up (optional)
}
void loop()
{
}
There are quite a few problems in your code. Let's go over them one by one, see if it clears things up.
Firstly, don't delete the task in setup():
vTaskDelete(NULL); // Deletes the setup/loop task now that we are finished setting up (optional)
Arduino will manage the FreeRTOS tasks on its own, don't interfere with it. You may be causing your crash with that line alone.
Secondly, you're creating your tasks with a stack size of 1024 bytes which is too small. The task will likely corrupt the stack and crash. Start with a stack size of 4096 bytes for simple tasks, see if you can optimize later. Incidentally, you don't need any tasks at all for a simple implementation.
Thirdly, you don't seem to understand what an interrupt is and how to handle it. By calling this you're attaching the function getEncoderTickNumber() as an interrupt handler to all 4 GPIO inputs:
attachInterrupt(INT_PIN1, getEncoderTickNumber, RISING);
attachInterrupt(INT_PIN2, getEncoderTickNumber, RISING);
attachInterrupt(INT_PIN3, getEncoderTickNumber, RISING);
attachInterrupt(INT_PIN4, getEncoderTickNumber, RISING);
The function getEncoderTickNumber() cannot be the interrupt handler because it blocks with a while(1) loop - it will quickly trigger the watchdog and reboot. Additionally, you've already used this function as a task which runs in the background (and seems to expect input from the interrupt handlers).
Finally, you seem have a more suitable candidate for the position of an interrupt handler - the function io_expander_interrupt() - which currently doesn't do anything useful. Let's fix that.
You would need 4 interrupt handlers, one per each GPIO you're monitoring. Each handler is attached to its respective GPIO pin, triggers when the IO rises and each does its own encoder calculation. A simple implementation without extra tasks would look like this:
#include <Arduino.h>
// Motor encoder output pulse per rotation (AndyMark Neverest 60)
int ENC_COUNT_REV = 420;
// Pulse count from encoder. Must be volatile as it's shared between ISR and main task
volatile int encoderValueA1 = 0;
volatile int encoderValueA2 = 0;
volatile int encoderValueA3 = 0;
volatile int encoderValueA4 = 0;
#define INT_PIN1 17
#define INT_PIN2 18
#define INT_PIN3 19
#define INT_PIN4 16
void isr_rising_gpio1() {
encoderValueA1++
}
void isr_rising_gpio2() {
encoderValueA2++
}
void isr_rising_gpio3() {
encoderValueA3++
}
void isr_rising_gpio4() {
encoderValueA4++
}
void setup()
{
Serial.begin(115200);
pinMode(INT_PIN1, INPUT);
attachInterrupt(INT_PIN1, isr_rising_gpio1, RISING);
pinMode(INT_PIN2, INPUT);
attachInterrupt(INT_PIN2, isr_rising_gpio2, RISING);
pinMode(INT_PIN3, INPUT);
attachInterrupt(INT_PIN3, isr_rising_gpio3, RISING);
pinMode(INT_PIN4, INPUT);
attachInterrupt(INT_PIN4, isr_rising_gpio4, RISING);
}
void loop()
{
int rpm1 = (encoderValueA1 * 60) / ENC_COUNT_REV;
encoderValueA1 = 0;
int rpm2 = (encoderValueA2 * 60) / ENC_COUNT_REV;
encoderValueA2 = 0;
int rpm3 = (encoderValueA3 * 60) / ENC_COUNT_REV;
encoderValueA3 = 0;
int rpm4 = (encoderValueA4 * 60) / ENC_COUNT_REV;
encoderValueA4 = 0;
Serial.print("1:");
Serial.print(rpm1);
Serial.print(" 2:");
Serial.print(rpm2);
Serial.print(" 3:");
Serial.print(rpm3);
Serial.print(" 4:");
Serial.println(rpm4);
vTaskDelay(pdMS_TO_TICKS(1000));
}

atmega328 ctc mode timer

So i wanted to make a timer on the atmega328p µC using the CTC Modus. The idea was, that every 10milliseconds when the interrupt function is called , in that function i schould increase a variable millisekunden by 10. and once it reaches 1000 it schould be printed out .
The datasheet can be found here: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf With registers i can change the Mode to the CTC Mode and set up the right Prescaler on the timer.
It is a 16Mhz CPU. So the formula is : T_clock * Prescaler * OCR0A = time( unit is seconds)
So i calculated: (1/ 1610^6) * 1024 * x = 1010^-3(i wanted 10 milli seconds).
and x is then 155.
With the bits CS00 and CS02 i set up the prescaler to 1024. OCR0A was then set to 155 as the formula says. CTC mode was enabled by setting the BIT WGM01. And the last thing was that i increase the variable millisekunden in the interrupt function. For some reason it doesnt want to work. Can anyone pease help me?
#include "Arduino.h"
volatile unsigned long int millisekunden;
unsigned long int last_msg;
char buffer[128];
void setup() {
TCCR0A |= (1 << WGM01); // CTC Modus
TCCR0B |= (1 << CS02) | (1 << CS00); // Prescaler 1024
OCR0A = 155;
// Compare Interrupt
TIMSK0 |= (1 << OCIE0A);
Serial.begin(9600);
}
void loop() {
if (millisekunden - last_msg >= 1000) {
sprintf(buffer, "t=[%lu]", millisekunden);
Serial.println(buffer);
last_msg = millisekunden;
}
}
// Timer-Interrupt-Routine
ISR(TIMER0_COMPA_vect) {
millisekunden = millisekunden + 10;
}
You forgot to globally enable interrupts. Add sei() at the end of setup()

Atmega328P+ENC28J60 freezes after 12 hours operation

I am quite new to the ethernet world. So please bear with me if I do ask stupid questions.
I designed a PCB using Atmega328P+ENC28J60 chip (schematic attached in the images below - sch1, sch2). The function of this board is basically sending GET requests to the server and retrieve a set of json data to turn on output pins, so based on my understanding my board acts as a client only right? The code is attached below:
#include <EEPROM.h>
#include <ArduinoJson.h>
#include <EthernetENC.h>
#define OUT0 2
#define OUT1 A3
#define OUT2 A2
#define OUT3 A1
#define OUT4 A0
#define OUT5 9
#define OUT6 8
#define OUT7 7
#define OUT8 6
#define OUT9 5
#define CS 10
// mac: 46 57 5a 6b 48 51
#define HOSTNAME "autolighting.afa-sports.com"
#define ID_SIZE 6
static byte mac[ID_SIZE];
static char macBuffer[ID_SIZE*2+1];
const byte output[] PROGMEM = {OUT0, OUT1, OUT2, OUT3, OUT4, OUT5, OUT6, OUT7, OUT8, OUT9};
EthernetClient client;
void clientRead() {
StaticJsonDocument<40> filter;
StaticJsonDocument<120> doc;
filter.clear();
doc.clear();
filter["data"]["relay_actions"] = true;
client.find("\r\n\r\n");
deserializeJson(doc, client, DeserializationOption::Filter(filter));
client.flush();
delay(50);
if (!doc["data"]["relay_actions"].isNull()) {
for (byte i = 0; i < 10; i++) {
// Serial.print(doc["data"]["relay_actions"][i].as<bool>());
digitalWrite(pgm_read_byte_near(&output[i]), doc["data"]["relay_actions"][i].as<bool>());
}
// Serial.println();
}
filter.clear();
doc.clear();
}
void sendReq() {
client.println(F("GET /api/iot/master-controller/get-command HTTP/1.1"));
client.println(F("Host: autolighting.afa-sports.com"));
// client.println(F("DEVICE-ID: 46575a6b4851"));
client.print(F("DEVICE-ID: "));
client.println(macBuffer);
client.println(F("Connection: close"));
client.println();
}
void setup() {
Serial.begin(115200);
for (byte i = 0; i < 10; i++) {
pinMode(pgm_read_byte_near(&output[i]), OUTPUT);
digitalWrite(pgm_read_byte_near(&output[i]), LOW);
}
for (uint8_t i = 0; i < ID_SIZE; i++) {
byte charByte = EEPROM.read(i);
if (charByte != 0) {
char temp[2];
mac[i] = charByte;
itoa(mac[i], temp, 16);
strcat(macBuffer, strlwr(temp)); // REMOVE strlwr IN RELEASE VERSION
free(temp);
delay(10);
}
}
strcat(macBuffer, '\0');
Ethernet.init(CS);
while (!Ethernet.begin(mac));
client.setTimeout(5000);
delay(1000);
}
void loop() {
while (!Ethernet.begin(mac)); // init fail
delay(1000);
if (client.connect(HOSTNAME, 80)) {
sendReq();
clientRead();
client.stop();
}
delay(3000);
}
Due to the high SRAM consumption and I might have other things (not sure what yet) to add in to the board in the future, I tried to minimize the dynamic memory by changing this (in the uipethernet-conf.h file):
#define UIP_SOCKET_NUMPACKETS 5
#define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_UDP_CONNS 4
to this:
#define UIP_SOCKET_NUMPACKETS 2
#define UIP_CONF_MAX_CONNECTIONS 2
#define UIP_CONF_UDP_CONNS 1
I'm wondering will this affect the system performance? Btw, I've also set the timeout to 5s
After 13 hours of smooth operation, the board freezes and only became normal when i hard-reset the board. Currently, I'm connecting my board to a wireless extender, because I am not sitting right next to the wifi router. It looks like a memory leakage issue to me, but does memory leakage issue still exists in the latest ArduinoJson and EthernetENC/UIPEthernet library?
P/S: I was using UIPEthernet.h previously, but someone guided me to try out the EthernetENC library, the memory consumption definitely gone down a little bit, but the freezing problem still persist
Feel free to point out any mistakes I make, still in the learning adventure. =)
Your help is greatly appreciated. Thank you very much.
Library version:
ArduinoJson 6.17.2
EthernetENC 2.0.0
UIPEthernet 2.0.9
Schematics:
don't have these hardware, only analyses based on your code and Arduino references.
from your code
while (!Ethernet.begin(mac)); // init fail
which "may" cause freeze if :
Ethernet.begin always return false
is Ethernet.begin "ok" to call multiple time ?
These are some reference which may help :
Arduino DHCP failed to configure
https://electronics.stackexchange.com/questions/67045/ethernet-begin-only-works-with-sd-card-removed-why
according to the wiki :
https://github.com/jandrassy/EthernetENC/wiki/Examples
You should use :
Ethernet.maintain();
client.available();
write your own delay function :
void mDelay(unsigned long milliseconds) {
const unsigned d = 1;
while (milliseconds > d) {
Ethernet.maintain();
delay(d);
milliseconds -= d;
}
Ethernet.maintain();
delay(milliseconds);
}
note: for arduino or electronics question, may be
https://electronics.stackexchange.com/
is a more suitable site.
not sure about if the hardware can handle, you may try to "burst test" :
void loop() {
unsigned long currentMillis = millis();
Serial.print("Time: ");
Serial.println(currentMillis);
// burst test
if (client.connect(HOSTNAME, 80)) {
sendReq();
Serial.print(", After sendReq(); ");
clientRead();
Serial.print(", After client.clientRead(); ");
client.stop();
Serial.print(", After client.stop(); ");
}
mdelay( 500 );
Serial.println( ', mdelay(500); ' );
// mdelay will call Ethernet.maintain();
// Serial.print("After Ethernet.maintain(); ");
// use Serial.println to check where it freeze ?
}
based on your code, may be these can help to reduce memory problem :
move these two outside of void clientRead() as these 2 used every 4 seconds :
4 sec * 60 = 240 times / minutes
240 * 24 = 5760 times / day
StaticJsonDocument<40> filter;
StaticJsonDocument<120> doc;
void clientRead() {
...
note: all the code are illustration, not tested. you may need to modify to make it work.
note: please check with your hardware if it can handle, or will it burn when run such test ?
lots of thanks to #ocrdu and #Flash Ang for the suggestions, the code below is the working code and my PCB has been running continuously for 58 hours till now:
#include <EEPROM.h>
#include <ArduinoJson.h>
//#include <UIPEthernet.h>
#include <EthernetENC.h>
#define OUT0 2
#define OUT1 A3
#define OUT2 A2
#define OUT3 A1
#define OUT4 A0
#define OUT5 9
#define OUT6 8
#define OUT7 7
#define OUT8 6
#define OUT9 5
#define CS 10
// host name: "autolighting.afa-sports.com
// resource: "/api/iot/master-controller/get-command"
// mac: 46 57 5a 6b 48 51
// mac (char): FWZkHQ
#define HOSTNAME "autolighting.afa-sports.com"
#define ID_SIZE 6
static byte mac[ID_SIZE];
static char macBuffer[ID_SIZE*2+1];
const byte output[] PROGMEM = {OUT0, OUT1, OUT2, OUT3, OUT4, OUT5, OUT6, OUT7, OUT8, OUT9};
EthernetClient client;
void clientRead() {
StaticJsonDocument<40> filter;
StaticJsonDocument<120> doc;
filter.clear();
doc.clear();
filter["data"]["relay_actions"] = true;
client.find("\r\n\r\n");
deserializeJson(doc, client, DeserializationOption::Filter(filter));
client.flush();
delay(50);
if (!doc["data"]["relay_actions"].isNull()) {
for (byte i = 0; i < 10; i++) {
// Serial.print(doc["data"]["relay_actions"][i].as<bool>());
digitalWrite(pgm_read_byte_near(&output[i]), doc["data"]["relay_actions"][i].as<bool>());
}
// Serial.println();
}
filter.clear();
doc.clear();
}
void sendReq() {
client.println(F("GET /api/iot/master-controller/get-command HTTP/1.1"));
client.println(F("Host: autolighting.afa-sports.com"));
// client.println(F("DEVICE-ID: 46575a6b4851"));
client.print(F("DEVICE-ID: "));
client.println(macBuffer);
client.println(F("Connection: close"));
client.println();
}
void setup() {
for (byte i = 0; i < 10; i++) {
pinMode(pgm_read_byte_near(&output[i]), OUTPUT);
digitalWrite(pgm_read_byte_near(&output[i]), LOW);
}
for (uint8_t i = 0; i < ID_SIZE; i++) {
byte charByte = EEPROM.read(i);
if (charByte != 0) {
char temp[2];
mac[i] = charByte;
itoa(mac[i], temp, 16);
strcat(macBuffer, strlwr(temp)); // REMOVE strlwr IN RELEASE VERSION
free(temp);
delay(10);
}
}
strcat(macBuffer, '\0');
Ethernet.init(CS);
while (!Ethernet.begin(mac));
client.setTimeout(5000);
delay(1000);
}
void loop() {
Ethernet.maintain();
while (!Ethernet.begin(mac)) //Serial.println(F("IF")); // init fail
// Serial.println(F("IS")); // init success
delay(1000);
if (client.connect(HOSTNAME, 80)) {
sendReq();
clientRead();
client.stop();
}
Ethernet.maintain();
delay(3000);
}
//int freeRam () { // check remaining RAM space
// extern int __heap_start, *__brkval;
// int v;
// return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
//}
This time to work smart, I used the default ip address to my router and monitor whether my PCB is still connected to the router by looking at the DHCP client list, and remove all the serial commands in the code. I'm afraid for my past experiences on the disconnection issues, it might be just a short temporary disconnect from the router, instead of a permanent disconnection.
I'm sorry if there is any lack of testing in this program. Thank you for the time spent to provide me all the useful suggestions =)

Trying to use DHT11 with a PxMatrix display on ESP32 board

I'm trying to display the readings from a DHT11 onto an LED Matrix. I can get the basic display to work, the issue is when I also put the time on the display. I started with the Morphing Clock as a base for the time then used the Adafruit Sensor code to read the DHT11. The issue seems to be with"
timerAlarmWrite(timer, 2000, true);
Which is setup to call:
void IRAM_ATTR display_updater(){
// Increment the counter and set the time of ISR
portENTER_CRITICAL_ISR(&timerMux);
display.display(10);
portEXIT_CRITICAL_ISR(&timerMux);
}
If I slow the timer down I can get readings from the DHT11 but the morphing time display doesn't update enough to look fluid. I'm new to coding for these devices so I'm not sure where I should be looking to move these things out of each others way. Here is the full app if the timer is set to something above 25000 you will get temp results most of the time, but the less are dimmer and the colons flash (they shouldn't).
#define double_buffer
#include <PxMatrix.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "Digit.h"
#include <Adafruit_Sensor.h>
#include <DHT.h>
const char* ssid = "Gallifrey";
const char* password = "ThisIsAGoodPlaceToPutAPassword!";
// ESP32 Pins for LED MATRIX
#define P_LAT 22
#define P_A 19
#define P_B 23
#define P_C 18
#define P_D 5
#define P_E 15 // NOT USED for 1/16 scan
#define P_OE 2
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);
void IRAM_ATTR display_updater(){
// Increment the counter and set the time of ISR
portENTER_CRITICAL_ISR(&timerMux);
display.display(10);
portEXIT_CRITICAL_ISR(&timerMux);
}
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;
unsigned long prevEpoch;
byte prevhh;
byte prevmm;
byte prevss;
//====== Digits =======
Digit digit0(&display, 0, 63 - 1 - 9*1, 17, display.color565(0, 250, 0));
Digit digit1(&display, 0, 63 - 1 - 9*2, 17, display.color565(0, 250, 0));
Digit digit2(&display, 0, 63 - 4 - 9*3, 17, display.color565(0, 250, 0));
Digit digit3(&display, 0, 63 - 4 - 9*4, 17, display.color565(0, 250, 0));
Digit digit4(&display, 0, 63 - 7 - 9*5, 17, display.color565(0, 250, 0));
Digit digit5(&display, 0, 63 - 7 - 9*6, 17, display.color565(0, 250, 0));
#define DHTPIN 27
#define DHTTYPE DHT11
//DHT_Unified dht(DHTPIN, DHTTYPE);
DHT dht(DHTPIN, DHTTYPE);
//DHT dht;
const uint32_t delayMS = 6000;
uint32_t lastRead;
void setup() {
display.begin(16); // 1/16 scan
display.setFastUpdate(true);
// Initialize Serial Monitor
Serial.begin(115200);
pinMode(DHTPIN, INPUT_PULLUP);
dht.begin();
// // Set delay between sensor readings based on sensor details.
lastRead = 0;
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &display_updater, true);
timerAlarmWrite(timer, 1500, true); /// The Problem is Here!!!???!!!!?
timerAlarmEnable(timer);
display.fillScreen(display.color565(0, 0, 0));
digit1.DrawColon(display.color565(100, 175, 0));
digit3.DrawColon(display.color565(100, 175, 0));
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Initialize a NTPClient to get time
timeClient.begin();
timeClient.setTimeOffset(-28800);
}
void loop() {
while(!timeClient.update()) {
timeClient.forceUpdate();
}
formattedDate = timeClient.getFormattedDate();
// Extract date
int splitT = formattedDate.indexOf("T");
dayStamp = formattedDate.substring(0, splitT);
// Extract time
timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
displayLocalTemp();
updateTimeDisplay();
}
String readDHTTemperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// Read temperature as Celsius (the default)
float t = dht.readTemperature(true);
// Read temperature as Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(t);
return String(t);
}
}
String readDHTHumidity() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(h);
return String(h);
}
}
void displayLocalTemp() {
uint32_t currentTime = millis();
uint32_t waited = currentTime - lastRead;
static String lastTemp;
static String lastHumid;
if (waited > delayMS) {
lastRead = currentTime;
String temp = readDHTTemperature();
String humidity = readDHTHumidity();
String preTemp = "T:";
String preHumidity = "H:";
String tempDisplay = preTemp + temp;
String humidDisplay = preHumidity + humidity;
Serial.print("temp: ");
Serial.print(temp);
Serial.print(" -- humidity: ");
Serial.println(humidity);
display.setTextColor(display.color565(0,0,0));
display.setCursor(20,16);
display.print(lastTemp);
display.setCursor(20,25);
display.print(lastHumid);
display.setTextColor(display.color565(0,255,0));
display.setCursor(20,16);
display.print(tempDisplay);
display.setCursor(20,25);
display.print(humidDisplay);
lastTemp = tempDisplay;
lastHumid = humidDisplay;
}
}
void updateTimeDisplay() {
unsigned long epoch = timeClient.getEpochTime();
if (epoch != prevEpoch) {
int hh = timeClient.getHours();
int mm = timeClient.getMinutes();
int ss = timeClient.getSeconds();
if (hh > 12) hh = hh % 12;
if (prevEpoch == 0) { // If we didn't have a previous time. Just draw it without morphing.
digit0.Draw(ss % 10);
digit1.Draw(ss / 10);
digit2.Draw(mm % 10);
digit3.Draw(mm / 10);
digit4.Draw(hh % 10);
digit5.Draw(hh / 10);
}
else
{
// epoch changes every miliseconds, we only want to draw when digits actually change.
if (ss!=prevss) {
int s0 = ss % 10;
int s1 = ss / 10;
if (s0!=digit0.Value()) digit0.Morph(s0);
if (s1!=digit1.Value()) digit1.Morph(s1);
//ntpClient.PrintTime();
prevss = ss;
}
if (mm!=prevmm) {
int m0 = mm % 10;
int m1 = mm / 10;
if (m0!=digit2.Value()) digit2.Morph(m0);
if (m1!=digit3.Value()) digit3.Morph(m1);
prevmm = mm;
}
if (hh!=prevhh) {
int h0 = hh % 10;
int h1 = hh / 10;
if (h0!=digit4.Value()) digit4.Morph(h0);
if (h1!=digit5.Value()) digit5.Morph(h1);
prevhh = hh;
}
}
prevEpoch = epoch;
}
}
You could try to assign tasks explicitly to a core.
When you start playing with ESP32 multi core code execution be aware of the following issues:
Both the setup and the main loop functions execute with a priority of 1.
Arduino main loop runs on core 1.
The execution is pinned, so it’s not expected that the core will change during execution of the program
On FreeRTOS (the underlying OS), tasks have an assigned priority which the scheduler uses to decide which task will run.
High priority tasks ready to run will have preference over lower priority tasks, which means that as long as a higher priority task can run, a lower priority task will not have the CPU.
CAUTION shared resources like Serial might be potential issues. Due to two core tasks accessing uncoordinated the same hardware may lead to deadlocks and crashes
For implementation purposes, you need to take in consideration that FreeRTOS priorities are assigned from 0 to N, where lower numbers correspond to lower priorities. So, the lowest priority is 0.
First of all, declare a global variable that will contain the number of the core where the FreeRTOS task to launch will be pinned
static int taskCore = 0; // The core the task should run on
now create the assignment of a task to the core in Setup()
xTaskCreatePinnedToCore(
myCoreTask, /* Function to implement the task */
"myCoreTask", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
NULL, /* Task handle. */
taskCore); /* Core where the task should run */
Here is a test function which you call in loop()
void myCoreTask( void * pvParameters ){
while(true){
Serial.println("Task running on core ");
Serial.print(xPortGetCoreID());
// This is here to show that other tasks run
// NEVER use in production
delay(1000);
}
}
Hope this gives you an idea how to tackle your problem, read more here RTOS and here ESP32-IDF

Arduino uint8_t variables

I'm having trouble with some arduino code. im using an Ethernet tutorial code i found and some IR emitter and receiver code i found, and im trying to combine them.
http://www.ladyada.net/learn/sensors/ir.html
http://g33k.blogspot.com/2010/09/arduino-data-webserver-sample-web.html
Both codes work fine by themselves.
The code compiles but when i call the following void IRDetector() , it doesn't work. I have debugged it and so far ive found when i use the variable uint8_t or uint16_t (ive tried replacing them with ints and longs). Do i have to import and libraries to use uint8_t ? Any thoughts?
Any help would be appreciated.
uint16_t pulses[100][2]; // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing
uint8_t highpulse, lowpulse; // temporary storage timing
void IRDetectCode(void)
{
while(true){
highpulse = lowpulse = 0; // start out with no pulse length
while (IRpin_PIN & (1 << IRpin)) {
// pin is still HIGH
// count off another few microseconds
highpulse++;
delayMicroseconds(RESOLUTION);
// If the pulse is too long, we 'timed out' - either nothing
// was received or the code is finished, so print what
// we've grabbed so far, and then reset
if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
Serial.print(" usec, ");
// printpulses();
//currentpulse=0;
return;
}
}
// we didn't time out so lets stash the reading
pulses[currentpulse][0] = highpulse;
// same as above
while (! (IRpin_PIN & _BV(IRpin))) {
// pin is still LOW
Serial.print(" usec, ");
lowpulse++;
delayMicroseconds(RESOLUTION);
if ((lowpulse >= MAXPULSE) && (currentpulse != 0)) {
// printpulses();
// currentpulse=0;
return;
}
}
//pulses[currentpulse][1] = lowpulse;
// we read one high-low pulse successfully, continue!
currentpulse++;
}
}
void printpulses(void) {
Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
for (uint8_t i = 0; i < currentpulse; i++) {
Serial.print(pulses[i][0] * RESOLUTION, DEC);
Serial.print(" usec, ");
Serial.print(pulses[i][1] * RESOLUTION, DEC);
Serial.println(" usec");
}
// print it in a 'array' format
Serial.println("int IRsignal[] = {");
Serial.println("// ON, OFF (in 10's of microseconds)");
for (uint8_t i = 0; i < currentpulse-1; i++) {
Serial.print("\t"); // tab
Serial.print(pulses[i][1] * RESOLUTION / 10, DEC);
Serial.print(", ");
Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
Serial.println(",");
}
Serial.print("\t"); // tab
Serial.print(pulses[currentpulse-1][1] * RESOLUTION / 10, DEC);
Serial.print(", 0};");
}
The uint8_t is a unsigned integer on 8 bits. In Arduino, it's called a "byte", so you can use it like that:
for (byte i = 0; i < currentpulse; i++) {....
It's far better than using the Arduino's "int" type (== int16_t) or "unsigned int" (== uint16_t) because the ATmega328 is 8-bit. So handling an 8-bit var is faster (a lot).
I hope it can help.