What I'm looking for is a book about software design in microcontrollers.
C is C, whether on a mcu or on a large machine. I don't think this "Learn C on ARM/PIC/xxx" ever works.
There are many ways to learn to code in a prudent way. The one that has worked for me is to think about coding as an investment that you can rip its benefits over and over in the future.
So whenever you write a piece of code, think about how you can write it in a way that you can use it easily in the future.
This typically means to write to a logic layer of the device.
For example, setting a pin can be done on a PIC like this:
RA0 = 1; //set porta.0
Next time if you want to move that pin to PORTB.4, you have to find out all the RA0 and replace them. Worse yet, if you were to move the code to a platform that doesn't offer bit-addressable pins, you have to rewrite it.
So something like this would be better:
#define LED_PORT PORTA
#define LED (1<<0)
#define PIN_SET(port, pins) port |= (pins)
PIN_SET(LED_PORT, LED); //set led on led_port
If you move the pin, you can simply change LED_PORT / LED and recompile.
If you change the platform, you can simply change PIN_SET() and recompile, with the confidence that it would work.
It is small things like that that makes coding robust. The focus on portability or readability isn't actually about porting the code. It is about building code that works under many circumstances.