Closed Shumatic closed 3 years ago
Hi,
Could you please provide code example that doesn't work for you?
Hi,
Thank you for taking the time to answer. I tried to strip my code, and I am not sure it is your code that is the problem, but I hope it is OK to send the code anyway, i understand if you dont answer.
I am using a Nano3 ATMEL 168 I found out if i reduced the buffer in my function subStr to 38 (#define MAX_STRING_LEN 38) i works. and the freeRam() report 135 bytes, when i increase MAX_STRING_LEN 39, it fails and the freeRam() report 151 bytes free RAM. I havent made this RAM function.
Any help would be appriciated, I like to know what i am missing.
/**************************************************************************************************
Filename: ClickEncoder_timer2.ino
Description: ClickEncoder using Timer2
Author: Jesper Schumacher
Last modified: 08-02-2021
*******Version history****************
V1.0 08-02-2021 - Initial
**************************************************************************************************
*/
#define __FILENAME__ strrchr("\\" __FILE__, '\\') + 1
const byte numChars = 32; // for serial
char receivedChars[numChars]; // an array to store the received data from serial
boolean newData = false; // for serial
int DutyCycle = 50; // default
int cursorLCD = 9;
#include <ClickEncoder.h> //encoder
ClickEncoder *encoder; //encoder
long last; //encoder
int value; //encoder
int modeEncoder = 0; //encoder
//encoder interrupt
ISR(TIMER2_COMPA_vect) {
encoder->service();
// digitalWrite(A0, !digitalRead(A0));
}
#include "ssd1306.h" // I2C A5 SCL - A4 SDA
int freeRam() {
extern int __heap_start, *__brkval;
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);
}
void setup() {
Serial.begin(115200); Serial.print(F("\r\nFilename: ")); Serial.println(__FILENAME__);
Serial.print(F(" Compiled: ")); Serial.print(__DATE__); Serial.print(" "); Serial.println(__TIME__);
pinMode(9, OUTPUT); //50% dutycycle
pinMode(10, OUTPUT);
//set timer2 interrupt at 1kHz
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 1khz increments
OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS21 bit for 8 prescaler
TCCR2B = _BV(CS22); //prescaler 32
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
encoder = new ClickEncoder(A1, A0, 6, 4); //encoder
last = -1; //encoder
value = 0; //encoder
ssd1306_setFixedFont(ssd1306xled_font6x8);
ssd1306_128x32_i2c_init();
ssd1306_clearScreen();
ssd1306_printFixed(0, 8, "Normal text", STYLE_NORMAL);
Set_frequency(1000);
}
long selector = 1000;
long frequency = 1000; //default
char buffer2[14];
void loop() {
char *ptr;
recvWithEndMarker();
if (newData == true) {
frequency = strtol(subStr((receivedChars), ",", 1), &ptr, 10);
Serial.print(F(" FreeRAM: ")); Serial.println(freeRam());
Serial.print(Set_frequency(frequency)); Serial.print(F(" Hz"));
newData = false;
}
//encoder
long curretFreq;
if (modeEncoder == 0) {
frequency += encoder->getValue() * selector;
if (frequency != last) {
last = frequency;
Serial.print(F(" Encoder Value: ")); Serial.println(value);
frequency = constrain(frequency, 1, 8000000);
curretFreq = Set_frequency(frequency);
Serial.print(ultoa(curretFreq, buffer2, 4)); Serial.print(F(" Hz"));
Serial.print(F(" Selector: ")); Serial.println(ultoa(selector, buffer2, 4));
}
} else {
DutyCycle += encoder->getValue();
if (DutyCycle != last) {
last = DutyCycle;
DutyCycle = constrain(DutyCycle, 0, 101);
curretFreq = Set_frequency(frequency);
}
}
buttons();
}
long Set_frequency(long freq) {
freq = constrain(frequency, 1, 8000000);
// TCCR1A Bit 7 6 5 4 3 2 1 0
TCCR1A = 0b01100011; //COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
// 0 1 0 0 0 0 0 0
uint16_t ocr1a;
if (freq < 2) {
// TCCR1B Bit 7 6 5 4 3 2 1 0
TCCR1B = 0b00011100; //ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
// 0 0 0 0 1 1 0 0
ocr1a = 62500UL / freq - 1; // count 0-1-2-3...
freq = 62500UL / (ocr1a + 1);
Serial.println(F(" prescaler 256"));
} else if (freq < 16) {
TCCR1B = 0b00011011;
ocr1a = 250000UL / freq - 1;
freq = 250000UL / (ocr1a + 1);
Serial.println(F(" prescaler 64"));
} else if (freq < 123) {
TCCR1B = 0b00011010;
ocr1a = 2000000UL / freq - 1;
freq = 2000000UL / (ocr1a + 1);
Serial.println(F(" prescaler 8"));
} else {
TCCR1B = 0b00011001;
ocr1a = 16000000UL / freq - 1;
freq = 16000000UL / (ocr1a + 1);
Serial.println(F(" NO prescaler"));
}
if (DutyCycle > 100) DutyCycle = 100;
Serial.print(F(" ocr1a: ")); Serial.print(ocr1a);
unsigned long maxDutyCycle = ocr1a - 1;
OCR1A = ocr1a;
unsigned long ocr1b = (ocr1a + 1); //as zero is first count
ocr1b = (ocr1b * DutyCycle / 100);
if (ocr1b != 0) ocr1b = ocr1b - 1; //-1 as ocr1b counts from zero
if (ocr1b > maxDutyCycle) ocr1b = maxDutyCycle; // needs to 1 below OCR1A
int DutyCycleCorr = (ocr1b + 1) * 100 / (ocr1a + 1);
Serial.print(F(" DutyCycleCorr: ")); Serial.println(DutyCycleCorr);
// lcd.setCursor(11, 1);
//Serial.print(ultoa(Set_frequency(frequency), buffer2,4))
// lcd.print(ultoa(DutyCycleCorr, buffer2, 11));
// lcd.print("%");
OCR1B = ocr1b;
TIMSK1 = 0;
return freq;
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void buttons() {
ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
Serial.print("Button: ");
#define VERBOSECASE(label) case label: Serial.println(#label); break;
switch (b) {
VERBOSECASE(ClickEncoder::Pressed);
VERBOSECASE(ClickEncoder::Held)
VERBOSECASE(ClickEncoder::Released)
VERBOSECASE(ClickEncoder::Clicked)
case ClickEncoder::DoubleClicked:
Serial.println("ClickEncoder::DoubleClicked");
encoder->setAccelerationEnabled(!encoder->getAccelerationEnabled());
Serial.print(" Acceleration is ");
Serial.println((encoder->getAccelerationEnabled()) ? "enabled" : "disabled");
}
}
}
/**************************************************************************************************
@fn ultoa
@brief Format an unsigned long (32 bits) into a string in the format "23.854.972".
@param val input long value
s The provided buffer must be at least 14 bytes long. The number will
be right-adjusted in the buffer. Returns a pointer to the first digit.
testcode char buffer2[14];
Serial.println(ultoa(val, buffer2));
@return char with thousin seperator
https://arduino.stackexchange.com/questions/28603/the-most-effective-way-to-format-numbers-on-arduino
/**********************************************************************************************
*/
char *ultoa(unsigned long val, char *s, int padding) {
char *p = s + 13;
*p = '\0';
do {
if ((p - s) % 4 == 2) // plads 4 - 8 -12 ...
*--p = '.';
*--p = '0' + val % 10;
val /= 10;
} while (val);
//this adds padding
for (0; p - s > padding; 0) {
*--p = ' ';
}
return p;
}
/**************************************************************************************************
@fn subStr
@brief split string on given delimiter
@param str input string to splitted
delim char to use as delimiter
index block to return,1 is first block BEFORE delim.
@return Block between chosen delimiters
/**********************************************************************************************
*/
char* subStr (char* str, const char *delim, int index) {
#define MAX_STRING_LEN 100
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;
// Since strtok consumes the first arg, make a copy
strcpy(copy, str);
copy[MAX_STRING_LEN] = '\0';
for (i = 1, act = copy; i <= index; i++, act = NULL) {
////Serial.print(".");
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
return sub;
} //subStr
Hi,
Unfortunately, I cannot compile the example. The system doesn't know anything about #include <ClickEncoder.h>
.
As for ssd1306 library, the only place, where interrupt handlers are declared for VGA mode is vga_isr.h
header, which is not included by library cpp/c files. The only place, where this header is included, is examples. So, I don't think that library affects TIMER0 in your case.
As for free ram. What is reported by Arduino, when it compiles your code?
Hi
No, it is an external lib https://github.com/0xPIT/encoder. i Like it becurse it handle both button and encoder (with acceleration) Arduino dosnt report freeRam, only flash, and the sketchuse app. 10500byte /j
Arduino dosnt report freeRam, only flash, and the sketchuse app. 10500byte
That's very strange. My Arduino IDE 1.8.3 for Arduino Nano based on Atmega328p shows:
Sketch uses 5826 bytes (18%) of program storage space. Maximum is 32256 bytes.
Global variables use 360 bytes (17%) of dynamic memory, leaving 1688 bytes for local variables. Maximum is 2048 bytes.
So, it actually displays how much memory is required for global variables, the rest 1688 can be used for local variable and function calls (all of these ones are allocated in Stack)
Hi Aleksei Yes i had comprehensive output on, so i didnt notice. then i wouldn't have posted this in the first place, as it clearly say Sketch uses 10572 bytes (73%) of program storage space. Maximum is 14336 bytes. Global variables use 862 bytes (84%) of dynamic memory, leaving 162 bytes for local variables. Maximum is 1024 bytes. Low memory available, stability problems may occur. Theres a little diff, this says 162 b, FreeRAM states 151 b
Thanks for you positive attitude and explanation. Sorry for wasting you timeon such triviallity. BR Jesper
Hi
You're welcome. Did you solve the original problem with timers?
Best regards
Hi Yes, it wasn't a timer og SSD issue, it was only a too big program for a too small Proc. :-) Normally ClickEncoder use a lib called TimerOne, that ...... use timer1 The code i posted here, use Timer2, i have also teste with Timer0, but that them millis() are gone.
Thank you for the great explanation and a lot of code examples. I think all those information will be very helpful for everyone.
For now, I'm closing the issue. Feel free to open the new one if you have any problems.
Best regards
Hi Thanks for the lib. it is awsome I am using an Nano with the lib and a 128x32 I2C. afaik this lib uses othe Timer0 and Timer2, could this be avoided or is it I2C