There are good answers already from people way more experienced than me. I don’t know that many resources myself apart from one I’ll link to below. But I’d like to add something about what you’re about to learn, so you may have a better idea of how you want to go about it. I am going to assume you are starting without any prior knowledge.
I’d say learning embedded programming has 3 main elements to it.
1) Learning the concepts of programming and the mindset of a programmer
2) Learning a programming language, in your case; learning C
3) Learning how microcontrollers work and how this all applies to programming them
Let’s have a look at those in a little more detail.
1) Learning the concepts of programming and the mindset of a programmerThis is learning about such things as variables and variable types, loops, conditional statements, functions and splitting up your program in smaller subsections. About how to test your code. Best practices. Algorithms perhaps, and ways to design and structure your program; i.e. it’s architecture. And so on. You’ll get a feel for *how* to think, as well as the concepts involved in programming. While you learn them at first tied to your first programming language, many ideas are applicable to any language, even if they look very different. Which leads me to the next element.
2) Learning a programming languageThis is learning the actual language, C in your case. Compare it with languages like English, or Spanish or French, etc. If 1) is about the ideas of nouns and verbs and how to build a sentence, and such, 2) is the actual language, the words, phrases, saying and idiom. You’ll need to get familiar with the way C does things. What you can and can’t do. And how to “say” what you want to achieve in C. And as with English, Spanish and French etc., There are things that you can easily do in C that another language doesn’t have naturally and you’ll need a workaround. And there are things that are easily done in another language, that C needs a lot of “words” for.
3) Learning how microcontrollers work and how this all applies to programming themEmbedded programming comes with its own set of ideas, and concepts. Now you are applying the above to a specific environment: a microcontroller (MCU). (Embedded programming is broader than only microcontrollers, but I’ll stay with what you mentioned in your first post). You’ll need to learn what a MCU really is, like on the inside. What things like the core, clocks, peripherals, registers, and many more parts are. You’ll learn about GPIO, timers, ADCs and about communication between the MCU and other chips with say UART (Serial), I2C, SPI, for a start. You’ll learn elements of electronics design, so you can understand how to power the chip, and connect it to other things outside it. You’ll learn how to read a data sheet or reference manual and find the information you’re looking for. In summary: you need to come to understand a microcontroller and it’s environment.
When you’re an absolute beginner 1 and 2 will go hand in hand. When you’re more experienced and ever want to try another language, you’ll find that many ideas and concepts in programming are similar, except different languages implement it in a different way. (This is too generic, I know that, and there’s more to the differences in languages. But for now that’s a starting point).
How to get startedSo now to your question as to
how to get started with this. There are multiple ways to go about it. Here is one:
You could separate 1) and 2) from 3) at first so you don’t get too overwhelmed with all these new ideas. That’s how I leant, by first learning C, and then starting to apply it to a microcontroller. The upside of this is that you are able to focus more on understanding the language and the concepts of programming first. And when you get to learn how the apply to a microcontroller you already know the basics of a language. The downside is, that you may learn things from C that work well for a PC programmer, but are best avoided when using C in an embedded environment. Specifically because the embedded environment puts constraints on what you can and cannot do, and if you only learn C for PC programming at first, you may need to unlearn things when you apply it to a microcontroller.
I don’t think that risk is too high when you’re only just starting out. If you go this route, start by getting familiar with the language C and concepts from variables, types and loops and if/else statements and structs. Pointers too perhaps, but by the time you get there, you’ll likely understand the basics of programming and the language C. That is a good time to switch what you just learned and apply it to a microcontroller. You'll need to decide on a microcontroller type you want to start to learn on. And with that comes a computer program in which you can write the code, compile it and download it into your controller. That's usually refered to by people as the IDE, for Intergrated Development Environment.
I’m not too familiar with (free online) courses or tutorials that I would be able to recommend anything for where you are at. I do highly recommend that when you feel familiar with C and have some experience with a microcontroller that you look up this course on YouTube:
Modern Embedded Systems Programming Course. I wouldn’t recommend you start with it. Get to know C a bit first. But when you do, and have some first experience with a microcontroller, it’s a really good one to get in depth insight in how it works on a modern ARM microcontroller. Even if you end up using a different ARM MCU and different programming environment (IDE)
To Arduino or not ArduinoThere is an ongoing debate about whether Arduino is a good starting point for learning to program. On one hand, when you are an absolute beginner it may be the quickest way to get you started with an actual microcontroller. However, Arduino does many things
for you, specifically to make it so easy for you to just make something. I’d say that is one of its strengths, to provide something for people who just want to make something. The flipside to that, in my opinion, is that you run the risk that you don’t actually learn to program (well). And may even need to unlearn a few things. Depending on where you want to go with programming and microcontrollers, my personal suggestion would be to skip Arduino. This is just my opinion, but without it you’ll more likely to learn to program well. And you’ll more likely to get to understand how a microcontroller works. From personal experience it is very satisfying when you make the microcontroller do exactly what you want, after finding out which registers to set in a certain way. I found I learnt a lot faster that way and I had to really understand what I was doing, rather than typing one line of code that someone else made and does everything for you like a magic black box. It still feels like a reward to me each time.
An option could be to start with using an Arduino Uno as your hardware, with the Arduino PC program to write your code at first. But then actually not use anything Arduino gives as code at all. Just use the board and the software, but learn how to use the actual microcontroller by yourself. Like Siwastaja said above:
Try to find some old tutorials for programming PIC or AVR microcontrollers in C, before the time of Arduino, bloat libraries and frameworks and whatnot.
The Arduino Uno uses a Microchip (Atmel) ATmega328P. If you search for AVR programming you can find many examples from people who learned to program these before Arduino existed. Eventually though, you will want to use something else than the Arduino software with more capabilities and more control for you. So perhaps skipping it altogether is still the better option.
(edit: some typos)