I have one project based on Arduino nano. I would like to switch to something simpler (minimal possible configuration).
I'm using function to receive data via some software serial (non standard) - it's based on delays and delayMicroseconds.
I'm familiar with MicroCore and burning bootloader.
When i set nano to internal 8 MHz clock, received data is garbage - as expected, since it is quite inaccurate. So i was wondering if i can use quite accurate 16 MHz nano clock and divide it by 2 or even more.
The problem with the first approach is this will only define that macro in the translation unit of the files that contain the definition. So if you do that in the sketch, it's not going to have any effect on the code that uses F_CPU in libraries, which are in their own translation units.
The build.f_cpu platform property defined in boards.txt is used to define the F_CPU macro via a -D compilation flag, which causes it to be visible in all translation units.
Battery usage reduction, parts number reduction - as i was hoping to run from internal 8 MHz. It won't. So i wanted to check if it will run from stable "external". When it start i can check internal. And i will know where the problem is.
This seems to be correct, although it is not accurate 1s... I'll check my test program:
#define RXPIN 2
#define TXPIN 3
#define BAUDRATE 9600
#define BITTIME 1000000/BAUDRATE
#define HALFBITTIME 500000/BAUDRATE
void setup() {
clock_prescale(1);
// Serial.begin(500000);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("RS Test ok");
pinMode(RXPIN,INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.write(GPSread());
}
char GPSread()
{
char rxdata=0;
while(!digitalRead(RXPIN)); //wait until rxline get high if low
while(digitalRead(RXPIN)); //wait until rxline goes low
delayMicroseconds(HALFBITTIME); //wait to get the center of bit time
for(byte i=0;i<8;i++)
{
delayMicroseconds(BITTIME);
rxdata = rxdata | (digitalRead(RXPIN)<<i);
}
delayMicroseconds(HALFBITTIME); //wait till the stop bit time begins
return rxdata;
}
void clock_prescale(uint8_t factor)
{
if (factor > 8) factor = 8;
CLKPR = (1 << CLKPCE);
CLKPR = factor;
}
but this does not work for 8MHz. Also, it works when clock_prescale(0) and burned bootloader is 16 MHz (so standard Nano). Whats going on?
Lower clock rates are often necessary for battery operation ( say 3.3volts). If you use a Nano on 3.3 volts and retain the 16MHz resonator/crystal, you can fix the CPU rate in a special boards.txt entry and set the pre-scaler early in setup.
The internal 8MHz oscillator may not be very accurate.
For long term battery operation, a Nano is not ideal because it has lots of power hungry components. But 3.3 volt operation can also be useful if you have peripherals which operate only at this voltage. I did once a Nano 3.3volt conversion for exactly this reason: Arduino Nano CH340G 3.3 volt conversion
Can you use software serial in your sketch to interpret the data stream from your GPS device instead of what appears to be a direct digital interpretation of the RX pin ?
Ok, short story long: I'm building a GPS logger. The goal is to build a simple device that can track for a few days without charging. It is built of FLASH, GPS, NANO, and two 18650.
I was hoping to replace NANO with barebone 8A (got a few). I know Its power-saving functions look bad when compared to 328p, so I'll probably go with 168/328p. Eighter I was hoping to use an internal 8MHz clock (or even slower, since in general CPU just waits for pieces of information from GPS, writes down, and goes sleep) to reduce power usage.
Two 18650 gives 7.2-8.4V. In the current build, it is just burned in voltage regulators (NANO is 5V, GPS is 1.8V, Flash 2.7v) - that's just waste, so I wanted to clock down 328p to use two 18650 in parallel.
So, my idea was to change things step by step:
nano -> nano with internal 8MHz -> barebone
But, since the first conversion didn't work I've decided to try Nano with a stable clock, that's why I'm trying to run nano from 16MHz with a clock divider.
I've read this topic earlier, and I was inspired by it to my solution. Isn't it what I'm doing currently? Burn bootloader and program 16MHz Nano as if it was 8MHz and add divider as soon as possible.
I can do anything!
Do You mean to pass incoming data bit by bit to PC?
That appears OK in principle. A Nano is not ideal for this though. You are better off with a simpler design such as a barebones or a pro-mini which, depending on the clone, may have solder jumpers to isolate the power led, voltage regulator etc.
I have a project published here : Arduino NRF24L01 Mailbox Monitor/Notifier which is a barebones, but with a 16MHz crystal which is convenient for loading the standard bootloader, but is pre-scaled down, in normal use, to 4MHz so that it can run on batteries down to 1.8 volt (just look at the transmitter part).
What I meant was this:
Which appears to be some sort of manual interpretation of a serial bit stream.
add this before anything else in setup() and I think you should be fime
// change system clock pre-scaler to 2, run CPU at 8 MHz from 16MHz crystal
CLKPR = 1<<CLKPCE;
CLKPR = 0<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 1<<CLKPS0;
#define RXPIN 2
#define TXPIN 3
#define BAUDRATE 9600
#define BITTIME 1000000/BAUDRATE
#define HALFBITTIME 500000/BAUDRATE
#define LED 9
unsigned long tajm = 0;
void setup() {
// clock_prescale(1);
// change system clock pre-scaler to 2, run CPU at 8 MHz from 16MHz crystal
CLKPR = 1<<CLKPCE;
CLKPR = 0<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 1<<CLKPS0;
Serial.begin(500000);
//Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("RS Test ok");
pinMode(RXPIN,INPUT);
pinMode(LED, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.write(GPSread());
if (millis() > tajm){
digitalWrite(LED, !digitalRead(LED));
tajm += 1000;
}
}
char GPSread()
{
char rxdata=0;
while(!digitalRead(RXPIN)); //wait until rxline get high if low
while(digitalRead(RXPIN)); //wait until rxline goes low
delayMicroseconds(HALFBITTIME); //wait to get the center of bit time
for(byte i=0;i<8;i++)
{
delayMicroseconds(BITTIME);
rxdata = rxdata | (digitalRead(RXPIN)<<i);
}
delayMicroseconds(HALFBITTIME); //wait till the stop bit time begins
return rxdata;
}
void clock_prescale(uint8_t factor)
{
if (factor > 8) factor = 8;
CLKPR = (1 << CLKPCE);
CLKPR = factor;
}
Gives me garbage like f⸮ff⸮⸮~⸮⸮⸮⸮怘⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮憞⸮⸮x⸮⸮⸮x怞`. Also, "RS test ok" doesn't work anymore.
OK. If that part works, then leave it or treat it as a potential optimisation to look at in the future.
"Never touch a running system" comes to mind here.
// change system clock pre-scaler to 2, run CPU at 8 MHz from 16MHz crystal
CLKPR = 1<<CLKPCE;
CLKPR = 1<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 1<<CLKPS0;
starting message works. With original 0<<CLKPCE in second line LED is on for 2 sec... Passthrough does NOT.
Nah, quite usual speed. On modern devices using 9600 etc has no sense - its pointless slow.
This value was to prevent hardware RS influence software serial read. With 9600 same situation.
Since you are changing the clock speed from 16MHz to 8MHz in your code, did you remember to set the serial monitor to 1/2 the baud rate - 250,000 in this case.
I thought about it. I even have one on my desktop. But I have already built this device (custom PCB with everything nicely attached to battery holder). I wanted to test it before moving to barebone 8a/168/328p.
I've already decided to build it anyway - as finding a solution seems to be too much... but I'll reprogram it to use hardware serial for both: PC and GPS communication.
Arduino sends data to PC only at boot, I'll use N-MOSFET to disable GPS until everything is sent. No data is meant to be sent from PC to Arduino.