I was wondering if anyone knew the code that was used to create the shiftOut function. I've heard that it just uses bit banging, but when I tried to create my own code to bit bang the shift of the eight bits, it won't work. The reason why I'm asking is I would like to work on my project without using the arduino higher level functions. Any help is appreciated.
Thanks.
P.S. Here's my code that I was using (the commented portion under shiftOut is what I was using to replace it):
void send_info(uint8_t select, uint8_t byte_send){
// select either command or data to be sent
if(select == 0x00){
PORTA &= ~_BV(PA2);
}else{
PORTA |= _BV(PA2);
}
PORTA &= ~_BV(PA4); // SET SCLK TO LOW
PORTA &= ~_BV(PA0); // SET SCE TO LOW (ENABLE)
shiftOut(25, 26, MSBFIRST, byte_send);
/*
uint8_t temp = 0;
uint8_t i = 7;
for(i = 7; i >= 0 ; i--){
temp = byte_send &(0x01 << i); // mask the current bit
temp = temp >> i; // move the current bit to bit 0
temp = temp & 0x01; // make sure only the LSB is included
// send current bit through DN (IF LOW FOR DN BITWISE AND WITH REGISTER, IF HIGH FOR DN BITWISE OR WITH REGISTER)
if(temp == 0x01){
PORTA |= _BV(PA3);
}else{
PORTA &= ~_BV(PA3);
}
// PULSE THE SCLK
PORTA &= ~_BV(PA4);
delay(1);
PORTA |= _BV(PA4);
delay(1);
}
*/
PORTA |= _BV(PA0); // SET SCE TO HIGH (DISABLE)
}
I recently spent a bit of time optimizing an 8-bit shift out function and settled on this:
void putByte(uint8_t value) {
uint8_t mask = 0x80, i;
for (i = 8; i > 1; i--) {
digitalWrite(dataPin, value & mask);
delayMicroseconds(SETUP_TIME);
digitalWrite(clockPin, HIGH);
delayMicroseconds(CLOCK_HIGH);
digitalWrite(clockPin, LOW);
delayMicroseconds(CLOCK_LOW);
mask >>= 1;
}
}
Only one shift instruction per loop, digitalWrite sets the pin HIGH for any non-zero value, and found that counting down from 8 resulted in smaller code than counting up from 0. YMMV.
(edited: originally typed "delay" when I meant "delayMicroseconds". I included these because I don't like depending on the execution time of digitalWrite)
I recently spent a bit of time optimizing an 8-bit shift out function and settled on this
Changing from the data and clock pins being input to being global variables is not a good thing.
Your function can not be used to output data to different pins in one sketch, if #define or const int is used to define the pin numbers (which is preferred).
I don't want to hijack this thread but I am interested in best practices for the libraries I am writing. Specifically to this case, you could take a look at the enhancements I've posted to the Sensirion library (which contains putByte and getByte functions to keep this thread relevant ) The original version of the library I based my work on passes the pin numbers via the constructor and stores them in private variables. I prefer this over including them in each user-level function call (which I hope isn't what you mean). Inside the library, I could pass the pin numbers down from the public functions to the low-level functions that will eventually require them but wouldn't that add bytes to the stack for each level of function call? I am trying to keep this library as small as possible (RAM and program memory) and I'm not clear this is worth the trade-off. Thanks.
I prefer this over including them in each user-level function call (which I hope isn't what you mean).
It wasn't. I was referring more generally to sketch functions.
Inside the library, I could pass the pin numbers down from the public functions to the low-level functions that will eventually require them but wouldn't that add bytes to the stack for each level of function call?
Two bytes for each int argument. One byte for each byte argument. I'm not sure why pin numbers are ints. They really don't need to be. There are not even close to 255 of them on any Arduino.
The stack consumes space in SRAM, but only during the function call. It would be an issue only when SRAM is in very short supply. Even then, I don't think that global variables or private/public members are the answer.
They shouldn't be - I used uint8_t (and I believe Arduino's digitalWrite / digitalRead do as well).
The stack consumes space in SRAM, but only during the function call.
True - and I don't think I have more than three levels of calls so the usage would be small but I've run out of RAM enough times to be sensitive to it.
Even then, I don't think that global variables or private/public members are the answer.
Trying to understand the alternatives for libraries as I'm not a c++ expert:
Passing the pin numbers via the constructor seems like a good idea. Is there another way to store them besides as private class variables?
If not, doesn't that make them accessible to all functions in the class? If so, then I'm not sure what I gain by not simply referencing directly them where needed.
Passing the pin numbers via the constructor seems like a good idea.
Agreed.
Is there another way to store them besides as private class variables?
No.
If not, doesn't that make them accessible to all functions in the class?
Yes.
If so, then I'm not sure what I gain by not simply referencing directly them where needed.
None.
When I first brought the issue up, it was not in the context of a member of a class. The shiftOut function that was shown as an alternative to the Arduino-provided shiftOut function was not (that I remember) mentioned as being a class method.
In that case, not passing the pin numbers as arguments IS a big(ger) deal.
As I/O objects the pin numbers are stored as constants within the object itself thus it knows its pin assignment. Additionally being an object it is able to set its pin mode during construction. Remember that class instance constants must be initialized in the constructors initializtion list before any instance variables.