Hi Ralph Many thanks for such an informative video, I have a question, is it possible to open the *.h and *.cpp files in the Arduino IDE, sorry if I missed something in your video which explains this I have watched it three times. You stated in the video that we could play around with these files and if we made a mess of them we just download them again, from that I thought you meant we can alter things in all three of the files. Many thanks Graham
Hi Graham! THREE times you say? You probably know it word for word by now! Yes, you most certainly CAN open the .h (header) and .cpp (c plus plus) files using the Arduino IDE. There are some caveats: 1. To CREATE a new file (which will reside in the same folder as your sketch) click the small triangle at right hand side of the toolbar (containing the sketch tab). You will then be prompted to enter a name (eg myheader.h). The prompt appears at the bottom of the code window (!) 2. To OPEN an existing library file, copy both the .h and .cpp files to your sketch folder, then open your sketch. The additional files will appear as separate tabs next to your sketch's tab. 3. To include a library file in your sketch, when the library file header resides in the same folder as your sketch, use the format #include "mylibrary.h" *not* #include as the latter format is used when you want the Arduino IDE to search your libraries folder (and elsewhere) to find a library. 4. If you muck up the .h or .cpp files you can just re-copy them over to your sketch folder again whilst you experiment. If you enhance the library, and want to keep the changes MOVE the files back to the libraries folder (but do take a backup of the original files first, just append .old to the filename or something). Then refer to that library in the usual way with the standard #include again. I guess I should have clarified this in the video better, but maybe this comment will be read by gazillions of viewers too. Thanks for posting this question, it will benefit others wondering this.
Hi Ralph! Many thanks for the quick reply, Item 2 answers my question and works fine, I now have all three files together so I can play with them. Please keep up the great work, very interesting content, I am also going to watch more of you videos. Regards Graham
@@RalphBacon Well, I don't know about gazillions... but I've definitely read it. Comments can hold vast amounts of additional information and are worth reading.
@@RalphBacon Thanks for the informative video. As for #2, it would seem that you're opening a copy of the library that you're using via , not the actual library that it's compiling? That there's not an easier way to view libraries with the IDE is a bit of an annoyance (not your fault, obviously). Seems like Notepad++ or similar is a good way to take a peak at them to figure out what functions etc are available, but that's not perfect either.
arduino noob here... after months and months and months of studying, watching videos... its the first time i see how to collapse sets of codes... my gosh, so many tutorials and this is the only one that explains that! thank you!
Wow thank you so much. Some people are complaining about how long this video is but its was great because you not only created a library live in front of us but also explained the background of whats happening. Great Video!!
Complaining? About MY video lengths! Actually, Aldrick, I gave up trying to make shorter videos some time ago and now just make them whatever length they need to be, usually around the 30-minute mark. It's about the right length if we're going to discuss stuff in the correct level of detail, don't you think? Well, it seems you do! Thanks for posting!
I very much like the way you teach. It is as if I was sitting down with a friend or colleague who wants me to understand something, but wants it to be a pleasant experience.
thanks for this lesson with detail explanations on each lines and resons. I picked up many knowledge not known before as I was trying to make my own library.
Ralph, I came across this video (#71) a few months back, and am now proud to say that I have written my first Arduino library. I've a lot of work to do on the code, but I have built a class with methods, and it is likable into a users sketch. I am now working to configure it to allow easy importing into the IDE and compliance with Github standards. So many thanks for your inspiring and instructive videos.
Thank you Ralph. I hesitated to start a 38 minute video tutorial, but it was worth it just for the calm Pommy accent and absence of duffa duffa music! I am an old veteran since the 70s of programming assembler on bare metal for embedded realtime controls, and only just in retirement wrapping my head around C/CPP. Some of the syntax conventions really "get" me, and I have to remind myself I am dealing with a very simplistic one-pass compiler that needs lots of cues in order to work. The work flow from multiple tabs / project folder to files in the library folder was very helpful.
Glad you found it useful, David. All my videos are a bit long but watch them at 1.25 speed and it shaves many minutes off the length. And I don't sound like a chipmunk on helium either!
I never thought I would understand such a complicated subject but you made it so understandable. Thank you so much! You have a special 'teaching gift'...
Hi Ralph, Your videos are wonderful. Very instructive and very easy to understand. I have written my first library using your video and just wanted to say thanks and keep it up!
Thank you very much Timothy, I'm glad I'm being of some use! Like most things, once you're shown how (and, possibly, why) then the mystery disappears and you think "Is that it then?" I hope you create many more libraries (I must admit to cheating whilst developing and just stuffing items into a .h file until I'm ready but don't tell anyone!). Thanks for posting, much appreciated.
Thank you, Harry, for your supportive words. I'm glad it's helped you (and hopefully others too!). Once you've done it a couple of times it gets quite automatic to move stuff into a library. Good to hear from you.
Thanks for this walkthrough, Ralph. I'm coming from other programming languages (primarily web dev), and this was a great overview of the idiosyncrasies of c++ when it comes to object oriented code and including local libraries. I had been reading through articles and posts that explain the same thing, but none of them were as clear and well presented as this video :) Thanks for taking the time to make this and for posting a link to the code. It's much appreciated :D
Well, thank you, cschmitz, for your kind words! I'm glad to have helped. I, too, have taken many paths in coding, from µProcessor assembler through various BASIC dialects, C#, JavaScript, and C++. I think once you have a programmer's way of thinking then the language is secondary to what you want to do, so you (as a web developer) are well placed to mastering this very quickly. Thanks for posting and good luck in creating your own libraries!
Awesome, Bernebeer! Congratulations on having done this. Now you have started you can progress to more complex libraries. Perhaps one day I will be using a library that you created, who knows. Thanks for letting me know, great post.
You are the man, I could not figure out how to use the serial port in my cpp file. I tried everything until you showed the method to - begin serial. Like you said, there just isn't any useful online documentation available for this - JOLLY GOOD SHOW !
Well thank you Goldichan92, I appreciate that you took the time and trouble to post that. Unless my Arduinite viewers tell me how I'm doing I have to guess which is not the best way to build up an audience. So thanks again, and keep watching! And don't forget, if you like what you see, consider subscribing! :)
Glad you liked it, Franz-Juergen, ziemlich einfach, gel? Now that you have some knowledge you can create your own libraries, but start slowly, as there are some 'gotchas' as they get more complicated. Thanks for posting.
Omg this is so good... I learned a lot today for me to try write a code to sniff the LIN bus protocol. going to use this way of clean setup and also make it easy for me to reference to other codes available. now I can connect the dots a lot better.
Totally brilliant ! Thank you so much for explaining that ... and at a good pace: neither too fast or too slow, and in an accent that my ancient ears can cope with!
You sound surprised! Yes, once you have written one library you can progress and learn all about classes, objects, private, protected and public functions and variables... the list goes on. Well done!
very helpful! I also had forgotten the semi-colon at the end of the class declaration. Luckily, it was the first thing I randomly landed on when I was flipping through the video to check if it was any good.
Ralph many thanks for a very clear explanation of how to create an Arduino library. Apart from tidying up the sketch I would say the other main reason to create a library is for code that you tend to find yourself using in several projects. Once it's been debugged then you can forget about the dirty details and simply use it every time you need those methods. BTW I never knew about the IDE being able to collapse or 'fold' code so thanks also for that insight!
You've grasped the real use of a library completely, Philip. TBH even if you don't use the code elsewhere it's still good to 'modularise' the sketch this way as you quite rightly say you can forget about it. Glad you now know about code folding, it's quite useful. Thanks for your supportive words, appreciated.
Benny says that you are most welcome too, and sends his regards to Sammy & Morgan who are probably experts in Arduino C++ now (cats learn fast apparently). 😺
Extremely interesting and useful. Wish I had found it a couple of months ago when I was just getting started with Arduino. I'll have to watch it a couple of more times as I'm a slow learner.
Thanks much Ralph! Here's where I get into stall mode. For instance if I wanted to output an instantiation message to another device apart from a serial port or output to another library function ie. write to an SD card then things get confusing. I know that your code is just an example and that any 'portable' library wouldn't open a serial port regardless, but further thinking brings on many complex options. Great example nonetheless!
Hi ya Phil, interesting comment there! If you wanted to output serial data to another device, when we have already used it for our debugging window (Serial Monitor), you could always use the Software Serial library which allows any pin to use serial data. I've used it many times and it works well and stops you being restricted to pins 0 & 1. But as you say, this was but an example showing how to put a library together (rather than concentrating on the functionality) and I'm glad you liked the example. Good to hear from you.
I forgot how good this video is. I think the grammar of classes are what make them seem intimidating. The textbook jargon like instantiate, constructors, deconstructors, self.label type stuff. But if people let go of the jargon like you're showing then people understand it better. When I started, and I'm no expert but the 'self.' Stuff got me confused the worst because all the constructor variables were just stated above. Haha
When I created this video, Joey, I was very careful to _not_ mention anything OOP-related as I knew it would put viewers off! Talking about polymorphic inheritance might be a bit off-putting (just a wild guess). 😁
Thanks for a very clear and informative video. I had wondered what the cpp and .h files were for - now I know. Not sure I like OOP, it just adds another level of complexity. Many thanks for sharing this. Best wishes Arthur
Hi Arthur! I'm glad you enjoyed the video, but what's all this about "adding complexity"? :) OK, it IS something different but simple classes in Arduino can lead to better programming. Mmm, perhaps I need to do an introductory video into classes (well, OOP) for Arduino! Maybe. Lots of other stuff to cover first. Anyway, glad you liked it and thanks for posting, great to hear from you.
Nice job explaining what can be somewhat daunting for those learning. One thing, when coding in C/C++ you should also include a destructor in the class, but not sure if necessary on an MCU which will most likely loop forever anyway.
It has been many years since I have done it, but if you break the source code file into different files according to the different methods in the class, GCC will include only the functions called in the final binary. It will do this process during the linking process. An example is the standard libraries. If you examine the libraries they are an agglomeration of separate object files per standard function.
Yes, you're right of course Uzi, the compiler/linker is intelligent enough, thank goodness, to only include code that is actually called! Just as well, given the limited space in an Arduino Uno. For us Arduinites that have created their own 'Utilities' library (a collection of 'useful methods') it means that not all the library is included each time, so it doesn't really matter how many methods you place in it (within reason, we don't want a huge monolith of unrelated functions!).
Again relying on memory, The procedure of separating the functions or methods is tedious and you have to pay attention to the separate source files, edssentially treating them as a separate project each.
Thanks for a great tutorial it has helped me on my Arduino journey as it’s time to really understand what some libraries do and the place to start is making your own.
Yes do try, Bob (Yoda: there is do or not do, there is no try), it's not difficult but start small and work your way up! Thanks for posting here, nice to hear from you. (I hope you got the Yoda reference)
Thank you for your time and effort in making this video, i was able to follow along in real time recreating the sketch while modifying various attributes of it. Very good tutorial highly recommended.
@@RalphBacon Not a trouble I always leave a like. Don't suppose you fancy making a video about using other libraries with a library. Got square eyes trying to figure out how to include the wtv20sd16p library in my library. 😅
@@RalphBacon I did figure it out in the end but it's surprising how scattered the info is, I couldn't figure out where to instance the object correctly to use it throughout the library. I actually found two methods one used pointers which I no longer use but Google hot to use a library in a library and there is no definitive guide or tutorial on the do's and don'ts thanks for your reply though.
Don't tell anyone, Pekka, but I do the same when I need some (good) advice, heh heh! I guess as long as you know there is a video with information here then it's perfect that you returned and watched it when you needed it. Thanks for getting in touch, good to hear from you.
Very nice tutorial! The explanation speed was perfect since it allowed me to think deeply about what you were saying. I subscribed to your channel too. Thanks a lot!
very helpful. I have done a lot of programming but never really took the time to sit down and do that library stuff (eventhough I started a few times) . Will do again with help of your video. Oops, Sorry, I forgot I already commented on this video. Must be my age. Anyway, extra proof I like the video
I think you have just proven that you REALLY like this video! I'm happy with that! Constructing library classes is not magic, voodoo or only for "experienced" programmers. It's a series of steps and concepts that can make your programs "better" (oh, dear, red rag to a bull I know). Best thing is to try it with a really, really simple function (as per my demo) and get that working - then build on that. Thanks for reiterating your love of this video, I hope others feel the same way :)
indeed. I am no stranger to making 'classes' but wrapping it in the library files is something I just haven't taken enough time for yet to be able to do it fluently. Enjoy yr weekend
@@RalphBacon this is definitely the best arduino library tutorial so far on TH-cam and it's nice to see you answering peoples question on your older videos. i'll keep eye on for second part. Love from Finland👍
Actually, Arduino now admits they made a mistake with their Serial.flush implementation. It _usually_ means "clear down any outstanding characters in the output buffer" but they implemented it as "wait until the buffer has been naturally cleared by being sent out the UART". I suspect that curtailed message was because the Serial.begin() was in the wrong place, but whatever the reason I've always had it work just fine since!
Thanks Ralph. Great info! I'm used to C, not C++, but I will definitely switch over. Then I can put my common useful functions in a library instead of re-copying them into various ino sketches(and which one has the latest modified version?). I saw that I can also create a subfolder in ../libraries/TestLibrary/examples/LibraryExample1/LibraryExample1.ino so that it is visible from the Arduino ide files/examples. GREAT STUFF! Made my day!
Great video Ralph. Oop for newbs is a hard topic to teach. When I went to university they were just defining the standard for oop in c/c++ so I missed out because I stopped coding from 20 years. I had a fun time learning all the arduino basics because it all came back to me. It woke something in me so I took an advanced pointers course, data management and then I took the course for oop and made like ten fake entities then wrote code based on the classed I created. Haha You make the complex make sense very well my friend.
It sounds like your interest in OOP programming is still strong. Those developers that put in the effort to learn how to make a class will make better programs for sure.
Actually, the last software house I worked in for five years built software for their own company but it was used (implemented) throughout the UK. 22,000 clients. Tricky stuff!
Ah! An anomaly for the Arduino IDE then. Strictly speaking, quotes around a library simply mean "look in the sketch folder _FIRST_ then in the usual place(s)". But without the quotes it won't look in the sketch folder at all, it seems. I shall be aware of that in the future.
Hi, Ralph. You explained this quite well. However, I'd like to share a convention I've used in C++, PHP and several other languages. When writing a class, I will always add a private variable (as a programming flag) named 'debug', along with a setDebug() function. Throughout the code of the class, I test for this value to determine whether to display generalized debug messages, much like you did with the _msg variable you used here. Then, from the main "sketch", I call object.setDebug(true); while developing, and object.setDebug(false); when all is working. Another thing I include in every class is a public function named ReportSelf(); This function reports every variable name and value the class contains. I find these practices to be quite useful, and in fact use them a *lot*.
Hi there chopzuki! Your points are well made and should probably be standard when creating a class (oops, I said that word again, I've just lost 50% of the viewers reading this post!). Seriously, though, when using classes such things become much easier and abstracted away from the main sketch. You've probably noticed my use of a templated global debug function in my other scripts which beginner Arduinites might not have fully understood but at least grasped its usefulness. At least it stops the dreaded if(debug) Serial.print.... littered throughout the code! Glad you visited, I hope you stay, and thanks for that excellent point in your post, most appreciated by me and others reading this :)
The usefulness of this approach is two-fold: First, the _debug flag is quite useful during class development. Second, even when the _debug flag is set to false, the ReportSelf() function is especially useful when working with database records to help ensure data is being handled correctly.
This is a great suggestion and is very helpful during development. The only caveat to this approach is that unlike general computers, microcontrollers have very limited amounts of memory for code and stack variables. A better approach would be to use a preprocessor directive to remove any debug code that you can during builds for "production". I'll try to build some example code and post it up in the next few days.
The reason why the text does not come out correctly while the "void setup() {...}" is not called, is very simple. The "void setup() {...}" is just part of a basic library framework library that sets up stuff like buffers, timers and so on. While the "void setup() {...}" was not called already, the text written makes the serial-out-buffer overflowing and from the most characters, apart from those that had gone into the hardware fifo from the USART hardware, are lost. So it is a pre-initialization issue, since in the first version the constructor was already called at the "TestLib testlib(true);", before ever entering "void setup() {...}". By the way, putting serial initialization routines in classes is very bad style, since having more classes then just your gives the problem that they might all try to intialize serial, one after another when called trough out constructors/methods. So your "serial.begin(...)" to put once into your "setup()" is certainly the better way to go, because then it does not get out of control if, when and how many times this is issued.
Spot on, I realised this belatedly, but as it was more about how a library is constructed I kept it going. The whole serial thing is a bit of a mess - I traced the code (the Arduino.cc written code) and it really is a bit convoluted, to say the least. Definitely not the best thing to put into a library example. I hope you still consider there is still value in the video though for others to learn about OOP.
Of course it is usefull, expscially for beginners into C/C++ along with Arduino, to see how Libraries could be done, instead of having endless spagetti code like looking source files. So I think your video is very good to take a look into the Libs aspect of Arduino developments.
Great video Ralph. This steps it up a gear for anyone who wants to understand object oriented programming. Once you 'Get It' the concepts are then only language specific. C++ is a bit unwieldy with its header files and you explained the concepts really well. The only thing , (and could be difficult for beginners), is Scope, the :: syntax. Really good Ralph, excellent mental workout following the code, cheers Alan
Ha ha, I'm glad your brain got a good mental workout trying to follow my meanderings through class construction! But the point you make about 'getting' the concepts is spot on. Once you have that lightbulb moment all else is 'just typing'. I'm hoping enough people take my example, break it, fix it, break it again and basically get a good grasp on how libraries work and in doing so understand how classes work too in the (semi-) object oriented world of Arduino C++. Thanks for your kind words about me explaining it well. I don't normally watch my videos all the way through (after a couple of hours of editing I've usually had enough of my own voice) but I felt this time I had to make sure it all hung together properly and I think it does provide a good starting point for Arduinites expanding their wings, so to speak. Thanks for posting Alan, always good to get constructive feedback.
Thanks for the video Ralph - yes I know it's mature. Lovely to see Benny again. I think the reason you cant put Serial.begin in a constructor is that Serial is a static class, it's a single resource. That's to say you can't really create another Serial for each instance of your class. I created a Ping)) class with OTT features including limiting the time pulseIn will wait based on a user decided maximum distance of interest. I wanted to check the maths with a debug method; in that method I simply use if (Serial) { print lovely stuff}.
A good workaround you have there. Another solution is to try a singleton for the Serial.begin but I suspect that might not work either. Probably just better is the user sets up the Serial interface anyway, as it might be Serial1 on another device.
It's more an introduction of OOP/C++, the function doesn't need a whole class, simply putting the function in the .cpp and making a .h file, would work too. You can even use only an .h file, because of the preprocessor… and there is the possibility to use more .ino files too.
Hey AltMarc, great to hear from you! You are of course correct in your observations, but if you notice I steered well clear of mentioning OOP hardly at all as there's nothing better to deter beginners of C++. A large proportion of Arduinites expect (and can understand) procedural code (like VB Basic 6, perhaps!) but as soon as classes are mentioned, along with overrides, polymorphism, inheritance, templates and what have you they will go back to the 'safety' of their standard procedural code. So I was hoping that putting a very simple function into a library class might get them using a bit of OOP (even though it didn't really require it) and so not be put off. And, of course, it might actually encourage some developers to put their code into a library so they can concentrate on new stuff they are building. There's no easy way of learning C++ OOP without doing it - ideally doing it without realising you're doing it. Hence the video! Did I succeed, that is the question? Great to hear from you, always keen to get my viewers' perspective on things, and I appreciate you took the time and trouble to post here.
Hi Ralph. I found the video to be clear and helpful, and I will be definitely looking at your others. But I think you should have left the OOP out of this. I know it confused me. In fact, I only scrolled down to find this message because my research so far into creating a library led me to believe no OOP is necessary, and I wanted to check if that was true by seeing if anyone had commented to that effect. OOP doesn't bother me, I've done mountains of it in Delphi, but I'm new to C++ and I just want to learn how move some code into a library, and not have the process complicated by unrelated concepts if not needed. I haven't yet learned how to write classes in C++, and I didn't come here to learn that now - I came here to learn how to make a library. Only after success in that, would I want to convert it to OOP where appropriate. The video as it sits, leaves the new library writer with the notion that a library MUST involve classes, which (from what I have gathered) is simply not true. I can imagine someone with a large chunk of code involving a bunch of interrelated functions and data that they want to wrap into a library, getting into all sorts of bother trying to make them into classes when they don't actually need to (even though they probably should). If I had watched only your video, I know this would have happened to me. In essence I'm saying that as libraries and classes are distinct concepts, they should be taught as such. Confusing them in the teaching, confuses them in the student. I can see that you are concerned with OOP being a deterrent to some people. But I think introducing it "by stealth" where not required is the wrong approach. I would address that by a separate video about classes. (which would include an admonishment to those afraid of OOP to stop being such little girls) I hope you see my criticism as constructive, and thanks again for making these videos.
True, Dr. Jones, true. Or is it the linker? Whatever it is, I think we are now all in agreement that unused functions and/or libraries are not included in the final, downloaded hex file, just as well! Thanks for the confirmation and posting.
Thanks you!, very clean explication i like your style, only a note that could be tricky: in the #ifndef statement we can't use the same name of the library, this could be confussing because the declaration of the files .h .cpp and the constructor needs to be namend equal.
Indeed, you are correct, the common practice is to use a name in capitals or with underscores after the name or both - you get the idea! Pity that I used a lower case two character name called tl (for test library) but then again this was just a demo)! Thanks for the advice, good to hear from you.
The reason why the constructor (ctor) behaves differently to other methods is because it is a very different animal. Methods (other than the ctor or destructor (~classname)) are stored differently. They are in fact static code stored in the code. This affects the 'lifetime' of the methods. Yes, there is a difference from other static methods and functions and that is 'this'. 'this' is a hidden parameter to all non-static methods. The parameter is in fact the first in the parameter list; such is the case even if there are no declared parameters (i.e. classname::foo (void);). this is a pointer to this instance of the object. Now the constructor has a very short lifetime only surviving as long as the object is instatiating; as such the constructor can only be accessed when a variable of the objects type is declared. or new is used. A call to a serial method shares the cycles with your code (unless it is blocked by, say delay(100). So if one watched code such as [serialPrint('Test)'; digitalWrite(13, HIGH); ] on a logic analyser, one will observe that the TX pin becomes active AFTER pin 13 goes high. Now, if that behaviour is repeated when calling serial from a constructor, that temporary string created in the parameter of the call, may no longer exist. As serial accesses the string character by character, later characters cease to exist before the message is sent. Arduino doesn't support new or destructors (because no libc functions accessing dynamic memory are supported). Constructors are partially supported but only for access to the object's variables.
BTW I am confident that Ralph is fully cognizant of 'this' etc. I just mentioned those aspects of the constructor problem for his other disciples who, like me, are lesser mortals.
I think, Michael, you underestimate your already considerable skills on OOP, given your posting above, nicely put. What you have described belongs in the "advanced" Arduinite class, of course, and I should have remembered (or at least understood) why there are difficulties in putting that Serial.print in the class' constructor. What is clear to me is that most writers of libraries (and therefore classes) do already understand the above and therefore that is why they suggest the addition of a begin() function; it cleans it all up rather nicely as well as using a well-established pattern that beginners can grasp very easily. Thanks for the excellent explanation above; if nothing else it makes it clear why I had that issue, like most things in computing there's *always* a reason for a computer's behaviour even if we don't understand *why* at that time! Great to hear from you and I hope you enjoy the other videos on my channel :)
I enjoyed this video, as I have with all your presentations. It is always a joy to look down my list of subscriptions and see that you have submitted a new submission. I couldn't agree more on your comments on libraries and their valuable facilitation of code re-use. You are right to encourage your viewers to gain confidence in developing their own libraries. We are all beginners in this environment that is changing so quickly. Rapid change makes books poor resources for all but the most fundamental aspects of embedded development. However, all that your viewers have already learnt from your and their projects could fill a library (of books). The more we share with each other the better the technology will be. Thank you for enabling this process.
The reason the call to Serial.begin() in your ctor doesn't work is because in C++, all static objects are constructed before main(), which means the application owned objects are not necessarily fully initialized yet. You can see in arduino/core/main.cpp that USB.attach() is called in main() before the call to setup() (which is the call into your sketch's setup function), so USB (and therefore Serial) is not ready for your use until your setup function is called. In C++ you don't want any static object function calls (e.g. ctors) to call into any other static objects before main() because they many not be fully initialized yet. The order that static objects are initialized is not guaranteed to be knowable. That is why many libraries have setup/begin calls that need to be called in your setup function, after all static objects have been constructed. Otherwise, ctors are not particularly different that any other code - all code is stored in PROGMEM. There are a few caveats with ctors/dtors, mostly related to inheritance and virtual functions.
Ralph, great tutorial. I now have some idea what I'm looking at when I poke around in library files. More like this please - a debug library would be ideal. Regards Alan
Hey Alan! I was going to include my debug routine in the library video but found that my code was "too advanced" for the compiler to figure out how to use it! Seriously! It's a limitation of the compiler but as always, there are workarounds but it just made it a bit messy and not really for a "first time" video - but I will include it (or upload it) with a future video. At least you now have a better understanding of how the libraries hang together and can appreciate the work some of the authors have gone to just to give us Arduinites an easy way of interfacing with bits of hardware. And of course, you could create your own libraries just to make things easier to work with. A nice cold Saturday afternoon project, perhaps? Thanks for the feedback and suggestion, great to hear from you.
When I was doing C back in the days of Borland C, cpp was brought in as I understand in programs to differentiate C code (vanilla) from C++ cpp = c plus plus
Indeed you are correct, Steve, that was your starter for 10. Now, what does .ino stand for? Previously known as .pde, which stands for? Finally, why did Arduino.cc change it all? Why not just keep to one name for everything, ideally, .cpp? More questions than answers, I'll be bound. You're not allowed to Google the answers, either!
@@RalphBacon Not sure what .ino stands for for .pde is an extension from the Processing language which Arduino and the Arduino IDE is based upon. I think They changed it to .ino to make it clear that the file is an Arduino file instead of a .pde (Processing) file. If they did not do that many noobs would run into issues.
Ralph: How do you find out what functions a library includes and what there parameters are? I want to use the AccelStepper library but I don't know what functions it includes or how to use them. Thanks
Most libraries are on GitHub. The GitHub for a particular library should have documentation (or a pointer to the Wiki for it). This will tell you everything you need to know. Secondly, if you look at the library, in particular the library headers (files ending in ".h") these will provide the PUBLIC functions you can call. From there you can find the relevant function in the associated c++ file (ending in ".cpp") and read it, to see whether it's documented enough. Also the GitHub will probably contain an "Examples" folder with some simple get-you-going sketches. Another source of gold to beginners.
Hello Arduinite! I'm currently on vacation 5,000 miles away from home so I'll have to be brief with these comments until my return, mid-July. Glad you found it useful, John, I like comments which contain the words "brilliant tutorial"! It's not so hard once you get to grips with the fundamentals. Thanks for posting.
Excellent, Ricky, start small and work up. And look at other libraries to see whether there are any other techniques you might use. Great to hear from you.
TWO thumbs up? Wow! Actually, just the one is awesome as it tells Google that viewers are appreciating my videos. Thanks for posting golanramati11, great to hear from you.
if I can add something that you didnt cover in the video: I wrote a library to create an instance of some object and another library that creates an object consisting of an array of the first object. in the both original librarys I included standart librarys (looked like the right thing to do, thing like servo.h) but it wouldnt compile, the error said the first object does not name a type. after a long time of asking aroung and pulling hairs, I removed the standard included librarys from the second library and included only the first library I wrote and theat seemed to solve the problem. thought it could help somebody
Thanks Ralph - very informative. Do you know if it is possible to inherit a more complex type like HttpClient and create a custom library wrapping HttpClients functions in the class?
Yes, absolutely, Robert. Include the library you want to wrap, and in the class constructor inherit the underlying class. For example, if you wanted to inherit the "Print" class so you could "print" characters to a new LCD screen you could inherit that (but remember to define all underlying virtual members): #include class myLCDPrinter: public Print { public: virtual size_t write(uint8_t); etc using Print :: write; } This then gives you access to ALL the underlying print functions (you don't need to define each one individually). Your class must now declare this method: size_t myLCDPrinter :: write(uint8_t value) { send(value); return true; } The method you write to do the "send" will be declared as "private" in your class: void myLCDPrinter::send(uint8_t value) { // your code here to do whatever you need to do to get the value // onto the LCD screen } As you already seem to know about inheritance I guess this is enough to get you started with the HttpClient!
@@RalphBacon Thanks Ralph Yes and know on the inheritance most of my recent experience (last 15-20 years) is C# so syntactically a little different :-) I copied the HttpClient virutal methods into my header class (as you can see by the comments with the exception of endOfStream() and completed() they were all inherited from Print and Client, I'm not sure if I should have included them?) My header class looks like this. class SparkfunWifi : public HttpClient { public: // Contructor SparkfunWifi(Client& client, char* serverName, char* port, char* ssid, char* pass);
// Methods /** Connect to the server and start to send a GET request. @return true if connection successful */ bool connectWifi(); /** Sends HTTP weather POST to weather.api. @return 200 if successful response from api. */ int sendWeather(); // Inherited from HttpClient which inherited them from Print // Note: 1st call to these indicates the user is sending the body, so if need // Note: be we should finish the header first virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(); }; return iClient-> write(aByte); }; virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(); }; return iClient->write(aBuffer, aSize); }; // Inherited from Stream virtual int available(); /** Read the next byte from the server. @return Byte read or -1 if there are no bytes available. */ virtual int read(); virtual int read(uint8_t *buf, size_t size); virtual int peek() { return iClient->peek(); }; virtual void flush() { iClient->flush(); }; // Inherited from Client virtual int connect(IPAddress ip, uint16_t port) { return iClient->connect(ip, port); }; virtual int connect(const char *host, uint16_t port) { return iClient->connect(host, port); }; virtual void stop(); virtual uint8_t connected() { return iClient->connected(); }; virtual operator bool() { return bool(iClient); }; virtual uint32_t httpResponseTimeout() { return iHttpResponseTimeout; }; virtual void setHttpResponseTimeout(uint32_t timeout) { iHttpResponseTimeout = timeout; };
private: int _serverName; int _status; char* _ssid; char* _pass; }; My .cpp constructor is as follows. // inlcludes #include "arduino.h" #include "SparkfunWifi.h" // constructor SparkfunWifi::SparkfunWifi(Client& client, char* serverName, int port, char* ssid, char* pass) : client(client), serverName(serverName), serverAddress(), serverPort(port), iConnectionClose(true), iSendDefaultRequestHeaders(true) { _ssid = ssid; _pass = pass; _status != WL_CONNECTED; } The error I get when I compile my sketch is: SparkfunWifi.cpp:6:1: error: prototype for 'SparkfunWifi::SparkfunWifi(arduino::Client&, char*, int, char*, char*)' does not match any in class 'SparkfunWifi' SparkfunWifi::SparkfunWifi(Client& client, char* serverName, int port, char* ssid, char* pass) ^~~~~~~~~~~~ In file included from sketch\SparkfunWifi.cpp:3:0: SparkfunWifi.h:13:7: error: candidates are: SparkfunWifi::SparkfunWifi(SparkfunWifi&&) class SparkfunWifi : public HttpClient { ^~~~~~~~~~~~ SparkfunWifi.h:13:7: error: SparkfunWifi::SparkfunWifi(const SparkfunWifi&) SparkfunWifi.h:24:5: error: SparkfunWifi::SparkfunWifi(arduino::Client&, char*, char*, char*, char*) SparkfunWifi(Client& client, char* serverName, char* port, char* ssid, char* pass); ^~~~~~~~~~~~ sketch\SparkfunWifi.cpp: In member function 'int SparkfunWifi::sendWeather()': SparkfunWifi.cpp:48:5: error: 'client' was not declared in this scope client.beginRequest(); ^~~~~~ sketch\SparkfunWifi.cpp:48:5: note: suggested alternative: 'Client' client.beginRequest(); ^~~~~~ Client exit status 1 [Error] Exit with code=1 Thanks again for your assistance & I look forward to watching more of your videos. Cheers Rob
Whether you need to include libraries is easy enough to test; just comment out the #include and see if you get a gazillion errors! In the line "SparkfunWifi::SparkfunWifi(Client& client" how is the Client being instantiated? Make sure you have the "Client" object in your class or reference it in some way. The compiler doesn't know this is HttpClient. Write a simple sketch to invoke all this first and you might see how to include it in your class. And use PlatformIO or Eclipse as they give you Intellisense that can _really_ help when doing this sort of thing. From one C# developer (.Net in my case) keep going. Sometimes it can take a while (and a few hours Googling) but eventually the solution will be found.
@@RalphBacon Hi Ralph - I did persist and was able to get my custom class to compile - sort of - at least sorted out the inheritance side. I can get my library to send formatted JSON out the serial port and connect but when I try to serialize my JSON it the compiler complains when I uncomment serializeJsonPretty(doc, iClient); Thanks for all your help. I'll keep working on this last hurdle. Regards Rob
Hi Ralph, thank you for explaining. Unfortunately, I have one question. What if I need (I don't know, how to say it correctly) some class variable, that is shared across all instances. For real example. I have a few moisture soil meters and I have decided, that I will write library for them. There are some instance variables, unique for each instance like "pump_relay_pin" or "moisture_limit". But I need one shared variable for the whole class. It's called "vcc_moisture_pin" and its value is same for all possible created instances, because it's shared pin, which turn vcc of all sensors on. It doesn't matter how many there are. So, I need this "class variable", which I can set directly via class name in main program, not via instance name. This variable I want to use only in library cpp file afterwards. Yes, I can use this variable as instance one, but I don't like it. I think, it is not programmerly correct. What I can use now H file class MyLib public: MyLib(); byte vcc_pin; INO file MyLib Inst1; Inst1.vcc_pin = 2; What I want to use H file class MyLib byte vcc_pin; // I don't know, where to put this declaration public: MyLib(); INO file MyLib.vcc_pin = 2; and then, every instance gets this vcc_pin variable with value 2, but I need to set this value in main program, not in library, because I want it versatile. Is there any option, how to do this? Could you please help me? Thanks a lot :)
It sounds like you need to write a public function in the class that updates that variable (which should be private, not public). Another function to read it back. But that gives you that value for the class instance you are addressing, it's not global across all instances. You could accomplish that by creating another instance that you call globalMylib (or whatever) and use those functions I mentioned wherever you need to update or read it. What you really need is a singleton, or static class, but I only know this from C# not C++ - would have to check that out (or you could).
Thank you so much for sharing this great information ...... but I have a question... how can I include some sketch examples within the library? and again thank you so much !
Hey Baraa, glad you liked the video. But I don't quite understand your question. Do you mean how to include your library into a new sketch? Or something else? If you could clarify that would be great.
Thanks for this , it has given me a chance to try and debunk some previous written software ( ble for arduinos) . A question , how do we best debunk what are the available commands ( methods ) within a defined class and their uses ?
Debugging code for an Arduino is somewhat crude. It involves using the Serial.print() method to write out to the Serial Monitor (aka debugging window) messages that might help you understand what is going on or wrong. And judicious use of the delay() statement to slow things down a bit so we can see what is happening in slow motion. Newer versions of some µControllers (including the MKR boards from Arduino) allow hardware debugging but that's for the future - for now you're stuck with Serial.print(), I'm afraid.
Heyy Ralph!! I want to include LiquidCrystal.h lib in my custom library. I am not able to understand how should I go about. Where should i write #include and where should i create my object 'lcd'??
Hello Arduinite! I'm currently on vacation 5,000 miles away from home so I'll have to be brief with these comments until my return, mid-July. Write the 'include' statement at the top of your .h library file. If you want to use the LCD library ONLY in your own library then create the lcd object in exactly the same way as you would with a standard Arduino sketch. If you want the user to be able to access the lcd object then you must use the EXTERN keyword which I'll explain in a future video (you can Google it for now!). If you get stuck let me know exactly what you are trying to achieve and I'll explain further on my return, Interesting question you asked here, Abinav!
Ralph S Bacon, thank you so much for your time and knowledge. I followed your video minute by minute and have learned so much. Thank you so so very much. I must of missed a step between 35:10 and 35:15. What in the world did you do? Perhaps you included this step in a different video. Can you send ma info as to what you did? Or a link to another video?. At any rate thank you so much. I have been following step by step of this video for the past five days, and every time I do I learn something new. Thank you.
Are you referring to the colour-coding that appeared? Making some keywords highlighted? That is all explained at time th-cam.com/video/fE3Dw0slhIc/w-d-xo.html (35:51) which is basically just typing the words you want highlighted into a text file in the library's folder. Is this the information you need?
The libraries are not compressed, Rocky. They were moved OUT of the folder in which they previously resided (the same one as the sketch, so they were, up to that point, only LOCAL libraries) and moved into a folder of their own in the standard "libraries" folder (which is a sub-folder of your sketches folder). Now they can be included in _any_ sketch. Wow, that was confusing to write, did you understand that?
@@RalphBacon , yes sir, that is exactly what I do not understand. How did you move the library from the sketch into the main library folder. Yes Sir' how did you move the library and save it into the main library.
Dear Ralph, Great video, thanks! Explained exactly what I am trying to create at the moment. And I still have a questions.. One thing I did probably wrong is that I put all the functions inside *.h file, did not made and *.cpp file. It somehow works, but let me change it and see it working again. In my project (remote control tank) I am going to use GPS module and GSM module (and some others as well), so I really do not need that additional code into my main code, just a results, e.g. GPS coordinates, so library is excellent solution.
Technically speaking, Valters, putting all your code in the header file (whilst punishable by watching the BLINK program for several hours) _should_ work. But, as you are aware, it's just not done that way so do split them as you have outlined - and let us know how you get on.
do you reallt need to wite the "testLib::" dont the complier know that by itself? but need to write if its nothing else it want to point to. dont think i was wtiting it when i used visial studio.
You do have to write the library name followed by two colons in front of every method in the library .cpp file. This is so the compiler knows it's part of the library class and not some other method/function you happen to be declaring at that point.
Hello Ralph, Great tutorial as usual. Can you make a video on the NRF24lo1 using 2way communication but with a view to simplicity? There are many good tutorials about nrf24 on utube that are spoiled by overcomplicating them with sophisticated sensors and the like.It is quite difficult to even get them to work in duplex mode .Sending a simple string or Pot out put both ways is all that is needed , then it could be elaborated on when all is working.
Oh Steve, if only you knew how long that topic has been on my video 'to do' list! Perhaps your post is the nudge I need to get a simple project together and just 'do it'. Don't hold your breath too long, from idea conception to posted video can take some weeks but I too think I need to promote this one up the list a bit. Thanks for giving me the nudge, and I take on board about over-complicating it. Simple is best. Or as Albert Einstein said, "Make it as simple as possible but no simpler". As I'm fairly simple it should be a breeze...
Hi, great video. I have a question. In my main code, I have things such as #define MOTOR_1 13, etc for my motor driver. Where do those go or how do I put those into my header files?
You must understand how the compiler treats those #define lines. They are purely *textual substitution* and have no meaning beyond that. If you #define LED 4 then whenever the compiler finds a strange word called LED in your code it checks to see if you have defined it and then substitutes, exactly, what you have written, in this case 4. That's it. So you can continue to define these in your header or cpp files just as before. As the library is compiled (as part of an #include statement in another sketch) it finds all your #define lines and compiles the library as though it were part of the original code. Watch out for #define statements that might be used by the user (that will confuse the hell out of the compiler). Put a leading underscore or some other identifying character(s) as part of your defines. So in the above example you might use #define __LED_ 4 and then you use __LED_ instead of just LED in case your library consumer uses the LED define (a common enough word). Understood? Or clear as mud?
If you are new to my channel, Joel, you may not realise that Benny writes most of the C++ code. If he does deign to let me have a go he then monitors everything I write with a beady eye. He is a hard taskmaster. Of course, if you have watched more of my videos than you already know this and the fact that he sometimes sneaks into my workshop at night and corrects all my syntax mistakes, recompiles everything and uploads it all to the µcontroller board I'm using. I'd be lost without him.
for those great programmers that have developed their own library you can have a look at the arduino spec to improve the sharing capability. Here is the link: github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification
That's great Paul, thanks for the link. I think I followed some of it (but not sure whether I shared it in my video, eg keywords, library.properties and the like). Note the different versions now available, 2.1 being the latest for IDE 1.6.10 (although we are already using 1.8.x, it's the latest we have). Thanks for sharing Paul, appreciated. :)
Hi, Ralph, thank you so much for sharing your knowledge. I am new to the microcontrollers world. I have downloaded your LibraryExample1 sketch - I actually created the sketch by copying and pasting the contents of the three files (Arduino, .h and .cpp). Here is what it says when I compile it:LibraryExample1:1:10: error: TestLibrary.h: No such file or directory #include ^~~~~~~~~~~~~~~compilation terminated.exit status 1 TestLibrary.h: No such file or directoryThank you for your help, Mac
Did you put the library files in the SAME folder as the Arduino sketch (the .ino file)? In which case use quotes around the library header file name not chevrons: #include "TestLibrary.h" Let me know if you still have problems.
Thank you, Ralph. I am afraid it did not work. I cannot I am a beginner, so I do not know enough to think my way through. So I ordered an ESP32 with USB connector and do the test again.
Hi Ralph
Many thanks for such an informative video, I have a question, is it possible to open the *.h and *.cpp files in the Arduino IDE, sorry if I missed something in your video which explains this I have watched it three times. You stated in the video that we could play around with these files and if we made a mess of them we just download them again, from that I thought you meant we can alter things in all three of the files.
Many thanks
Graham
Hi Graham! THREE times you say? You probably know it word for word by now! Yes, you most certainly CAN open the .h (header) and .cpp (c plus plus) files using the Arduino IDE. There are some caveats:
1. To CREATE a new file (which will reside in the same folder as your sketch) click the small triangle at right hand side of the toolbar (containing the sketch tab). You will then be prompted to enter a name (eg myheader.h). The prompt appears at the bottom of the code window (!)
2. To OPEN an existing library file, copy both the .h and .cpp files to your sketch folder, then open your sketch. The additional files will appear as separate tabs next to your sketch's tab.
3. To include a library file in your sketch, when the library file header resides in the same folder as your sketch, use the format #include "mylibrary.h" *not* #include as the latter format is used when you want the Arduino IDE to search your libraries folder (and elsewhere) to find a library.
4. If you muck up the .h or .cpp files you can just re-copy them over to your sketch folder again whilst you experiment. If you enhance the library, and want to keep the changes MOVE the files back to the libraries folder (but do take a backup of the original files first, just append .old to the filename or something). Then refer to that library in the usual way with the standard #include again.
I guess I should have clarified this in the video better, but maybe this comment will be read by gazillions of viewers too.
Thanks for posting this question, it will benefit others wondering this.
Hi Ralph! Many thanks for the quick reply, Item 2 answers my question and works fine, I now have all three files together so I can play with them.
Please keep up the great work, very interesting content, I am also going to watch more of you videos.
Regards
Graham
@@RalphBacon Well, I don't know about gazillions... but I've definitely read it. Comments can hold vast amounts of additional information and are worth reading.
@@RalphBacon Thanks for the informative video.
As for #2, it would seem that you're opening a copy of the library that you're using via , not the actual library that it's compiling? That there's not an easier way to view libraries with the IDE is a bit of an annoyance (not your fault, obviously). Seems like Notepad++ or similar is a good way to take a peak at them to figure out what functions etc are available, but that's not perfect either.
arduino noob here... after months and months and months of studying, watching videos... its the first time i see how to collapse sets of codes... my gosh, so many tutorials and this is the only one that explains that! thank you!
Glad I could help! Funny what you find at unexpected moments!
Wow thank you so much. Some people are complaining about how long this video is but its was great because you not only created a library live in front of us but also explained the background of whats happening. Great Video!!
Complaining? About MY video lengths! Actually, Aldrick, I gave up trying to make shorter videos some time ago and now just make them whatever length they need to be, usually around the 30-minute mark. It's about the right length if we're going to discuss stuff in the correct level of detail, don't you think? Well, it seems you do! Thanks for posting!
I very much like the way you teach. It is as if I was sitting down with a friend or colleague who wants me to understand something, but wants it to be a pleasant experience.
Nice of you to say, thank you 😉
thanks for this lesson with detail explanations on each lines and resons. I picked up many knowledge not known before as I was trying to make my own library.
Glad it was helpful!
Ralph, I came across this video (#71) a few months back, and am now proud to say that I have written my first Arduino library. I've a lot of work to do on the code, but I have built a class with methods, and it is likable into a users sketch. I am now working to configure it to allow easy importing into the IDE and compliance with Github standards.
So many thanks for your inspiring and instructive videos.
Fantastic! And by writing the library your understanding of Object Oriented Programming has taken a giant leap for Dale-kind! Really happy about this!
@@RalphBacon Yes and thanks to your tutelage, I have now written and tested a Python class. This could become addictive 😁
Thank you Ralph. I hesitated to start a 38 minute video tutorial, but it was worth it just for the calm Pommy accent and absence of duffa duffa music! I am an old veteran since the 70s of programming assembler on bare metal for embedded realtime controls, and only just in retirement wrapping my head around C/CPP. Some of the syntax conventions really "get" me, and I have to remind myself I am dealing with a very simplistic one-pass compiler that needs lots of cues in order to work.
The work flow from multiple tabs / project folder to files in the library folder was very helpful.
Glad you found it useful, David. All my videos are a bit long but watch them at 1.25 speed and it shaves many minutes off the length. And I don't sound like a chipmunk on helium either!
I never thought I would understand such a complicated subject but you made it so understandable. Thank you so much! You have a special 'teaching gift'...
Glad it was helpful!
Beautiful, non ambiguous, simple example... Clear and pleasant to listen presentation...
Glad you liked it!
I do programming for past 4 years and this was like the best tutorial which Ive ever seen. Thanks!
High praise indeed, Mibra, thank you for that and for posting here.
Hi Ralph,
Your videos are wonderful. Very instructive and very easy to understand. I have written my first library using your video and just wanted to say thanks and keep it up!
Thank you very much Timothy, I'm glad I'm being of some use! Like most things, once you're shown how (and, possibly, why) then the mystery disappears and you think "Is that it then?" I hope you create many more libraries (I must admit to cheating whilst developing and just stuffing items into a .h file until I'm ready but don't tell anyone!). Thanks for posting, much appreciated.
Great informative video. This has helped me to no end.
Thank you 😀👍🏻
Thank you, Harry, for your supportive words. I'm glad it's helped you (and hopefully others too!). Once you've done it a couple of times it gets quite automatic to move stuff into a library. Good to hear from you.
Thank you so very much. One of the best tutorials on C++ code that I have seen. It helped me a lot. You are the best.
You're very welcome!
Thanks Ralph. A straightforward explanation that has stopped me binning my Uno! I have 18 switch x inputs to pick up and three sensors
Glad it helped!
Binning you uno! I am deeply offended. Joking, but glad it helped.
You are a king. In 1.5x it is the perfect introduction to Arduino. Thank you so much
I suppose I could speak slower, that would confuse you! Glad you liked it, thanks for posting.
Thanks for this walkthrough, Ralph. I'm coming from other programming languages (primarily web dev), and this was a great overview of the idiosyncrasies of c++ when it comes to object oriented code and including local libraries.
I had been reading through articles and posts that explain the same thing, but none of them were as clear and well presented as this video :)
Thanks for taking the time to make this and for posting a link to the code. It's much appreciated :D
Well, thank you, cschmitz, for your kind words! I'm glad to have helped. I, too, have taken many paths in coding, from µProcessor assembler through various BASIC dialects, C#, JavaScript, and C++. I think once you have a programmer's way of thinking then the language is secondary to what you want to do, so you (as a web developer) are well placed to mastering this very quickly. Thanks for posting and good luck in creating your own libraries!
Many thanks Ralph, have just written my first library. Excellent resource!
Awesome, Bernebeer! Congratulations on having done this. Now you have started you can progress to more complex libraries. Perhaps one day I will be using a library that you created, who knows. Thanks for letting me know, great post.
You are the man, I could not figure out how to use the serial port in my cpp file. I tried everything until you showed the method to - begin serial. Like you said, there just isn't any useful online documentation available for this - JOLLY GOOD SHOW !
Glad this video helped you, Jeff, nice to hear from you.
great and clear lesson ... needed to refresh classes... need to refresh everything to be honest.:) thanks a lot Mr R.B.
You're welcome!
Thank you. I really liked the way you explained everything without rushing :)
Well thank you Goldichan92, I appreciate that you took the time and trouble to post that. Unless my Arduinite viewers tell me how I'm doing I have to guess which is not the best way to build up an audience. So thanks again, and keep watching! And don't forget, if you like what you see, consider subscribing! :)
Hello Ralph, very many thanks for the great overview within 30'. Well done ! - All the Best, Franz-Juergen
Glad you liked it, Franz-Juergen, ziemlich einfach, gel? Now that you have some knowledge you can create your own libraries, but start slowly, as there are some 'gotchas' as they get more complicated. Thanks for posting.
Omg this is so good... I learned a lot today for me to try write a code to sniff the LIN bus protocol. going to use this way of clean setup and also make it easy for me to reference to other codes available. now I can connect the dots a lot better.
Glad it was helpful!
Totally brilliant ! Thank you so much for explaining that ... and at a good pace: neither too fast or too slow, and in an accent that my ancient ears can cope with!
You are most welcome James Hardiman, I'm glad you like the video. Nice to hear from you.
Hi Ralph
Thanks for this clear explanation ! I created my first library files and ... it works !! :)
You sound surprised! Yes, once you have written one library you can progress and learn all about classes, objects, private, protected and public functions and variables... the list goes on. Well done!
very helpful!
I also had forgotten the semi-colon at the end of the class declaration. Luckily, it was the first thing I randomly landed on when I was flipping through the video to check if it was any good.
I'm glad it helped, Jason, thanks for posting.
Ralph many thanks for a very clear explanation of how to create an Arduino library. Apart from tidying up the sketch I would say the other main reason to create a library is for code that you tend to find yourself using in several projects. Once it's been debugged then you can forget about the dirty details and simply use it every time you need those methods. BTW I never knew about the IDE being able to collapse or 'fold' code so thanks also for that insight!
You've grasped the real use of a library completely, Philip. TBH even if you don't use the code elsewhere it's still good to 'modularise' the sketch this way as you quite rightly say you can forget about it. Glad you now know about code folding, it's quite useful. Thanks for your supportive words, appreciated.
Oh, and ... thanks to Benny for helping you. Here in Cirencester Sammy and Morgan were helping me to absorb the knowledge.
Benny says that you are most welcome too, and sends his regards to Sammy & Morgan who are probably experts in Arduino C++ now (cats learn fast apparently). 😺
Extremely interesting and useful. Wish I had found it a couple of months ago when I was just getting started with Arduino. I'll have to watch it a couple of more times as I'm a slow learner.
I have to watch my own videos sometimes to see what I said!
Thanks much Ralph!
Here's where I get into stall mode.
For instance if I wanted to output an instantiation message to another device apart from a serial port or output to another library function ie. write to an SD card then things get confusing.
I know that your code is just an example and that any 'portable' library wouldn't open a serial port regardless, but further
thinking brings on many complex options.
Great example nonetheless!
Hi ya Phil, interesting comment there!
If you wanted to output serial data to another device, when we have already used it for our debugging window (Serial Monitor), you could always use the Software Serial library which allows any pin to use serial data. I've used it many times and it works well and stops you being restricted to pins 0 & 1.
But as you say, this was but an example showing how to put a library together (rather than concentrating on the functionality) and I'm glad you liked the example. Good to hear from you.
I forgot how good this video is. I think the grammar of classes are what make them seem intimidating. The textbook jargon like instantiate, constructors, deconstructors, self.label type stuff. But if people let go of the jargon like you're showing then people understand it better. When I started, and I'm no expert but the 'self.' Stuff got me confused the worst because all the constructor variables were just stated above. Haha
When I created this video, Joey, I was very careful to _not_ mention anything OOP-related as I knew it would put viewers off! Talking about polymorphic inheritance might be a bit off-putting (just a wild guess). 😁
Thanks for a very clear and informative video. I had wondered what the cpp and .h files were for - now I know. Not sure I like OOP, it just adds another level of complexity.
Many thanks for sharing this.
Best wishes
Arthur
Hi Arthur! I'm glad you enjoyed the video, but what's all this about "adding complexity"? :)
OK, it IS something different but simple classes in Arduino can lead to better programming. Mmm, perhaps I need to do an introductory video into classes (well, OOP) for Arduino! Maybe. Lots of other stuff to cover first.
Anyway, glad you liked it and thanks for posting, great to hear from you.
I have subscribed and looking forward to more videos - I have a lot to learn!
Nice job explaining what can be somewhat daunting for those learning. One thing, when coding in C/C++ you should also include a destructor in the class, but not sure if necessary on an MCU which will most likely loop forever anyway.
Destructors can be included if there is ever a need to destroy the object, good point, thanks for mentioning it.
It has been many years since I have done it, but if you break the source code file into different files according to the different methods in the class, GCC will include only the functions called in the final binary. It will do this process during the linking process. An example is the standard libraries. If you examine the libraries they are an agglomeration of separate object files per standard function.
Yes, you're right of course Uzi, the compiler/linker is intelligent enough, thank goodness, to only include code that is actually called! Just as well, given the limited space in an Arduino Uno. For us Arduinites that have created their own 'Utilities' library (a collection of 'useful methods') it means that not all the library is included each time, so it doesn't really matter how many methods you place in it (within reason, we don't want a huge monolith of unrelated functions!).
Again relying on memory, The procedure of separating the functions or methods is tedious and you have to pay attention to the separate source files, edssentially treating them as a separate project each.
Superb explain on how to make a library. Thank you sir.
You are most welcome!
Thanks for a great tutorial it has helped me on my Arduino journey as it’s time to really understand what some libraries do and the place to start is making your own.
Glad it helped!
Thanks again for another very useful tutorial. Can't wait to write my own library in my next project.
Yes do try, Bob (Yoda: there is do or not do, there is no try), it's not difficult but start small and work your way up! Thanks for posting here, nice to hear from you. (I hope you got the Yoda reference)
“PATIENCE YOU MUST HAVE my young padawan”
Excellent video, simple and easy to follow. My wife also liked your cat. Regards
I feel sure I would also like your wife, as anyone who is a cat-lover is a friend of mine (and Benny). Glad yo liked the video, thanks for posting.
Thank you for your time and effort in making this video, i was able to follow along in real time recreating the sketch while modifying various attributes of it. Very good tutorial highly recommended.
Thanks Chris! You did exactly what I hoped other viewers would do. It's only by actually doing that you learn things. Thanks very much for posting.
@@RalphBacon Not a trouble I always leave a like. Don't suppose you fancy making a video about using other libraries with a library.
Got square eyes trying to figure out how to include the wtv20sd16p library in my library. 😅
You should be able to just #include the library.h you want within your library in the standard way. What's the problem?
@@RalphBacon I did figure it out in the end but it's surprising how scattered the info is, I couldn't figure out where to instance the object correctly to use it throughout the library.
I actually found two methods one used pointers which I no longer use but Google hot to use a library in a library and there is no definitive guide or tutorial on the do's and don'ts thanks for your reply though.
Great stuff. Revisited this video today when I actually needed the information.
Don't tell anyone, Pekka, but I do the same when I need some (good) advice, heh heh! I guess as long as you know there is a video with information here then it's perfect that you returned and watched it when you needed it. Thanks for getting in touch, good to hear from you.
Very nice tutorial! The explanation speed was perfect since it allowed me to think deeply about what you were saying. I subscribed to your channel too. Thanks a lot!
Thanks for your post, Gabriele Fugazzi, I'm glad you enjoyed the video. Good to hear from you.
very helpful. I have done a lot of programming but never really took the time to sit down and do that library stuff (eventhough I started a few times) .
Will do again with help of your video.
Oops, Sorry, I forgot I already commented on this video. Must be my age. Anyway, extra proof I like the video
I think you have just proven that you REALLY like this video! I'm happy with that! Constructing library classes is not magic, voodoo or only for "experienced" programmers. It's a series of steps and concepts that can make your programs "better" (oh, dear, red rag to a bull I know). Best thing is to try it with a really, really simple function (as per my demo) and get that working - then build on that. Thanks for reiterating your love of this video, I hope others feel the same way :)
indeed. I am no stranger to making 'classes' but wrapping it in the
library files is something I just haven't taken enough time for yet to
be able to do it fluently. Enjoy yr weekend
Yep, DRY, good work.
Love this about making libraries.
Plz make another video of making libraries.
Thanks for your post, Hans Sandberg, I'll think about making another. Good to hear from you.
@@RalphBacon this is definitely the best arduino library tutorial so far on TH-cam and it's nice to see you answering peoples question on your older videos. i'll keep eye on for second part. Love from Finland👍
Incredible explanation and pace
Glad you liked it!
Hi Ralph. This video helps me a lot. Congratulations!!!
Thanks for your post, emilio zelione, good to hear from you.
I QUEST ALWAYS BENNY IS HELPING OUT! VERY GOOD PRESENTATION RALPH
Thanks for your post, demetrios demetriou, good to hear from you. Benny is pleased too!
Very helpful information for sure. Thanks much for taking the time to explain this.
Thanks for that, gene guru1, nice to hear from you.
Hi Ralph!
Thank you for this amazing vidro, made it realy easy!
You're very welcome!
Hi Ralph. At 21:16 in your video, it's only print "Te". You must to write this line after the Serial.println("The blabla...'); :: Serial.flush(); 😉
Actually, Arduino now admits they made a mistake with their Serial.flush implementation. It _usually_ means "clear down any outstanding characters in the output buffer" but they implemented it as "wait until the buffer has been naturally cleared by being sent out the UART".
I suspect that curtailed message was because the Serial.begin() was in the wrong place, but whatever the reason I've always had it work just fine since!
Great tutorial! Would you be able to do a tutorial on how to deploy library’s so that others can use them and find them in the library manager?
Great suggestion! I'll have to look at that, Douglas, as I've never released a library into the wild other than on my GitHub.
Thanks Ralph. Great info! I'm used to C, not C++, but I will definitely switch over. Then I can put my common useful functions in a library instead of re-copying them into various ino sketches(and which one has the latest modified version?). I saw that I can also create a subfolder in ../libraries/TestLibrary/examples/LibraryExample1/LibraryExample1.ino so that it is visible from the Arduino ide files/examples.
GREAT STUFF!
Made my day!
If you know C you will pick up C++ very quickly (but you will also confuse the two I'm sure)! I'm glad this video helped you though!
Great video Ralph. Oop for newbs is a hard topic to teach. When I went to university they were just defining the standard for oop in c/c++ so I missed out because I stopped coding from 20 years. I had a fun time learning all the arduino basics because it all came back to me. It woke something in me so I took an advanced pointers course, data management and then I took the course for oop and made like ten fake entities then wrote code based on the classed I created. Haha
You make the complex make sense very well my friend.
It sounds like your interest in OOP programming is still strong. Those developers that put in the effort to learn how to make a class will make better programs for sure.
@@RalphBacon what language do you use at work? I think I asked you this before. I apologize if I did.
At work I used C# in a dot Net full-stack environment: JavaScript, Dapper, SQL server, HTML... the list goes on.
@@RalphBacon you build end to end software for other companies ehh
Actually, the last software house I worked in for five years built software for their own company but it was used (implemented) throughout the UK. 22,000 clients. Tricky stuff!
Very good. Note: the Github TestLibrary example has #include instead of #include "TestLibrary.h". It does not compile as #include .
Ah! An anomaly for the Arduino IDE then. Strictly speaking, quotes around a library simply mean "look in the sketch folder _FIRST_ then in the usual place(s)". But without the quotes it won't look in the sketch folder at all, it seems. I shall be aware of that in the future.
Hi, Ralph.
You explained this quite well. However, I'd like to share a convention I've used in C++, PHP and several other languages.
When writing a class, I will always add a private variable (as a programming flag) named 'debug', along with a setDebug() function. Throughout the code of the class, I test for this value to determine whether to display generalized debug messages, much like you did with the _msg variable you used here. Then, from the main "sketch", I call object.setDebug(true); while developing, and object.setDebug(false); when all is working.
Another thing I include in every class is a public function named ReportSelf();
This function reports every variable name and value the class contains.
I find these practices to be quite useful, and in fact use them a *lot*.
Hi there chopzuki! Your points are well made and should probably be standard when creating a class (oops, I said that word again, I've just lost 50% of the viewers reading this post!). Seriously, though, when using classes such things become much easier and abstracted away from the main sketch.
You've probably noticed my use of a templated global debug function in my other scripts which beginner Arduinites might not have fully understood but at least grasped its usefulness. At least it stops the dreaded if(debug) Serial.print.... littered throughout the code!
Glad you visited, I hope you stay, and thanks for that excellent point in your post, most appreciated by me and others reading this :)
The usefulness of this approach is two-fold:
First, the _debug flag is quite useful during class development.
Second, even when the _debug flag is set to false, the ReportSelf() function is especially useful when working with database records to help ensure data is being handled correctly.
This is a great suggestion and is very helpful during development. The only caveat to this approach is that unlike general computers, microcontrollers have very limited amounts of memory for code and stack variables. A better approach would be to use a preprocessor directive to remove any debug code that you can during builds for "production". I'll try to build some example code and post it up in the next few days.
Thank you for this great video .I must watch again
Please do!
Great video helped me a lot with my project! Keep up the good work!
I'm pleased to hear that Davis, excellent! Thanks for posting.
Thank you very much for your clear and rich explanation.
Glad it was helpful!
The reason why the text does not come out correctly while the "void setup() {...}" is not called, is very simple.
The "void setup() {...}" is just part of a basic library framework library that sets up stuff like buffers, timers and so on. While the "void setup() {...}" was not called already, the text written makes the serial-out-buffer overflowing and from the most characters, apart from those that had gone into the hardware fifo from the USART hardware, are lost. So it is a pre-initialization issue, since in the first version the constructor was already called at the "TestLib testlib(true);", before ever entering "void setup() {...}".
By the way, putting serial initialization routines in classes is very bad style, since having more classes then just your gives the problem that they might all try to intialize serial, one after another when called trough out constructors/methods.
So your "serial.begin(...)" to put once into your "setup()" is certainly the better way to go, because then it does not get out of control if, when and how many times this is issued.
Spot on, I realised this belatedly, but as it was more about how a library is constructed I kept it going. The whole serial thing is a bit of a mess - I traced the code (the Arduino.cc written code) and it really is a bit convoluted, to say the least. Definitely not the best thing to put into a library example. I hope you still consider there is still value in the video though for others to learn about OOP.
Of course it is usefull, expscially for beginners into C/C++ along with Arduino, to see how Libraries could be done, instead of having endless spagetti code like looking source files. So I think your video is very good to take a look into the Libs aspect of Arduino developments.
The most high quality thing, thank you
Glad you think so!
Great video Ralph. This steps it up a gear for anyone who wants to understand object oriented programming. Once you 'Get It' the concepts are then only language specific. C++ is a bit unwieldy with its header files and you explained the concepts really well. The only thing , (and could be difficult for beginners), is Scope, the :: syntax.
Really good Ralph, excellent mental workout following the code, cheers Alan
Ha ha, I'm glad your brain got a good mental workout trying to follow my meanderings through class construction!
But the point you make about 'getting' the concepts is spot on. Once you have that lightbulb moment all else is 'just typing'. I'm hoping enough people take my example, break it, fix it, break it again and basically get a good grasp on how libraries work and in doing so understand how classes work too in the (semi-) object oriented world of Arduino C++.
Thanks for your kind words about me explaining it well. I don't normally watch my videos all the way through (after a couple of hours of editing I've usually had enough of my own voice) but I felt this time I had to make sure it all hung together properly and I think it does provide a good starting point for Arduinites expanding their wings, so to speak.
Thanks for posting Alan, always good to get constructive feedback.
Thanks for the video Ralph - yes I know it's mature. Lovely to see Benny again. I think the reason you cant put Serial.begin in a constructor is that Serial is a static class, it's a single resource. That's to say you can't really create another Serial for each instance of your class. I created a Ping)) class with OTT features including limiting the time pulseIn will wait based on a user decided maximum distance of interest. I wanted to check the maths with a debug method; in that method I simply use if (Serial) { print lovely stuff}.
A good workaround you have there. Another solution is to try a singleton for the Serial.begin but I suspect that might not work either. Probably just better is the user sets up the Serial interface anyway, as it might be Serial1 on another device.
.cpp is C++ as that is what the Arduino is written in, and that is what you actually code in (Well C and C++)
Yup, I think we got that sorted now!
Oh! Good man for showing me the option to collapse code!
Happy to help! It's the little things that can make a big difference!
Very nice tutorial. Good content explained in a nice and relaxed way.
You found yourself a new subscriber.
Thanks for your post, Zeedijk Mike, thanks for subscribing, too. Good to hear from you.
And again a great video. I learn a lot and it saves a lot of problems
Glad you liked it, kees 7777, it's not so difficult once you're shown how to do it.
It's more an introduction of OOP/C++, the function doesn't need a whole class, simply putting the function in the .cpp and making a .h file, would work too. You can even use only an .h file, because of the preprocessor… and there is the possibility to use more .ino files too.
Hey AltMarc, great to hear from you! You are of course correct in your observations, but if you notice I steered well clear of mentioning OOP hardly at all as there's nothing better to deter beginners of C++.
A large proportion of Arduinites expect (and can understand) procedural code (like VB Basic 6, perhaps!) but as soon as classes are mentioned, along with overrides, polymorphism, inheritance, templates and what have you they will go back to the 'safety' of their standard procedural code.
So I was hoping that putting a very simple function into a library class might get them using a bit of OOP (even though it didn't really require it) and so not be put off. And, of course, it might actually encourage some developers to put their code into a library so they can concentrate on new stuff they are building.
There's no easy way of learning C++ OOP without doing it - ideally doing it without realising you're doing it. Hence the video! Did I succeed, that is the question?
Great to hear from you, always keen to get my viewers' perspective on things, and I appreciate you took the time and trouble to post here.
Hi Ralph. I found the video to be clear and helpful, and I will be definitely looking at your others.
But I think you should have left the OOP out of this. I know it confused me. In fact, I only scrolled down to find this message because my research so far into creating a library led me to believe no OOP is necessary, and I wanted to check if that was true by seeing if anyone had commented to that effect.
OOP doesn't bother me, I've done mountains of it in Delphi, but I'm new to C++ and I just want to learn how move some code into a library, and not have the process complicated by unrelated concepts if not needed. I haven't yet learned how to write classes in C++, and I didn't come here to learn that now - I came here to learn how to make a library. Only after success in that, would I want to convert it to OOP where appropriate.
The video as it sits, leaves the new library writer with the notion that a library MUST involve classes, which (from what I have gathered) is simply not true. I can imagine someone with a large chunk of code involving a bunch of interrelated functions and data that they want to wrap into a library, getting into all sorts of bother trying to make them into classes when they don't actually need to (even though they probably should). If I had watched only your video, I know this would have happened to me.
In essence I'm saying that as libraries and classes are distinct concepts, they should be taught as such. Confusing them in the teaching, confuses them in the student.
I can see that you are concerned with OOP being a deterrent to some people. But I think introducing it "by stealth" where not required is the wrong approach. I would address that by a separate video about classes. (which would include an admonishment to those afraid of OOP to stop being such little girls)
I hope you see my criticism as constructive, and thanks again for making these videos.
the compiler is smart enough to know which functions are usend and just compile the ones you use in your code ;)
True, Dr. Jones, true. Or is it the linker? Whatever it is, I think we are now all in agreement that unused functions and/or libraries are not included in the final, downloaded hex file, just as well! Thanks for the confirmation and posting.
Ralph S Bacon thank you for the tutorial ;) you could do a second part and show how to add example sketches and library properties :)
That's a good suggestion, I shall add it to the list. Thanks for posting.
Fantastic explanation! Thank you very much.
Glad it was helpful!
Thanks you!, very clean explication i like your style, only a note that could be tricky: in the #ifndef statement we can't use the same name of the library, this could be confussing because the declaration of the files .h .cpp and the constructor needs to be namend equal.
Indeed, you are correct, the common practice is to use a name in capitals or with underscores after the name or both - you get the idea! Pity that I used a lower case two character name called tl (for test library) but then again this was just a demo)! Thanks for the advice, good to hear from you.
Really good work and explanation, you have a new subscriber, thank you
Thanks, Dean, glad you found it useful and thanks for subscribing!
The reason why the constructor (ctor) behaves differently to other methods is because it is a very different animal. Methods (other than the ctor or destructor (~classname)) are stored differently. They are in fact static code stored in the code. This affects the 'lifetime' of the methods. Yes, there is a difference from other static methods and functions and that is 'this'. 'this' is a hidden parameter to all non-static methods. The parameter is in fact the first in the parameter list; such is the case even if there are no declared parameters (i.e. classname::foo (void);). this is a pointer to this instance of the object. Now the constructor has a very short lifetime only surviving as long as the object is instatiating; as such the constructor can only be accessed when a variable of the objects type is declared. or new is used. A call to a serial method shares the cycles with your code (unless it is blocked by, say delay(100). So if one watched code such as [serialPrint('Test)'; digitalWrite(13, HIGH); ] on a logic analyser, one will observe that the TX pin becomes active AFTER pin 13 goes high. Now, if that behaviour is repeated when calling serial from a constructor, that temporary string created in the parameter of the call, may no longer exist. As serial accesses the string character by character, later characters cease to exist before the message is sent. Arduino doesn't support new or destructors (because no libc functions accessing dynamic memory are supported). Constructors are partially supported but only for access to the object's variables.
BTW I am confident that Ralph is fully cognizant of 'this' etc. I just mentioned those aspects of the constructor problem for his other disciples who, like me, are lesser mortals.
I think, Michael, you underestimate your already considerable skills on OOP, given your posting above, nicely put. What you have described belongs in the "advanced" Arduinite class, of course, and I should have remembered (or at least understood) why there are difficulties in putting that Serial.print in the class' constructor.
What is clear to me is that most writers of libraries (and therefore classes) do already understand the above and therefore that is why they suggest the addition of a begin() function; it cleans it all up rather nicely as well as using a well-established pattern that beginners can grasp very easily.
Thanks for the excellent explanation above; if nothing else it makes it clear why I had that issue, like most things in computing there's *always* a reason for a computer's behaviour even if we don't understand *why* at that time! Great to hear from you and I hope you enjoy the other videos on my channel :)
I enjoyed this video, as I have with all your presentations. It is always a joy to look down my list of subscriptions and see that you have submitted a new submission.
I couldn't agree more on your comments on libraries and their valuable facilitation of code re-use. You are right to encourage your viewers to gain confidence in developing their own libraries. We are all beginners in this environment that is changing so quickly. Rapid change makes books poor resources for all but the most fundamental aspects of embedded development. However, all that your viewers have already learnt from your and their projects could fill a library (of books). The more we share with each other the better the technology will be.
Thank you for enabling this process.
The reason the call to Serial.begin() in your ctor doesn't work is because in C++, all static objects are constructed before main(), which means the application owned objects are not necessarily fully initialized yet. You can see in arduino/core/main.cpp that USB.attach() is called in main() before the call to setup() (which is the call into your sketch's setup function), so USB (and therefore Serial) is not ready for your use until your setup function is called. In C++ you don't want any static object function calls (e.g. ctors) to call into any other static objects before main() because they many not be fully initialized yet. The order that static objects are initialized is not guaranteed to be knowable. That is why many libraries have setup/begin calls that need to be called in your setup function, after all static objects have been constructed. Otherwise, ctors are not particularly different that any other code - all code is stored in PROGMEM. There are a few caveats with ctors/dtors, mostly related to inheritance and virtual functions.
Ralph, great tutorial. I now have some idea what I'm looking at when I poke around in library files. More like this please - a debug library would be ideal.
Regards Alan
Hey Alan! I was going to include my debug routine in the library video but found that my code was "too advanced" for the compiler to figure out how to use it! Seriously! It's a limitation of the compiler but as always, there are workarounds but it just made it a bit messy and not really for a "first time" video - but I will include it (or upload it) with a future video.
At least you now have a better understanding of how the libraries hang together and can appreciate the work some of the authors have gone to just to give us Arduinites an easy way of interfacing with bits of hardware. And of course, you could create your own libraries just to make things easier to work with. A nice cold Saturday afternoon project, perhaps?
Thanks for the feedback and suggestion, great to hear from you.
When I was doing C back in the days of Borland C, cpp was brought in as I understand in programs to differentiate C code (vanilla) from C++ cpp = c plus plus
Yes, cpp is really the object oriented capable platform, although much of the syntax is the same as pure C.
.cpp just means "C++ (C plus plus)" file
Indeed you are correct, Steve, that was your starter for 10. Now, what does .ino stand for? Previously known as .pde, which stands for? Finally, why did Arduino.cc change it all? Why not just keep to one name for everything, ideally, .cpp? More questions than answers, I'll be bound. You're not allowed to Google the answers, either!
Ralph S Bacon lol
@@RalphBacon Not sure what .ino stands for for .pde is an extension from the Processing language which Arduino and the Arduino IDE is based upon. I think They changed it to .ino to make it clear that the file is an Arduino file instead of a .pde (Processing) file. If they did not do that many noobs would run into issues.
@@RalphBacon I guess the .ino is just ardu*ino*
Nathan Villicaña-Shaw I remember this happened to the noob typing. 😂
Ralph: How do you find out what functions a library includes and what there parameters are? I want to use the AccelStepper library but I don't know what functions it includes or how to use them. Thanks
Most libraries are on GitHub. The GitHub for a particular library should have documentation (or a pointer to the Wiki for it). This will tell you everything you need to know.
Secondly, if you look at the library, in particular the library headers (files ending in ".h") these will provide the PUBLIC functions you can call. From there you can find the relevant function in the associated c++ file (ending in ".cpp") and read it, to see whether it's documented enough.
Also the GitHub will probably contain an "Examples" folder with some simple get-you-going sketches. Another source of gold to beginners.
brilliant tutorial , explained so well thanks
Hello Arduinite! I'm currently on vacation 5,000 miles away from home so I'll have to be brief with these comments until my return, mid-July.
Glad you found it useful, John, I like comments which contain the words "brilliant tutorial"! It's not so hard once you get to grips with the fundamentals. Thanks for posting.
Oh I'm going to use this info for sure. Thank you sir
Excellent, Ricky, start small and work up. And look at other libraries to see whether there are any other techniques you might use. Great to hear from you.
great video, very informative. I wish I could give it two thumbs up.
the explanation in the arduino website was missing a few things...
TWO thumbs up? Wow! Actually, just the one is awesome as it tells Google that viewers are appreciating my videos. Thanks for posting golanramati11, great to hear from you.
if I can add something that you didnt cover in the video:
I wrote a library to create an instance of some object and another library that creates an object consisting of an array of the first object.
in the both original librarys I included standart librarys (looked like the right thing to do, thing like servo.h) but it wouldnt compile, the error said the first object does not name a type.
after a long time of asking aroung and pulling hairs, I removed the standard included librarys from the second library and included only the first library I wrote and theat seemed to solve the problem.
thought it could help somebody
Thanks for that, golanramati11, always good to share experiences like this to hope others. Nice to hear from you.
Thanks Ralph - very informative. Do you know if it is possible to inherit a more complex type like HttpClient and create a custom library wrapping HttpClients functions in the class?
Yes, absolutely, Robert.
Include the library you want to wrap, and in the class constructor inherit the underlying class.
For example, if you wanted to inherit the "Print" class so you could "print" characters to a new LCD screen you could inherit that (but remember to define all underlying virtual members):
#include
class myLCDPrinter: public Print {
public:
virtual size_t write(uint8_t);
etc
using Print :: write;
}
This then gives you access to ALL the underlying print functions (you don't need to define each one individually). Your class must now declare this method:
size_t myLCDPrinter :: write(uint8_t value) {
send(value);
return true;
}
The method you write to do the "send" will be declared as "private" in your class:
void myLCDPrinter::send(uint8_t value) {
// your code here to do whatever you need to do to get the value
// onto the LCD screen
}
As you already seem to know about inheritance I guess this is enough to get you started with the HttpClient!
@@RalphBacon
Thanks Ralph
Yes and know on the inheritance most of my recent experience (last 15-20 years) is C# so syntactically a little different :-)
I copied the HttpClient virutal methods into my header class (as you can see by the comments with the exception of endOfStream() and completed() they were all inherited from Print and Client, I'm not sure if I should have included them?)
My header class looks like this.
class SparkfunWifi : public HttpClient {
public:
// Contructor
SparkfunWifi(Client& client, char* serverName, char* port, char* ssid, char* pass);
// Methods
/** Connect to the server and start to send a GET request.
@return true if connection successful
*/
bool connectWifi();
/** Sends HTTP weather POST to weather.api.
@return 200 if successful response from api.
*/
int sendWeather();
// Inherited from HttpClient which inherited them from Print
// Note: 1st call to these indicates the user is sending the body, so if need
// Note: be we should finish the header first
virtual size_t write(uint8_t aByte) { if (iState < eRequestSent) { finishHeaders(); }; return iClient-> write(aByte); };
virtual size_t write(const uint8_t *aBuffer, size_t aSize) { if (iState < eRequestSent) { finishHeaders(); }; return iClient->write(aBuffer, aSize); };
// Inherited from Stream
virtual int available();
/** Read the next byte from the server.
@return Byte read or -1 if there are no bytes available.
*/
virtual int read();
virtual int read(uint8_t *buf, size_t size);
virtual int peek() { return iClient->peek(); };
virtual void flush() { iClient->flush(); };
// Inherited from Client
virtual int connect(IPAddress ip, uint16_t port) { return iClient->connect(ip, port); };
virtual int connect(const char *host, uint16_t port) { return iClient->connect(host, port); };
virtual void stop();
virtual uint8_t connected() { return iClient->connected(); };
virtual operator bool() { return bool(iClient); };
virtual uint32_t httpResponseTimeout() { return iHttpResponseTimeout; };
virtual void setHttpResponseTimeout(uint32_t timeout) { iHttpResponseTimeout = timeout; };
private:
int _serverName;
int _status;
char* _ssid;
char* _pass;
};
My .cpp constructor is as follows.
// inlcludes
#include "arduino.h"
#include "SparkfunWifi.h"
// constructor
SparkfunWifi::SparkfunWifi(Client& client, char* serverName, int port, char* ssid, char* pass)
: client(client), serverName(serverName), serverAddress(), serverPort(port),
iConnectionClose(true), iSendDefaultRequestHeaders(true)
{
_ssid = ssid;
_pass = pass;
_status != WL_CONNECTED;
}
The error I get when I compile my sketch is:
SparkfunWifi.cpp:6:1: error: prototype for 'SparkfunWifi::SparkfunWifi(arduino::Client&, char*, int, char*, char*)' does not match any in class 'SparkfunWifi'
SparkfunWifi::SparkfunWifi(Client& client, char* serverName, int port, char* ssid, char* pass)
^~~~~~~~~~~~
In file included from sketch\SparkfunWifi.cpp:3:0:
SparkfunWifi.h:13:7: error: candidates are: SparkfunWifi::SparkfunWifi(SparkfunWifi&&)
class SparkfunWifi : public HttpClient {
^~~~~~~~~~~~
SparkfunWifi.h:13:7: error: SparkfunWifi::SparkfunWifi(const SparkfunWifi&)
SparkfunWifi.h:24:5: error: SparkfunWifi::SparkfunWifi(arduino::Client&, char*, char*, char*, char*)
SparkfunWifi(Client& client, char* serverName, char* port, char* ssid, char* pass);
^~~~~~~~~~~~
sketch\SparkfunWifi.cpp: In member function 'int SparkfunWifi::sendWeather()':
SparkfunWifi.cpp:48:5: error: 'client' was not declared in this scope
client.beginRequest();
^~~~~~
sketch\SparkfunWifi.cpp:48:5: note: suggested alternative: 'Client'
client.beginRequest();
^~~~~~
Client
exit status 1
[Error] Exit with code=1
Thanks again for your assistance & I look forward to watching more of your videos.
Cheers
Rob
Whether you need to include libraries is easy enough to test; just comment out the #include and see if you get a gazillion errors!
In the line "SparkfunWifi::SparkfunWifi(Client& client" how is the Client being instantiated? Make sure you have the "Client" object in your class or reference it in some way. The compiler doesn't know this is HttpClient. Write a simple sketch to invoke all this first and you might see how to include it in your class. And use PlatformIO or Eclipse as they give you Intellisense that can _really_ help when doing this sort of thing.
From one C# developer (.Net in my case) keep going. Sometimes it can take a while (and a few hours Googling) but eventually the solution will be found.
@@RalphBacon Hi Ralph - I did persist and was able to get my custom class to compile - sort of - at least sorted out the inheritance side. I can get my library to send formatted JSON out the serial port and connect but when I try to serialize my JSON it the compiler complains when I uncomment serializeJsonPretty(doc, iClient); Thanks for all your help. I'll keep working on this last hurdle. Regards Rob
Very nice explanation, thanks!
Glad you liked it, thanks for posting.
Thanks a lot for the clear explanation. I hope your cat did not hide any components or knock anything off the table
Benny is always hiding components from me!
Hi Ralph,
thank you for explaining. Unfortunately, I have one question. What if I need (I don't know, how to say it correctly) some class variable, that is shared across all instances.
For real example. I have a few moisture soil meters and I have decided, that I will write library for them. There are some instance variables, unique for each instance like "pump_relay_pin" or "moisture_limit". But I need one shared variable for the whole class. It's called "vcc_moisture_pin" and its value is same for all possible created instances, because it's shared pin, which turn vcc of all sensors on. It doesn't matter how many there are.
So, I need this "class variable", which I can set directly via class name in main program, not via instance name. This variable I want to use only in library cpp file afterwards.
Yes, I can use this variable as instance one, but I don't like it. I think, it is not programmerly correct.
What I can use now
H file
class MyLib
public:
MyLib();
byte vcc_pin;
INO file
MyLib Inst1;
Inst1.vcc_pin = 2;
What I want to use
H file
class MyLib
byte vcc_pin; // I don't know, where to put this declaration
public:
MyLib();
INO file
MyLib.vcc_pin = 2;
and then, every instance gets this vcc_pin variable with value 2, but I need to set this value in main program, not in library, because I want it versatile.
Is there any option, how to do this?
Could you please help me? Thanks a lot :)
It sounds like you need to write a public function in the class that updates that variable (which should be private, not public). Another function to read it back. But that gives you that value for the class instance you are addressing, it's not global across all instances.
You could accomplish that by creating another instance that you call globalMylib (or whatever) and use those functions I mentioned wherever you need to update or read it. What you really need is a singleton, or static class, but I only know this from C# not C++ - would have to check that out (or you could).
Amazing stuff! Subscribed. Cheers!
Thanks, Daniel, glad you liked the video and thanks for the sub!
watching old ones, waiting for new ones. those library cards are some distance apart.
New videos are there now, Lez, a couple at least in the last two weeks!
@@RalphBacon your library cards still puzzle. There not Exactly next door to each other
Brilliant Video. Thank you so very much.
Glad it was helpful!
Hi Ralph. .cpp is the C++ file extension.
Yes, it is, Henri, I think a figured that out now!
best tutorial on libs. thanks.
Thanks for your post, iceberg789, good to hear from you.
Thank you so much for sharing this great information ......
but I have a question... how can I include some sketch examples within the library?
and again thank you so much !
Hey Baraa, glad you liked the video. But I don't quite understand your question. Do you mean how to include your library into a new sketch? Or something else? If you could clarify that would be great.
Thanks for this , it has given me a chance to try and debunk some previous written software ( ble for arduinos) . A question , how do we best debunk what are the available commands ( methods ) within a defined class and their uses ?
Debugging code for an Arduino is somewhat crude. It involves using the Serial.print() method to write out to the Serial Monitor (aka debugging window) messages that might help you understand what is going on or wrong. And judicious use of the delay() statement to slow things down a bit so we can see what is happening in slow motion. Newer versions of some µControllers (including the MKR boards from Arduino) allow hardware debugging but that's for the future - for now you're stuck with Serial.print(), I'm afraid.
Heyy Ralph!! I want to include LiquidCrystal.h lib in my custom library. I am not able to understand how should I go about. Where should i write #include and where should i create my object 'lcd'??
Hello Arduinite! I'm currently on vacation 5,000 miles away from home so I'll have to be brief with these comments until my return, mid-July.
Write the 'include' statement at the top of your .h library file. If you want to use the LCD library ONLY in your own library then create the lcd object in exactly the same way as you would with a standard Arduino sketch. If you want the user to be able to access the lcd object then you must use the EXTERN keyword which I'll explain in a future video (you can Google it for now!). If you get stuck let me know exactly what you are trying to achieve and I'll explain further on my return, Interesting question you asked here, Abinav!
Ralph S Bacon, thank you so much for your time and knowledge. I followed your video minute by minute and have learned so much. Thank you so so very much. I must of missed a step between 35:10 and 35:15. What in the world did you do? Perhaps you included this step in a different video. Can you send ma info as to what you did? Or a link to another video?. At any rate thank you so much. I have been following step by step of this video for the past five days, and every time I do I learn something new. Thank you.
Are you referring to the colour-coding that appeared? Making some keywords highlighted? That is all explained at time th-cam.com/video/fE3Dw0slhIc/w-d-xo.html (35:51) which is basically just typing the words you want highlighted into a text file in the library's folder. Is this the information you need?
@@RalphBacon ,thanks. Yeah I did not see how or when you compressed the libraries so that the libraries are no longer listed in tab(s).
The libraries are not compressed, Rocky. They were moved OUT of the folder in which they previously resided (the same one as the sketch, so they were, up to that point, only LOCAL libraries) and moved into a folder of their own in the standard "libraries" folder (which is a sub-folder of your sketches folder). Now they can be included in _any_ sketch. Wow, that was confusing to write, did you understand that?
@@RalphBacon , yes sir, that is exactly what I do not understand. How did you move the library from the sketch into the main library folder. Yes Sir' how did you move the library and save it into the main library.
@@RalphBacon how did you move the library from the local sketch into the Arduino library.
Dear Ralph,
Great video, thanks! Explained exactly what I am trying to create at the moment. And I still have a questions.. One thing I did probably wrong is that I put all the functions inside *.h file, did not made and *.cpp file. It somehow works, but let me change it and see it working again. In my project (remote control tank) I am going to use GPS module and GSM module (and some others as well), so I really do not need that additional code into my main code, just a results, e.g. GPS coordinates, so library is excellent solution.
Technically speaking, Valters, putting all your code in the header file (whilst punishable by watching the BLINK program for several hours) _should_ work. But, as you are aware, it's just not done that way so do split them as you have outlined - and let us know how you get on.
Excellent video. Thank you!
You are most welcome Dan M, I'm glad you like the video. Nice to hear from you.
do you reallt need to wite the "testLib::" dont the complier know that by itself? but need to write if its nothing else it want to point to. dont think i was wtiting it when i used visial studio.
You do have to write the library name followed by two colons in front of every method in the library .cpp file. This is so the compiler knows it's part of the library class and not some other method/function you happen to be declaring at that point.
Hello Ralph, Great tutorial as usual. Can you make a video on the NRF24lo1 using 2way communication but with a view to simplicity? There are many good tutorials about nrf24 on utube that are spoiled by overcomplicating them with sophisticated sensors and the like.It is quite difficult to even get them to work in duplex mode .Sending a simple string or Pot out put both ways is all that is needed , then it could be elaborated on when all is working.
Oh Steve, if only you knew how long that topic has been on my video 'to do' list! Perhaps your post is the nudge I need to get a simple project together and just 'do it'.
Don't hold your breath too long, from idea conception to posted video can take some weeks but I too think I need to promote this one up the list a bit.
Thanks for giving me the nudge, and I take on board about over-complicating it. Simple is best. Or as Albert Einstein said, "Make it as simple as possible but no simpler". As I'm fairly simple it should be a breeze...
Sunday, 5th Feb, 12:00 GMT. Could be what you need. Video #73. Thanks for the nudge. :)
Hi, great video. I have a question. In my main code, I have things such as #define MOTOR_1 13, etc for my motor driver. Where do those go or how do I put those into my header files?
You must understand how the compiler treats those #define lines. They are purely *textual substitution* and have no meaning beyond that. If you #define LED 4 then whenever the compiler finds a strange word called LED in your code it checks to see if you have defined it and then substitutes, exactly, what you have written, in this case 4. That's it.
So you can continue to define these in your header or cpp files just as before. As the library is compiled (as part of an #include statement in another sketch) it finds all your #define lines and compiles the library as though it were part of the original code.
Watch out for #define statements that might be used by the user (that will confuse the hell out of the compiler). Put a leading underscore or some other identifying character(s) as part of your defines. So in the above example you might use #define __LED_ 4 and then you use __LED_ instead of just LED in case your library consumer uses the LED define (a common enough word). Understood? Or clear as mud?
Helllooo dear have you done any videos about DTMF(dual tone mid frequncey) intergration with arduino?
Not yet! I'm not sure where telephony integrates with an Arduino although I did a video about a telephone dialler.
@@RalphBacon then i have already watch the video about intergrating DTMF with arduino so would you like to take it a look? Then i can send it ok
But first I must feed Benny!!! LMAO :) Love it
If you are new to my channel, Joel, you may not realise that Benny writes most of the C++ code. If he does deign to let me have a go he then monitors everything I write with a beady eye. He is a hard taskmaster.
Of course, if you have watched more of my videos than you already know this and the fact that he sometimes sneaks into my workshop at night and corrects all my syntax mistakes, recompiles everything and uploads it all to the µcontroller board I'm using. I'd be lost without him.
RIP Benny
for those great programmers that have developed their own library you can have a look at the arduino spec to improve the sharing capability.
Here is the link:
github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification
That's great Paul, thanks for the link. I think I followed some of it (but not sure whether I shared it in my video, eg keywords, library.properties and the like).
Note the different versions now available, 2.1 being the latest for IDE 1.6.10 (although we are already using 1.8.x, it's the latest we have). Thanks for sharing Paul, appreciated. :)
perhaps you could do a follow up video next time you do a library.
No problem glad to help out.
Thank you, sir. You helped me a lot.
I'm happy about that, Ryan, keep going!
Hi, Ralph, thank you so much for sharing your knowledge. I am new to the microcontrollers world. I have downloaded your LibraryExample1 sketch - I actually created the sketch by copying and pasting the contents of the three files (Arduino, .h and .cpp). Here is what it says when I compile it:LibraryExample1:1:10: error: TestLibrary.h: No such file or directory #include ^~~~~~~~~~~~~~~compilation terminated.exit status 1
TestLibrary.h: No such file or directoryThank you for your help, Mac
Did you put the library files in the SAME folder as the Arduino sketch (the .ino file)? In which case use quotes around the library header file name not chevrons: #include "TestLibrary.h"
Let me know if you still have problems.
@@RalphBacon Thank you so much for your prompt reply. Yes that was the problem.
Thank you, Ralph. I am afraid it did not work. I cannot I am a beginner, so I do not know enough to think my way through. So I ordered an ESP32 with USB connector and do the test again.