Path: AVR_EN => Applications => IR-controlled steppers    (Diese Seite in Deutsch: Flag DE)
IR-stepper ATtiny24 Applications of
AVR Single chip controllers AT90S, ATtiny, ATmega and ATxmega
Infrared controlled stepper motors with two ATtiny24
Logo

Two infrared-controlled stepper motors on one ATtiny24

If you need to this here is the correct solution for all your needs.

0 Structure

  1. Hardware needed
    1. Stepper motor hardware
    2. Controller hardware
  2. How it works
    1. The IR protocol and transmit algorithm
    2. The receiver algorithm
    3. The steppers
    4. The controller's keys
    5. The controller's LCD
  3. The software needed
    1. Software to download
    2. IR communication
      1. The IR protocol
      2. IR transmit
      3. IR receive
    3. The stepper motor software
      1. The stepper timing
      2. The stepper algorithm
    4. The controller software
      1. Display of positions
      2. Key software

1 The hardware needed

The hardware consists of two separate components: one that runs the model and controls the stepper motors in the model, and one where you can manually control direction and position by keys, with which you can transmit these commands to your model and read the target and the actual position of those on a LCD.

1.1 Stepper motor hardware

Schematic of the stepper motor controller This is the hardware for driving the two stepper motors. It consists of The operating voltage of the ATtiny24 (VCC) can be between 3.3 and 5 Volts (battery operation is possible). Currents are depending from the following. The IR transmit LED consumes roughly 20 mA at average during the rather short transmission time and at maximum 100 mA during the short active LED-on times at 40 kHz.

Top of page Structure Hardware How it works Software

1.2 IR controller hardware with LCD

Controller schematic This is the hardware needed for the controller board: The operating voltage depends from the LCD, either 3.3 or 5.0 V or anything in between can be used, therefore battery operation is possible.

Top of page Structure Hardware How the hardware works Software

2 How the hardware works

This chapter describes how the different components work.

2.1 IR transmitting

IR transmitting uses portpin PA3. It is an output, that is switched by the interrupt service routine of TC1 on compare match A. This switching implies the use of the "toggle" mechanism, by writing a one to bit 3 of the PINA port register.

A high on the PA3 pin switches the base of the driver transistor to +1.2 to +1.3 V, as set by the 1N4148 diodes. That leads to an initiated current of approx. 100 mA through the collector-emitter connection, until the emitter voltage reaches (+1.3 - 0.6) Volt, which is the case when 0.7 [V] / 6.8 [Ω] = 103 mA. Base current at this CE current is roughly 0.3 mA, so that the current through the diodes (either (3.3 - 1.3) [V] / 330 [Ω] = 6.1 mA at 3.3 Volt or (5 - 1.3) [V] / 330 [Ω] = 11.2 mA at 5 Volt operating voltage is not influenced significantly, it remains nearly constant.

The IR LED diode has a forward voltage of VForw = 1.6 V, so the heat power of the transistor is either (3.3 - 1.6 - 0.7) * 103 = 103 mW at 3.3 V operating voltage or (5.0 - 1.6 - 0.7) * 103 = 278 mW at 5 Volt. At these maximum heat powers the transistor does not need any additional cooling. From the thermal power view, a smaller transistor would also be possible, but the maximum current of a TO18 transistor of 100 mA could be exceeded.

At 40 kHz transmitting frequency one on/off cycle of the LED is lasting 25 µs. The minimum number of bursts (on/off cycles) to be detected by the TSOP31240 is 10, so the minimum duration of a complete burst signal is 250 µs. The same applies for the pause following the burst. So, 0.25 ms for an on as well as for the minimum-length of an off cycle is sufficient for a reliable operation of the receiver. The protocol of the IR transmission/receive is based on that and described in the software section. The assembler software allows other timing parameters, such as other LED frequencies, longer on and off times, etc., too. So design your own, if you aren't happy with the default settings.

2.2 IR receiving

IR reception is performed by the TSOP31240 module. If enough IR signals of its filter frequency of 40 kHz have been received, its output pin changes to low. Missing IR signals lead to the output pin going to high. Both level changes initiate PCINT0 interrupts, if so enabled by the mask and the PCINT0 interrupt enable.

The duration of those signals (active and pauses) is measured using the TC1, clocked by the ATtiny24 clock frequency (at 8 or 4 MHz). Each of the signal changes restarts TC1.

The further algorithm is described in the software section below.

Top of page Structure Hardware How the hardware works Software

2.3 The steppers

The two steppers are connected to the lower and the higher nibble of port A. If you use an ULN2801/2/3, you're fine. If it is a ULN2003A, this has only seven darlington drivers, the eight's driver is via an additional transistor.

Stepper motor internals Driving the motors forward and backwards, or left and right, is either done in full step mode or in half step mode. When in full-step mode, coils 1, 2, 3 and 4 are activated stepwise in a row to drive the motor forward. The magnet follows the changes in the magnetic fields produced by the four coils.

In half-step mode, first coil 1 is activated. In the next step coil 2 is additionally activated and the magnet moves to a position between coil 1 and coil 2. After that coil 2 is activated alone, so the magnet moves towards coil 2. Further five steps follow with either two or one coil activated.

That yields, when moving clockwise (forward) the following nibbles are used to drive the active stepper in the following manner:

ModeStepsDriver nibble movement forward
Full-step40b0001=0x1 => 0b0010=0x2 => 0b0100=0x4 => 0b1000=0x8= > (repeat)
Half-step80b0001=0x1 => 0b0011=0x3 => 0b0010=0x2 => 0b0110=0x6 => 0b0100=0x4 => 0b1100=0xC => 0b1000=0x8 => 0b1001=0x9 => (repeat)


Backward or left direction simply reverses the direction of those steps.

Note that in full-step mode only one of the four magnets of the stepper is sourcing current, while in half-step mode every second step switches two magnets on. So the power with which the steppers are driven is by 33% higher in half-step mode. That also means that the motor speed in half-step mode can be slightly higher than in the full-step mode. The desired speed of movement, at starting the motor and accelerated over the next following steps, is configurable in the source code.

The two stepper motors are implemented with the following algorithm.

Motor speed after motor start On start-up and when target positions change, the motor is driven with a lower frequency in cStepSlow (in Hz) to allow for a smooth motor start. This can for example be 100 Hz (10 ms/step) and is configurable by the source code. In each round (e.g. in 96 full steps (as shown here) or in 192 half steps, as defined in the constant cStepsSlowFast) the frequency is first slowly, later faster increased by reducing the delay between the steps. This repeats until the motor is driven with the maximum frequency as set in cStepFast. The acceleration is then stopped and the motor frequency remains at that value.

The same happens in reverse, if the motor nears its target position: the speed is step by step reduced with its speed reduction constant cStepsFastSlow until he reaches its lowest speed.

For the detailed implementation see the software section below.

Top of page Structure Hardware How it works Software

2.4 How the keys in the controller work

Design and operation of the four keys has been described here. When using the right resistors, each key combination of the four keys produces a unique voltage on the output. So if the keys Forward and Left are both pressed, the target position of motor 1 increases and the target position of motor 2 decreases. The longer a certain key is pressed, the larger is the increase or decrease caused by the key. The following table shows the increases with time.
Key pressed for ... secondsPosition increase/decrease
Half-stepFull-step
<0.8512
0.85224
1.7048
2.56816
3.411632
4.263264
5.1164128
5.96128256
6.82256512
7.675121,024
8.52++1,0242,048


Each change of the target position is immediately transmitted from the controller to the model, so that reaction times are very short.

Top of page Structure Hardware How it works Software

2.5 How the LCD in the controller works

The LCD is driven like shown here. The include file lcd.inc provides all necessary routines, such as LcdInit that configures the LCD, LcdSram that writes SRAM content to the LCD, etc. etc.. If you want to know how that works, follow the above link.

A special feature of the LCD are the special characters that are applied to display the current stage of transmit/receive on the IR:

TransmitReceive
# CharDescription # CharDescription
0Special character 0Transmit has started 4Special character 4Reception has started
1Special character 1Transmit has failed 5Special character 5Reception has failed
2Special character 2Transmit completed 6Special character 6Reception completed
3Special character 3Transmitter empty 7Special character 7Receiver empty


Those special characters are updated whenever the display of the line is necessary (because a value has changed) or when the respective event (error during transmission or reception) occurs.
Top of page Structure Hardware How it works Software

3 The software

3.1 Download of asm source code for controller and motor

The software for the controller and the motors is written in AVR assembler source code. It is under contruction.

Both work with the standard fuses. The clock frequencies are increased by software (writing to the CLKPR portregister), so no clock fuses have to be changed in advance.

Top of page Structure Hardware How the hardware works Software

3.2 How the IR communication software works

Both, the controller and the motors use a bi-directional IR transmit/receive connection. The following describes how this works in detail.

3.2.1 How the IR protocol has been designed

IR protocol This is how the IR communication protocol works. It starts with phase I, where any incoming IR receiver bits are detected, and transmit is skipped if any activities on the receiver happen during that time. The register rBits starts at 32. This is resulting from
  1. the inactive signal in phase I, plus
  2. one long start signal in phase II, plus
  3. one shorter start signal in phase III, plus
  4. four bits with motor number, plus
  5. 24 bits that encode the position, plus
  6. the final phase that ends transmission and finally restarts the receiver.
rCnt is decresed every time that an inactive phase ends and the next active phase starts.

If no signals are detected in phase I, the receiver is disabled by clearing its interrupt-enable bit and the LED-active part of phase II starts. In this phase the compare match A in TC1 is set to 12.5 µs for generating a 40 kHz signal (@8 MHz = 99, @4 MHz = 49). The register rCnt counts the number of ON/OFF phases of the LED. For the 2 ms long active LED signal 2,000 / 12.5 = 160 of such phases are necessary, providing 80 cycles of 25 µs each with the LED switched on and off.

After having switched the LED on and off, a duration of 2 ms pause is performed. This is done by setting the compare match value to 16,000 (at 8 MHz clock) and setting rCnt to one. In this phase no active switching takes place.

After the 2 ms phase II is over, the 1 ms long active signal phase III starts. The following pause of 1 ms duration is again achieved by a pro-longed OCR1A value.

The following 28 single bits to be transmitted all start with a 250 µs long active phase. If a zero is to be transmitted, a pause of 250 &mico;s follows. If a one is transmitted the pause is longer, 500 µs.

Finally a last active phase of 250 µs and a prolonged pause of 750 µ follows. After that the receiver is switched on again by enabling its interrupt flag.

The complete cycle lasts for between 22 and 29 ms, depending from the number of longer-lasting one-bits to be send.

Top of page Structure Hardware How the hardware works Software

3.2.2 How the transmission works

IR transmit flow diagram Transmit and receive both use TC1 in normal CTC mode with compare match A and the corresponding interrupt. The flow is shown in the diagram to the right.

The red clock cycle counts in the flow diagram are relevant to ensure that during active LED phases, where compare A matches occur every 12.5 µs @40 kHz LED frequency (10.4 µs @48 kHz) resp. every 100 (clock=8 MHz) or 50 clock cycles (clock=4 MHz) and the maximum number of consumed clock cycles in the compare match interrupt routine must not exceed these available clock cycles. Otherwise compare matches would be missed and the whole timing would get corrupted.

In receive mode the number of to-be-tranmitted bits in rBits is zero and OCR1A is set to 0xFFFF. If the compare match occurs, the counter is restarted at a high count to signal an illegal overflow of the TC1 to the receiver software part (normal receptions of IR signals do not last that long).

Prior to starting a transmission (by setting rBits to a non-zero value) the bits to be transmitted have to be prepared. Those are left-adjusted in the four transmit registers rTxN, where N ranges from 0 to 3 and 3 is the most significant. The toggle register rTgl has to be cleared, because transmit starts with an inactive LED. The compare match A of TC1 is set to the length of this inactive period and the cycle counter rCnt is set to one. Lastly rBits is set to the number of bits (header plus data bits plus one last bit) and transmission starts.

If rBits is not zero, the transmitting part of the TC1's compare match interrupt starts. At first, the register rTgl is written to LED input portregister. If the respective bit in rTgl is one, writing this bit toggles the port pin switching the LED on and off. As this register is zero at the beginning of the transmit cycles no toggling occurs in this stage.

Then the number of pulse counts in rCnt is decreased. If it is not zero (as it will be at start-up the transmission), the interrupt returns by restoring SREG to its initial value and a RETI. As this code sequence is needed very often, it is written as the macro RetInt to reduce source code lines and to increase code readability.

If rCnt reaches zero, the toggle bit in rTgl is reversed by ex-oring it with the active LED bit set. This operation either results in a zero- or a non-zero state. If the toggle bit now is one, an active phase starts. If it is zero, a pause starts and the flow diverts to the right side.

In case a new active phase starts (rTgl not zero), first the number of bits is decreased. If that reaches zero, the transmit process is over, the receiver interrupt is enabled and the compare match value is set to the top of TC1. As rBits now is zero until software starts a new transmit sequence, normal receive takes place. This is particularly relevant when switching from transmit to receive: to ensure that the receiver sensor does not get activated, a long pause at the end of the end of the transmit allows the receiver to get rid of pulses and to return to the normal receive situation.

If rBits does not get zero zero after decreasing it, the pulse duration in TC1 is set to 12.5 µs at 40 kHz. As this source code is also used very often, it is written into a macro SetOc, which expets as first parameter @0 the value that OCR1A should be set to.

The remaining code sets the number of LED on/off cycles in rCnt and depends from the number of rBits: If rTgl was zero after inverting it, the register rCnt has to be set one and the pause duration has to be written to OCR1A. If rBits is 30, the duration of phase III is written to OCR1A. If it is 31, the duration of phase II is written. If neither it is checked whether it is the last bit, in which case the final pause duration is written. In the other cases, the next bit to be transmitted is shifted to the carry flag, and the duration either of a zero or a one is written to OCR1A.

The longest of all these subdivisions of the interrupt service routine needs 38 clock cycles. That limits the clock frequency to at least 3 MHz at 40 kHz IR frequency or to 3.65 MHz at 48 kHz and provides even the opportunity to use even higher IR frequencies than 48 kHz with a 4 or 8 MHz controller clock.

At 8 MHz the sleep share in LED active phases is at 86%, over all transmit phases the sleep share is at 93.4%. This increase of the sleep share results from the fact that TC1 absolves the long pause cycles in an inactive manner with just counting clock cycles and without any interrupts in between until the pause ends. If many ones have to be processed, the sleep share even increases to up to 95.2%.

As all the times are configurable by changes to the source code the IR signal can be flexibly designed. The number of bits is not configurable but needs major changes in the source code if more or less than 28 are to be processed.

The first pulses of an active LED cycle To the right are the first pulses of an active LED cycle in the simulator avr_sim's oscilloscope view. Frequency and pulse width are exact.

The 2 ms pulse phase II On the left side are the active LED pulses with 2 ms length in phase II.

The first two header signals On the right you see the two header signals transmitted. The durations of 2 and 1 ms length are obvious.

The headers and the first four motor bits Left are the header signals in phase II and III and the first four bits (the motor number) have been transmitted.

The complete transmit On the right all 28 data bits and the final bit have been transmitted.

The complete transmit of ones On the left are 24 ones and four zeroes transmitted.

The complete transmit of all ones And right is the transmit of all ones.


Top of page Structure Hardware How the hardware works Software

3.2.3 How the IR receiver software works

IR receiver algorithm The receiver procudes a PCINT interrupt every time the IR sensor sees an active IR LED (high-to-low signal) and if the LED cycle turns off (low-to-high signal). The receiver uses the 16-bit timer TC1 to measure the time over which the input pin remains low and over which it remains high. The receiver algorithm uses these durations to check whether these times are correct (= within the expected duration) and collects the 28 data bits from this stream.

In order to do the duration measurement accurate, the PCINT interrupt service rotine starts by reading the MSB of TCNT1, and by that ignoring and overwriting the LSB. TCNT1 is then cleared by writing zeroes to it. That means the timer restarts on every signal reception. Setting the bRx flag on each signal reception event to block the start of the transmission algorithm. Finally SREG is read for later recovery of the SREG flags.

The flow then is diverted depending from the polarity of the receiver pin: if it is clear, an inactive LED signal had been coming in and was measured, otherwise the receiver sensor had seen an active LED signal.

In case of a pause received (left part of the flow diagram), its duration is compared with the shortest length of pause signals (which is a data zero). If the pulse is shorter (below its minimum length, the carry flag is set), an error has happened and the bRxE bit in rFlag is set one.

If it is longer and shorter than its maximum length, the zero bit is fine, the carry flag is cleared and the zero is shifted into the reception area in the SRAM buffer. If after shifting a one comes out of the four bytes, all bits have been received correct and the received position is copied to the respective registers of the position and the bRx flag is cleared to enable transmissions to start.

If not a zero bit has been received, it has to be tested if a one has been received. If the duration is higher or equal to the minimum duration and smaller than the maximum duration, a one-bit has been received and it is proceeded similarly with a one in the carry flag.

If the duration exceeds the maximum of a one-bit, the algorithm diverts to the check of the header lengthes of header 2 and then header 1. As both the active and inactive phases of the two header signals have identical duration, this simplification is possible. If the header 1 is correct, the receiver storage buffer is set to 0x000008 to collect data bits and finalize the bit collection.

This is the complete reception of incoming IR signals. The algorithm is used in the controller board's tiny as well as in the motor's tiny. Both, the transmit and the receive algorithm can be used generally, therefore those are encoded as include source code file that can be included into both source codes without any specific modification. That structuring of the source code requires that used parameters, such as the controller's clock rate, are provided to the include. All parameters that have to be defined outside the include are listed on top of the include source code. If entry parameters are missing within the include source code the assembler run will lead to errors and assembling will fail. So when assembling other source code that uses this include take care that anything has been set correct.

Top of page Structure Hardware How the hardware works Software

3.3 How the stepper software works

As the 16-bit timer/counter 1 is completely and permanently occupied by the IR transmit and receive algorithm, only the 8-bit timer TC0 is available for timing of the stepper motors. The TC0 runs permanently, with a fixed prescaler value.

3.3.1 Timing of the two steppers

The stepper motors are to be driven with a frequency of between, e.g., 100 to 400 Hz. That means that their stepping requires delay times between 10 and 2.5 ms. As the motor controller ATtiny24 runs with either 8 or 4 MHz and TC0 needs 256 clock cycles for its turn-around, the following times are achieved with the different prescaler values:

ClockPrescalerTurn-around timeDelayDelayMin=2Max fMax=254Min f
MHz(ms)(10 ms)(2.5 ms)(µs)Hz(µs)Hz
810.03280,00020,0000.254,000,00063.515,748.03
80.25610,0002,5002500,0005081,968.50
642.0481,250312.51662,5004,064246.06
2568.192312.578.1256415,62516,25661.52
1,02432.76878.12519.531252563,906.2565,02415.38
410.06440,00010,0000.52,000,0001277,874.02
80.5125,0001,2504250,0001,016984.25
644.096625156.253231,2508,128123.03
25616.384156.2539.06251287,812.532,51230.76
1,02465.53639.06259.7656255121,953.135130,0487.69


That means that The range of potential frequencies is broad enough with a fixed prescaler value of 1,024. At that and at 8 MHz TC0 runs with 7.8125 kHz or at 4 MHz at 3.90625 kHz. Its two compare matches A and B control the motor movements of motor 1 and motor 2. Those can occur at multiples of 128 or 256µs, depending from the controller clock.

The stepper algorithm

From that the following algorithm results for driving the motors:
  1. Timer TC0 runs with the clock rate divided by 1,024 (at 7.81 resp. 3.91 kHz). On compare match the flags bM1 or bM2 are set. Compare match interrupt service routines
  2. Further processing of the flagged compare matches is performed outside the interrupt service routines. The two flags are checked and if set the respective motor is moved (or not). Sleep and motor driver wake-up
  3. The further processing of the motors is formulated as a macro, because the code for the two motors does not differ much. The macro takes parameter @0 as motor number (either 1 or 2) to do the different tasks, if necessary. Motor algorithm
  4. First of all the set flag has to be cleared. Then the respective old motor position is copied to the SRAM storage space, where it substracted from the target position. If after that the carry flag is set, the motor is to be moved backwards. If the carry flag is clear, and the Z flag is clear, then a move forward is performed. This is also the case if the lower bytes of the position are not equal to the target position's lower bytes.
  5. In case the motor is to move backwards, either a 1 (in half step mode) or a 2 (in full step mode) is to be subtracted from the current motor position. Additionally, the distance is to be negated because it is negative (to get the positive distance to the target positionand needed later on). In case motor movement is forward, the 1 or 2 are added to the current position.
  6. The motor's sCnt is cleared, so if the next position matches the target position, the routine will start with that count. The the lower three bits of the actual position are then converted to the next driver nibble (by use of the nibble table and of LPM) and are written to the respective motor nibble by reading and saving the other nibble.
  7. To increase the speed of the next motor step, the speed delta is the subtracted from the sDlyN variable by a 16-bit subtraction. If the MSB of the sDlyN is smaller than the minimum delay (at the highest motor movement frequency), sDlyN is set to this minimum to prevent from too high driving speed.
  8. The distance to the target position, as calculated in sMNP, is the checked. If the distance is smaller than the constant cNearN the delay is increased by the constant cFastSlow. In that case it is checked whether the delay would exceed the maximum delay (and set to the maximum if that is the case).
  9. Finally, the variable sDlyN is added to the current TC0 count and then written to the respective compare match register port.
  10. If the motor finally reaches its target position and the counter sCntN is at zero (the last compare match was a movement), the current postion is transmitted via the infrared conncetion. This is repeated at every compare match after 256 clock cycles (every 65 ms) if the flag bTxSkipped had been set. If sCntN reaches the constant cMotorOffN the motor driver is switched off by clearing its motor bits.
The algorithm that determines which coil(s) of the stepper need to be activated uses the following table:

StepTable:
  .db 1,3,2,6,4,12,8,9 ; Stepper coils to be activated

In full-step mode, advancement of the positions are with two (so that only four of these values are used), while in half-step mode each single position is used.

Algorithm uses the lowest three bits of the position as displcement to this table to read the driver value nibble with the LPM instruction for the next driver nibble. If motor 2 is to be written, the lower nibble read has to be swapped to the higher nibble and the upper nibble has to be overwritten with the next nibble. In case of motor 1 the upper nibble is preserved, the lower nibble is cleared and overwritten by the nibble read from the table.

Top of page Structure Hardware How the hardware works Software

3.4 How the controller software works

3.4.1 How the display of target and actual positions works

The controller's display The controller's LC Display shows
  1. in line 1 the target position of the first motor, as adjusted with the forward/backward keys,
  2. in line 2 the actual position of the first motor, as reported via the IR backlink by the stepper software,
  3. in line 3 the target position of the second motor, as adjusted with the right/left keys,
  4. in line 4 the actual position of the second motor, as reported via the IR backlink by the stepper software.
The target and actual positions are in steps of the motor, so +100 means that motor 1 has to move to step 100 and then reports back 100 as position. As the 24-bit signed integers cover a range between -8,388,608 and +8,388,607, the positions need a conversion software that handles up to 9,000,000. The conversion is in detail as shown below.

The actual positions of motor 1 and motor 2 are also converted from positions to rounds. This is done by multiplying the position with the factor 16,777,216 / steps per round and dividing the result by 16,777,216 (to round up and skip the last three bytes of the multiplication result), just to avoid a perform a 24-by-24-bit division. The number of steps that the stepper motor and its gear reduction need for one round of the wheel are configurable for motor 1 and 2 separately, but can well exceed 1,000 steps per round. For example: the small stepper motor 28BYJ-48 needs 96 steps per round, so the position is multiplied with 16,777,216 / 96 = 174,762, rounded up to 174,763. By doing a 24-by-24-bit multiplication, the error margin is very small. The result is displayed behind the R: in the actual line.

In both cases only negative numbers are signed, the sign character is placed immediately in front of the numbers for better recognition.

The display of 24-bit-signed integers of positions and of the rounds is performed using the decimal conversion of the 24-bit numbers in the routine DecimalConv. Depending from the input in rmp (0 to 3) this routine does all converting, multiplying and formatting of one complete line for the LCD. To save registers, the decimal conversion is done by loading the decimal number to the registers rDec2:rDec1:rDec0 and by repeated subtraction of this decimal from the number in rNmb2:rNmb1:rNmb0. The digit subtraction, counting as well as the leading zero blanking is done in the subroutine DecDigit. By calling this routine with 1 million, 100,000, 10,000, 1,000, 100 and 10 in rDec the single digits are determined and written to their appropriate positions in the line buffer. Lastly an eventual negative sign is added on an appropriate position, if necessary.

Top of page Structure Hardware How the hardware works Software

3.4.2 Changing the target positions with the ADC values

The four keys Forward, Backward, Right and Left are connceted to a resistor matrix R1 to R5, which produces a characteristic voltage on the AD input pin ADC0.

Top of page Structure Hardware How the hardware works Software



©2020-2022 by http://www.avr-asm-tutorial.net