Reading avr ports in c. Learning the AVR Microcontroller Command System

Introduction

All I / O ports (IO) of AVR microcontrollers operate on the read-modify-write principle when used as universal I / O ports. This means that changing the I / O direction of one port line with the SBI and CBI commands will occur without false changes in the I / O direction of other port lines. This also applies to changing the logic level (if the port line is configured for output) or for enabling / disabling pull-up resistors (if the line is configured for input). Each output buffer has a symmetrical control characteristic with high sinking and sinking output currents. The output driver is capable of driving the LEDs directly. An individual selective pull-up resistor can be connected to all port lines, the resistance of which does not depend on the supply voltage. Protective diodes are installed on all IHO lines, which are connected to VCC and Common (GND), as shown in Figure 29. A detailed list of IHV parameters is given in the Electrical Characteristics section.

Figure 29 - Equivalent circuit of the PVV line

References to registers and register bits in this section are given in general terms. In this case, the symbol "x" replaces the name of the PVB, and the symbol "n" replaces the number of the digit of the IVB. However, when compiling the program, it is necessary to use the exact form of notation. For example, PORTB3, which stands for bit 3 of Port B, is written as PORTxn in this document. The addresses of the physical I / O registers and the distribution of their bits are given in the “Description of I / O Ports Registers” section.

For each I / O port, three cells are reserved in the I / O memory: one for the data register - PORTx, the other for the data direction register - DDRx and the third for the state of the port inputs - PINx. The cell holding the state at the port inputs is read-only, and the data registers and data directions are bi-directional. In addition, setting the SFIOR PUD Pull Off bit disables the pull-up function on all pins of all ports.

The following is a description of the I / O port for universal digital I / O. Most of the port pins support the alternative functionality of the on-board peripheral devices microcontroller. For a description of the alternative functions, refer to the subsection “Alternative port functions” below (see also the description of the functions of the corresponding peripheral modules).

Note that for some ports, enabling the alternate function of some pins makes it impossible for other pins to be used for universal digital I / O.

Ports as universal digital I / O

All ports are bi-directional I / O ports with optional pull-up resistors. Figure 30 illustrates a functional block diagram of one line of the I / O port, designated Pxn.


Figure 30 - Organization of universal digital input-output (1)

Approx. 1: WPx, WDx, RRx, RPx and RDx signals are common within the same port. The clkI / O, SLEEP, and PUD signals are common to all ports.

Configuring pins

The mode and state for each pin is determined by the value of the corresponding bits of the three registers: DDxn, PORTxn and PINxn. As shown in the “Description of I / O Ports Registers”, the DDxn bits can be accessed at the DDRx address in the I / O space and, accordingly, the PORTxn bits at the PORTx address, and the PINxn bits at the PINx address.

The DDxn bits of the DDRx register determine the directionality of the I / O line. If DDxn = 1, then Pxn is configured to output. If DDxn = 0, then Pxn is configured to be input.

If PORTxn = 1 when configuring the port line to input, then the pull-up resistor is enabled. To turn off this resistor, you must write to PORTxn log. 0 or set the port line to output. During a reset, all port lines are in the third (high impedance) state, even if sync is not working.

If PORTxn = 1 when configuring the port line to output, then the output state will be determined by the PORTxn value.

Since simultaneous writing to the DDRx and PORTx registers is impossible, then when switching between the third state ((DDxn, PORTxn) = 0b00) and the log. 1 ((DDxn, PORTxn) = 0b11) an intermediate state should occur either with a pull-up resistor connected ((DDxn, PORTxn) = 0b01) or with a log. 0 ((DDxn, PORTxn) = 0b10). As a rule, the transition through the state with a pull-up resistor is equivalent to the state of the pin 1, if the pin of the microcontroller is connected to a high-impedance input. Otherwise, the PUD bit of the SFIOR register must be set to turn off all pull-up resistors on all ports.

Switching between pull-up input and output low level is related to a similar problem. Therefore, the user is forced to use either the third state ((DDxn, PORTxn) = 0b00) or log output. 1 ((DDxn, PORTxn) = 0b11) as an intermediate step.

Table 25 summarizes the effect of the control signals on the pin state.

Table 25 - Port pinout configuration

DDxn PORTxn PUD (in SFIOR) Input Output Pull-up resistor A comment
0 0 X Input No
0 1 0 Input Yes Pxn will be the current source when external low is applied
0 1 1 Input No Third state (Z-state)
1 0 X Output No Log output. 0 (sinking current)
1 1 X Output No Log output. 1 (leakage current)

Reading the state of the output

Regardless of the value of the DDxn data direction bit, the state of the port pin can be polled through the PINxn register bit. As shown in Figure 30, the register bit PINxn and the preceding flip-flop latch constitute the synchronizer. This approach allows you to avoid metastability if a change in state at the pin occurred near the edge of the internal clock. However, this approach is associated with the occurrence of a delay. Figure 31 shows the timing diagram of the synchronization during polling of the layer externally applied to the pin. The durations of the minimum and maximum propagation delays are denoted as tpd, max and tpd, min, respectively.


Figure 31 - Synchronization during polling of the layer applied to the port pin

The following examples show how to set the log level on lines 0 and 1 of port B. 1, and on lines 2 and 3 - log. 0 and how to set lines 4 ... 7 to input with pull-up resistors on lines 6 and 7. The resulting state of the lines is read back, but with that said, a nop instruction is included to enable the newly assigned state of some pins to be read back.

Sample code in Assembler (1) ...; Allow pull-ups and set high output levels; We determine the directions of these lines of ports ldi r16, (1<

Approx. 1: The assembler program uses two time registers to minimize the time interval from setting the pull-up resistors at bits 0, 1, 6, and 7 to the correct setting of the direction bits, allowing log output. 0 on lines 2 and 3 and replacing the high level on bits 0 and 1, formed by connecting pull-up resistors, to the high level of the high-current driver.

Digital Input Resolution and Sleep Modes

As shown in Figure 30, the digital input signal can be shunted to the common at the Schmitt trigger input. The signal denoted as SLEEP in the figure is set when the microcontroller is switched to power-down, economy mode, standby mode, and extended standby mode. This avoids an increase in current consumption in the event that some of the input signals are in a floating state or the level of the analog input signal is close to VCC / 2.

The SLEEP signal is ignored by external interrupt inputs. If external interrupt requests are disabled, then SLEEP affects these pins as well. SLEEP is also ignored on some other inputs when performing their alternative functions (see “Alternative Port Functions”).

If the pin of an external asynchronous interrupt is set to an interrupt on a rising edge, a falling edge, or any change, a log level is present. 1 and the external interrupt is not enabled, then the corresponding external interrupt flag will be set when exiting the above-mentioned sleep modes, since the bypass function at the input in sleep modes causes logical changes.

Unconnected pins

If several pins remain unused, it is recommended to ensure that a certain logic level is present on them. Although most of the digital inputs are disabled in deep sleep modes as described above, floating inputs must be avoided to avoid excessive current consumption in all other microcontroller operating modes where digital input is enabled (Reset, Active, and Idle).

The simplest way to ensure that a certain level is present on an unused pin is to allow the internal pull-up resistor to be connected. However, in this case, the pull-up resistors will be disabled in reset mode. If low power consumption is required in reset mode, then an external pull-up resistor must be installed to the positive or negative supply. Connecting the pins directly to VCC or GND is not recommended because Dangerous currents can occur if such a pin is inadvertently configured on a data pin.

Bitwise operations are based on logical operations that we discussed earlier. They play a key role in programming AVR microcontrollers and other microcontrollers. Almost no program is complete without the use of bitwise operations. Before that, we deliberately avoided them in order to facilitate the process of learning MK programming.

In all previous articles, we programmed only the I / O ports and did not use additional built-in nodes, for example, such as timers, analog-to-digital converters, interrupts and other internal devices without which the MK loses all its power.

Before proceeding to mastering the built-in MK devices, it is necessary to learn how to control or check individual bits of the AVR MK registers. Previously, we checked or set the bits of the entire register at once. Let's figure out what the difference is, and then continue further.

Bitwise operations

Most often, when programming AVR microcontrollers, we used it, since it has a greater clarity compared to and is well understood for novice MK programmers. For example, we only need to set the 3rd bit of port D. For this, as we already know, we can use the following binary code:

PORTD = 0b00001000;

However, with this command, we set the 3rd digit to one, and we reset all the others (0, 1, 2, 4, 5, 6 and 7th) to zero. And now let's imagine the situation that the 6th and 7th bits are used as the inputs of the ADC and at this time a signal from a device is sent to the corresponding pins of the MC, and we, using the command used above, reset these signals. As a result, the microcontroller does not see them and considers that the signals did not come. Therefore, instead of such a command, we should apply another, which would set only the 3rd bit to one, while not affecting the rest of the bits. For this, the following bitwise operation is usually applied:

PORTD | = (1<<3);

We will analyze its syntax in detail below. And now one more example. Let's say we need to check the state of the 3rd bit of the PIND register, thereby checking the state of the button. If this bit is reset to zero, then we know that the button is pressed and then the command code is executed, which corresponds to the state of the pressed button. Previously, we would have used the following entry:

if (PIND == 0b00000000)

(some code)

However, with the help of it, we check not a separate, - the 3rd, but all the bits of the PIND register at once. Therefore, even if the button is pressed and the required bit is cleared, but at this time a signal is received on some other output of port D, the corresponding life will be set to one, and the condition in parentheses will be false. As a result, the code in curly braces will not be executed even when the button is pressed. Therefore, to check the status of a separate 3rd bit of the PIND register, a bitwise operation should be used:

if (~ PIND & (1<<3))

(some code)

To work with individual bits of the microcontroller in the arsenal of the C programming language, there are, with which you can change or check the state of one or more individual bits at once.

Setting a single bit

A bitwise OR operation is used to set a single bit, such as port D. We used it at the beginning of the article.

PORTD = 0b00011100; // initial value

PORTD = PORTD | (1<<0); применяем побитовую ИЛИ

PORTD | = (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // result

This command sets the zero bit, and leaves the rest unchanged.

For example, let's install another 6th bit of port D.

PORTD = 0b00011100; // initial port state

PORTD | = (1<<6); //

PORTD == 0b01011100; // result

To write one at once into several separate bits, for example, zero, sixth and seventh ports B the following entry applies.

PORTB = 0b00011100; // initial value

PORTB | = (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // result

Clearing (zeroing) individual bits

To clear a single bit, the three previously discussed commands are used at once: .

Let's clear the 3rd bit of the PORTC register and leave the rest unchanged.

PORTC = 0b00011100;

PORTC & = ~ (1<<3);

PORTC == 0b00010100;

Let's perform similar actions for the 2nd and 4th digits:

PORTC = 0b00111110;

PORTC & = ~ ((1<<2) | (1<<4));

PORTC == 0b00101010;

Bit switching

In addition to setting and resetting, a useful command is also used that switches a single bit to the opposite state: one to zero and vice versa. This logical operation is widely used in the construction of various lighting effects, for example, such as a New Year's garland. Let's look at the example of PORTA

PORTA = 0b00011111;

PORTA ^ = (1<<2);

PORTA == 0b00011011;

Let's change the state of the zero, second and sixth bits:

PORTA = 0b00011111;

PORTA ^ = (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Checking the status of a single bit. Let me remind you that checking (as opposed to writing) the I / O port is carried out by reading data from the PIN register.

The most common test is performed by one of two loop statements: if and while. We are already familiar with these operators earlier.

Checking the discharge for the presence of a logical zero (reset) with if

if (0 == (PIND & (1<<3)))

If the third bit of port D is cleared, then Code1 is executed. Otherwise, Code2 is executed.

Similar actions are performed with this form of recording:

if (~ PIND & (1<<3))

Checking the discharge for the presence of a logical unit (setting) with if

if (0! = (PIND & (1<<3)))

if (PIND & (1<<3))

The above two loops work in a similar way, but due to the flexibility of the C programming language, they can have a different notation. The operation! = Means not equal. If the third bit of the PD I / O port is set (one), then Code1 is executed, if not - Code2.

Waiting for a bit to be cleared with while

while (PIND & (1<<5))

Code1 will be executed as long as the 5th digit of the PIND register is set. When it is reset, Code2 will start executing.

Waiting for a bit to be set while

Here, the C syntax allows you to write code in the two most common ways. In practice, both types of recording are used.

One of the most important aspects of microcontroller programming is working with registers and ports. The AVR series microcontrollers have multiple I / O registers and 32 general purpose working registers. The programmer cannot directly write a number to the I / O register. Instead, it must write a number to a general register and then copy the value of that register to an I / O register. Work registers are designated as R1, R2, ..., R31.

To simplify the writing of programs, it is very convenient to give names to registers. It is advisable to give names that correspond to the stored information. For example, if register R16 is used to store temporary information, then it might be called temp. This is done as follows:

In order not to "call" the I / O registers and the main registers of the microcontroller, it is enough to connect the header file corresponding to the used microcontroller at the beginning of the program. Those. no need to name port registers, timers / counters, etc. For example, if the program is for the AT90s8515 microcontroller:

Include "8515def.inc"

For the AT90s1200 microcontroller - the very first AVR microcontroller, the I / O registers are numbered from $ 0 to $ 3F (depending on the MK model). Separately, I / O registers PortB, PinB, PortD, PinD can be distinguished (they have letter designations after connecting 1200def.inc, as well as their addresses are $ 18, $ 16, $ 12, $ 10 - you must agree that it is very difficult to keep digital constants in your head, simpler alphabetic names) ... The latest AVR microcontrollers have many more ports, they are called A, B, C, D, E ...

Consider the pinout of the popular ATtiny2313 microcontroller. Pins 2-9, 11 named PD0 - PD7 are Port D, similar to Port B. Note that Port B is 8-bit and Port D is 7-bit.

Ports can act as inputs and outputs. If the port works as an input, then in order to read the values, it is necessary to refer to the PinB or PinD register - depending on which port we are reading from. If some pins have high levels, the corresponding log. "1", the corresponding bits in the read values ​​will be set to "1". The pins are capable of withstanding a current of up to 20 mA, but do not forget about the total current of all port pins, since there are restrictions. If the port is an output, then the values ​​on the port lines are set by writing the corresponding value to the PortB or PortD register. To establish a log. "1" at the port output, set the corresponding bit in the PortB or PortD register.

The most important point of working with a port is working with a latch register, which is responsible for the operation of the port's input or output lines. The name of this register is DDRx, where x is the port letter. In order to make the legs outputs, we must write "1" to the corresponding bits. For example, we want to make the PB7 leg of port B an input, and the rest of the legs - outputs, then for this we need to write the value 0b01111111 to the DDRB register. The prefix 0b means that the number is written in binary. At startup, the DDRx registers are cleared, i.e. all legs are entrances. It is recommended to make unused feet in the device as inputs.

Consider a simple program that works with a microcontroller port:

Include "8515def.inc"; include the file with the descriptions of the registers. def temp = r16 rjmp RESET; RESET transition vector: ldi temp, 0b00000011; define PC0 and PC1 as outputs out DDRC, temp ldi temp, 0b00000001; light the LED on the PC0 out PORTC leg, temp in temp, PinC; reading levels from port C ... LOOP:; main loop of the program nop rjmp LOOP

Bit

Read / Write

Initial value

· Bit 7 - Enable all interrupts. To enable interrupts, this bit must be set to 1. The enablement of a specific interrupt is controlled by the interrupt mask registers EIMSK and TIMSK. If this bit is cleared (= 0), then none of the interrupts are processed. The bit is cleared by hardware after an interrupt occurs and is set to enable the interrupt later with the RETI instruction.
· Bit 6 - Save copy bit. Bit copy commands BLD and BST use this bit as source and destination for bit operations. The BST instruction copies the bit of the general register to the T bit, and the BLD instruction copies the T bit to the bit of the general register.
· Bit 5 - Half-carry flag. It indicates the transfer between tetrads when performing a number of arithmetic operations.
· Bit 4 - Sign bit. Bit S has the value of the result of the exclusive OR (N (+) V) operation on the negative (N) and two's complement overflow flags (V).

· Bit 3 - Two's complement of the overflow flag. It supports two's complement arithmetic.
· Bit 2 - Negative value flag. This flag indicates a negative result of a number of arithmetic and logical operations.
· Bit 1 - Flag of zero value. This flag indicates the zero result of a number of arithmetic and logical operations.
· Bit 0 - Carry flag. This flag indicates carry for arithmetic and logical operations.

The AT90S8535 microcontroller has 4 parallel I / O ports A, B, C, and D.
Port A is an 8-bit bidirectional port. Interaction with port A is carried out through three registers in the data memory input / output space: data register - PORTA, $ 1B ($ 3B), data direction register - DDRA, $ 1A ($ 3A), input data register - PINA, $ 19 ($ 39 ). The PINA register is read-only, and the PORTA and DDRA registers are read-write. The PINA register is not a register in the full sense of the word. Accessing it provides a read of the physical state of each port pin. Port A also serves to input analog A / D signals.

Port A Data Register -PORTA

Bit

Read / Write

Initial value

Port A Data Direction Register -DDRA

Bit

Read / Write

Initial value

Port A Input Data Register -PINA

Bit

Read / Write

Initial value

Port B is an 8-bit bidirectional I / O port. As well as port A, interaction with port B is carried out through three registers in the data memory input / output space: data register - PORTB, $ 18 ($ 38), data direction register - DDRB, $ 17 ($ 37) and input data register - PINB, $ 16 ($ 36). The PINB register is read-only. The PINB register is not a register in the full sense of the word. Accessing it provides a read of the physical state of each port pin. Port B pinouts can perform alternative functions, as shown in table. 2.1.

Table 2.1. Port B pinout alternatives

Port pin

Alternative function

T0 - Timer / Counter 0 clock input

T1 - Timer / Counter 1 clock input

AIN0 - positive terminal of the comparator

AIN1 - negative pin of the comparator

- slave SPI selection input

MOSI - set master output / slave SPI input

MISO - setting the master input / slave SPI output

SCK - SPI clock signal

When using pins for alternate functions, the PORTB, DDRB registers must be set appropriately.

Port data registerBPORTB

Bit

Read / Write

Initial value

Port B Data Direction Register -DDRB

Bit

Read / Write

Initial value

Port B Input Data Register -PINB

Bit

Read / Write

Initial value

Port C is an 8-bit bidirectional I / O port. As with ports A and B, interaction with port C is carried out through three registers in the data memory input / output space: data register - PORTC, $ 15 ($ 35), data direction register - DDRC, $ 14 ($ 34) and input data register - PINC, $ 13 ($ 33). The PINC register is read-only, and the PORTC and DDRC registers are read and write. The PINC register is not a register in the full sense of the word. Accessing it provides a read of the physical state of each port pin.
Port C has only two pins that can perform alternative functions: pins PC6 and PC7 serve as TOSC1 and TOSC2 of Timer / Counter 2.

Port data registerCPORTC

Bit

Read / Write

Initial value

Port C Data Direction Register -DDRC

Bit

Read / Write

Initial value

Port C Input Data Register -PINC

Bit

Read / Write

Initial value

Port D is an 8-bit bidirectional I / O port. As with ports A, B and C, interaction with port D is carried out through three registers in the data memory input / output space: data register - PORTD, $ 12 ($ 32), data direction register - DDRD, $ 11 ($ 31) and input data register - PIND, $ 10 ($ 30). The PIND register is readable, and the PORTD and DDRD registers are read and write. The PIND register is not a register in the full sense of the word. Accessing it provides a read of the physical state of each port pin.
Port D pins can perform alternative functions, as shown in table. 2.2.

Table 2.2. Port D Pin Alternate Functions

Port pin

Alternative function

RxD - UART receiver input

TxD - UART transmitter output

INT0 - external interrupt 0 input

INT1 - external interrupt 1 input

OC1B - output comparison of output B of timer / counter 1

OC1A - comparison pin of output A of timer / counter 1

ICP - Timer / Counter Capture Trigger Input 1

OC2 - output comparison of timer / counter 2 output

When using pins for alternative functions, the PORTD, DDRD registers must be set appropriately.

Port data registerDPORTD

Bit

Read / Write

Initial value

Port Data Direction RegisterDDDRD

Bit

Read / Write

Initial value

Port Input Data RegisterDPIND

Bit

Read / Write

Initial value

Since the work in question is the first one, in order to acquire the skills of working with the laboratory complex, all students first do the same work. From their workplaces, they enter into the PC the same problem of subtracting the number 3 from the number 5, given in paragraph 1.5.3.1. After compiling the program, it is written into the microcontroller of the workplace and its work is demonstrated to the teacher.
After such an acquaintance with the complex, the student proceeds to the individual assignment. If there is time, the teacher can complicate the individual task.