Procedure for programming avr microcontrollers. Advice for novice microcontroller programmers. Which development environment should I use to program the selected microcontroller?

The schematic diagram of the LPT port programmer is shown in the figure. As a bus driver, use the 74AC 244 or 74HC244 (K1564AP5), 74LS244 (K555AP5) or 74ALS244 (K1533AP5) microcircuit.

LED VD1 indicates the recording mode of the microcontroller,

LED VD2 - reading,

LED VD3 - presence of power supply to the circuit.

The circuit takes the voltage required for power supply from the ISP connector, i.e. from the programmable device. This circuit is a redesigned STK200/300 programmer circuit (added LEDs for ease of operation), so it is compatible with all PC programmer programs that work with the STK200/300 circuit. To work with this programmer, use the program CVAVR

The programmer can be made on a printed circuit board and placed in the LPT connector housing, as shown in the figures:




To work with the programmer, it is convenient to use an LPT port extension, which is easy to make yourself (for example, from a Centronix cable for a printer), the main thing is not to spare the conductors for the ground (18-25 connector legs) or buy. The cable between the programmer and the programmable chip should not exceed 20-30 cm.

programs and data are separated (unlike classical architecture
von Neumann in ordinary computers where the memory is shared). Separate tires for
these memory areas significantly speed up program execution: data and
teams can be selected simultaneously.

32 general purpose registers (RON). Atmel was the first company, far
departed from the classical model of the computing core, in which
command transmission involves the exchange of data between the ALU and storage
cells in shared memory. The introduction of RON in such quantities (remember that in
architecture X 86 there are only four such registers, and in x 51 concept of RON, as such,
absent) in some cases makes it possible to completely abandon the location of the global
ball and local variables in RAM and from the use of the stack, operations with
which complicate and clutter the program. As a result, the structure of the ac-
A sample program is closer to programs in high-level languages.
True, this led to some complication of the command system, the nomenclature
of which there are more for AVR than in other RISC families (although a significant
some instructions are aliases).

Flash program memory(10,000 erase/write cycles) with the ability
in-system reprogramming and downloading via serial
channel directly in the finished circuit. About the advantages of this approach, which has now become
generally accepted, described in detail in administered.

Separate area of ​​non-volatile memory(EEPROM, 100,000 cycles
erase/write) for data storage, with the ability to write by software
by, or external download via SPI interface.

Built-in analog signal processing: analog
comparator and multi-channel 10-bit ADC.

Watchdog timer, allowing automatic reboot
controller at certain intervals (for example, to exit
"sleep" mode).

Serial SPI Interfaces, TWI (I

C) And UART (USART), I allow-

capable of communicating with most standard sensors and
other external devices (including such as personal computers)
hardware.

Timers-counters with preset and the ability to select the source of counting
nal pulses: usually one or two 8-bit and at least one
16-bit, including those that can operate in multi-channel 8-, 9-,
10-, 16-bit pulse width modulation (PWM).

Ability to operate at clock speed from 0 Hz to 16–20 MHz.

Supply voltage range from 2.7 to 5.5 V(in some cases from 1.8 or
up to 6.0 V).

Numerous energy saving modes, differing in the number of nodes,
remaining connected. Exiting "sleep" modes using watchdog
timer or external interrupts.

Built-in power monitor- voltage drop detector (Brown-out
Detection).

Not all features characteristic of various models are listed here.
AVR. We will get to know some others later, as well as in practice.
Let's look at the above in more detail. But first let's give a general description
various AVR families in terms of their primary purpose.

AVR families

In 2002, Atmel began releasing new subfamilies of 8-bit MKs based on
AVR cores. Since then, all MKs of this family are divided into three groups (subfamily
va): Classic, Tiny and Mega. MK of the Classic family (AT90S xxxx) are no longer produced;
the one that stayed in production the longest was a very successful one (simple, compact and
high-speed model) AT90S2313, but it was also replaced in 2005 by
ATtiny2313. All "classic" AVRs with the first numbers 2 and 8 in the name
models (which means the amount of program memory in kilobytes) have analogues in
families Tiny and Mega. For Mega, during programming it is possible to install special
cial compatibility bit, which allows the use without any changes
use programs created for the Classic family. Therefore, a number of examples in
In order to simplify the presentation, this book is presented in a version for the family
Classic.
Examples of different types of cases in which AVR chips are produced,
are shown in Fig. 1.1. More information on this topic can be found in
Appendix 1(Table A1.2), as well as in the technical documentation for the devices.
Note that for amateur radio needs and prototyping, it is most convenient to use micro-
circuits in PDIP packages, but not all MK models are produced in such packages.
All families can have two modifications: the letter "L" in the designation says
about the extended power range 2.7–5.5 V, the absence of such a letter means the
power range 4.5–5.5 V. When choosing a specific type of microcircuit, you need to be
careful, since the L-versions are also less fast-acting,
Most of them have a maximum clock speed of 8 MHz.
For "regular" versions the maximum frequency is 16 or 20 MHz. Although, how
As a rule, when starting L-chips with a supply voltage of 5 V at frequencies up to 10–
12 MHz problems should not be expected (similar to the version without the letter L, quite
can operate at a supply voltage of about 3 V, of course, not at extreme
frequency values), however, when designing highly reliable devices
companies should take this requirement into account.
Tiny chips have Flash ROM of programs with a capacity of 1–8 kbytes and are located in
mainly in packages with 8–20 pins (except ATtiny28), i.e. they are generally intended
are intended for simpler and cheaper devices. This does not mean that they are possible -
The properties are in all cases more limited than those of the Mega family. For example,
At under $2, the ATtiny26 contains a high-speed PWM timer
mode (other models do not have this), as well as an 11-channel ADC with the possibility
Possibility of operation in differential mode, with adjustable input amplifier

Part I. General principles of design and operation of Atmel AVR

and a built-in reference voltage source, which is typical for high-power
share. The ATtiny2313 chip, as already mentioned, is an improved
new version of one of the most versatile and convenient "classic" AVRs
AT90S2313.

Rice. 1.1. Examples of different types of housings for AVR MCUs

The Mega subfamily is equipped with Flash ROM of programs with a capacity of 8–256 KB and a housing
themselves with 28–100 pins. In general, MKs of this group are more sophisticated than
Tiny, have a more extensive system of embedded devices with more advanced
functionality.
Tables with the main characteristics of some Tiny and Mega models from among
the most popular ones are listed in Appendix 1. Some general techniques are also given there.
technical characteristics of the AVR family. More detailed information can be obtained from
from and proprietary technical documentation, which is available on the website
Atmel for every model.
In addition to these three families, specialized ones are produced based on the AVR core
microcircuits for working with a USB interface (AT90USB xxxx), industrial in-
CAN interface (AT90CAN xxx), for controlling LCD displays (ATmega329, etc.),
with wireless IEEE 802.15.4 (ZigBee) interface for trade and
some others. Recently, some microcontrollers of the Tiny and
Mega began to be produced in versions with ultra-low consumption (technology
picoPower with a supply voltage of 1.8 V, at the end of the name of the MK of this series
letter "P" added) and high temperature for automotive use
industry (Automotive versions). The XMega family has appeared with voltage
power supply 1.8–3.6 V, increased speed (clock frequency up to 32 MHz),

Chapter 1. Overview of Atmel AVR microcontrollers

12-bit 16-channel ADC and 2–4 channels DAC (still in the structure
AVR they were missing), several UART channels and other serial
ports (and with the ability to work in offline mode, when stopped
kernel), built-in cryptography support, advanced mode
picoPower and other bells and whistles. There is also a separate family of 32-times
in-line MK AVR32, designed for high-speed applications such
such as video stream processing or real-time image recognition.

Peculiarities
practical use of MK AVR

When using AVR, a number of practical issues arise, ignoring
correction of which can sometimes lead to inoperability or failure of the device.
swarms (and in some cases - even the impossibility of programming it).
For example, one of these problems is the possibility of losing the contents of the EEPROM
when turning off the power. We will consider this and similar problems in detail in
relevant chapters. Here we will focus on some general issues
turning on the AVR MK.

About consumption

AVR MCUs consume an average of 5–15 mA (excluding the consumption of external devices).
roy through the conclusions of the MK). The current consumption depends not only on the degree of "navo-
"term" of the model, but also on the clock frequency and supply voltage. In Fig. 1.2
shows a typical diagram of the dependence of current consumption on supply voltage
tion and clock frequency for the younger models of the Mega family.
From Fig. 1.2, in particular, it follows that consumption can be significantly reduced by
reducing the clock frequency in cases where the program execution time is not
critical. This allows you to simplify the program by eliminating the energy modes
savings: for example, when installing a “clock” quartz of 32,768 Hz as a so-
tyrating MK consumption can be on the order of 200–300 μA.

Z

NOTES ON THE MARGIN

A current consumption value of 1–2 mA or less can be conditionally considered acceptable for
battery devices that are designed for long-term continuous operation
work. AA size elements (alcaline type, i.e. alkaline) have a capacity of
charging about 2000 mAh, i.e. a device with the specified consumption from these elements
works for at least 1000 hours (actually even a little more) or more than 40 days. Time
operation on D-size batteries with an energy capacity of about 15–18,000 mAh
takes about a year, which is enough for most practical applications.
Choose to power such devices (especially those that turn on periodically)
for a short time) it is the alkaline elements that should be used, since they have great
capacity, do not leak when overdischarged and, most importantly, have a significantly longer service life
storage (about 7 years) compared to other types of elements.

But a careful consideration of the issue shows that this is precisely what simplifies
program - in the vast majority of cases, the benefits are more

Part I. General principles of design and operation of Atmel AVR

low clock speed and are limited. Graphs in Fig. 1.2 are linear, hence
it follows that in proportion to the decrease in clock frequency, the execution time increases
commands. Thus, a procedure whose execution at a clock frequency
4 MHz will take 100 µs, at a clock speed of 32,768 Hz it will last more than 12 ms.
It is easy to calculate that in both cases the amount of energy consumed by
performing this procedure will be the same.

Rice. 1.2. Diagram of current consumption versus supply voltage

and clock frequency for younger models of the Mega family

Therefore, we can draw the following general conclusion: if you do not want to delve into
subtleties of energy saving modes and do not implement them in the program, then for general
To reduce consumption, you need to choose a clock frequency as low as possible (at
In practice, it is usually sufficient to limit the value to 1 MHz, since further
the reduction will most likely have no effect due to the additional consumption of external
them circuits, inevitably present in all circuits). If you have a warning
We looked at one of the “deep” energy saving modes (see. chapter 4), then the clock
Frequency from the point of view of total consumption is practically irrelevant.
Another thing is the choice of supply voltage, which it is advisable to do as much as possible
less if external devices allow it. Dependence of current consumption on
supply voltage, as can be easily understood from the graphs in Fig. 1.2, nonlinear: with increasing
As the voltage increases, the current consumption increases rapidly. Therefore, reduce
supply voltage even taking into account the clock frequency limitation for most
va AVR models (no more than 8 MHz with a 2.7 V supply) are still profitable. For example,
device with 3 V power supply at a clock frequency of 8 MHz, according to Fig. 1.2, will be
consume about 3 mA or, in terms of power units, 9 mW; for the procedure-

Chapter 1. Overview of Atmel AVR microcontrollers

ru with a duration of 100 μs will require an energy of 0.9 μJ. At a frequency of 16 MHz the same pro-
The procedure will take 50 µs, but consumption at the required supply voltage of 5 V
will be about 14 mA, i.e. 70 mW; in total it will take energy to complete the procedure
3.5 µJ, almost 4 times more.
For all external digital devices, with very few exceptions, you can
get a modern analogue designed to operate at voltages of 2.7–
3.0 V (and even lower if the controller model allows it), so on this side
no restrictions; that most of the examples in this book are focused on
The supply voltage is 5 V, there is only a tribute to tradition. Moreover, these examples are like
As a rule, they imply power supply from the network, where consumption is not very significant.
readings. LED indicators can limit the decrease in supply voltage
tors (due to the fact that the direct voltage drop across the LEDs itself is
is about 2 V, and for large indicators even 5 V to control the under-
exactly), but in such devices the controller consumption no longer plays a big role
roles: four seven-segment digits themselves will consume a current of the order of
100 mA or more. Another case is represented by analog circuits, where the increase
supply voltage is beneficial from the point of view of increasing the signal-to-noise ratio.
Note that the AVR pins can produce significant long-term
current (up to 20-40 mA), but do not forget about the general total limitation
for consumption by power output (see . table P1.3). It should also be noted that
when applying analog voltages to the ADC inputs, the input digital CMOS-
element (input of the corresponding port) is not disabled, and with the value of this
voltage near the element’s response threshold, this can lead to increased
consumption due to the flow of through current through the output stages
CMOS (including sometimes when the microcircuit is in sleep mode,
cm. chapter 14). Microcircuits with picoPower technology do not have this drawback.

Some features of using AVR in circuits

Most MK pins have a built-in plug-in “pull-up”
(i.e. connected to the power bus) resistor, which would seem to solve one of the
common circuit problems when the presence of such a resistor is required
for connecting two-pin buttons or "open collector" outputs.
However, in critical cases an external resistor with a resistance of 2–
5 kOhm (in consumption-critical cases up to 10–30 kOhm).
The pull-up resistor should be installed not only at the /RESET pin
(which will be discussed in chapter 2), but also in the case when the SCK, MOSI and MISO pins
corresponding ports are used for programming and are connected to
ISP programming connector (see chapter 5), as well as from the outputs of external interrupts
vaniya, if they are involved. If these conclusions are not “pulled up” to voltage
power supply with additional resistors (although this is not specified in the technical
documentation), then false triggering of external interrupts cannot be ruled out,
restarting the system, and with very powerful interference - even damaging the program in memory -
these programs. On the other hand, when programming outputs also serve as

Part I. General principles of design and operation of Atmel AVR

Most of the usual ports configured for output, and the device uses
energy saving modes, the presence of “pull-up” resistors can lead to
to unnecessary current consumption (when setting the output to logical zero through the resistor
side, current will flow from the power source to the input of the MK). If one of the re-
energy saving modes, you need to carefully analyze the circuit in order to use
include situations in which current flows through these resistors.
You should also always install external resistors when operating the MK pins on
common bus, as in interface I

C (or simply by connecting the MK input to

output of another open collector device, such as power supply monitors
developments described in chapter 3), when connecting to two-pin buttons (especially
if there is an external interrupt, see chapter 4 And 5 ). Built-in resistance
resistor (actually, of course, a field-effect transistor)
in such cases is too great for electromagnetic interference ("on-
vodka") they effectively "sat" on it.
AVR chips, like any CMOS logic, due to their high threshold
tyings are effectively protected from interference on the ground bus. However they behave
much worse with interference on the power bus. Therefore, do not forget about untie-
power capacitors, which must be installed directly at the pins of the power supply
tania (ceramic 0.1–0.5 μF), as well as about the quality of network rectifiers and
stabilizers.

C H A P T E R

General device
memory organization,
clocking, reset

The general structure of the internal structure of the AVR MK is shown in Fig. 2.1. In this
the diagram shows all the main components of the AVR (except for the JTAG module);
in some models, some components may be missing or different -
characteristics, only the common 8-bit processor remains unchanged
new core (GPU, General Processing Unit). Let us briefly describe the most important components
nents, most of which we will consider in detail later.
Let's start with memory. There are three types of memory in the AVR structure: flash-
program memory, RAM (SRAM) for temporary data and non-volatile memory
memory (EEPROM) for long-term storage of constants and data. Let's look at them
separately.

Program memory

The volume of built-in flash memory of programs in AVR controllers ranges from
1 KB for ATtiny11 to 256 KB for ATmega2560. The first number in the name can-
division corresponds to the value of this memory from the series: 1, 2, 4, 8, 16, 32, 64, 128 and
256 kbytes. Program memory, like any other flash memory, has a page
organization (page size, depending on the model, ranges from 64 to
256 bytes). The page can only be programmed as a whole. Number of cycles
reprogramming reaches 10 thousand.
From a programmer's point of view, program memory can be considered constructed from
separate cells - words of two bytes each. The program memory device (and only
this memory) by double-byte words - a very important point that needs to be
firmly grasp. This organization is due to the fact that any team in AVR
is exactly two bytes long. The exception is teams

and some

ry others (for example,

), which operate with 16-bit and longer

addresses, the length of these commands is four bytes and they are used only
in models with program memory larger than 8 kbytes (for more details, see chapter 5). In
In all other cases, the program counter is shifted when the next one is executed.

Part I. General principles of design and operation of Atmel AVR

commands into two bytes (one word), so the required memory capacity is easy
count, knowing the number of commands used. Absolute addresses in memory
grams (indicated, for example, in interrupt vector tables in technical
description of MK) are also counted in words.

Rice. 2.1. General block diagram of AVR microcontrollers

Z

NOTES ON THE MARGIN

Let us give an example of an interesting addressing case that represents
command for reading constants from LPM memory (as well as ELPM in MK with program memory
128

kbytes or more). This command involves reading from byte address indicated -

nomu in the two highest RONs (forming the so-called Z register, see below). However, so as not
violate the “purity” of the concept of organizing program memory, according to the developers
confused this simple question by indicating in the description that when calling the LPM command, the old
The next 15 bits of the Z register address word in memory, and the least significant digit selects
low or high byte (if the bit is equal to 0 or 1, respectively) of this

words. It is easy, however, to notice that the byte and word organization of memory when
com approach are equivalent.

Last address of existing program memory for a specific model
denoted by a constant

By default, all AVR controllers are always

begin program execution at address $0000. If there is no interruption in the program
ny, then the application program can start from this address. Otherwise

tea at this address is the so-called. table interrupt vectors, details
which we will talk about in chapters 4 And 5 . Here we only point out that the first
this table (at the same address $0000) always contains a reset vector

which indicates the procedure performed when resetting the MK (including
when turning on the power).

P

NOTE

In AVR assembler you can represent hexadecimal numbers in "Pascal"
style, preceded by a $ sign, while the C language style (0x00) is also valid, but
The "Intel" method (00h) does not work. Read more about the designations of different numbers
number systems in the AVR assembler, see. chapter 5.

The last program memory addresses of Mega family controllers may contain
lie so-called loader- a special program that manages the loading and
unloading application programs from the main memory. In this case,
the location of the reset vector and the entire interrupt vector table (i.e., actually on-
starting address from which program execution begins) can be changed
not possible by installing special configuration cells (see. chapter 5).

Data memory (RAM, SRAM)

Unlike program memory, the data memory address space is addressed
byte by byte (not word by word). Addressing is completely linear, without any division
into pages, segments or jars, as is common in some other systems.
Junior MKs of the Tiny family (including Tiny1 X and Tiny28) data memory, such as
howl, they do not, limited only to the register file (RON) and the input registers
yes-output (RVV). In other models, the amount of built-in SRAM ranges from
128 bytes in Tiny family members (for example, ATtiny2313) up to 4–8 kbytes
for older Mega models.
The address space of static data memory (SRAM) is conventionally divided into
several areas shown in Fig. 2.2. The part from the
related to the built-in SRAM itself, before it in the order of addresses are located
but the address space of registers (the first 32 bytes are occupied by RON, another 64 -
RVV). For older Mega models with a complex structure (for example, ATmega128)
64 I/O registers may not be enough, so for additional
additional RVVs are allocated a separate address space (from $60 to max.
maximum possible value $FF in byte addressing, a total of such registers can
maybe only 160).

Z

NOTES ON THE MARGIN

In the architecture of the AVR MK, the concept of “input-output” is used in two senses: firstly

First, there are “input/output ports” (I/O ports), which we will look at in chapter 3.
Secondly, “input-output registers” (IO) in the AVR structure are the registers
which provide access to additional components external to

connection to the GPU, with the exception of RAM (including I/O ports). Such a sub-
separation brings the structure of the AVR MK closer to the familiar configuration of a personal
computer, where access to any external to the central processor
components other than memory are accessed through I/O ports.

Part I. General principles of design and operation of Atmel AVR

For some Mega models (ATmega8515, ATmega162, ATmega128, ATmega2560
etc.) it is possible to connect external memory up to
64 kB, which can be any static
variety (SRAM, Flash or EEPROM) with pa-
parallel interface.
Note that the addresses of RON and RVV do not take away the pro-
space of the data RAM (with the exception of the connected
expected external memory for older Mega models,
whose maximum address is limited by the value
$FFFF): so, if a specific MK model has
512 bytes of SRAM, and register space is occupied by
first 96 bytes (up to address $60), then SRAM addresses
will occupy address space from $0060 to $025F
(i.e. from the 96th to the 607th cell inclusive). End
built-in data memory is indicated by a constant

Rice. 2.2. Address space

static data memory (SRAM)

AVR microcontrollers

Memory read/write operations work the same with any addresses from the
blunt space, and when working with SRAM you need to be careful: instead of
writing to memory, you can easily “get” into some register. For example,
register value load command

to the register

) is equivalent

writes to SRAM at address zero (

). Address in memory for RON sov-

falls with his number. At the same time, for direct entry into the RVV according to his
address in memory should be added $20 to the register number: thus, the flag register

which for most models is located at the end of the RVV table at
$3F, has address $5F in memory. Install RON and RVV by direct addressing pa-
It’s inconvenient to remember: such a recording always takes two bars instead of one, typically
go for most other commands, although this can sometimes bypass restrictions
to manipulate some RVVs. But if there is a ready-made program, I work -
with SRAM, then when replacing processor models with older ones you need to be
careful due to the fact that low SRAM addresses in them may overlap
additional RVV.

Chapter 2. General structure, memory organization, clocking, reset

Non-volatile data memory (EEPROM)

All AVR MK models (except for the discontinued ATtiny11) have a built-in
EEPROM for storing constants and data when power is turned off.
In different models, its volume varies from 64 bytes (ATtiny1x) to 4 kbytes (higher
Mega models). The end of the EEPROM is indicated by a constant

(this denotes

This was introduced only for later AVR models, therefore when using
sometimes you will have to determine this constant yourself). Number of restart cycles
EEPROM programming can reach 100 thousand.
Let us recall that EEPROM differs from Flash in the possibility of selective pro-
programming byte by byte (in principle, even bit by bit, but this method is not available
user). However, in older models of the EEPROM family, like flash memory
programs, has a page organization, however, these pages are small - up to
4 bytes each. In practice, as when programming EEPROM in serial
body channel (i.e., via the SPI programming interface), and when recording and
when reading EEPROM from a program, this feature does not matter, and access is
is displayed byte by byte.
Reading from EEPROM is carried out within one machine cycle (though
In practice, it stretches over four cycles, but the programmer needs to keep track of this.
not required). But writing to EEPROM is much slower,
and, moreover, at a precisely undefined speed: a write cycle of one byte can
take from 2 to ~4 ms or more. The recording process is regulated by the built-in R.C.-
a generator whose frequency is unstable (at a lower supply voltage
you can expect the recording time to be longer). For such a time, under normal conditions,
At high frequencies, the MK manages to execute several thousand commands, so the program
The recording procedure requires care: for example, you need to ensure that
so that at the time of recording the interruption does not get “jammed” (for more information about this, see gla-
you 4
And 9 ).
The main difficulty when working with EEPROM is the possibility of damage to its components.
held when the supply voltage does not decrease quickly enough at the moment
shutdown This is due to the fact that when the supply voltage is reduced to
a certain threshold (below the threshold of stable operation, but not sufficient for full
turn off) due to voltage fluctuations, the MK begins to perform arbitrary
nary commands, including the ability to carry out the procedure of writing to EEPROM. If
take into account that a typical AVR MK command is executed in tenths of a microsecond,
then it is clear that no real power source can provide a reduction
voltage to zero in the required time. According to the author's experience, when powered by ordinary
stabilizer type LM7805 with recommended values ​​of capacitance
at the input and output, the contents of the EEPROM will inevitably be damaged due to
about half the time.
This problem should not exist if the constants are written to the EEPROM
when programming the MK, but there is no recording procedure in the program (about
how to generate a data file for EEPROM, see section "Directives and functions"
tion" of Chapter 5
). The greater safety of data in such cases is confirmed by em-

Part I. General principles of design and operation of Atmel AVR

pirical observations, and the fact that permission to write to EEPROM is procedural
ra two-stage (see. chapter 9). In all other cases (and there are, obviously,
the absolute majority - user settings are most often stored in EEPROM
new and current configuration when turning off the power) have to be accepted
special measures. The most cardinal and universal of them is the statute
New external power monitor that keeps the MK in the reset state when
supply voltage decreases below a threshold value. Serves the same purpose
built-in voltage drop detector (Brown-out Detection, BOD), available
in almost all Tiny and Mega models, but technical documentation does not exclude
At the same time, it is necessary to ensure the reliability of duplicating it with an external power monitor.
For more information about the BOD circuit and MK reset modes, see later in this chapter, and about the program
For EEPROM installation and precautions when using it, see chapter 9.

Clock methods

The canonical method of clocking an MK is to connect a quartz resonator to
corresponding conclusions (Fig. 2.3, A). Capacity of capacitors C1 and C2 in a typical
case should be 15–22 pF (can be increased to 33–47 pF from one
temporary increase in consumption). Most Tiny and Mega models have
There is a special configuration bit

which allows you to adjust

consumption. When this bit is set to 1 (unprogrammed state)
the range of oscillations of the generator decreases, but at the same time the possible
frequency range and general noise immunity, so use this mode
Not recommended. Low frequency quartz resonator can also be selected
(for example, “hourly” 32,768 Hz), while capacitors C1 and C2 may be absent -
vat, because during installation

the value 0 includes those included in the

MK internal capacitors with a capacity of 36 pF.
The quartz resonator can be replaced with a ceramic one. The author of these lines managed
run the MK at non-standard frequencies, using instead of quartz in the same sub-
including a miniature inductance (with its value of 4.7 μH and the capacitances of the
91 pF capacitors, the frequency is about 10 MHz), which at the same time allows a little
reduce the dimensions of the circuit.
Naturally, the MC can also be clocked from an external generator (Fig. 2.3, b). Oso-
This is especially convenient when you need to either synchronize the MK with external components
nents, or get a very precise clock frequency by selecting the appropriate
blowing generator (for example, Epson SG-8002 series).
On the contrary, when accuracy is not required, you can connect an external R.C.-chain
(Fig. 2.3, V). In this circuit, capacitance C1 must be at least 22 pF, and resistor R1
selectable from the range 3.3–100 kOhm. The frequency is determined by the formula
F= 2/3 R.C.. You don’t have to install C1 at all if you write down the log. 0 in config-
tion cell

Thus connecting the internal 36 pF capacitor.

Finally, you can completely abandon external components and make do with built-in
nom R.C.-a generator that is capable of operating at four approximate

Chapter 2. General structure, memory organization, clocking, reset

frequency values ​​(1, 2, 4 and 8 MHz). Some models provide the ability
adjusting the frequency of this generator (for more details, see or technical description
specific models). This opportunity is best used in
younger Tiny models, produced in an 8-pin package - then the conclusions
designed to connect a resonator or an external generator, you can
use for other purposes, like regular I/O ports.

Rice. 2.3. Methods for clocking an AVR microcontroller using: A- quartz resonator;

b- external generator; V - R.C.-chains

Classic Built-in Family R.C.-does not have a generator, but a special configuration-

These MKs have significantly fewer tion cells, and in the general case they can’t be used

to pay attention. This is not the case for other families. Default MK families

Tiny and Mega are set to work with the built-in generator on
frequency 1 MHz (

0001), so for other modes you need the appropriate

install configuration cells properly

(see table 2.1). Wherein

It should be taken into account that the condition of the cells

0000 (mirrored in relation to

the most commonly used value for a quartz resonator 1111) is re-

puts the MK into clock mode from an external generator, and at the same time it cannot

even program without supplying an external frequency. About recommended settings

for configuration cells and the features of their programming, see also

chapter 5.

Table 2.1. Installing configuration cells CKSEL

depending on clock modes

CKSEL3...0

Clock source

Frequency

External frequency

Built-in R.C.-generator

Built-in R.C.-generator

Built-in R.C.-generator

Built-in R.C.-generator

External R.C.-chain

Part I. General principles of design and operation of Atmel AVR

Table 2.1(ending)

CKSEL3...0

Clock source

Frequency

External R.C.-chain

0.9... 3.0 MHz

External R.C.-chain

3.0... 8.0 MHz

External R.C.-chain

8.0... 12 MHz

Low frequency resonator

Quartz resonator

0.4... 0.9 MHz

Quartz resonator

0.9... 3.0 MHz

Quartz resonator

3.0... 8.0 MHz

1xxx (CKPOT=0)

Quartz resonator

Reset

Reset (RESET) is the setting of the initial operating mode of the MK. Wherein
all RVVs are set to the default state - as a rule, these are zeros in
all categories, with a few exceptions (but RON can accept production
free values, so if necessary, start with a specific one
Variable values ​​should be set at the beginning of the program forcibly).
After a reset, the program starts executing from the starting address (by default
this is the address $0000).
Reset always occurs when power is turned on. In addition, sources of reset-
The following events may occur: hardware reset, i.e. low level supply
voltage to the RESET input (it is more correct to designate it with inversion: /RESET, because
the active level here is low, and we will stick to this rule); finished
counting down the set watchdog timer interval; circuit triggering
BOD. Meaning of the least significant four bits of the status register

must signal

information about the source from which the reset was made the previous time (installed
new to 1 bit 0 - power-on reset, bit 1 - hardware reset, bit 2 - from
BOD circuits, bit 3 - from the watchdog timer). In practice, according to the author’s experience, according to
The states of this register reliably differ from all others only in the states
timer reset (other flags may all be set at the same time)
temporarily). Nevertheless, this information can be useful, for example, when analyzing
analysis of the reasons for interruptions in the operation of devices operating around the clock (see. chapter 12).
Junior MKs of the Tiny family (except ATtiny28) do not have a built-in “pull-up”
th" resistor at the /RESET pin, therefore, for reliable operation, precautions should be taken
see connection of an external resistor of 2–5 kOhm from this pin to
supply voltage. The author also strongly recommends installing
suitable resistor for any AVR models, since the built-in resistor has a large
high nominal value (100–500 kOhm) and noise can be induced on it, which can cause
ty to an unpredictable reset. Also (although in technical descriptions such

Chapter 2. General structure, memory organization, clocking, reset

mending and is not contained) it would not hurt to install a capacitor 0.1–0.5 µF from
/RESET output to ground - this smoothes out the inevitable voltage bounce and
the rising edge of the voltage at the /RESET pin is slightly longer than
with increasing supply voltage: when the circuit’s response threshold is reached
reset, the supply voltage of the entire MK will already be established.
In Tiny models, produced in an 8-pin package (ATtiny11–ATtiny15),
If an external reset is not required, the /RESET pin can perform the functions normally
th I/O port. With just one caveat: when configuring this
contact to the output, it operates as an open collector output, and not as a conventional
nal logical element (for the configuration of port pins, see chapter 3).
The most preferred way to organize a power-on reset is as follows:
already mentioned earlier - installing an external power monitor. For example, when
For a 5-volt power supply, the popular MC34064 microcircuit with a trigger threshold is suitable.
4.6 V and typical consumption of about 300 µA or its more modern
analogue (for example, MAX803L with a consumption of 12 μA). For three-volt power supply
suitable circuit MAX803R (2.6 V) or a suitable version of DS1816 with the corresponding
current voltage. All listed microcircuits are three-pin (power, ground
la", reset control pin) and have an open collector output, i.e.
provide for the installation of a “pull-up” resistor. Typical response time
The duration of these microcircuits when the voltage decreases is microseconds, which provides
data safety in EEPROM. When the voltage increases, they provide
large time delay (on the order of fractions of a second), which allows reliable
reset the MK without rattling.
Built-in BOD circuit provides response times on the order of microseconds
delay to return to operating condition after voltage restoration, op-
determined by the same settings as the reset delay (cells

clock frequency of 4 MHz) and even its maximum possible value of ~68 ms can
turn out to be insufficient to bypass the chatter that occurs when the voltage decreases
power supply voltage of an autonomous source. To select the BOD operating mode, use
press three configuration cells

having the following states:

111 (default setting) - BOD circuit disabled;

101 - turns on BOD at an operating threshold of 2.7 V;

100 - corresponds to a threshold of 4.0 V.

Note that from the point of view of operational reliability, the smaller the difference between the
supply voltage and threshold of the power monitor (external or
built-in BOD circuit, it doesn’t matter), the better - with small power surges,
insensitive to the monitor, however, all sorts of inconveniences may occur.
pleasantries such as the spontaneous occurrence of an external interruption. One-
However, this difference should be taken into account when powering the device from batteries: for example,
for four AA alkaline batteries and a power monitor, calculate
tannoy at 4.7 V, residual voltage on the elements after the monitor is triggered

Kiselev Roman, May 2007 Article updated May 26, 2014

So, what is a microcontroller (hereinafter referred to as MK)? This is, relatively speaking, a small computer housed in a single integrated circuit. It has a processor (arithmetic logic unit, or ALU), flash memory, EEPROM memory, many registers, I/O ports, as well as additional bells and whistles such as timers, counters, comparators, USARTs, etc. After power is applied, the microcontroller boots up and begins executing the program stored in its flash memory. At the same time, it can control a wide variety of external devices via I/O ports.

What does this mean? This means that in the MK you can implement any logical circuit that will perform certain functions. This means that the MK is a microcircuit, the internal contents of which, in fact, we create ourselves. This allows, having bought several completely identical MKs, to assemble completely different circuits and devices on them. If you want to make any changes to the operation of an electronic device, you will not need to use a soldering iron; you will only need to reprogram the MK. In this case, you don’t even need to remove it from your device if you are using an AVR, since these MKs support in-circuit programming. Thus, microcontrollers bridge the gap between programming and electronics.

AVRs are 8-bit microcontrollers, i.e. their ALU can perform simple operations with only 8-bit numbers in one clock cycle. Now it's time to talk about which MK we will use. I'm working with an ATMega16 MK. It is very common and can be purchased in almost any radio parts store for about 100 rubles. If you don’t find it, then you can buy any other MK of the MEGA series, but in this case you will have to look for documentation for it, since the same “legs” of different MKs can perform different functions, and, having connected, it would seem If all the conclusions are correct, you may get a working device, or maybe just a cloud of stinking smoke. When purchasing an ATMega16, make sure that it comes in a large 40-pin DIP package, and also buy a socket for it into which it can be inserted. To work with it, you will also need additional devices: LEDs, buttons, connectors, etc.

ATMega16 has a very large number of diverse functions. Here are some of its characteristics:

  • Maximum clock frequency – 16 MHz (8 MHz for ATMega16L)
  • Most commands are executed in one clock cycle
  • 32 8-bit working registers
  • 4 full 8-bit I/O ports
  • two 8-bit timer/counters and one 16-bit
  • 10-bit analog-to-digital converter (ADC)
  • internal clock generator at 1 MHz
  • analog comparator
  • interfaces SPI, I2C, TWI, RS-232, JTAG
  • in-circuit programming and self-programming
  • pulse width modulation (PWM) module

Full characteristics of this device, as well as instructions for their use, can be found in the reference book (Datasheet) for this MK. True, it is in English. If you know English, be sure to download this Datasheet, it contains a lot of useful information.

Let's finally get down to business. I recommend making a special development and debugging board for the microcontroller, on which you can assemble any electrical circuit with a microcontroller without a soldering iron (or almost without it). Using such a board will greatly facilitate working with the MK and speed up the process of learning its programming. It looks like this:

What will you need for this?

First, you will need the board itself. I bought a ready-made one at a radio parts store for 115 rubles. Then I soldered all the necessary parts to it. The result is an incredibly convenient thing, on which you can assemble any electrical circuit in a matter of minutes by connecting cables and installing microcircuits and indicators.

To connect circuit elements, it is very convenient to use cables with connectors at the ends. These connectors are put on the “legs” sticking out next to each port of the MK. The microcontroller should be installed in the socket, and not soldered to the board, otherwise it will be very difficult to remove it if you accidentally burn it. Below is the pinout of the ATMEGA16 MK:

Let us explain which legs we are interested in now.

  • VCC - power is supplied here (4.5 - 5.5 V) from a stabilized source
  • GND – ground
  • RESET – reset (at low voltage level)
  • XTAL1, XTAL2 – a quartz resonator is connected here
  • PA, PB, PC, PD – input/output ports (A, B, C and D, respectively).

Anything that produces 7-11 V DC can be used as a power source. For stable operation of the MK, a stabilized power supply is needed. As a stabilizer, you can use 7805 series microcircuits. These are linear integrated stabilizers, the input of which is supplied with 7-11 V of direct unstabilized current, and the output is 5 V of stabilized current. Before and after 7805, you need to install filter capacitors (electrolytic for filtering low-frequency interference and ceramic for high-frequency). If you cannot find a stabilizer, then you can use a 4.5 V battery as a power source. The MK must be powered directly from it.

Below is a diagram of the MK connection:

Let's now figure out what's what here.

BQ1 is a quartz resonator that sets the operating frequency of the MK. You can set any up to 16 MHz, but since we plan to work in the future with a COM port, I recommend using resonators for the following frequencies: 14.7456 MHz, 11.0592 MHz, 7.3725 MHz, 3.6864 MHz or 1 ,8432 MHz (later it will become clear why). I used 11.0592 MHz. It is clear that the higher the frequency, the higher the speed of the device.

R1 is a pull-up resistor that maintains a voltage of 5 V at the RESET input. A low voltage level on this input indicates a reset. After the reset, the MK boots up (10 - 15 ms) and starts executing the program again. Since this is a high-impedance input, you cannot leave it “dangling in the air” - a small pickup on it will lead to an unexpected reset of the MK. This is exactly what R1 is for. For reliability, I also recommend installing capacitor C6 (no more than 20 µF).

SB1 – reset button.

The quartz resonator and filter capacitor C3 should be located as close as possible to the MK (no further than 5-7 cm), since otherwise interference may occur in the wires, leading to malfunctions of the MK.

The blue rectangle in the diagram outlines the programmer itself. It is convenient to make it in the form of a wire, one end of which is plugged into the LPT port, and the other into a certain connector next to the MK. The wire should not be excessively long. If problems arise with this cable (usually they don’t, but anything can happen), you will have to solder the Altera ByteBlaster adapter. How to do this is written in the description of the AVReal programmer.

Now that we've dealt with the hardware, it's time to move on to the software.

There are several development environments for AVR programming. Firstly, this is AVR Studio - the official programming system from Atmel. It allows you to write in assembler and debug programs written in assembly, C and C++. IAR is a commercial programming system in C, C++ and assembly language. WinAVR is an open source compiler. AtmanAVR is a programming system for AVR with an interface almost exactly the same as Visual C++ 6. AtmanAVR also allows you to debug programs and contains many helper functions that make writing code easier. This programming system is commercial, but, according to the license, you can use it for free for a month.

I suggest starting to work with IAR as the most transparent development environment. In IAR, a project is created entirely by hand; therefore, having completed several projects, you will already clearly know what each line of code means and what will happen if you change it. When working with AtmanAVR, you will either have to use a pre-created template, which is very cumbersome and difficult to understand for a person without experience, or have a lot of problems with header files when assembling the project from scratch. Having dealt with IAR, we will subsequently look at other compilers.

So, first, get some IAR. It is very common and finding it should not be a problem. After downloading IAR 3.20 from somewhere, install the compiler/working environment and launch it. After this you can start working.

Having launched IAR, select file/new/workspace, select the path to our project and create a folder for it and give it a name, for example, “Prog1”. Now let's create a project: Project / Create new project… Let's also call it “Prog1”. Right-click on the project title in the project tree and select “Options”

Here we will configure the compiler for a specific MK. First, you need to select the ATMega16 processor type on the Target tab, check the Enable bit definitions in I/O-include files checkbox on the Library Configuration tab (so that you can use the bit names of various MK registers in the program code), and select the C library type there /EU++. In the ICCAVR category, you need to check the Enable multibyte support checkbox on the Language tab, and turn off optimization on the Optimization tab (otherwise it will ruin our first program).

Next, select the XLINK category. Here you need to determine the format of the compiled file. Since we are now setting options for the Debug mode, as described in the title, we need to get a debug file as output. Later we will open it in AVR Studio. To do this, you need to select the extension.cof, and the file type is ubrof 7.

Now click OK, then change Debug to Release.

Go to Options again, where all parameters except XLINK are set to the same. In XLINK, change the extension to .hex, and the file format to intel-standart.

That's all. Now you can start writing your first program. Create a new Source/text and enter the following code in it:

#include"iom16.h" short unsigned int i; void main( void) (DDRB = 255; PORTB = 0; while(1) { if(PORTB == 255) PORTB = 0; else PORTB++; for(i=0; i

The file "iom16.h" is located in the folder (C:\Program Files)\IAR Systems\Embedded Workbench 3.2\avr\inc. If you are using another MK, for example, ATMega64, then select the file “iom64.h”. These header files store information about the MK: the names of registers, bits in registers, and the names of interrupts. Each individual pin of port A, B, C, or D can act as either an input or an output. This is determined by the Data Direction Register (DDR). 1 makes the leg an output, 0 an input. Thus, by setting, for example, DDRA = 13, we make the “legs” PB0, PB2, PB3 outputs, the rest - inputs, because 13 in binary is 00001101.

PORTB is a register that determines the state of the port pins. Having written 0 there, we set the voltage at all outputs to 0 V. Then there is an endless loop. When programming the MK, they always make an endless loop in which the MK performs some action until it is reset or until an interruption occurs. In this cycle they write, as it were, “background code”, which the MK executes as a last resort. This could be, for example, displaying information on a display. In our case, the contents of the PORTB register are increased until it is full. After that everything starts all over again. Finally, a ten thousand cycle for loop. It is needed to form a visible delay in switching the state of port B.



Now we save this file in the project folder as Prog1.c, copy the iom16.h file to the project folder, select Project/Add Files and add “iom16.h” and “Prog1.c”. Select Release, press F7, the program compiles and the message should appear:


Total number of errors: 0
Total number of warnings: 0

Here's a photo of my programmer:

Download the AVReal programmer. Copy it (AVReal32.exe) to the Release/exe folder, where the Prog1.hex file should be located. We supply power to the MK, connect the programming cable. Open Far Manager (it is most convenient to flash MK), go to this folder, press Ctrl+O. Since we have a completely new MK, we fill

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Don't forget to enter the correct frequency if you are not using 11059200 Hz! At the same time, the so-called fuses – registers that control its operation (use of an internal generator, Jtag, etc.). After this, it is ready to receive the first program. The programmer is given the used LPT port, frequency, file name, and others as parameters (all of them are listed in the description of AVReal). We dial:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

If the connection is correct, the programmer will report successful programming. There is no guarantee that this will work the first time (the first time you call the program). I myself sometimes get programmed the second time. Perhaps the LPT port is faulty or there is interference in the cable. If problems occur, check your cable carefully. From my own experience, I know that 60% of malfunctions are associated with a lack of contact in the right place, 20% with the presence of an unnecessary one, and another 15% with erroneous soldering of the wrong thing to the wrong thing. If all else fails, read the description of the programmer and try building Byte Blaster.

Let's assume everything works for you. If you now connect eight LEDs to port B of the MK (do this with the MK turned off, and it is advisable to include 300-400 Ohm resistors in series with the LEDs) and apply power, a small miracle will happen - a “wave” will run through them!

© Kiselev Roman
May 2007

Microcontrollers are small, but at the same time very convenient devices for those who want to create various amazing robotic or automated things at home. This article will discuss AVR programming for beginners, various aspects and nuances of this process.

general information

Microcontrollers can be found everywhere. They are found in refrigerators, washing machines, telephones, industrial machines, smart homes and many other technical devices. Their widespread use is due to the ability to replace more complex and large-scale analog device circuits. Programming the AVR MK allows for autonomous control of electronic devices. These microcontrollers can be thought of as a simple computer that can interact with external equipment. So, they can open/close transistors, receive data from sensors and display them on screens. Microcontrollers can also perform various processing of input information, similar to a personal computer. If you master AVR programming from scratch and reach the professional level, you will have almost limitless possibilities for controlling various devices using I/O ports, as well as changing their code.

A little about AVR

The article will consider a family of microcontrollers produced by Atmel. They have pretty good performance, which allows them to be used in many amateur devices. Widely used in industry. Can be found in this technique:

  1. Domestic. Washing machines, refrigerators, microwave ovens, etc.
  2. Mobile. Robots, communications, and so on.
  3. Computing. Peripheral device control systems, motherboards.
  4. Entertaining. Jewelry and children's toys.
  5. Transport. Vehicle safety and engine management systems.
  6. Industrial equipment. Machine control systems.

This, of course, does not cover all areas. They are used where it is advantageous to use not a set of control chips, but one microcontroller. This is possible due to low power consumption and C and Assembler languages ​​are used to write programs, slightly modified for the microcontroller family. Such changes are necessary due to weak computing capabilities, which are usually calculated in tens of kilobytes. AVR programming without learning these languages ​​is not possible.

How to get your first microcontroller?

AVR programming requires:

  1. Availability of the necessary development environment.
  2. Actually the microcontrollers themselves.

Let's consider the second point in more detail. There are three options to acquire the required device:

  1. Buy the microcontroller itself directly.
  2. Get a device as part of the designer (for example, Arduino).
  3. Assemble the microcontroller yourself.

There is nothing complicated in the first point, so let’s move on to the second and third.

Get a device as part of the constructor

The well-known Arduino will be chosen as an example. This is also a convenient platform for fast and high-quality development of various electronic devices. The Arduino board includes a specific set of components for operation (there are various configurations). It must include an AVR controller. This approach allows you to quickly start developing a device, does not require special skills, has significant capabilities in terms of connecting additional boards, and you can also find a lot of information on the Internet on questions of interest. But there were some downsides. By buying an Arduino, a person deprives himself of the opportunity to plunge more deeply into AVR programming, to better understand the microcontroller and the specifics of its operation. Also adding to the negative is the relatively narrow range of models, which is why you often have to buy boards for specific tasks. Another peculiarity is that programming in “SI” here differs quite strongly from the standard form. Despite all its shortcomings, Arduino is suitable for beginners to learn. But you shouldn't abuse it.

Self-assembly

It should be noted that AVR microcontrollers are quite friendly to beginners. You can assemble them yourself using available, simple and cheap components. If we talk about the advantages, then this approach allows you to become better acquainted with the device, independently select the necessary components, adjusting the final result to the requirements, the use of standard programming languages ​​and low cost. The only disadvantages that can be noted are the difficulty of self-assembly when it is carried out for the first time, and the lack of the necessary knowledge and skills.

How to work?

So, let's say that the issue with the microcontroller has been resolved. Further it will be considered that it was purchased or purchased independently. What else do you need to master AVR programming? For this purpose, you need a development environment (a regular notepad will do as a basis, but I recommend using Notepad++). Although there are other programs available for programming AVRs, this software will be able to handle all the requirements. A programmer is also required. You can purchase it at your local store, order it online, or assemble it yourself. A printed circuit board wouldn't hurt either. It is not required, but its use allows you to save your nerves and time. Also bought/created independently. And the last thing is the power source. For AVR it is necessary to provide a voltage supply of 5V.

Where and how to study?

You won't be able to create masterpieces from scratch. This requires knowledge, experience and practice. But where can I get them? There are several ways. Initially, you can independently search for the necessary information on the World Wide Web. You can enroll in programming courses (remote or face-to-face) to gain basic work skills. Each approach has its advantages. So, distance programming courses will be cheaper, and maybe even free. But if something doesn’t work out, then with face-to-face classes, an experienced developer will be able to quickly find the cause of the problem. It would also be a good idea to familiarize yourself with the literature that is freely available. Of course, you won’t be able to get by on books alone, but you can get basic knowledge about the device, programming in “SI”, “Assembler” and other working aspects.

I/O Ports

This is an extremely important topic. Without understanding how the I/O ports work, in-circuit programming of the AVR is not possible at all. After all, the interaction of the microcontroller with external devices is carried out precisely through their mediation. At first glance, it may seem to a beginner that the port is a rather confusing mechanism. To avoid such an impression, we will not consider in detail the scheme of its operation, but only get a general idea of ​​it. Let's consider the software implementation. As an example of a device, the AtMega8 microcontroller was chosen - one of the most popular of the entire AVR family. The I/O port consists of three registers that are responsible for its operation. At the physical level, they are realized as legs. Each of them corresponds to a specific bit in the control register. Each leg can work both to input information and to output it. For example, you can attach a function for igniting an LED or processing a button press on it. By the way, the three registers that were mentioned are: PORTx, PINx and DDRx. Each of them is eight-bit (remember, we're looking at AtMega8). That is, one bit is occupied by a specific leg.

Register operation

The most significant in terms of orientation is the DDRx control. It is also eight-bit. Values ​​for it can be written 0 or 1. How does the operation of the controller change when using zeros and ones? If a certain bit is set to 0, then the corresponding leg will be switched to input mode. And from it it will be possible to read data that comes from external devices. If set to 1, the microcontroller will be able to control something (for example, instruct a transistor to pass voltage and light an LED). The second most important is PORTx. He manages the condition of the leg. Let's look at an example. Let's say we have an output port. If we set a logical one in PORTx, then a signal is sent from the microcontroller to the control device to start working. For example, turn on the LED. When zero is set, it will be extinguished. That is, there is no need to work with the DDRx control register constantly. And finally, let's talk about PINx. This register is responsible for displaying the state of the controller pin when it is set to input state. It should be noted that PINx can only operate in read mode. You won't be able to write anything into it. But reading the current state of the leg is no problem.

Working with analogues

AVRs are not the only microcontrollers. This market is divided among several large manufacturers, as well as among numerous Chinese imitators and homemade devices. In many ways they are similar. For example, programming a PIC/AVR is not much different. And if you understand one thing, then understanding everything else will be easy. But we still recommend starting the journey with AVR due to its competent structure, developer-friendliness and the presence of a large number of auxiliary materials, which is why the development process can be significantly accelerated.

Safety precautions

When programming AVR microcontrollers in “SI” or “Assembler”, you must work very carefully. The fact is that by setting a certain combination of registers and changing internal settings, you can safely block the microcontroller. This is especially true for fuses. If you are not confident in the correctness of your actions, then it is better to refuse to use them. The same applies to programmers. If you buy factory equipment, it will flash microcontrollers without problems. When assembling it yourself, a sad situation may arise in which the programmer blocks the device. This can happen either due to an error in the program code or through problems in the code itself. By the way, about another (this time positive) point that was previously mentioned in passing, but was never fully disclosed. Nowadays, almost all modern microcontrollers have in-circuit programming functionality. What does it mean? Let's assume that the device was soldered on the board. And to change its firmware, now you don’t need to desolder it, because such intervention can damage the microcontroller itself. It is enough to connect to the corresponding pins and reprogram it through them.

Which model should you choose?

As part of the article, AtMega8 was reviewed. This is a rather mediocre microcontroller in terms of its characteristics, which, nevertheless, is enough for most crafts. If you want to create something large-scale, then you can take original monsters like Atmega128. But they are designed for more experienced developers. Therefore, if you do not have enough experience, it is better to start with small and simple devices. In addition, they are much cheaper. Agree, it’s one thing to accidentally block a microcontroller for a hundred rubles, but quite another thing to block it for half a thousand. It’s better to get into the swing of things and understand the various aspects of operation so that you don’t lose significant sums in the future. Initially, you can start with AtMega8, and then focus on your needs.

Conclusion

So the topic of AVR programming was considered in the most general terms. Of course, there is much more that can be said. So, for example, the marking of microcontrollers was not considered. And it can say a lot. So, microcontrollers generally operate at a voltage of 5V. Whereas the presence, for example, of the letter L can indicate that only 2.7 V is enough for the device to operate. As you can see, sometimes knowledge about markings can play a very important role in terms of the correct and durable operation of devices. The operating time of microcontrollers is also an interesting topic. Each device is designed for a certain period. So, some can work a thousand hours. Others have a guarantee reserve of 10,000!

I have said more than once or twice that studying MK should start with assembler. An entire course on the website was devoted to this (although it is not very consistent, but gradually I am combing it to an adequate appearance). Yes, it is difficult, the result will not be on the first day, but you will learn to understand what is happening in your controller. You will know how it works, and not copy other people’s sources like a monkey and try to understand why it suddenly stopped working. In addition, it is much easier for C to create redneck code that will come out with a pitchfork at the most inopportune moment.

Unfortunately, everyone wants results immediately. So I decided to go the other way - make a tutorial on C, but with showing his underwear. A good embedder programmer always holds his piece of hardware tightly, not allowing it to take a single step without permission. So first there will be the C code, then what the compiler produced and how it all actually works :)

On the other hand, C's strong point is code portability. If, of course, you write everything correctly. Separating the work algorithms and their hardware implementations into different parts of the project. Then, to transfer the algorithm to another microcontroller, it will be enough to rewrite only the interface layer, where all calls to the hardware are written, and leave all the working code as is. And, of course, readability. The C source code is easier to understand at first glance (although... for example, I don’t care what to point at - be it C or ASM :)), but, again, if everything is written correctly. I will also pay attention to these points.

My debug board will serve as the experimental hardware on which the lion's share of all examples will be installed.

The first C program for AVR

Choosing a compiler and setting up the environment
There are many different C compilers for AVR:
First of all this IAR AVR C- is almost definitely recognized as the best compiler for AVR, because The controller itself was created in close collaboration between Atmel and specialists from IAR. But you have to pay for everything. And this compiler is not only an expensive commercial software, but also has such a ton of settings that it takes a lot of effort to simply compile it in it. I really didn’t develop a friendship with him; the project was rotting due to strange errors at the linking stage (later I found out that it was a crooked crack).

Second comes WinAVR GCC- a powerful optimizing compiler. Fully open source, cross-platform, in general, all the joys of life. It also integrates perfectly into AVR Studio, allowing you to debug right there, which is damn convenient. In general, I chose it.

There is also CodeVision AVR C is a very popular compiler. It became popular due to its simplicity. You can get a working program in it in just a few minutes - the start code wizard greatly facilitates this, stamping standards for the initialization of all sorts of uarts. To be honest, I’m kind of suspicious of it - once I had to dismantle a program written by this compiler, it turned out to be some kind of mess and not code. A terrible amount of unnecessary movements and operations, which resulted in a considerable amount of code and slow performance. However, perhaps there was an error in the DNA of the person who wrote the original firmware. Plus he wants money. Not as much as IAR, but noticeable. And in demo mode it allows you to write no more than 2kb of code.
Of course there is a crack, but if you’re going to steal, it’s a million, in the IAR sense :)

There is also Image Craft AVR C And MicroC from microelectronics. I didn't have to use either one, but... S.W.G. very praising MicroPascal, they say, a terribly convenient programming environment and libraries. I think MicroC will be no worse, but it’s also paid.

As I said, I chose WinAVR for three reasons: it’s free, it integrates into AVR Studio and there’s just a ton of ready-made code written for it for all occasions.

So download the WinAVR installation with AVR Studio. Next, the studio is installed first, then WinAVR is rolled on top and attached to the studio in the form of a plugin. I strongly recommend installing WinAVR on a short path, something like C:\WinAVR, this way you will avoid a lot of problems with paths.

Creating a project
So, the studio is installed, C is screwed in, it’s time to try to program something. Let's start with the simple, the simplest. Launch the studio, select a new project there, as the AVR GCC compiler and enter the name of the project.

A work field opens with an empty *.c file.

Now it won’t hurt to configure the display of paths in the studio bookmarks. To do this, go to:
Menu Tools - Options - General - FileTabs and select “Filename Only” from the drop-down list. Otherwise, it will be impossible to work - the tab will contain the full path of the file and there will be no more than two or three tabs on the screen.

Project setup
In general, it is considered classic to create a make file in which all dependencies are described. And that's probably right. But for me, who grew up on fully integrated IDEs like uVision or AVR Studio this approach is deeply alien. Therefore, I will do it my way, everything using studio means.

Poke the button with the gear.


These are the settings for your project, or rather the settings for automatic generation of a make file. On the first page you just need to enter the frequency at which your MK will operate. This depends on the fuse bits, so we assume that our frequency is 8000000Hz.
Also pay attention to the optimization line. Now there is -Os - this is size optimization. Leave it as is for now, then you can try to play with this parameter. -O0 is no optimization at all.

The next step is to configure the paths. First of all, add your project directory there - you will add third-party libraries there. The path “.\” will appear in the list

The Make file has been generated, you can look at it in the default folder in your project, just take a look and see what’s there.


That's all for now. Click OK everywhere and go to the source.

Formulation of the problem
A blank sheet of paper is tempting to implement some cunning idea, since the banal blinking of a diode no longer works. Let's immediately take the bull by the horns and implement the connection with the computer - this is the first thing I do.

It will work like this:
When a one (code 0x31) arrives at the COM port, we will turn on the diode, and when a zero arrives (code 0x30) it turns off. Moreover, everything will be done on interrupts, and the background task will be the blinking of another diode. Simple and meaningful.

Assembling the circuit
We need to connect the USB-USART converter module to the USART pins of the microcontroller. To do this, take a jumper from two wires and place it crosswise over the pins. That is, we connect the Rx of the controller to the Tx of the converter, and the Tx of the converter to the Rx of the controller.

In the end, this is the diagram:


I don’t consider connecting the remaining pins, power, or reset, it’s standard.

Writing code

Let me make a reservation right away that I will not delve specifically into the description of the C language itself. There is simply a colossal amount of material for this, starting from the classic “C Programming Language” from K&R and ending with various manuals.

I found one such method in my stash; I once used it to study this language. Everything there is short, clear and to the point. I’m gradually putting it together and dragging it onto my website.

It’s true that not all the chapters have been transferred yet, but I think it won’t be for long.

It’s unlikely that I can describe it better, so from the training course, instead of a detailed explanation of the subtleties, I will simply provide direct links to individual pages of this manual.

Adding libraries.
First of all, we add the necessary libraries and headers with definitions. After all, C is a universal language and we need to explain to him that we are working specifically with AVR, so write the line in the source code:

1 #include

#include

This file is located in the folder WinAVR and it contains a description of all registers and ports of the controller. Moreover, everything there is cunning, with binding to a specific controller, which is transmitted by the compiler via make file in parameter MCU and based on this variable, a header file is connected to your project with a description of the addresses of all ports and registers for this particular controller. Wow! Without it, it’s also possible, but then you won’t be able to use symbolic register names like SREG or UDR and you’ll have to remember the address of each like “0xC1,” which is a headache.

The team itself #include<имя файла> allows you to add the contents of any text file to your project, for example, a file with a description of functions or a piece of other code. And so that the directive could find this file, we specified the path to our project (the WinAVR directory is already registered there by default).

Main function.
A C program consists entirely of functions. They can be nested and called from each other in any order and in different ways. Each function has three required parameters:

  • The return value is e.g. sin(x) returns the value of the sine of x. Like in mathematics, in short.
  • The transmitted parameters are the same X.
  • Function body.

All values ​​transmitted and returned must be of some type, depending on the data.

Any C program must contain a function main as an entry point into the main program, otherwise it’s not C at all :). By the presence of main in someone else’s source code from a million files, you can understand that this is the main part of the program, where everything begins. So let's ask:

1 2 3 4 5 int main(void) ( return 0 ; )

int main(void) ( return 0; )

That’s it, the first simplest program has been written, it doesn’t matter that it doesn’t do anything, we’ve just started.

Let's figure out what we did.
int This is the data type that the main function returns.

Of course, in a microcontroller main in principle nothing can be returned and in theory there should be void main(void), but GCC is originally designed for the PC and there the program can return the value to the operating system upon completion. Therefore GCC on void main(void) swears by Warning.

This is not an error, it will work, but I don’t like warnings.

void this is the type of data that we pass to the function, in this case main also cannot accept anything from the outside, therefore void- a dummy. A stub is used when there is no need to transmit or return anything.

Here they are { } curly braces are a program block, in this case the body of a function main, the code will be located there.

return- this is the return value that the main function will return upon completion, since we have an int, that is, a number, then we must return a number. Although this still does not make sense, because... on the microcontroller, we can only go nowhere from main. I return null. Because it doesn't matter. But the compiler is usually smart and does not generate code for this case.
Although, if perverted, then from main You can go to the MK - for example, fall into the bootloader section and execute it, but this will require low-level tinkering with the firmware in order to correct the transition addresses. Below you will see for yourself and understand how to do it. For what? This is another question, in 99.999% of cases this is not necessary :)

We did it and moved on. Let's add a variable, we don't really need it and there's no point in introducing variables without it, but we're learning. If variables are added inside the body of a function, then they are local and exist only in this function. When you exit the function, these variables are deleted, and the RAM memory is allocated for more important needs. .

1 2 3 4 5 6 int main(void ) ( unsigned char i; return 0 ; )

int main(void) ( unsigned char i; return 0; )

unsigned means unsigned. The fact is that in the binary representation, the most significant bit is allocated to the sign, which means that the number +127/-128 fits into one byte (char), but if the sign is discarded, it will fit from 0 to 255. Usually the sign is not needed. So unsigned.
i is just a variable name. No more.

Now we need to initialize the ports and UART. Of course, you can take and connect the library and call some kind of UartInit(9600); but then you won't know what really happened.

We do this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void ) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1)#define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider) ; UBRRH = HI(bauddivider) ; UCSRA = 0 ; UCSRB = 1<< RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

int main(void) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO( x) ((x)& 0xFF) UBRRL = LO(bauddivider); UBRRH = HI(bauddivider);<

Scary? In fact, there are only five last lines of real code. Everything, that #define It is a preprocessor macro language. Almost the same stuff as in Assembly, but the syntax is slightly different.

They will facilitate your routine operations of calculating the necessary coefficients. In the first line we say that instead XTAL you can safely substitute 8000000, and L— type indication, like long is the clock frequency of the processor. The same baudrate— frequency of data transmission via UART.

bauddivider already more complicated, instead of it the expression calculated using the formula from the two previous ones will be substituted.
Well and L.O. And HI The low and high bytes will be taken from this result, because It obviously may not fit into one byte. IN HI X (the macro input parameter) is shifted eight times to the right, resulting in only the most significant byte remaining. And in L.O. we do a bitwise AND with the number 00FF, as a result only the low byte will remain.

So everything that's done is like #define you can safely throw it away, and calculate the necessary numbers on a calculator and immediately enter them into the lines UBBRL = …. and UBBRH = …..

Can. But! Do this ABSOLUTELY IMPOSSIBLE!

It will work this way or that way, but you will have so-called magic numbers- values ​​​​taken from nowhere and for unknown reasons, and if you open such a project in a couple of years, it will be damn difficult to understand what these values ​​are. Even now, if you want to change the speed, or change the quartz frequency, everything will have to be recalculated again, but you changed a couple of numbers in the code and that’s it. In general, if you don’t want to be branded as a coder, then make your code so that it is easy to read, understandable and easy to modify.

Then everything is simple:
All these “UBRRL and Co” are configuration registers of the UART transmitter with the help of which we will communicate with the world. And now we have assigned them the required values, setting them to the desired speed and mode.

Record view 1< Means the following: take 1 and put it in place RXEN in byte. RXEN this is the 4th bit of the register UCSRB, So 1< forms the binary number 00010000, TXEN- this is the 3rd bit, and 1< will give 00001000. Single "|" it's bitwise OR, so 00010000 | 00001000 = 00011000. In the same way, the remaining necessary configuration bits are set and added to the general heap. As a result, the collected number is recorded in the UCSRB. More details are described in the datasheet on the MK in the USART section. So let's not get distracted by technical details.

Done, time to see what happened. Click on compile and start emulation (Ctrl+F7).

Debugging
All sorts of progress bars ran through, the studio changed and a yellow arrow appeared near the entrance to the main function. This is where the processor is currently running, and the simulation is paused.

The fact is that initially, in fact, it was on the line UBRRL = LO(bauddivider); After all, what we have in define is not code, but simply preliminary calculations, which is why the simulator is a little dull. But now he realized, the first instruction has been completed and if you climb into the tree I/O View, to the USART section and look at the UBBRL byte there, you will see that the value is already there! 0x33.

Take it one step further. See how the contents of the other register change. So go through them all, pay attention to the fact that all the indicated bits are set as I told you, and they are set simultaneously for the entire byte. It won't go any further than Return - the program is over.

Opening
Now reset the simulation to zero. Click there Reset (Shift+F5). Open the disassembled listing, now you will see what is actually happening in the controller. View -> Disassembler. And not YYAAAAAA!!! Assembler!!! HORROR!!! AND IT IS NECESSARY. So that later, when something goes wrong, you don’t be stupid in the code and don’t ask lame questions on the forums, but immediately get into the guts and see where you’re stuck. There's nothing scary there.

First there will be tops from the series:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump + 0000000E: 940C0034 JMP 0x000034 Jump +00000010: 940c0034 JMP 0x00000034 Jump +000012: 940c0034 JMP 0x00000034 Jump +00000014: 940c0034 JMP 0x00000034 Jump +00000016: 940C003 4 JMP 0x00000034 Jump +00000018: 940c0034 JMP 0x00000034 Jump +0000001a: 940c0034 JMP 0x00000034 Jump +0000001c : 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000 034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

00000000: 940C002A JMP 0x00002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x000034 JUMP +00000006: 940C0034 JMP 0x000034 Jump +000008: 940C0034 JMP 0x00000034 Jump +0000000a: 940c0034 JMP 0x00000034 Jump +0000000C: 940c0034 JMP 0x00000034 Jump +0000000EE : 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000 034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x0000003 4 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

This is the interrupt vector table. We will return to it later, but for now just look and remember that it exists. The first column is the address of the flash cell in which the command is located, the second is the command code, the third is the command mnemonic, the same assembly instruction, the third is the operands of the command. Well, automatic comment.
So, if you look, there are continuous transitions. And the JMP command code is four bytes, it contains the jump address written backwards - the low byte at the low address and the jump command code 940C

0000002B: BE1F OUT 0x3F,R1 Out to I/O location

Recording this zero at address 0x3F. If you look at the I/O view column, you will see that address 0x3F is the address of the SREG register - the flag register of the controller. Those. we reset SREG to run the program on zero conditions.

1 2 3 4 +0000002C: E5CF LDI R28,0x5F Load immediate +0000002D: E0D4 LDI R29,0x04 Load immediate +0000002E: BFDE OUT 0x3E,R29 Out to I/O location +0000002F: BFCD OUT 0x3D,R28 Out to I/O location

0000002C: E5CF LDI R28,0x5F Load immediate +0000002D: E0D4 LDI R29,0x04 Load immediate +0000002E: BFDE OUT 0x3E,R29 Out to I/O location +0000002F: BFCD OUT 0x3D,R28 Out to I/O location

This is loading the stack pointer. You cannot directly load into I/O registers, only through an intermediate register. Therefore, first LDI to intermediate, and then from there OUT to I/O. I’ll also tell you more about the stack later. For now, know that this is a dynamic memory area that hangs at the end of RAM and stores addresses and intermediate variables. Now we have indicated where our stack will start from.

00000032: 940C0041 JMP 0x00000041 Jump

Jump to the very end of the program, and there we have a ban on interrupts and looping tightly on itself:

1 2 +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relative jump

00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relative jump

This is in case of unforeseen circumstances, such as exiting the main function. The controller can be brought out of such a loop either by a hardware reset, or, more likely, by a reset from a watchdog. Well, or, as I said above, correct this in the hex editor and gallop off to wherever our heart desires. Also note that there are two types of transitions: JMP and RJMP; the first is a direct transition to an address. It occupies four bytes and can directly jump through the entire memory area. The second type of transition is RJMP - relative. His command takes two bytes, but he moves from the current position (address) 1024 steps forward or backward. And its parameters indicate the offset from the current point. It is used more often because takes up half the space in the flush, and long transitions are rarely needed.

1 +00000034: 940C0000 JMP 0x00000000 Jump

00000034: 940C0000 JMP 0x00000000 Jump

And this is a jump to the very beginning of the code. A reboot of sorts. You can check that all the vectors jump here. The conclusion from this is that if you now enable interrupts (they are disabled by default) and your interrupt occurs but there is no handler, then there will be a software reset - the program will be thrown back to the very beginning.

Function main. Everything is similar, you don’t even need to describe it. Just look at the already calculated number being entered into the registers. The compiler preprocessor rocks!!! So no “magic” numbers!

1 2 3 4 5 6 7 8 9 10 11 12 <

00000036: E383 LDI R24,0x33 Load immediate +00000037: B989 OUT 0x09,R24 Out to I/O location 15: UBRRH = HI(bauddivider); +00000038: BC10 OUT 0x20,R1 Out to I/O location 16: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 Out to I/O location 17: UCSRB = 1<

And here's the bug:

1 2 3 +0000003E: E080 LDI R24.0x00 Load immediate +0000003F: E090 LDI R25.0x00 Load immediate +00000040: 9508 RET Subroutine return

0000003E: E080 LDI R24.0x00 Load immediate +0000003F: E090 LDI R25.0x00 Load immediate +00000040: 9508 RET Subroutine return

The question is, why does the compiler add such tops? And this is nothing more than Return 0, we defined the function as int main(void) and so we wasted another four bytes for nothing :) And if you make void main(void) then only RET will remain, but a warning will appear, that our main function does not return anything. In general, do as you please :)

Difficult? Apparently not. Click step-by-step execution in disassembler mode and see how the processor executes individual instructions, what happens to the registers. How does movement through commands and final looping occur?

To be continued in a couple of days...

Offtop:
Alexei78 I created a plugin for Firefox that makes it easier to navigate my website and forum.
Discussion and downloading,