- Microcontrollers are often defined as being complete computers on a singly chip, and this is certainly true.
- Any way you slice it, digital output is the heart and soul of microcontroller programming. It’s how you “speak” to the outside world.
- One of my favorite uses of microcontrollers is as the connector between a real computer and interesting hardware.
- The AVR has three serial communications peripherals built in. Plain-vanilla USART serial is useful for communicating with your desktop computer, radio modems, and GPS units. SPI is good for ultra-fast communication over very short distances with peripherals like memories, ADCs, and DACs. I2C is like a small network, allowing you to connect up to 127 different sensors to the same couple of wires. Devices that move around a moderate amount of data tend to use I2C. That’s a good choice for the network of accelerometers.
- An interrupt service routine is a software function that you can write that automatically executes whenever an interrupt condition is met. They’re called interrupt routines because the processor stops whatever it was doing in the main flow of your program and runs the appropriate function. After it’s done with the interrupt routine, the processor picks up your program’s normal operation where it left off.
- Flash programmers are just USB devices that send bytes of your code across to the AVR chip.
- The flash programmer is a piece of hardware that sites in between your computer and the target AVR microcontroller. The AVR microcontrollers, when put into programming mode, listen over their serial peripheral interface (SPI) bus for incoming data to flash into program memory. The flash programmer’s job is to relay the compiled machine code to the target AVR over the SPI bus.
- A lot of you will have an Arduino sitting around. If so, it turns out to be fantastically easy to turn that Arduino (temporarily) into an AVR programmer.
- Far and away the most popular software uploader is AVRDUDE, which is available for all platforms and supports a wide variety of programmers.
- A flash programmer works by grounding the RESET line, which halts the CPU and signals the AVR to start listening on the SPI bus. The programmer then transmits programming instructions over the SPI bus. After each instruction or section of code, the AVR writes the received data to flash memory.
- One very real advantage of the Arduino hardware setup is that the chip comes pre flashed with a bootloader, which is code that enables the chip to communicate with your computer over the serial line in order to flash the program itself. This means that you can do away with the requirement for an external bit of hardware to flash the chip--there’s a tiny bit of bootloader code already running in your Arduino that’ll flash the chip for you!
- The second highlight of the Arduino package is that it comes with a built-in USB-to-serial converter, so you don’t have to buy a separate one just yet.
- Atmel’s current official USB in-system programmer, the AVRISP mkII is a very nice programmer that’s capable of programming the whole AVR line, including the newest XMega devices. It’s a bit more expensive than other programmers, but it’s rock solid and is quite a bargain all in all.
- Digital output is both the simplest and most common way that your microcontroller programs are going to control other devices in the outside world.
- The preamble is where you include information from other files, define global variables, and define functions.
- After the preamble comes the main() function. The name “main” is special--regardless of how many other functions are defined, your C program must have exactly one main() function. Main is where the AVR stats executing your code when the power first goes on. It’s the entry point.
- Inside the main function you’ll find a while(1) loop, often referred to as the “main loop” or “event loop”. while() loops are loops that continue running over and over as long as the condition inside the parentheses is true. And in C, 0 always resolves as false, and 1 always resolves as true. So everything that’s within this loop will run over and over again.
- Return codes are totally superfluous for AVR code, which runs freestanding without any supporting operating system; nevertheless, the compiler raises a warning if you don’t end main with return().
- The way we’re going to configure the pin as either input or output is deceptively simple in code--assigning a variable a certain value--but what goes on inside the dark wiring heart of the chip is interesting.
- When you want to configure a microcontroller pin, it looks the same in code as saving a value into a variable. And that’s because the same thing is going on inside the chip. The chip’s hardware registers are just like the RAM storage slots that you use for variables, only they each have side effects.
- Because hardware registers are special memory location, the compiler can’t treat them exactly the same as variables. When you create a normal variable, the compiler can pick and convenient place in memory for it. Because hardware registers are physically connected to the input/output circuitry, the location can’t change.
- Hardware registers can be accessed just like “normal” variables from your code, but inside the chip they have extra connections that let them influence the way the rest of the chip behaves.
- Each bank of pins (B, C, and D on the Mega series AVRs) has three hardware register memory locations associated with it. Let ‘x’ stand for each bank’s letter: so DDRx will be the DDRB, DDRC, or DDRD depending on which bank of pins you mean.
- DDRx data-direction registers. These registers control whether each pin is configured for input or output--the data direction.
- When the DDRx bits are set to one (output) for a given pin, the PORT register controls whether that pin is set to logic high or logic low.
- The PIN register addresses are where you read the digital voltage values for each pin that’s configured as input. Each PINx memory location is hooked up to a comparator circuit that detects whether the external voltage on that pin is high or low.
- A common beginner mistake is trying to write to the PORT register and expecting a voltage out when the DDR hasn’t been set to output yet.
- Bit shifts have the effect of rolling all the bits’ ‘n’ positions to the left or right, depending on your command. Bits that fall off either end just disappear, and any new bits added are all zeros.
- Zero-indexing is natural if you think of everything in terms of a base location and an offset, which is why it’s done in C.
- We use a bitmask, along with a bitwise logical operator, to change some bits in a target.
- If you XOR any bit with a fixed 0, you get a 1 if that bit is a 1 and a 0 if that bit is 0. Remember, this is the “exclusive” or and is only true if one or the other is true, but not both. So XORing with a 1 seems a good way to toggle bits!
- If we AND any bit with 0, the result is guaranteed to be 0. There’s no way they can both be 1 if one of them was a 0 to start with.
- Set a bit: BYTE |= (1 << i);
- Clear a bit: BYTE &= ~(1 << i);
- Toggle a bit: BYTE ^= (1 << i);
- Serial communication is the simplest possible way to interface your microcontroller with your desktop or laptop computer, your first step toward bridging the world of the physical and the virtual.
- Almost all modern serial protocols are specified this way: pins with the same names are connected together.
- When using (old-school) USART serial, you connect RX to TX, and vice versa.
- The essential outline of the hardware configuration is that there are a handful of registers for each of the AVR’s built-in peripherals. Each bit in a register byte is a switch that enables or disables some functions of the peripheral. Setting up the hardware to do its job, then, is just a matter of figuring out which switches you need to set and bit twiddling them into the right states.
- Microcontrollers are not meant to drive speakers. Speakers have a very low resistance to direct current (DC), around 8 ohms. The solution is to add a blocking capacitor to the circuit.
- When a capacitor is subject to a DC voltage, it lets a little current through until it is “charged up” to that voltage, then it blocks further current. This means that capacitors pass current only for changes in voltage.
- A wire that’s just dangling in the air, on the unconnected side of a switch, can act as an antenna. The voltage on that wire will wiggle around between high and low logic estates at whatever frequency the strongest local radio stations (or even “noisy” electrical appliances) broadcast. The only thing you do know about this voltage is that it’s unreliable.
- This physical open-close-open-close nature [bounce] of switches makes the voltage on the circuit bounce between high and low logic voltages over a timescale from a few microseconds to a few milliseconds. The really annoying thing about button bounce is that most of the time it doesn’t happen.
- The easiest solution is to have the AVR wait a few milliseconds and then check to see if the button is still dressed or not before making any decisions. Because the buttons bounce only for a “short” time, waiting for a little bit longer and then double-checking will ensure that we’re not mistaking bounce for a true change.
- The trick with debouncing-by-waiting is getting the timing right.
- Fundamentally, you need to debounce whenever you’re counting button press events. This goes equally for on/off toggling, scrolling through elements of a menu, or switching among modes.
- Putting a capacitor across the two contacts of a switch forces the voltage to rise slowly, and can ensure that it will not jump up and down along the way.
- In industry, almost everyone deb ounces in code, saving a few cents per capacitor.
- A lot of the real world is analog: voltages, currents, light levels, forces, etc., all take on continuously variable values. Deep inside the AVR, on the other hand, everything is binary: on or off. Going from the analog world to the digital is the job of the analog-to-digital converter (ADC) hardware.
- Mastery of microcontrollers starts with good use of the interrupt system.
- The event loop in a polling-style program is essentially a list of things that we’d like to check up on. The AVR then runs through that list repeatedly as fast as it can. If we keep our event loop short enough that any given part comes around frequently enough, it’s hard to tell that we’re polling.
- One problem with polling in event loops is that there's no concept of priority.
- Handling multiple jobs at once is where interrupts excel. Interrupts do just what they sound like--they interrupt the normal flow of the program. When an interrupt is triggered, all of the variables that you’re using are stashed in memory and then a special function, called an interrupt service routine (ISRs), is run. After the ISR is done, your program picks up again where it left off.
- There are internally triggered interrupts that respond to the internal AVR hardware peripherals.
- There are also externally triggered interrupts that can react to a voltage change on any of the AVRs pins.
- Without interrupts, you have to check each button in the system to see if it’s pressed, which waste shoe processor cycles and can result in serious delay if parts of the event loop take a long time. By using interrupts for each AVR pin, you can dispatch code that executes within a microsecond of the button press.
- ISRs are special routines that run when their interrupt flag is set, and their interrupt vector is called.
- sei() turns all interrupts on, and cli() turns them all off.
- For some timing-sensitive sections of code, especially if you have long-running interrupt service routines, you may want to disable interrupts before you call critical functions and re enable interrupts after you return.
- Also note that interrupts are automatically turned off when entering an ISR and turned back on again when finishing. This prevents a situation where an interrupt gets called from inside another interrupt, which itself had been called from inside another interrupt, and so on.
- Always remember that enabling interrupts is a two-step process; enable your specific interrupt vector, then enable the overall interrupt system with sei().
- Volatile warns the compiler that the declared variable can change at any time without warning, and that the compiler shouldn’t optimize it away no matter how static it seems.
- Forgetting to make global shared variables as volatile is probably pitfall #1 in advanced AVR programming. If you're ISR seems not to be working, and you’re sure you’ve run sei(), double-check your volatiles.
- Another place you’ll want to define a variable as volatile is when you’re using a loop to do nothing but delay. Because it’s doing nothing, the compiler will optimize it away.
- If you share a global variable between a function and an ISR, you must declare that variable as volatile.
- AM radio allows for a particularly simple receiver. When you tune the radio to the correct frequency, the antenna receives a time-varying voltage signal--the carrier modulated by the signal. To get rid of the carrier, you simply run the receive voltage through a diode, so that you get only the positive voltages. Now you’ve got a signal that varies from roughly zero to 1.6V, which you can output directly to a speaker with a capacitor.
- Indeed, the simplest version of AM radio receivers are crystal radios, which really only have four parts: an inductor and tuning capacitor to select the right carrier frequency, a diode to separate the signal from the carrier, and a high-impedance earpiece that doesn’t require amplification (and has the blocking capacitor built in).
- The worst thing you can do is change the SPI-programming bit, which disables your ability to further program the chip using your flash programmer.
- PWM is such a common method of creating analog voltages from digital devices that almost all microcontrollers, including the AVR, have dedicated internal peripheral hardware that takes care of this high-speed bit toggling for you, and I recommend using this feature whenever you can.
- When you’re playing with the LED demo, you may also notice that the human eye doesn’t respond to equal changes in brightness equally.
- The human eye is much better at telling the difference between low levels of light than higher ones. That is, the human eye’s response to light is nonlinear. Many LEDs are driven in PWM mode to exploit this fact.
- The reason that PWM-driven LEDs are so prevalent is that your eyes can’t really tell the difference between 90% and 100% duty cycles, so the city can run the traffic lights at 90% and pocket the 10% energy savings.
- Servos are positioning motors with a built-in feedback circuit, and it’s this internal circuitry that makes them so simple to use. As positioning motors, they don’t spin around and around like traditional motors. Instead, they only rotate through 180 degrees or so, and they can move to the desired position to roughly the nearest degree on command.
- You send position controls to a servo with a signal pulse that ranges nominally from 1 ms to 2 ms.
- The reason behind the lousy accuracy is that the AVR’s internal CPU clock isn’t really meant for time-keeping. It’s meant to give you a quick-and-dirty clock pulse so that the chip can run without any external parts.
- Measuring higher voltages is actually easy enough. We simply redivide the voltage down to our 5V range using a voltage divider.
- To get extra resolution in the measurement, we’ll use oversampling, which is a tremendously useful technique to have in your repertoire. The idea behind oversampling is that we take repeated measurements from our ADC and combine them. This almost sounds like averaging, but it’s not the same.
- When we oversample 4x we add the four numbers together and divide by two, increasing the number of bits in our result by one.
- The point is that you make the best use of the ADC’s resolution when the voltage range of the ADC matches the voltage range of the sensor.
- The piezoelectric disk, or piezo for short, is a crystal that deforms (slightly) when you apply a voltage to it, or conversely develops an electric voltage when you deform it.
- The more terms you choose to average together in your moving average, the better you’ll average out the noise signal. [...] There is always this trade-off between smoothing the values out better and having the average be up to date.
- To create audio that’s more interesting than square waves, we’re going to use PWM to create rapidly changing intermediate voltages that’ll trace out arbitrary waveforms.
- The secret to driving large loads is using transistors between the AVR and a motor.
- Bipolar transistors can be thought of as a way of taking an input current and using that to allow a much bigger, proportional current to flow between collector or emitter. For most transistors, this current gain is around 100x, which means that if you pass 10 mA through the base, the transistor will allow up to 1A to flow from collector to emitter.
- This is the sense in which transistors are amplifiers: small changes in a small current can create big changes in a bigger current.
- Darlington transistors are just a pair of transistors built together into the same chunk of silicon so that the first one supplies drive current to the second. Because the first transistor amplifies the current that is again amplified by the second transistor, instead of having a gain of around 35-100, Darlingtons have a current gain around 1,000 to 10,000.
- Unlike BJTs, MOSFETS are voltage-controlled devices, which means that you don’t have to include a base resistor when hooking them up to an AVR I/O pin--just wire up the AVR pin directly to the gate. Even better, small MOSFETs draw very little current when they’re switching on or off, and almost none when they’re in a steady state, so you don’t have to worry about the AVR’s current sourcing capabilities.
- Another nice feature with MOSFETs, although it’s kind of a hack, is that because they only require a little current when turning on, you can easily run a few in parallel off of one AVR pin, especially at low frequencies.
- Modern power MOSFETs are just like their smaller switching MOSFET cousins, only larger and with a geometry that’s adapted to deliver more current with less resistance, and this less wasted heat. The trade-off is that power MOSFETs usually require a higher gate voltage to turn fully on and a little more current as well if you’d like to turn them on and off quickly.
- Triacs are like transistors but used for AC current instead of DC. Solid State Relays (SSR) are basically triacs with some extra circuitry to help isolate the control side form the AC line voltage.
- The flyback diode is important to provide a path for the current that’s flowing through the motor to continue on after we’ve switched the motor off.
- Microstepping lets you drive a stepper motor to intermediate positions between the half steps by controlling the ratio of coil currents in the two coil pairs. You can control the coil currents by using PWM, changing the driving voltage, or using other current-limiting circuits, but the basic idea is that be varying the magnet pull on the rotor coming from the two coils you should be able to make the motor move to any angular position you’d like.
- One reason the SPI is so fast is that, unlike our old friend UART, it’s a clocked, or synchronous, protocol.
- Because the SPI bus is fast, you’ll find that it’s mostly used by devices that need speed: ADCs and DACs for audio or much faster signals, output expanders, and memory.
- I2C is a tremendously popular protocol for interfacing microcontrollers with small sensors and these days even with devices that require more speed. Its main advantage is that you can talk to a large number of devices with just a couple of wires, which makes it much more like a network than the SPI bus.
- The pointer is a special variable type that should be used specifically for stoner memory addresses.
- Pulse-code modulation is just producing audio by changing the binary data that you feed into a digital-to-analog converter over time.
- EEPROM provides low-power, long-term storage of fairly large amounts of data.
- The floating-point-compatible math libraries end up taking up a bunch of memory and are slow. In my experience, there’s almost always a way to rephrase your problem that can avoid using floating-point numbers.
- The most valuable (and fun) thing about EEPROM is that it’s nonvolatile. You can power down your chip completely, and the data in EEPROM will still be there when you turn the chip back on, even thirty years later.
- The watchdog system is a very slow timer that can be configured to run from 16 milliseconds all the way up to 8 seconds. It is special in that when it reaches the end of its time, it can fire an interrupt or reset the chip.
- The primary use of the watchdog timer is as a safeguard against runaway code.
- My first choice for lowering power consumption is just to stay in sleep mode as much as possible. Following that, I’ll shut down whatever peripherals I can, but this gets tricky if you’re actually using some of them. A no-code-change method to reduce your power usage is just to use a lower voltage for VCC--all of the A series chips run on 3.3-3.6 V just fine.
20190129
Make: AVR Programming by Elliot Williams
Labels:
books
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment