Atmega8 connection. Distance sensor URM37 - connection to the AVR and to the computer (via USB)

The article will consider connecting LEDs to the microcontroller, working with ports and writing a program in SI. The article is primarily intended for beginners who have just taken up AVR microcontrollers.

First you need to choose a microcontroller. In my case it is ATmega8535. In this case, you can take any microcontroller, since this task is easily implemented under any MK. You can write a program for the microcontroller in Assembler, C, Pascal and Bascom. I used C language, all these languages ​​are different.
The specific difference between C and Pascal can be seen below.

//Blinking LED void main() ( ddrB = 0b11111111; //set ports B to output portB = 0b11111111; //by default, everything is off while(1) ( portB = ˜portB; //switch the LED state to reverse delay_ms(100 ); //make a delay of 100 milliseconds ) )

Program First; begin ddrB:= $FF; //set port B to output portB:= $FF; //default is off while(1) do begin portB:= not(portB); //switch the LED state to reverse delay_ms(100); //do a little delay end; end.

List of radio elements

Designation Type Denomination Quantity NoteShopMy notepad
U1 MK AVR 8-bit

ATmega8535

1 To notepad
R1-R8 Resistor

220 Ohm - 1 kOhm

8 To notepad
R9-R11 Resistor

10 kOhm

3 To notepad
V1-V8 Light-emitting diode 8 To notepad
Tact button 3

We emulated the circuit in the Proteus program, blinked the LED and learned how to flash our virtual microcontroller. Surely many of the readers came up with the thought: “Is it possible to blink the LED using a button connected to the MK?

Yes, of course it's possible. It is implemented quite easily. Moreover, it is possible to emulate a button both with fixation and without fixation. Moreover, in the Proteus program, you can apply both types of buttons using the same identical button macro. In what cases can it be useful? For example, we need to select the operating modes of the device. Let's take a closer look at how to implement this using a microcontroller, and emulate it in the Proteus program.


In order to have a visual representation that we really have a choice of two modes, we will assemble a simple circuit on 4 LEDs with one button control. In the first option, we alternately light up from the first to the fourth LEDs. In the second option, the same thing, but in reverse order, that is, from the fourth to the first. The only thing I want to clarify is that our button is polled for pressing or releasing just before the start of the effect. Until the effect finishes its work, the program does not respond to pressing or releasing the button.

So to business. This is how our scheme looks like in the Proteus program (click to enlarge):

In this scheme, we already see differences from the one that was collected in the last article. On the left side of the diagram, we see the designations of the button and the +5 volt power supply.

As we have already discussed, we take power and land in the “Terminal” tab. They are denoted by us, respectively, Power and Ground.

We denote the power supply of the circuit by a triangle with a line dividing it in height. Nearby, in the figure, the designation of the button is shown. To the right of the button, we see a filled red circle with a double-headed arrow. If you click on it during emulation, then the button will be fixed and will be constantly pressed. After pressing it again, the fixation is removed.


Before using, we need to select a button in the library in the same way as the rest of the details. To do this, type the word “but” in the “Mask” field. Then in the field “Results” the word “BUTTON”:


After that, the button will appear in our list, along with the selected parts used in the project.

What ports do we use in the project. Below in the figure we see outgoing lines from the ports RA0, PB0, PB1, PB2 and PB3. We have LEDs connected to port B, and a button to port A.

So, when pressed, we close the circuit connecting +5 volts to the PA0 port and the top terminal of the resistor. Why do we have a resistor here at all? The fact is that the button circuit must be closed. After we installed the resistor, the current flows from the plus of the power supply through the button, the resistor and further to the ground.

The value of the resistor is enough to take equal to 200 ohms. So, when we press a button, we connect the PA0 port to the +5 volt supply, and if we poll the PA0 pin for voltage or not, we can influence the execution of our program.

Screenshots with the text of our program I have given below:


So, the differences from the previous project are that we configure all 8 pins of the RA port to the input, we configure the pins of the port PB0 - PB3 to the output, and PB4 - PB7 to the input.


Then we use in our program a condition check “ if"


So, we see in the line after “if”, in brackets, the execution condition. The code below is executed if we have a logical zero, or zero volts, on the PA0 port. This text in brackets is the port bit shift. We will analyze in one of the following articles, but for now it is enough to take it on faith that by doing this we are interrogating the button on wringing out. Then, in curly braces, there is the text of the program, which is executed if the condition is true. If the condition is not true, the program continues to run, skipping the text in curly braces.

Similarly, using the “if” condition, we poll the button on pressing. Please note that the text in brackets has changed. This means that if we have a logical unit on the PA0 leg, we fulfill the condition, that is, the text in curly brackets. That is, in other words, when the button is pressed, the LEDs from the first to the fourth alternately light up and go out, and when pressed and held, they light up and go out from the fourth to the first. Thus, we can influence the execution of the program by pressing a button, polling for the presence of a logical zero on it, or a logical one

Also, in which the “sishnik” file, HEX and the Proteus file are located.

And here is the video

Clocking methods

The canonical way of clocking the MK is to connect a quartz resonator to the corresponding outputs (Fig. 18.11, a). The capacitance of capacitors C1 and C2 in the typical case should be 22-36 pF (see chapter 15 for the inclusion of quartz). Most Tiny and Mega models have a special configuration bit skrot that allows you to adjust consumption. When this bit is set to one (unprogrammed), the amplitude of the oscillations is reduced, however, the possible frequency range and overall noise immunity are narrowed, so this mode is not recommended (see below). A low-frequency quartz resonator can also be used (for example, a “clock” 32,768 Hz), while capacitors C1 and C2 can be omitted, since when setting the skt to O, the internal capacitors 36 pF included in the MK are connected.

A ceramic resonator can be used instead of a quartz resonator. The author of these lines managed to run the MK at non-standard frequencies, using a miniature inductance instead of quartz in the same connection (with its value of 4.7 μH and capacitor capacities of 91 pF, the frequency is about 10 MHz).

Rice. 18.11. Methods for clocking MK AVR using: a - a quartz resonator; b - external generator; c - RC chains

Naturally, the MK can also be clocked from an external generator (Fig. 18.11, b). This is especially convenient when you need to either synchronize the MK with external components, or have a very accurate clock frequency when using appropriate generators (for example, Epson's SG-8002 series).

Conversely, when accuracy is not required, an external LC chain can be used (Fig. 18.11, c). In this circuit, the capacitance C1 must be at least 22 pF, and the resistor R1 is selected from the 3.3-100KΩ range. In this case, the frequency is determined by the formula F = 2/3 RC, CI can not be set at all, if you write a logical zero to the skrot configuration cell, thereby connecting an internal 36 pF capacitor.

Finally, you can do without any external components at all - use the built-in /rC oscillator, which can operate at four frequencies, approximately equal to 1, 2, 4 and 8 MHz. This feature is most appropriate to use in low-end modes. (Tiny 1s, available in an 8-pin package - then the outputs intended for connecting a resonator or an external generator can be used for other purposes, like regular I / O ports. The Classic family of the built-in RC generator didn't have.

By default, Tiny and Mega MCUs are set to work with the built-in oscillator at a frequency of 1 MHz (cksel = oooi), therefore, to work in other modes, you need to set the cksel configuration cells accordingly (see Table 18.1). How to put this into practice will be discussed in Chapter 19. The recommended value of these cells for conventional resonators from 1 MHz or more is all ones in cksel cells, and zero in sk.

Details

When installing the cells, it should be taken into account that the state cksel \u003d oooo (mirror with respect to the most commonly used value for the quartz resonator iiii) puts the MK into the clocking mode from an external generator, and in this state it cannot even be programmed without applying an external frequency. Also, if you try to set the mode with a low-frequency resonator, then the VU-frequency MK will no longer start, and not all programmers can work at such low clock frequencies. Therefore, when manipulating cells, and not just cksel, you need to be extremely careful and have a good idea of ​​what exactly you are installing. More on this in the next chapter.

Table 18.1. Setting CKSEL configuration cells depending on clocking modes

Clock source

External frequency

Built-in /? C-generator

Built-in RC generator

Built-in /? C-generator

Built-in RC generator

External RC chain

External /?C-chain

External RC chain

External RC chain

Low frequency resonator

Table 16.1 (end)

Clock source

Ceramic resonator

Ceramic resonator

quartz resonator

Quartz resonator

Parallel I/O ports

I / O ports (we repeat that they should not be confused with either I / O registers or MK serial ports for exchanging information with external devices) in different models can be from 1 to 7. Nominally 8-bit ports, in some cases bit depth is limited by the number of package pins and can be less than eight. The ports are designated by the letters A, B, C, D, etc., and not necessarily in order: in younger models, for example, only ports B and D (as in ATtiny2313) or only one port B (as in ATtinylx) ).

To reduce the number of case contacts, in the vast majority of cases, external pins corresponding to ports, in addition to their main function (bidirectional input / output), also have an additional one. Note that, except for the Reset pin, if it can work in alternate mode, no special port pin switching is required. If you, for example, initialize the UART serial port in your program, then the corresponding port pins (for example, in the ATmega8335 these are the PDO and PD1 port pins) will work exactly in an alternative function, like UART input and output. However, in the intervals between such special use of the pins, they can in principle be used as ordinary bidirectional pins. In practice, it is necessary to apply circuitry measures to isolate functions from each other, so it is not recommended to abuse this feature.

The port pins are fairly self-contained and their mode can be set independently of each other. By default, when the power is turned on, all additional devices are disabled, and the ports work as an input, and are in the third state with a high g-pedance (that is, with a high input impedance). Output operation requires a special indication, for which the program needs to set the bit corresponding to the desired output in the data direction register (this register is denoted by DDRx, where x is a letter denoting a specific port, for example, for port A it will be ddra). If the bit is reset (that is, it is equal to logical zero), then the output works as an input (as by default), if it is set (that is, it is equal to a logical one), then it goes to the output.

To set the output to one, you must separately set the corresponding bit in the port data register (denoted by portx), and to set it to 0, clear this bit. The direction of the output (input-output, DDRx register) and its state (O-1, portx) should not be confused.

The portx data register is actually just an output buffer, everything that is written to it is immediately output. But if you set the port pin to the input (that is, write a logical zero to the ddrx direction register), as is done by default, then the portx data register will play a slightly different role - setting its bits to zero means that the input is in the third state with a high resistance, and setting it to one will connect a “pull-up” resistor with a resistance of 35-120 kOhm to the output.

marginal notes

The built-in pull-up resistor in most cases is not enough for reliable operation - due to pickups, the MK may fail, and it is better to install an additional external resistor in parallel with this internal one, with a resistance of 1 to 5 kOhm (in critical cases with respect to consumption, its value can be increased to 20-30 kOhm). For example, if you connect a remote button with two pins to the input, which is switched to ground, or the pin works on a “common bus” with remote (located on another board) devices, or the pin performs the function of an external interrupt (see below), then such an additional resistor must be connected.

The procedure for reading the level on a port pin, if it is in the input state, is not entirely trivial. There is a temptation to read data from the portx data register, but this will not work - you will only read what you wrote there earlier. And to read what is really available at the input (directly at the output of the microcircuit), another possibility is provided. To do this, you need to refer to some array, which is denoted by pinx. Access is carried out in the same way as individual bits of ordinary RBB (see chapter 19 \ but pinx is not a register, it's just a range of addresses, reading from which provides access to information from the buffer elements at the input of the port. Write something to addresses piNx, of course, is impossible.

Interrupts

As in the PC, interrupts (interrupts) in microcontrollers are of two types. But if in a PC interrupts are divided into hardware (for example, from a timer or keyboard) and software (in fact, not interrupts, but subroutines written in the BIOS - with the spread of Windows, this concept has almost disappeared from programming practice), then in MK, of course, everything interrupts are hardware, and they are divided into ria internal and external. Any interruption separately, as well as the possibility of their occurrence in general, require prior special permission.

It should be firmly understood that in order to initialize any interrupt, four actions must be done in the program: enable interrupts in general (they are disabled by default), then enable this particular interrupt, set one of the available modes for it, and finally set the interrupt vector: pointer to label , where the interrupt handler routine is located. And, of course, after that you need to write the handler itself, otherwise it will all go to waste. More on this in chapter 19.

Internal interrupts can originate from any device that is additional to the system core - from timers, from an analog comparator, from a serial port, etc. An internal interrupt is an event that occurs in the system and interrupts the execution of the main program. The system of internal interrupts in the AVR is quite branched and represents the main system for the interaction of devices with the system core, and we will return to this issue more than once.

MK AVR has at least two external interrupts, INTO, INT1 (most Mega have a third one - ICT2). An external interrupt is an event that occurs when a signal appears on one of the inputs specially designed for this. There are three kinds of events that cause an interrupt, and they can be set in the program: it can be a low voltage level, as well as a positive or negative edge on the corresponding pin. Curiously, interrupts on all of these events are executed even if the corresponding port pin is configured to output.

Let's briefly consider the features of using these modes. A low-level interrupt (the mode is set by default, it is enough to enable the corresponding interrupt to initialize it) occurs whenever a low level is present at the corresponding input. "Whenever" - this means that really everyone, that is, if the negative pulse lasts for some time, then the interrupt handling procedure, having ended, will repeat again and again, preventing the main program from working. Therefore, the usual scheme for using this external interrupt mode is to disable it immediately upon occurrence (the processing procedure, once it has already begun, will be executed once to the end) and allow it again only when the external influence should already end (for example, if it is a button press , then it should be allowed again by the timer in one or two seconds).

In contrast, rising or falling interrupts are executed once. Of course, there is no protection from contact bounce and cannot be, because the MC is not able to distinguish bounce from a series of short pulses. If this is critical, you must either take external measures to protect against chatter, or use the same method as for interrupt by level - inside the interrupt handler procedure, disable the interrupt itself with the very first command, and after some time in another procedure (by timer or by another event) to allow it again (this method of "anti-bouncing" is actually identical to the use of a single vibrator, see Chapter 15).

Details

an attentive reader has a legitimate question - why do we need an external level interrupt mode at all? The fact is that in all models it is performed asynchronously - at the moment when the low level appeared at the output of the MK. Of course, interrupt detection can only occur at the end of the current instruction, so very short pulses may be lost. But the INTO and INT1 interrupts in edge control mode are determined in most models the other way around, only synchronously - at the moment of the controller clock signal level difference, therefore their duration should not be shorter than one clock signal period. But this is not the most important thing: by and large, there would be no difference in these modes if it were not for the fact that the synchronous mode certainly requires the presence of this very clock signal. Therefore, an asynchronous external interrupt, respectively, can "wake up" the controller, which is in one of the deep power saving modes, when the clock generator is not working, but the synchronous one is not. And ordinary MKs, like the AT90S8515 of the Classic family (but not its mega-analogue!), can be brought out of deep "sleep" only by an external level interrupt, which is not always convenient to use. Most models of the Meda family (from the younger models - except for ATmegaS) have one more interrupt INT2, which occurs only on the fronts (it cannot on the level), but, unlike INTO and INT1, asynchronously. In the ATtiny2313 (but not in its “classic” counterpart!) such an asynchronous interrupt can occur on a signal from any of the 8 pins of port B. This greatly improves the usability of the controller in power saving mode.

Timers-Counters

in most AVR MKs there are two or three timer-counters, one of which is 16-bit, and the rest are 8-bit (in older Mega models, the total number of counters can be up to 6). All counters have the ability to preload values ​​and can work directly from the clock frequency (CK) of the processor or from it, divided by 8, 64, 256 or 1024 (in some cases by 16 and 32), as well as from an external signal. In general, the device of timers in the MK, as we said, is similar to the 561HEU / 14 counters (see Chapter 15), only their functionality has been significantly expanded.

In the AVR architecture, 8-bit counter-timers are assigned numbers 0 and 2, and 16-bit counters 1, 3, and so on. Some 8-bit counters (usually Timer 2, if there are two of them) can operate in asynchronous mode from a separate clock generator, and continue to function even if the rest of the MK is “sleeping”, which allows them to be used as real time clocks.

When using counter-timers as conventional counters of external pulses (and the reaction is possible both on the decline and on the front of the pulse), the frequency of the counted pulses should not exceed half the frequency of the MK clock generator (moreover, with an asymmetric external meander, the instruction recommends an even lower value of the limiting frequency - 0.4 of the clock). This is due to the fact that when counting external pulses, their fronts are detected synchronously (at the moments of a positive edge of the clock signal). In addition, it should be taken into account that the delay in updating the contents of the counter after the arrival of an external pulse can be up to 2.5 clock cycles.

These are quite strong limitations, therefore, for example, it is not very convenient to use the MC as a universal frequency meter - it is better to design high-speed circuits on the appropriate combinational logic or on FPGAs (programmable logic integrated circuits).

When a counter overflow occurs, an event occurs that can trigger the appropriate interrupt. The 8-bit counter Timer O in some cases is limited to this function. The Timer 2 counter, if present, can also trigger an interrupt on the coincidence of the counted value with some predetermined value. 16-bit counters are more “advanced” and can trigger interrupts by coincidence with two independently specified numbers A and B. In this case, the counters can be reset to zero or continue counting, and pulses can be generated on special pins (hardware, without program intervention).

In addition, 16-bit counters can "capture" (capture) external single pulses on a special pin. In this case, an interrupt can be called, and the contents of the counter are placed in a certain register. In this case, the counter itself can be reset to zero and start counting again, or simply continue counting. This mode is convenient to use for measuring the period of an external signal or for counting some irregular events (like the passage of particles in a Geiger counter). It is important that the built-in analog comparator, which is then used as a pulse shaper, can also be the source of such events.

All counter-timers can work in the so-called. PWM modes, that is, as 8-, 9-, 10- or 16-bit pulse-width modulators (PWM), and independently of each other, which allows you to implement multi-channel PWM. In the technical documentation, many pages are devoted to these modes, due to their complexity, multivariance and cumbersomeness. The simplest use of these modes for sound reproduction will be briefly discussed in Chapter 22 in connection with voice signaling. Note that sound synthesis is not the only and even not the highest priority purpose of PWM modes, they can also be used to control power or current (for example, when charging batteries), control motors, signal rectification, and digital-to-analog conversion.

In addition to timer-counters, all AVR controllers without exception have a Watchdog timer. It is intended mainly to bring the MK out of the power saving mode after a certain period of time, but can also be used for an emergency restart of the MK. For example, if the operation of the program depends on the arrival of external signals, then if they are lost (for example, due to a break in the line), the MC may “hang”, and the Watchdog timer will bring it out of this state.

Serial ports

Serial ports for exchanging data with external devices are the most important component of any MK; without them, its “communication” with the outside world is sharply limited. They are called sequential because only one bit is transmitted at a time (in some cases, simultaneous transmission and reception is possible, but still only one bit at a time). The most important advantage of serial ports over parallel ones (when whole bytes or nibble-tetrads are exchanged at the same time) is the reduction in the number of connections. But it is not the only one: paradoxically, but serial interfaces give a significant head start to parallel ones at high speeds, when line delays begin to affect the transmission rate. The latter cannot be made exactly the same, and this is one of the reasons why serial interfaces are now beginning to dominate (typical examples are USB and FireWire instead of COM, LPT and SCSI, or Serial ATA instead of IDE).

In microcontroller devices with our data volumes, of course, the transfer speed is of secondary concern to us, but the number of connecting wires is a very critical factor. Therefore, all external devices that we will deal with in this book will have serial interfaces.

Almost any serial port can be simulated in software using conventional MCU pins. Once upon a time, this was done even in the case of the most popular of these noptoB - UART. However, since then, MKs have acquired hardware serial ports, which, however, does not mean that they must be used. The ease of software simulation of serial ports is another advantage.

Of all the varieties of ports that may be present in the AVR MK, we will especially pay attention to the UART - Universal Asynchronous Receiver-Transmitter, "universal asynchronous transceiver". UART is the main part of any device that supports the RS-232 protocol, but not only it (it’s not for nothing that it is “universal”) - for example, industrial standards RS-485 and RS-422 are also implemented via UART, since they differ from RS-232 only electrical parameters and permissible speeds, and not the general logic of construction. Personal computers have a COM port that operates on the same RS-232 protocol, and the UART node is also its basic part.

Therefore, the UART serves as the main way to exchange data between the MK and the computer. Note that the absence of a COM port in most modern PC models is not an obstacle: there are USB-COM adapters for this, and an additional card with COM ports can be inserted into a desktop model.

marginal notes

Why is this so important to us? The fact is that by connecting the instrument layout to the computer, even if the exchange of data by the instrument functionality is not provided, the program is much easier to debug by simply temporarily inserting the operations of sending the values ​​of the involved registers to the PC in the right places of the program and receiving them in real time using which or a terminal emulator program. This is much more convenient than mastering the bulky AVR Studio, and even bundled with some expensive debug board. Therefore, my advice is to immediately make yourself a debug board containing a programming connector (see the next chapter) and a UART / RS-232 level converter with a connector for connecting a null modem cable (see chapter 21).

See Chapter 21 for more information on how to use the UART in practice. In addition to the UART, almost all AVR MCUs include the simplest of all serial ports, the SPI (Serial Peripheral Interface). The principle of the SPI device was mentioned in Chapter 16. Its fundamental simplicity played a partly bad role: it is difficult to meet two devices where the SPI protocols are completely the same, usually the exchange on this port is accompanied by one or another “bells and whistles”. It should be noted that AVR programming is also carried out via SPI, however, in general, this interface and SPI for data exchange are different things, although in most cases they have the same outputs.

But in this book, in Chapter 21, we will look at the more complex, albeit slower, I^C interface, which is needed more often, since so many peripheral devices work through it.

We will consider some other nodes of the MK family of AVR (for example, ADC) in the course of presenting specific circuits - this will be clearer. Here we will finish our protracted acquaintance with the microcontroller and move on to the question of how to program it.

Today we try to use a simpler microcontroller ATtiny2313 and connect to it a character LCD display containing two lines of 16 characters.

We will connect the display in a standard 4-bit way.

First, let's start, of course, with the microcontroller, since we are already very familiar with the display from previous lessons.

Open controller datasheet ATtiny2313 and see its pinout

We see that this controller exists in two types of cases, but since it fell into my hands in a DIP case, we will consider this particular version of the case, and in principle, they do not differ much, except in appearance, so how the number of legs is the same - 20 each.

Since there are 20 legs compared to the 28 legs of the ATMega8 controller, which we have been working on for the entire time and will continue to do, then, accordingly, there will also be less opportunities.

In principle, everything that the ATmega8 had was here, the only thing is that there are fewer ports. But since the task before us is to try to connect it via the SPI bus to another controller, this does not depress us much.

There are some other differences, but they are minor and we will get to know them as needed.

Let's assemble such a scheme here (click on the picture to enlarge the image)

The display is connected to the pins of port D. PD1 and PD2 are connected to the control inputs, and the rest to the pins of the display module D4-D7.

We will create a project with the name TINY2313_LCD, transfer everything to it except the main module from the project for connecting the display to Atmega8.

Of course, some things will need to be redone. To do this, you need to carefully study which leg is connected to what. The E bus of the display is connected to PD2, and the RS bus is connected to PD1, so let's make changes to the file lcd.h

#definee1PORTD|=0b0000 01 00 // set line E to 1

#definee0PORTD&=0b1111 10 11 // set line E to 0

#definers1PORTD|=0b00000 01 0 // set RS line to 1 (data)

#definers0PORTD&=0b11111 10 1 // set RS line to 0 (command)

As we can see from the selection in bold type, we have not undergone such dramatic changes.

Now the information inputs. Here we use the legs PD3-PD6, that is, they are shifted by 1 point compared to connecting to Atmega8, so we will also fix something in the file lcd.c in function sendhalfbyte

PORTD&=0b 1 0000 111; //we erase the information on the inputs DB4-DB7, we do not touch the rest

But that is not all. We used to shift the transmitted data by 4, and now, due to the above changes, we will have to shift them only by 3. Therefore, in the same function, we will also correct the very first line

c<<=3 ;

That's all the changes. Agree, they are not so great! This is achieved by the fact that we always try to write universal code and use exactly macro substitutions. If we had not spent time on this, then we would have to correct the code in almost all the functions of our library.

In the main module, we do not touch the initialization of port D, let the whole get into the exit state, as in lesson 12.

Let's try to assemble the project and first see the result in proteus, since I also made a project for it, which will also be in the attached archive with the project for Atmel Studio

Everything works great for us! Here's how you can, it turns out to quickly remake the project for one controller under another.

Proteus is very good, but real parts are always more pleasant to look at. The whole circuit was assembled on a breadboard, since I did not make and did not assemble a debug board for this controller. We will connect the programmer through a standard connector like this

Here is the whole diagram

Everything is standard here. Pull-up resistor for RESET, etc.

Now, before flashing the controller in avrdude, we need to select the controller and read its flash memory

Then go to the FUSES tabs and set the fuses correctly. Since we do not have a quartz resonator, we set the fuses in this way

Connecting an LED to an I/O port line

After studying this material, in which everything is described in great detail and in detail with a large number of examples, you can easily master and program the input / output ports of AVR microcontrollers.

  • Part 2: Connect LED to I/O port line
  • Part 3. Connecting the transistor to the I/O port line
An example will be considered on a microcontroller ATMega8 .

We will write the program in Atmel Studio 6.0 .

We will emulate the circuit in Proteus 7 Professional .

The first example in the study of microcontrollers is connecting and controlling an LED, this is the simplest and most obvious example. This example has become a classic in the study of microcontrollers, like the "Hello World!" when learning other programming languages.
The maximum current that each I/O port can handle is 40 mA.
The maximum current that each I/O port line can carry is 20 mA.
Before connecting a load, including an LED, to the I / O port lines, you need to know that you can burn the microcontroller by exceeding the permissible load on the I / O port line.
To limit the current that flows through the I / O port lines of the microcontroller, you need to calculate and connect a resistor.

Fig: LED pinout.

Fig: Connecting an anode LED to a microcontroller.

Fig: Connecting the LED cathode to the microcontroller.

The resistance of the current-limiting resistor connected to the lines of the I / O ports when connecting the LED is calculated by the formula:

Where:
- Vs- power supply voltage;
- Vsp- voltage drop on the I/O port lines;
- Vd- direct voltage drop across the LED;
- ID- direct current on the LED;
- Kn- coefficient of reliability of LED robots;

Example:
- power supply voltage - 5V;
- direct voltage drop across the LED - 2B ;
10mA (taken from datasheet to LED);
- coefficient of reliability of LED robots - 75% (taken from datasheet to LED);
- voltage drop on the I / O port lines - 0.5V (Taken from the datasheet to the microcontroller: Vol(output low voltage) - if current flows in, and Voh (output high voltage) - if current flows out);

So the resistor value R = 166.66 Ohm, the nearest higher resistance value is selected.

If the forward voltage of the LED is not known, the resistance can be calculated using Ohm's law.

Where:
- U- voltage applied to the circuit section;
- I

Example:
4.5V;
- rated current of the I/O port line - 20mA.

Determining the value of the resistor R, it is necessary to calculate the power P, measured in watts, that will be released in the resistor as heat when current flows in the circuit.

Where:
- U- voltage applied to the circuit section;
- I- rated current of the I/O port line.

Example:
- the voltage applied to the circuit section - 4.5V;
- direct current on the LED - 20mA.

Having calculated the dissipated power on the resistor, we choose the nearest higher value of the power of the resistor. If the power dissipation of the resistor is insufficient, then it may fail.

- connecting a low-power LED with an anode to the I / O port line:

#include // Main program int main(void) ( // Set up the input/output ports DDRC = 0b11111111; // Set all bits of port C to "Output" mode PORTC = 0b11111111; // Set all bits of port C to log. "1" (Port output voltage is Vcc) // Eternal loop while (1) ( ) )

- connecting a low-power LED with a cathode to the I / O port line:

// Include external libraries #include #include // Main program int main(void) ( // Set up the input/output ports DDRC = 0b11111111; // Set all bits of port C to "Output" mode PORTC = 0b00000000; // Set all bits of port C to log. "0" (Port output voltage equal to GND) // Eternal loop while (1) ( ) )

- connecting a low-power LED with an anode and a cathode to the I / O port line:

// Include external libraries #include #include // Main program int main(void) ( // Set up the input/output ports DDRD = 0b11111111; // Set all bits of port D to the "Output" mode PORTD = 0b11111111; // Set all bits of port D to log. "1" (At the port output, the voltage is Vcc) DDRC = 0b11111111; //Set all bits of port C to the "Output" mode PORTC = 0b00000000; //Set all bits of port C to log. "0" (At the output of the port, the voltage is equal to GND) / / Eternal loop while (1) ( ) )