I want to be able to read serial data received via an IR detector on an Attiny operating at 1Mhz and I got interested in this Thread SoftwareSerial magic numbers - Libraries - Arduino Forum about SoftwareSerial which "out of the box" only works at 8MHz and above.
SoftwareSerial uses various tables of "magic numbers" to define the different times needed for different baudrates and @robtillart had figured out a formula as an alternative to the tables.
It seemed to me that there must surely be a simple "formula" that could deal with any baudrate and any CPU frequency (always recognizing that high baudrates and low MHz are incompatible). For low baudrates it is possible to use micros() for timing but as the baudrates increase the 4 microseconds (usecs) granularity of micros() becomes a problem. That got me thinking that any code loop can be its own clock if you carefully measure how long it takes to run.
The attached file BlinkSmallSerial.zip contains SmallSerial.ino and BlinkSmallSerial.ino which together comprise a little demo sketch. BlinkSmallSerial will work on an Uno at 38400 baud and on the 1MHz Attiny at 2400 baud WITHOUT ANY CHANGES. (In case it's not obvious 38400 / 16 = 2400). The demo is designed to work with the IDE Serial Monitor and an FTDI cable (or equivalent). If you send the character '0' it will respond with some text. If you send one of the characters '1' to '9' it will flash an led on Pin 2 - 2 flashes for the character '2', 3 flashes for '3' etc. Note that Arduino Pin 2 is physical pin 7 on an Attiny.
The demo should be sufficient to illustrate how SmallSerial.ino can be included in your own project.
SmallSerial.ino is not intended to be a general purpose replacement for SoftwareSerial. Rather it is intended for use in a situation where small amounts of data need to be exchanged between an Arduino and a PC or another Arduino and where small size and simplicity have a high value. (I don't know whether the timing concept in SmallSerial could be adopted into SoftwareSerial to dispense with the magic numbers and make it more broadly applicable).
My goal was to keep the code in SmallSerial easy to understand and small. It doesn't use any interrupts. It should be easy to understand and adapt. It seems to operate comfortably up to 115200 baud on my 16MHz Uno. It can operate at any baudrate (specified in the #defines) and it can use different baudrates for send and receive. As written it expects Tx on pin8 and Rx on pin9 on the Uno or Pins 5 and 6 on the Attiny45. This is to minimize the amount of code and maximize the speed. If people need to change the speed-sensitive code (the routines recvBits() and sendBits()) they will need to recalibrate the speed and I have also included a sketch to do that.
The key to SmallSerial is the time it takes for the loops in recvBits() and sendBits() to run. Their speed is measured in the sketch CalibrateSmallSerial.ino and its associated file TestSpeed.ino that are included in CalibrateSmallSerial.zip. To use CalibrateSmallSerial you must add SmallSerial.ino to the project (it would not fit within the 4k upload limit if I included it in the zip file).
The calibration has already been done for this version of SmallSerial.ino and the loop speeds are included in the lines #define sendShortLoop1024 386 and #define sendLongLoop1024 2055 (and their equivalents in the recv routine). The numbers 386 and 2055 are the number of microseconds for 1024 iterations of the short and long loops. In other words 0.377usecs and 2.007usecs. These values are appropriate for a 16MHz CPU and pro-rata adjustments should work at different CPU speeds. For example 386 at 16Mhz should be 193 at 8Mhz or 24 at 1MHz. I suspect calibration needs to be done at 16Mhz to get sufficient resolution.
I have made no attempt to package SmallSerial.ino into a library as that seems to contradict the purpose of keeping it small and simple, and easy to uderstand and modify. It does mean there is a slight risk of conflicting global variable names, but the user should be able to deal with that as the code is very short.
Comments and observations are welcome.
...R
BlinkSmallSerial.zip (3.02 KB)
CalibrateSmallSerial.zip (2.35 KB)