The ATMega32 will not run from a 16MHz external crystal by default. If you have not programmed its fuse bits for a 16MHz external clock (or the fuse bits are otherwise set to their factory defaults), then the ATMega32 will not use the external crystal and it will not be running at 16MHz.
Don't be intimidated by the name 'fuse bit', the 'fuse' part is not meant to imply that they are one-time programmable. Rather, it is referring to the low level operation of this form of non-volatile memory. You can pretend the bits are fuses, with a 0 meaning that bit is programmed/active/there is a closed circuit connection. 1, on the other hand, means the fuse is 'blown', and that bit is unprogrammed or open circuit.
But nothing is really getting blown or damaged, you can rewrite them at will. You're limited by the write cycles of course, but that number is in the thousands or more. And unlike flash memory, fuse bits are not changed by a chip erase, nor are they programmed during flashing of the microcontroller. They also cannot be changed from the microcontroller itself, but require a programmer to change.
There is potential for rendering the microcontroller no longer programmable via an ISP programmer, requiring the use of a high voltage parallel programmer instead. Fortunately, these dangerous fuse bits are all located in the high fuse byte, and the only things you need to change are located in the low fuse byte, so there is zero risk as long as you only write to the low fuse byte.
In the lower fuse byte, there are 4 bits called CKSEL[3-0], which is short fort Clock Select. These select the frequency and clock source for the chip. By default, they're programmed to use the 1MHz internal RC oscillator, and not an external crystal.
There are also different settings for a crystal oscillator vs. an external clock (where the clock input is driven by some independent clock source, which is different from using a crystal oscillator).
To use an external 16MHz crystal, you must deactivate all 4 CKSEL bits. Remember, this is the opposite of other registers, meaning you must write a 1 to all 4 bits to turn them off.
Additionally, external crystals and resonators are both resonate oscillators. It takes a little bit of time for their frequency to become stable after power on. Depending on the quality of your crystal, this can happen quickly, or it can take several milliseconds. There is another 2 bit field in the low fuse byte called SUT[1-0] that allows you to set a startup delay, giving time for the clock to become stable. By default, this is set to 4ms, but it is best practice to set it to the longest startup time (65ms) unless you really need startup to be faster and know your crystal is good enough. If both bits are unprogrammed (a value of 1 written to them), this will set the startup delay to 65ms.
By default, no other fuse bits in the low byte are programmed, and setting the longest delay requires neither SUT bits be programmed, and a high frequency external crystal also requires CKSEL 3-0 to not be programmed... if this sounds like it is going to be convenient, it is. We want to turn off every single bit in the low fuse byte (unless you want to turn on brown-out detection, but that's not important right now).
So you simply need to write 0xFF to the lower fuse byte. 0xFF turns off every single fuse bit, as writing a 1 turns them off. It feels weird since this goes against how pretty much everything else normally works, but that's just how it is.
Just to be explicitly clear, this is a zero risk operation. When being programmed, the chip's clock source is the ISP programmer itself, so you can't 'brick' your chip in anyway by doing this. It might not correctly run your program if you set something wrong, but you can simply write the correct fuse byte to it with the programmer to fix such a problem.
To do this with avrdude
, simply add this command switch: -U lfuse:w:0xff:m
That will correctly configure your ATMega32 to run from an external 16MHz crystal, and your code's timing problems should no longer be a problem after that. You can write fuse bytes without performing any other operations, like flashing or erasing, so you should even see your chip boot up and begin flashing the LED after you have programmed the fuse byte and reset it. It will just work.
But don't take my word for it, there are some very nice tools that will give you the commands for avrdude, ready to be copy and pasted, and let you configure things like the clock etc. using drop down menus. It really is next to impossible to mess anything up if you also use one of these tools. I like this one.