You don't need much. You need to understand the basic concepts & structure of the language.
A lot of standard C++ doesn't run on the Arduino because there is no operating system, no standard display, no standard keyboard and no standard disc storage. I've got several C++ books and probably NONE of the examples will run on the Arduino.
And the Arduino functions like analogRead(), digitaWrite(), digitalRead(), etc. are not part of standard C++.
I've never used object oriented programming (classes) with the Arduino.
I feel introductory structure of a C program and using reference material is "all" the information needed to become independent of personal help.
As you said, depth of subject is difficult to judge. Too deep, and only the naturals or classically trained will listen to the end ("gets scary" - that's me). Too shallow and help is always needed.
I consider myself "new" in programming because I have not advanced beyond maintenance-oriented coding. You can see my lack of "knowledge" in my simplistic sketches. I do not "know" C++ or classes... or anything else, for that matter... however; I use them, obliviously. I rely on reference material and adapting it to basic structure. It took me some time to "let it go" when @gcjr wrote his RPN style c-lang sketches, even though I could see his code working. I would de-construct his work to a "basic" style to understand his style. I won't say I learned, rather interpreted.
Oh, and WOKWI.COM... even though it is not "real" it puts tangible meaning to vague words.
A long time ago, when the earth was cooling and JavaScript was young, it didn't have classes either. (It did have prototype inheritance -- or prototypal, which sounds like a dinosaur to most people.)
But people were happily using the dot operator, just as with Arduino's Serial.print. You don't need classes. Maybe structs? Is there something common where you are manipulating the members/fields of a single object, like setting the font and color of a piece of HTML?
This points to the difficulty with the question. What is the background of the 'noob'? Bringing a ten year old up to speed is in many ways more difficult than working with someone who's already programmed in another language.
A translation dictionary between Arduinoese and C/C++ would be nice.
Basics, yes, but you know why it gets scary? Because the C/C++ resources don't tell me anything I might use in a way I might use it.
A quick anecdote: a friend of mine going back to the 1990s used to be the techy guy, built his own PCs, IT guy, etc. I was most certainly not that. He'd say "oh check this out, this PC is so fast it can do anything, it can do x, y and z and look at this (pick any circa 1990s example, I don't remember because) my answer to that was always "oh cool, man, that looks really cool...what can it do?"
"Anything"
"Can it make me a coffee?"
Fast forward to 2014 iirc and I discover Arduino. Ah...the computer that can make me a coffee. I'm in!
Point of that story is, all the stuff I see on using pointers, arrays, passing parameters to functions and all the rest, in C/C++ guides and forums is all so...dated. I'm an Arduino guy. All the examples are about doing things in a PC console that I would never do as a project.
Arduino was designed in the first place, like it or not, for people like me*. Non experts. Ambitious rogues who had no interest in traditional computing tasks like spreadsheets, databases, whatever else people use computers for in office type settings. And yes, in my metaphor, I have flowing blond locks of hair blowing in the wind as I ride my black Percheron stallion wearing a ruffled shirt and capris but I digress.
So I guess what's needed to bridge the gap between C/C++ and Arduinoese might be:
a glossary of terms that makes sense to regular Joes. "Registers", "Direct Port Manipulation", stuff like that in terms that are easy to relate to real things Joes actually do. Why should I care if digitalWrite(nerfBlasterPin, HIGH); gets the job done? Is there any reason?
what I should NOT learn in C++. Why would I read anything on cout << "Welcome to GFG"; (just a random example I found just now) when I have Serial.println(F("Light 'Em UP!"));
A useful guide to when and why to use pointers and other things like even arrays when the clunky way I do it, well, works well enough. Show me the money! It's one thing to say "it's better to do this and that" and quite another to show me that your robot can outdraw my robot in a duel. Action, action, action.
OK, and here's my ignorance on full display, I feel a little vulnerable here if I'm honest (I'm not, I'm just kidding) but what in the actual love of all that is holy is all the bitmasking, bit shifting, bitmath and the like for?! As a regular Joe hobbyist, you might as well ask me to design a Falcon rocket system as use all that. Is there a good reason to bother? What is it? What does it do for Arduino type projects folks will actually build? Am I missing a big toolset in not knowing?
I hope I don't come off as rude or brutal in this response, that's not my intention.
But in short, I don't want to learn or see stuff in C/C++ that has nothing to do with physical computing project scenarios. I suspect that's the case for so many, or else they would have already learned C/C++. To me, I won't want or need to learn aspects of a programming language I'll never use because I came here in the first place for action, not spreadsheets. I want to make THIS (the Mutant) and can C/C++ get me there faster than Arduinoese?:
I've used, begged borrowed and stolen ones I found online, and adapted to my needs if I didn't have to change much.
There is very little, easily found, that shows how to write these in a mnemonic sort of way, a way that is easy to sort of learn as a series of steps or a habit, I guess.
An answer about bitshifting, admittedly from a guy who was doing just that in 1983...
It's about the hardware your programming on. It doesn't matter a fig when you've got all the memory of a PC to play on/waste. But when you've got 2k of RAM, you actually may benefit from putting that information representing 256 buttons into an array that's only 32 bytes long.
As for the hardware itself, the registers that control the various elements of the processor contain bits that control even tinier facets of those elements. To access those bits, you need to be able to set/clear/mask bits within a byte, usually.
If you're completely happy to have library code from others do all this for you, you needn't worry too much about it. But, you do know it's there.
Oh, and then there's the handy trivia - like shifting an int one bit right divides by two, left multiplies by two. Repeat multiple times if needed.
Want to average a bunch of small ints (say, from reading A0)? Well, you can sum 64 of them in an unsigned int, then right shift by 6 places to arrive at an average.
Want to know if somethings odd or even, just check the lowest bit.
Many of these tricks may actually be done automatically by the compiler, if it can figure out what it is you really want, but it's still useful.
But I know, you weren't seriously asking for this explanation, so I'll step away now.
You don't need to know any C++. You need to know the basics of C and the rest you will get looking at the examples and posts of others.
You will also pick up a lot of syntax help from the Arduino reference pages.
True, though I do wish "they'd" put a bit more effort into the caveats of some of the explanations and examples. Cue the "well, you can contribute too" comments.
Fair, and I appreciate your responses and time, as always.
But again, what does that have to do with anything the target market of Arduino might actually make? Please, you know I respect you but you asked in the topic of this thread. Are my suggestions just unreasonable? That's very possible. But I think I sort of cross the bridge between the guy today looking to build a 300 car parking lot system as a first project without a resource or mentor to show him the way and people like you with a skill set and wisdom that is unfortunately going of style, and that's a real tragedy.
(EDIT: it needs clarified that what I mean here is a knowledge and skill set that is earned through careful, deliberate study of a subject matter as opposed to the instant gratification style of learning [chatGPT, anyone?] that has caught on like wildfire).
My stepdad is like so many of you gurus here. Absolute genius in electronics, but as Einstein said, that came from 99% perspiration. He's also 85. Enough said and I hope his knowledge carries on in some way, not lost like tears in the rain.
But times have changed and we all know that, probably not for the better but let's leave that at that. Let's get down to business in the ADHD era (and I'm here for it).
Say I have four PIR sensors on a six foot tall robot (mine is only five but fellas gonna exaggerate) and they all detect clean, no crosstalk. I also have 12 Nerf blasters (circuit's great, i have 1.21 jigawatts of power all star grounded, say) on pins 2-13 inclusive and each PIR is responsible for detecting and hence triggering three blasters apiece. As an example in the Arduino Cookbook style, is there for example, a quick and dirty bitmask way to blast guys if they get too close to the Hallowe'en loot chest?
It's a very specific example I of course don't expect you to answer in code, but this is what I'm getting at. Whatever the answer, all I'm really saying is, whether in C/C++ or Arduinoese, it's not the steak that needs to be sold, but the sizzle.
Hey, maybe us forum folk could write a book or such, like a discussion that posts our own project code with a forum like analysis to translate from Arduinoese to C/C++ like in Art of War by Sun Tzu.
I'm not a programmer. I'm and engineer who programs as part of a project.
When I started programming PIC microcontrollers in C I purchased the venerable Kernighan and Ritchie book. It was like reading a math book, very difficult to relate to. I had purchased a low cost compiler by CCS. It came with a small book named PIC C. This book got me going and was complete enough for me to program successfully (for my needs).
Now I'm a little better at programming. But I find I'm learning more about hardware and how to incorporate it into my project than becoming a better programmer.. i.e. EEPROM, SD, Displays, assortment of sensors etc.
there's knowing the language and knowing how to use it.
A good example can teach a lot. my first really 102 program was writing a sort routine and exercising it. monitoring buttons, dealing with time are all applicable on Arduino. recognizing commands with numeric arguments bring human interaction
more elaborate coding should be based on sets of data and functions that operate on them (i.e. OO)
You don't know so much about bit math then. Sorry.
A byte holds up to 8 T/F states that can be operated on to return single multi-state results in one cycle with bitmath, for instance.
I have showed debounce via bitmath, I wonder how few members got how it works of how RAM and cycle-lean the technique is.
With an INPUT_PULLUP pin, 0b10000000 shows pin transition from button up to button down plus stable for 7 reads.. I use reads 512 micros apart to get fast debounce for example.
Learning bitmath is like learning pointers; not beginner subjects!
My first C book was K&R or based on it.
It was rather thin.
I learned C after some FORTRAN, lots of Basic and Tutor, some ASM and then Forth79 that changed my coding life through OOP.
Then years later C++ let me do OOP and people were more open to paying for what they heard of!
I lost more C++ than I now know to medical trauma but for what I do with Arduino, I don't need it! Yeah class objects and dot-functions need to be partly understood but how many times have I seen -> used instead of . here? Nada!
It takes a good bit of code to get where C++ is a real boon.
an even more succinct but more instructive book is The Elements of Programming Style that explains what is wrong(!) is textbook examples of code and how to correct and make the programs better
Noobs often have trouble following one line of code to the next, just reading code at all.
Beginners past that stage can learn more but need practice modifying simple examples for experience with commands before they're not beginners still learning basics. It takes hours at the keys to to get long term memory.
OTOH too much time spent writing big start level code will teach and reinforce Bad Habits!
Very true. I'm a stubborn, sometimes boorish newbie, but a newbie nonetheless. Zero formal education or training in anything to do with computers, electronics or programming. And I do mean zero.
Almost, I don't want to waste my time. I have no interest in learning for the sake of education, I'm way too old for that.
I also think I represent a great many approaching Arduino as a way to make something that's super duper. I would rather bulldog my way through my code, my way, than sit around like a student in a lecture hall. This isn't university. \
To the topic of this thread once again, with all respect to forum members wiser and more skilled than I (which is most of you), using C/C++ and not arduinoese, as is said so often to beginners here:
Show me your code, using code tags how your robot can defeat mine using C/C++ coding techniques that might well be faster or better than what Arduinoese has to offer. Not an explanation. Not a link to a book. Show me the code. Here's mine:
/*
BUILT OCT 26, 2023. SEEMS TO BE WORKING WELL.ADDS NEW
FEATURE OF WAND INTERACTIVITY TO BOT.
DO NOT MODIFY!!! BUILD ANY REVISIONS IN NEW SKETCH!
Processing companion sketch sentryBotMarkX2BirthdayEdition
Relay triggers for sentry bot blasters. Reworked from MarkI Arduino,
took out testing servo triggers and replacing with 4 channel relay module
Relay module will control:
relay 1 - left feeder motor (red and black wires) arduino white wire
relay 2 - left dual firing motors (2x in parallel) arduino orange
relay 3 - right feeder motor (red and black motors) arduino yellow
relay 4 - right dual firing motors (2x in parallel) arduino purple
Arduino Nano Every 5V pin to VCC on relay board
Arduino ground not connected (since using JD-VCC option header removed on relay board which isolates
completely the Arduino from the 12V switching side)
+12V to buck converter to +5V and ground (the one along the Arduino pins next to "IN1"
to power relay coils via JD-VCC (header removed)
+12V power rail to each relay N/O
Each relay COM connects to positive on respective motors/blaster wires
whole circuit relies on 12V switched power so one switch kills whole blaster capability
(rocker switch on right side)
NOTE:
The input pins are active low, which means that a logic LOW activates
the relay and a logic HIGH deactivates it.
The relay module has two LED_BUILTINs that indicate
the status of the relay. When a relay is activated,
the corresponding LED_BUILTIN lights up.
October 23-26, 2022
*/
#include <elapsedMillis.h>
#include <IRremote.h>
#include <IRremoteInt.h>
elapsedMillis timeElapsed;
// MagiQuest protocol for IR
#define MAGIQUEST_PERIOD 1150
#define MAGIQUEST_MARK_ZERO 280
#define MAGIQUEST_SPACE_ZERO 850
#define MAGIQUEST_MARK_ONE 580
#define MAGIQUEST_SPACE_ONE 600
#define MAGIQUEST_BITS 56
// we use an alternate `decode_type` for our IRremote decoding
#define MAGIQUEST 11
union magiquest {
uint64_t llword;
uint8_t byte[8];
uint32_t lword[2];
struct {
uint16_t magnitude;
uint32_t wand_id;
uint8_t padding;
uint8_t scrap;
} cmd ;
} ;
#define ERR 0
#define DECODED 1
const int receiver = 6;
IRrecv irrecv(receiver);
decode_results results;
magiquest data;
char command;
int idleCounter = 0;
unsigned int interval = 20000;
const int leftFeederRelay1 = 2; //white
const int leftFiringMotorsRelay2 = 3; // orange
const int rightFeederRelay3 = 4; // yellow
const int rightFiringMotorsRelay4 = 5; // purple
void setup() {
pinMode(receiver, INPUT);
pinMode(leftFeederRelay1, OUTPUT);
pinMode(leftFiringMotorsRelay2, OUTPUT);
pinMode(rightFeederRelay3, OUTPUT);
pinMode(rightFiringMotorsRelay4, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
// digitalWrite(leftFeederRelay1, HIGH);
// digitalWrite(leftFiringMotorsRelay2, HIGH);
// digitalWrite(rightFeederRelay3, HIGH);
// digitalWrite(rightFiringMotorsRelay4, HIGH);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(57600); // sentryBotMarkX2_rev1 baud rate
Serial.println(F("sentryBotMarkX2Magi"));
// turn on IR receiver
irrecv.enableIRIn();
data.cmd.wand_id = 0;
restState();
}
void loop() {
if (Serial.available()) {
command = Serial.read();
switch (command) {
// noted are the companion Processing functions driving these chars
// giveInfo();
case 'i':
informMode();
break;
//addingTarget(); alrtNonComNoSafe(); alrtNoWarning(); hostTarLockGrn();
case 'j':
threatFound();
break;
//no Processing function uses char t yet
case 't':
targeting();
break;
//giveTheMini();
case 'w':
weaponsHot();
break;
// givetheGat();
case 'x':
bulletRain();
break;
default:
restState();
}
}
else if (Serial.available() == 0) {
restState();
if (timeElapsed > interval) {
if (idleCounter == 1) {
Serial.println('1');
timeElapsed = 0;
}
else if (idleCounter == 2) {
Serial.println('2');
timeElapsed = 0;
}
else if (idleCounter == 3) {
Serial.println('3');
timeElapsed = 0;
}
else if (idleCounter == 4) {
Serial.println('4');
timeElapsed = 0;
}
else if (idleCounter == 5) {
Serial.println('5');
timeElapsed = 0;
}
else if (idleCounter == 6) {
Serial.println('6');
timeElapsed = 0;
}
else if (idleCounter == 7) {
Serial.println('7');
timeElapsed = 0;
}
idleCounter++;
if (idleCounter > 6) {
idleCounter = 0;
}
}
}
if (irrecv.decode(&results)) {
decodeMagiQuest(&results, &data);
/* Winterra*/
if (data.cmd.wand_id == 470994049) {
blueDragonWand(); // ascending warp tone
}
/* Red Dragon */
if (data.cmd.wand_id == 839110017) {
redDragonWand(); // ascending warp tone
}
/* trixter -- insanity */
else if (data.cmd.wand_id == 969260033) {
trixterWand();
}
/* frostwand, cold in the USD */
else if (data.cmd.wand_id == 962781697) {
frostWand();
}
/* evil. */
else if (data.cmd.wand_id == 965771137) {
skullWand();
}
/* dark gem */
else if (data.cmd.wand_id == 469759489) {
darkWand();
}
else {}
// wait a bit, and then back to receiving and decoding. shortening this seems to get repeated unwanted reads
delay(200); // 200 seems better LATE CHANGE, THIS WAS MOVED UP FROM END OF LOOP
data.cmd.wand_id = 0;
irrecv.resume();
}
}
/*
This decodeMagiQuest method cribbed from mpflaga (https://github.com/mpflaga/Arduino-IRremote)
mode of the Arduino IRremote library. Excised and updated to work with current IRremote
library.
https://github.com/mpflaga/Arduino-IRremote/blob/master/IRremote.cpp
*/
int32_t decodeMagiQuest(decode_results *results, magiquest *mdata) {
magiquest data;
data.llword = 0;
int16_t offset = 1;
uint16_t mark_;
uint16_t space_;
uint8_t multiple_;
if (irparams.rawlen < 2 * MAGIQUEST_BITS) {
return ERR;
}
while (offset + 1 < irparams.rawlen) {
mark_ = results->rawbuf[offset];
space_ = results->rawbuf[offset + 1];
multiple_ = space_ / mark_;
// it is either 25% + 75% or 50% + 50%
if (MATCH_MARK(space_ + mark_, MAGIQUEST_PERIOD)) {
if (multiple_ > 1) {
data.llword <<= 1;
} else {
data.llword = (data.llword << 1) | 1;
}
} else {
return ERR;
}
offset++;
offset++;
}
// Success
results->bits = (offset + 1) / 2;
if (results->bits < 12) {
results->bits = 0;
return ERR;
}
//results->magiquestMagnitude = data.cmd.magnitude;
results->value = data.cmd.wand_id;
results->decode_type = MAGIQUEST;
// fill in our magiquest struct
mdata->cmd.magnitude = data.cmd.magnitude;
mdata->cmd.wand_id = data.cmd.wand_id;
return DECODED;
}
void redDragonWand() {
// increments hadoukens
delay(700);
Serial.println(" ");
}
void blueDragonWand() {
// increments spellcaster magic casts
delay(700);
Serial.println("m");
}
void trixterWand() {
delay(700);
// sends key to to insanity
Serial.println("<");
}
void frostWand() {
delay(700);
// sends key to hacker transition then to USD
Serial.println("%");
}
void skullWand() {
// sends key to death
delay(700);
Serial.println(">");
}
void darkWand() {
delay(700);
// c4Mem+=500
Serial.println("e");
delay(6000);
// s4+=500
Serial.println("q");
delay(6000);
// hacks it large with doomslayer, wins
Serial.println("+");
delay(10000);
}
// weapons cold
void restState() { // off
digitalWrite(leftFeederRelay1, HIGH); // recall these relays are active LOW
digitalWrite(leftFiringMotorsRelay2, HIGH); // so HIGH is off or not activated
digitalWrite(rightFeederRelay3, HIGH);
digitalWrite(rightFiringMotorsRelay4, HIGH);
digitalWrite(LED_BUILTIN, LOW);
}
// go time
void bulletRain() { // on
digitalWrite(leftFeederRelay1, LOW); // recall these relays are active LOW
digitalWrite(leftFiringMotorsRelay2, LOW); // so HIGH is off or not activated
digitalWrite(rightFeederRelay3, LOW);
digitalWrite(rightFiringMotorsRelay4, LOW);
digitalWrite(LED_BUILTIN, HIGH);
// Serial.println("light 'em up!");
delay(5000);
}
void weaponsHot() { // on, quick blast audio clip is a second long
digitalWrite(leftFeederRelay1, LOW);
digitalWrite(leftFiringMotorsRelay2, LOW);
digitalWrite(rightFeederRelay3, LOW);
digitalWrite(rightFiringMotorsRelay4, LOW);
digitalWrite(LED_BUILTIN, HIGH);
// Serial.println("quick shot");
delay(1000);
}
// the following three modes are relics of original design
// that I'm leaving in because I don't want to mess with
// the Processing sketch that sends chars to activate these modes.
// I may be able to add on in the future using these modes
// which originally set servo positions
// commented out in each function
// who knows? maybe laser targeting in the future or something?
// or using 1/5 scale servos to tilt the arms up and down
void informMode() { // off
digitalWrite(leftFeederRelay1, HIGH);
digitalWrite(leftFiringMotorsRelay2, HIGH);
digitalWrite(rightFeederRelay3, HIGH);
digitalWrite(rightFiringMotorsRelay4, HIGH);
digitalWrite(LED_BUILTIN, LOW);
// Serial.println("interrogative");
}
void threatFound() { // off
digitalWrite(leftFeederRelay1, HIGH);
digitalWrite(leftFiringMotorsRelay2, HIGH);
digitalWrite(rightFeederRelay3, HIGH);
digitalWrite(rightFiringMotorsRelay4, HIGH);
digitalWrite(LED_BUILTIN, LOW);
// Serial.println("threat found");
}
void targeting() { // off
digitalWrite(leftFeederRelay1, HIGH);
digitalWrite(leftFiringMotorsRelay2, HIGH);
digitalWrite(rightFeederRelay3, HIGH);
digitalWrite(rightFiringMotorsRelay4, HIGH);
digitalWrite(LED_BUILTIN, LOW);
}