'Embedded' is a bit of a loaded term..
In some respects, any system dedicated to running a single application could be called an embedded system, as long as there is some hardware to be controlled. You can arguably call a 400MHz PPC604 with 2GB of RAM running a java application on top of linux an embedded system, if it happens to be controlling a process through local I/O modules. On the other hand, an arduino just running some kind of minimal network application wouldn't be much of an embedded system. But probably 'embedded' makes most people think of flash based controllers with only a few hundred bytes of RAM, no operating system to speak of, and a plethora of on-chip peripherals.
That being said, probably the two biggest hurdles non-embedded programmers usually face learning embedded systems are I/O registers and interrupts.
Interrupts may actually be the easier of the two concepts for non-embedded programmers to deal with, since the main issues with these, concurrency and event driven programming, are often encountered in mainstream applications. What makes interrupts a pain is realizing the extreme sensitivity of a system to the quality of its interrupt handling, and the intricacies of dealing with hardware to clear the interrupt condition and set up for the next one. With a GUI, a deadlock kills just the application. With an interrupt handler, a deadlock causes your entire system to lock.
I/O devices seem to be the area that cause the most difficulty. For the uninitiated, it can be quite a surprise to discover that reading this register here has an effect on that register there. Writing 1's to clear bits. Status bits that clear themselves when you read a data register, etc. There are so many possibilities with I/O hardware that there is no general rule for dealing with it, except to learn how to find and interpret device data sheets. Writing a device driver for a serial port will teach you much about low level I/O programming.
There's really no substitute for learning these things than to roll up one's sleeves, and program some straight C and/or assembly language on the bare metal. Even the aforementioned java based embedded system eventually needs a device driver for the I/O, and this means ultimately dealing with some C. Experience is the best teacher. Pick a microcontroller, be it MSP430, TMS320, AVR, ARM, PIC, 68HC11, whatever, find an eval kit, and build some systems.