Programming MK from scratch. AVR programming

I have not once and not two saying that the study of the MK should be started with the assembler. This was dedicated a whole course on the site (although it is not very consistent, but gradually I combed it to an adequate type). 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 on the monkey copy other people's sources and try to understand why it suddenly stopped working. In addition, the SI is much easier to overtake by the middle oflood, which will come out with forks at the most inopportune moment.

Unfortunately, everyone wants the result immediately. Therefore, I decided to go on the other hand - to make training on SI, but with the show of his underwear. A good programmer-embedder always holds his piece of iron for a squall, without giving her a step to step without permission. So it will be at the beginning of the SO code, then what born the compiler and how it really works in fact :)

On the other hand, si strong side This is porteability code. If, of course, writing everything correctly. Separating the work algorithms and their iron implementations in different parts of the project. Then, to transfer the algorithm to another MK, it is enough to rewrite only the interface layer, where all appeal to the gland is written, and leave the entire working code as it is. And, of course, readability. The sash source source is easier to understand at first sight (although .. I, for example, do not care about what to flirt is at least si, at least AFM :)), but, again, if you write everything right. With this moments, I will also pay attention.

As a conducting piece of hardware on which the lion's share of all examples will be mine debug fee.

First program on C for AVR

Choosing a compiler and installation of the environment
For AVR, there are many different C compilers:
First of all it IAR AVR C. - Almost uniquely recognized as the best compiler for AVR, because The controller itself was created by the close cooperator of ATMEL and specialists from IAR. But for everything you have to pay. And this compiler is not enough of what is expensive commercial software, it also possesses such a breakfast settings that just take and compile it in it should be rushed. I really didn't have a friendship with him, the project was drunk on strange mistakes at the linkage stage (later found out that it was a crack curve).

The second is coming WinAvr GCC. - Powerful optimizing compiler. Full opens, cross-platform, in general, all the joys of life. He also integrates perfectly in Avr Studio allowing you to debug right there that hell is comfortable. In general, I chose it.

Also there is CodeVision AVR C.- Very popular compiler. He became popular in connection with his simplicity. Working program You can get in it in a few minutes - the master of the starting code is greatly promoted, the stamp of the initialization of all kinds of ears. Honestly, I'm sorry with suspicion to him - somehow I had to disassemble a prog written by this compiler, some kind of meant, but not the code was obtained. A terrible amount of unnecessary televitations and operations, which was poured into a slight codes and slow speed. However, perhaps there was a mistake in DNA wrote the original firmware. Plus he wants money. Not much like Iar, but noticeable. And in demozhim gives not more than 2KB code.
Crack of course there is, but if you steal, so a million, in the sense of IAR :)

There is also Image Craft AVR C and Microc from microelectronics. Neither to use any other use, but here SWG. Very plowing MicropascalMelt is a terribly convenient programming environment and library. I think Microc will not be worse, but also paid.

As I said, I choose WinAvr. For three reasons: free, it is integrated into AVR Studio and it is written simply a breakdown of the finished code for all occasions.

So download yourself to install WinAvr C and AVR Studio. Then the studio is first put, then, from above, WinAvr rolls over and clings to the studio in the form of a plugin. I strongly recommend installing WinAvr on a short way, something like C: \\ WinAvr Thereby, thereby you avoid piles of problems with the ways.

Creating a project
So, the studio is delivered, Si is fastened, it is time to try something to program. Let's start with a simple, simplest. Launch the studio, choose there new project, as a compiler AVR GCC and enter the name of the project.

Opens the work field with an empty * .c file.

Now it does not prevent configure the display of paths in the Studio tabs. For this, the slant at:
The Tools menu - Options - General - Filetabs and select "FileName Only" in the drop-down list. Otherwise it will be impossible to work - on the tab there will be a full path of the file and there will be no more than two tabs on the screen.

Project Setup
In general, the creation of the Make file in which all dependencies would be described. And this is probably correct. But I grew up on fully integrated IDE like uvision or AVR Studio. This approach is deeply alien. Therefore, I will do in my own way, all the studios.

Pile into the button with a gear.


These are the settings of your project, or rather the setting of automatic generation of the Make file. On the first page you just need to enter the frequency on which your MK will work. It depends on the fuses of bits, so we believe that the frequency is 8000000Gz.
Also pay attention to the optimization string. Now there is --OS is optimization in size. While leave as it is, then you can try to play with this parameter. -O0 is removable optimization at all.

The next step is to configure paths. The first thing to add the directory of your project there is - you will put a third-party library there. The list will appear ". \\"

Make file generated, you can see it in the Default folder in your project, just run through your eyes, see what is there.


That's all. Jim everywhere OK and go to the source.

Formulation of the problem
The blank sheet is so waved to embody some tricky idea, since the banal blinking of the diode does not insert. Let's immediately take a bull for the horns and implement a connection with the computer - this is the first thing that I do.

It will work like this:
Under the arrival of the COM port, the unit (code 0x31) will light the diodion, and when the arrival of zero (code 0x30) is extinguished. Moreover, everything will be done on interrupts, and the background task will be blinking another diode. Simply and with meaning.

Collect the scheme
We need to connect the USB-USart Converter module with the microcontroller usart converters. To do this, take a jumper of two wiring and put the cross in the pins of the cross. That is, the Rx controller connects with the TX converter, and the TX converter with the RX controller.

It turns out, as a result, this is such a scheme:


Connecting other conclusions, nutrition, discharge, it is standard

We write code

Immediately make a reservation that I will not deepen specifically in the description of the SI language itself. For this, there is simply a tremendous amount of material, ranging from the classics "SI programming language" from K & R and ending with different techniques.

One such method was found in me in the honeycomb, I once studied this language on it. There everything is brief, understandable and in the case. I gradually make it up and rearranged to my site.

There's really not all chapter postponed, but I think it's not for long.

It is unlikely that I will describe better, so from the training course, instead of a detailed exposure of the blue subtleties, I will simply give direct links to certain pages of this technique.

Add libraries.
First of all, we add the necessary libraries and titles with definitions. After all, si is a universal language and he needs to explain that we work with AVR, so enter into the source line:

1 #Include.

#Include.

This file is in the folder WinAvr. And it contains a description of all registers and ports of the controller. And there all cunning, with reference to a specific controller, which is transmitted by the compiler through make File in the parameter MCU. And on the basis of this variable in your project, a header file with a description of the addresses of all ports and registers is on this controller. In how! Without it, too, it is also possible, but then you will not be able to use the symbolic names of the registers like a SREG or UDR and have to remember the address of each such as "0xc1", and this is a head.

The same team itself #Include.<имя файла> Allows you to add to your project the contents of any text file, for example, a file describing the functions or a piece of another code. And so that the directive could find this file, we indicated ways to our project (the WinAvr directory is already spelled out there).

Main function.
The program in the SI language consists of functions. They can be embedded and brought from each other in any order and in different ways. Each function has three required parameters:

  • Return value, for example, sIN (X) Returns the value of the X Sinus. As in mathematics, in short.
  • Transmitted parameters, the same X.
  • Body function.

All values \u200b\u200btransmitted and returned must be any type, depending on the data.

Any program on C must contain a function main. As a point of entry to the main program, otherwise it is nifiga not si :). According to the presence of Main in someone else's source from a million files, it can be understood that this is the head 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;)

Everything, the first simplest program is written, it does not matter that she does nothing, we just started.

We will analyze what we did.
int. This type of data that the Main function returns.

Of course, in a microcontroller main. I can not return anything in principle and in theory should be void Main (Void)But the GCC is initially sharpened on the PC and there the program can return the value of the operating system upon completion. Therefore GCC on void Main (Void) swearing warning.

This is not a mistake, it will work, but I do not like Varnings.

void. This type of data that we transmit to the function in this case main. Also can't take anything from the outside, the poet void. - Dummy. The plug is applied when it is not necessary to transmit anything or return.

These are { } Figure brackets are a software block, in this case the body function main., there will be the code.

return. - This is the return value that the Main function will give upon completion, since we are int, that is, the number that we must return the number. Although it still does not make sense, because On the microcontroller from Main, we except for nowhere. I return zero. For nonfig. And the compiler is usually smart and the code does not generate the code.
Although, if you pervert, then from main. You can go to the MC - for example, fall into the bootloader section and fulfill it, but there is already a low-level firmware picking, to adjust the transition addresses. Below you will see and understand how to do it. What for? This is another question, in 99.999% of cases this nafig is not necessary :)

Made, went further. Add a variable, it is not particularly necessary for us and it is not necessary to introduce variables, but we are learning. If the variables are added within the body of the function - then they are local and exist only in this function. When you leave the function, these variables are removed, and the memory of RAM is given to 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. So unsaluable. The fact is that in binary representation, we have a senior bit for the sign, which means in one byte (char) the number + 127 / -128, but if the sign discardes it gets already from 0 to 255. Usually the sign is not needed. So that unsigned..
i. - This is just the name of the variable. No more.

Now you need to initialize ports and UART.. Of course, you can take and connect the library and call some kind of uartinit (9600); But then you will not know what happened in fact.

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) \u003e\u003e 8) #define Lo (x) ((x) & 0xFF) uBrrl \u003d Lo (Bauddivider); UBRRH \u003d HI (Bauddivider); Ucsra \u003d 0; UCSRB \u003d 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) \u003e\u003e 8) #define Lo ( x) ((x) & 0xFF) uBrrl \u003d Lo (Bauddivider); uBrrh \u003d Hi (Bauddivider); ucsra \u003d 0; ucsrb \u003d 1<

Scary? In fact, the real code here is only five last lines. Everything, that #Define This is a macro-language preprocessor. Almost the same tops as in the assembler, but the syntax is somewhat different.

They will facilitate your routine operations to calculate the necessary coefficients. In the first line we say that instead Xtal You can safely substitute 80,000,000, and L.- Type specification, Long Mall are a processor clock frequency. Same baudrate. - Data frequency by UART.

bauddivider. Already more complicated, the expression calculated by the formula of two previous ones will be substituted instead.
Well and LO. and HI From this result will take the younger and senior bytes, because In one byte it clearly may not fit. IN HI Icse shift is done (the input parameter of the macro) eight times in the right, as a result, only the oldest byte will remain. A B. LO. We make a batch and with a number 00FF, as a result, only the youngest byte will remain.

So all that is done as #Define You can safely throw out, and the desired numbers count on the calculator and immediately enter them into the UbBrl \u003d lines .... and ubbrh \u003d ... ..

Can. But! Do this It is categorically impossible!

It will also work to work, but you will have the so-called magic numbers - The values \u200b\u200btaken incomprehensibly from where it is not clear why and if you donate such a project in a couple of years, then it is difficult to understand that it will be damn it. Yes, and now, you want to change the speed, or change the frequency of quartz and everything will have to recalculate, and so changed a couple of tsiferok in the code and everything itself. In general, if you do not want to enjoy Bydlokoder, then do the code so that it is easy to read, it was understandable and easily modified.

Then everything is simple:
All these "UBRRL and CO" are the registers of the configuration of the transmitter with which we will communicate with the world. And now we have assigned the necessary values \u200b\u200bby configuring the desired speed and the right mode.

Recording view 1< Means the following: take 1 and put it in place RXEN. In the fly. RXEN. This is the 4th bit of the register UCSRB., so that 1< forms a binary number 00010000, TXEN. - this is a 3rd bit, and 1< Dast 00001000. Single "|" It is broken ORso 00010000 | 00001000 \u003d 00011000. The remaining necessary configuration bits are exhibited in the same way and added to the general bunch. As a result, the assembly number is written in UCSRB. Details are written in Datashet on the MC in the USArt section. So do not get distracted by technical details.

Ready, it is time to see what happened. Pips on the compilation and launch of emulation (Ctrl + F7).

Debugging
All sorts of progress bars ran, the studio changed and a yellow arrow appeared near the Main function. This is where the processor is currently current, and the simulation on the pause.

The fact is that initially, in fact, it stood on the row UBrrl \u003d Lo (Bauddivider); After all, the fact that we have in define it is not code, but simply preliminary calculations, then the simulator fastened a little. But now he realized, the first instruction is completed and if you climb into a tree I / O View, In the USArt section and win there on the UbBrl byte, you will see that there is already there already! 0x33.

Make one more step. Looking at how the contents of another register change. So fuse them all, pay attention to the fact that all the indicated bits are exhibited as I said, and it is set at a time for the entire byte. Next Return does not work, the program is over.

Opening
Now reset the simulation in zero. Click there RESET (SHIFT + F5). Open disassembly listing, now you will see what happens in the controller in fact. View -\u003e Disassembler. And not yyaaaa !!! Assembler !!! Uzhos !!! BUT YOU MUST. So that later, when something goes wrong, did not dare into the code and did not ask Lamer issues on the forums, and immediately climbed into the loss and watched where you have a stall. There is nothing terrible there.

First, it will be a top of 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 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 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 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

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 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 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 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

This is the table of interrupt vectors. We will come back to it, while just see and remember that it is. The first column is the flash address of the flash in which the command is lying, the second command code of the third mnemonic team, the same assembler instruction, the third operand of the team. Well, an automatic comment.
So, if you look, then there are solid transitions. And the JMP command code is four byte, it contains the transition address recorded by the backward - the younger byte for the younger address and the code of the transition command 940C

0000002B: BE1F OUT 0X3F, R1 Out to I / O Location

Recording this zero to 0x3F address if you see the I / O View column, then you will see that 0x3f address is the address of the SREG - Flag Register Controller Register. Those. We reset the SREG to run the program at 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 the loading of the stack pointer. Directly shipping in I / O registers can not, only through the intermediate register. Therefore, first LDI in the intermediate, and then from there Out in I / O. I will also tell you more about the stack. In the meantime, it is known that this is such a dynamic memory area, hanging in the end of RAM and keeps addresses and intermediate variables. Now we pointed out where we will have a stack.

00000032: 940C0041 JMP 0x00000041 JUMP

Jump to the Saaaeaeee End of the program, and there we have a ban of interrupts and looping tightly by 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 output from the Main function. From such a loop, the controller can be displayed either with a hardware reset, or that is likely, discharge from the watchdog dog - Watchdog. Well, or, as I said above, correct these places in Hex editor and routing where we have a soul. Also pay attention to the fact that there are two types of JMP and RJMP transitions The first is a direct transition to the address. It takes four bytes and can make a direct transition throughout the memory area. The second type of transition - RJMP - relative. His team takes two bytes, but the transition it does from the current position (addresses) by 1024 steps forward or backward. And in its parameters, the offset from the current point is indicated. Used more often, because It takes two times less space in flush, and long factors are rarely needed.

1 +000034: 940c0000 JMP 0x00000000 JUMP

00000034: 940C0000 JMP 0x00000000 JUMP

And this is a jump at the very beginning of the code. Restart a kind. You can check, all the vectors jump here. From this output - if you allow you to allow interrupts (they are prohibited by default) and you will be interrupted, but there is no handler, then there will be a program reset - the program will throw the program at the very beginning.

Main function. Everything is similar, you can even not describe. Looking just to the registers already calculated the number. Preprocessor compiler taxis !!! So no "magic" numbers!

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

00000036: E383 LDI R24.0X33 LOAD IMMEDIATE +000037: B989 OUT 0X09, R24 OUT TO I / O Location 15: UBRRH \u003d HI (Bauddivider); +000038: BC10 OUT 0x20, R1 OUT TO I / O Location 16: UCSRA \u003d 0; +000039: B81B Out 0x0b, R1 Out to I / O Location 17: UCSRB \u003d 1<

And here is the jamb:

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

It is asked why this compiler adds such a topmaster? And this is nothing but Return 0, then we have identified as int Main (Void). So I won more than four bytes do not understand what :) And if you do a Void Main (Void), it will only be RET, but varning will be. What they say we do not return anything to the Main function. In general, do it like you :)

Complicated? It seems to be no. I skip step-by-step performance in the disassembler mode and the pokery as the processor performs individual instructions, which happens with registers. How to move on commands and final looping.

Continuation follows in a couple of days ...

Offtop:
Alexei78. Gang a fixing plugger for firefox facilitating navigation in my site and forum.
Discussion and download

For programming AVR microcontrollers, there are a lot of development tools, however, the most popular, undoubtedly, a package should be recognized AVR Studio. . There are a number of reasons for such popularity - this is a free package developed by the company Atmel , It combines text editor, assembler and simulator. The AVR Studio package is also used in conjunction with fixing hardware. In the proposed article, the examples consider techniques to work with a package, which will help beginner programmers to understand the interaction of individual components of AVR Studio.

In the next part of the article will be described about debugging in the AVR Studio environment of programs written in SI.

The AVR Studio package has a solid development history, which is reflected in the number of existing versions. At the end of 2003, version 4.08 was released, which has a number of useful additions, and at the beginning of 2004 an update (Service Pack 1) has been released, adding support for the AVR-controllers of the third generation of the ATMEGA48 family. The production of chips of this family is scheduled for the second half of 2004.

The package distribution and service pack can be downloaded from www.atmel.com or get a CD with this distribution from the Russian Distributor of ATMEL.

The work of the AVR Studio package is conveniently reviewed on any specific program. As an opinion, we will consider creating a project for the simplest program, which will be in turn to light two LEDs. For definiteness, take a microcircuit ATMEGA128. and connect the two LEDs in the conclusions 31 and 32 (these are bits 6 and 7 of the port D chip ATMEGA128). AVR controllers have powerful output cascades, the typical current of each output is 20 mA, the maximum output current is 40 mA, and this refers to both flowing and to the flowing current. In our example, the LEDs are connected to the anodes to the conclusions of the controller, and the cathodes through the quenching resistors are connected to the ground. This means that the LED is ignited by the feeding "1" to the corresponding port output. The schematic diagram is shown in the figure. The diagram also shows the two buttons to be used in one of the programs.

Here it is appropriate to make a small digression about choosing a type of chip for the simplest example. Indeed, at first glance, it may seem strange, why you need such a powerful crystal in a 64-pin case where there is enough 8-pin chip Attiny12. ? However, in this approach there is logic. It is known that at the heart of almost any AVR controller lies the same kernel. By and large, controllers differ in memory, the number of I / O ports and a set of peripheral modules. Features of each specific controller - binding logical name / output registers to physical addresses, addresses of interrupt vectors, identifying port bits, etc. Describes in files with extension.inc, which are included in the AVR Studio package. Consequently, using a specific type of crystal, you can debug the program as itself for it and for any younger crystal. Further, if you use the most senior crystal as a debugging, today it is ATMEGA128, you can debug a program for almost any AVR controller, you just need to use hardware resources that are missing from the target microcontroller. Thus, for example, you can debug the program to be performed on the ATMEGA128 Attiny13. . In this case, the source code will remain practically the same, only the name of the connected file with 128def.inc on TN13DEF.INC will change. This approach also has its advantages. For example, "extra" I / O ports can be used to connect. LCD indicator which you can withdraw debug information. Or, use the intrahemum emulator that connects to the JTAG port of the ATMEGA128 chip (the ATTINY13 controller does not have this port). Thus, it is possible to use a single debug board on which the "senior" AVR controller is installed, to debug any newly developed systems, naturally based on AVR microcontrollers. One of these boards is called AS-Megam. It was it that was used to create examples of programs given in the article. This is a universal single-board controller based on the ATMEGA128 chip, which contains external RAM, two ports RS-232. , port for connecting LCD indicator, intrahemnoe programmer and emulator AT JTAG ICE . The board also has a place to split Flash-ROM series chip AT45 In the housings TSOP32 / 40/48 and a two-channel series DAC AD5302 / AD5312 / AD5322 . Now, after explaining the causes of the use of AVR monster to ignite a pair of swatodiodes, you can go further.

When programming in the AVR Studio environment, you need to perform a standard sequence of actions:

  • compilation
  • The project creation begins with the selection of the Project \\ New Project menu. In the "CREATE NEW PROJECT" window that opens, you must specify the name of the project, (in our case - sample1) and the name of the initialization file. After pressing the "Next" button, the Select Debug Platform and Device window opens, where the debug platform (simulator or emulator) is selected and the type of microcontroller.

    You can choose one of the offered intrahemny emulators, we note that each emulator has its own list of microcircuits supported. For the example under consideration, we choose as a debug platform AVR Simulator and the ATMEGA128 chip. After pressing the "FINISH" button, our output appears the work windows of the AVR Studio package, while empty. It follows the right window to place the source text of the program. This can be done in two ways, or dial all the text directly in the editor window, or download an existing file. Below is the full text of the simplest program with comments.

    ; Example "LED control"; written for AS-Megam debug board; The frequency of the parameter generator is 7.37 MHz; LEDs are connected to PD6 and PD7 conclusions and through resistors - on a shared wire. ; Connecting the ATMEGA128 Circuit I / O Details File "M128DEF.INC"; The beginning of the Begin program :; first operation - stack initialization; If this is not done, then call a subroutine or interrupt; will not return control back; The pointer at the end of the stack is set to the last address of the internal RAM - Ramend LDI R16, LOW (RAMEND) OUT SPL, R16 LDI R16, HIGH (Ramend) Out Sph, R16; In order to control LEDs connected to PD6 and PD7 conclusions; It is necessary to declare these conclusions output. ; To do this, write "1" to the corresponding bits of the DDRD register (Datadirection) LDI R16, (1<<6) | (1<<7) out DDRD,r16 ; основной цикл программы loop: ldi r16,(1<<6) ; светится один светодиод out PORTD,r16 rcall delay ; задержка ldi r16,(1<<7) ; светится второй светодиод out PORTD,r16 rcall delay ; задержка rjmp loop ; повторение цикла; процедура задержки; примерно полсекунды при частоте 7,37 МГц; три пустых вложенных цикла соответственно delay: ldi r16,30 ; 30 delay1: ldi r17,200 ; 200 delay2: ldi r18,200 ; и еще 200 итераций delay3: dec r18 brne delay3 dec r17 brne delay2 dec r16 brne delay1 ret ; возврат в главную программу

    The project may consist of several files, while one file is assigned the main one. All operations are convenient to produce using the context button of the mouse. After connecting the source file, the windows have the following form.

    The compilation of the project is made by the \\ Project \\ Build command or by pressing the F7 button. The compilation process is displayed in the "OUTPUT" window. This window can be "pulling" the \\ View \\ Output command.

    In principle, we have already received an output file in format.Hex, which can already be loaded into the microcircuit and observe the trustees of the LEDs. However, the purpose of the article is to show the full cycle of work in the AVR Studio environment, so we go to the debug stage. This is done by the \\ Debug \\ Start Debugging team.

    Now set the frequency of quartz frequency 7,3728 MHz in the "Simulator Options" window to accurately measure the execution time of the program.

    The remaining options should be left unchanged. Now you can perform a program in step-by-step mode using the mouse or the F11 button.

    The AVR Studio package contains powerful tools for viewing and editing the state of the internal registers and I / O ports of the debugged microcontroller, as well as the time, program execution. Access to them is carried out through the "I / O" window.

    In fact, the amount of information available through the AVR Studio package viewing windows is so large that it is necessary to use a computer in a two-monitor configuration to obtain maximum comfort.

    To debug our example, to access the ports d bits, you need to reveal the I / O ATMEGA128 string and then the portd line. Now all three registers of this port, Portd, DDRD and PIND are visible. To see the fields of Value, Bits and Address, you will have to expand the right border of the window, sweating the window with the source text of the program.

    Now, passing the program in step-by-step mode, you can see the change in the current states of these registers in the BITS field. It is possible to quickly change the state of any bit of the port registers, and this can be done either by writing a new code in the Value field, or directly by clicking on the desired bit of the register.

    For independent exercises, the following program is proposed, which differs from the previous one that the ignition of the LEDs is controlled by two buttons.

    ; Example "LED control from buttons"; written for AS-Megam debug board; LEDs are connected to PD6 and PD7 conclusions and through resistors - on a shared wire. ; Buttons - on PE4 and PE5 .include "M128DEF.INC"; BEGIN main program:; Stack initialization LDI R16, LOW (RAMEND) OUT SPL, R16 LDI R16, HIGH (Ramend) Out Sph, R16; Initialization of LED LEDs R16, (1<<6) | (1<<7) out DDRD,r16 ; инициализация выводов, к которым подключены кнопки (на вход) ; внутренние подтягивающие резисторы подключены; для этого в PORTE нужно установить соответствующие биты в единицы ldi r16,(1<<4) | (1<<5) out PORTE,r16 ; а в DDRE - в нули ldi r16,0 out DDRE,r16 ; бесконечный цикл forever: in r16,PINE ; теперь в r16 находится текущее "состояние" кнопок com r16 ; кнопка "нажимается" нулем, поэтому инвертируем регистр lsl r16 ; переносим биты 4,5 в позиции 6,7 lsl r16 ; и обновляем "показания" светодиодов andi r16,(1<<6) | (1<<7) out PORTD,r16 rjmp forever ; цикл выполняется бесконечно

    Thus, on the example of the simplest programs, some features of the AVR Studio package are shown. It is necessary to understand that this is only the first acquaintance that allows you to quickly get used with the basic package commands. Meanwhile, the capabilities of the package under consideration are much wider. For example, here you can debug programs written in high-level languages. In particular, the C-compiler of the company ImageCraft uses the AVR Studio debugger "as a native". To do this, when compiling the source code, you need to set the output file generation option in a format compatible with AVR Studio. At the same time, it is possible to debug in the source codes.

    Another of the many characteristics of the AVR Studio package is the ability to connect external programs. For example, to ensure that the AS2 inspection programmer is needed to perform several simple operations.

    In the Tools menu of the main window AVR Studio, you must select Customize;

    In the Customize window, select the Tools item;

    Double-clicking the mouse button or pressing insert on the keyboard, add a new command to the list and call it "AS2 programmer";

    Specify the path to the programmer executable file by entering it directly in the "Command" input field, or by clicking on the "..." button to the right of this field;

    Now the Tools menu appears "Programmer AS2".

    AVR Studio 4.08 package means allow you to connect auxiliary programs - plugins. The first plugin for AVR Studio is a graphic editor program that simplifies the initialization process of the LCD indicator, which can directly manage the AVR controller ATMEGA169. The maximum logic size of the LCD indicator is 100 segments, each element of the indicator is made in accordance with the BIT in the special register of the controller. To simplify the routine binding procedure for certain bits to each segment, you can use the above-mentioned program.

    While visiting the "Motherland of AVR" - the Norwegian office of ATMEL, one of the authors of the article talked with Lars Quener, the head of the programmer group, which created and supports the AVR Studio package. This person, a classic programmer, with a beard, in a sweater and woven in the socks sandals, spoke about the prospects for the development of the package. On the next version (4.09), the interface will be enabled for a new intrahemnoe emulator - JTagice MKII (it is also called AT JTagice2), which in the second half of the year will replace At Jtagice. This emulator has two essential differences. On the one hand, supported support for a new single-wire debug interface for younger AVR controllers, Debugwire. This interface is interesting because it does not occupy an additional conclusions of the microcontroller for its work, as it uses to exchange the output of the reset microcontroller! On the other hand (you can understand this expression literally), at the AT JTagice2 emulator will appear, finally, the USB interface to communicate with the computer.

    Literature

    1. AVR Technical Training Technical Seminar Materials. ATMEL. Norway. Deceptber 2003.
    2. Nikolay Korolev, Dmitry Korolev AVR-microcontrollers of the second generation: The developer's medium. // Components and Technologies, 2003 No. 7
    3. AVR-microcontrollers of the second generation: new hardware capabilities // Components and technologies. 2003. No. 4.
    4. Nikolay Korolev, Dmitry Korolev. AVR microcontrollers: large in small. // Schemery ", 2001, №5
    5. Nikolay Korolev, Dmitry Korolev. AVR microcontrollers: software // Components and technologies, 2000. No. 4.
    6. Nikolay Korolev. AVR: developer hardware // Components and technologies, 1999 № 1
    7. Nikolay Korolev. ATMEL RISC-microcontrollers // Chip-News 1998, №2
    8. Nikolay Korolev, Dmitry Korolev AVR: New 8-bit RISC-microcontrollers of the company ATMEL // Microprocessor Review, 1998, №1

    Somehow immediately pulled to give advice on the choice of programming environment for AVR controllers. Just do not throw in me sneakers. I'm quite a little bit

    Languages \u200b\u200bprogramming for microcontrollers a lot. Programming media is also not enough and compared to them incorrectly. There are no better programming languages. So you have to choose the most suitable language for you and programming environment.

    If you are at the moment, stand in front of the selection, on what to start working, here's a few recommendations.

    Former programming experience. Do not neglect the former experience in programming. Even if it was a Baisik. Even if it was a long time in school. Programming like a bike ride - you just have to start and quickly remember everything forgotten. Start with the Beysika - unwitted - later it will be easier to choose something more suitable for your purposes.

    Help the environment.Do your friends write on Pascal? For you, a question is resolved - write on Pascal! You will always help with the Council, libraries will be thrown into the libraries, will give ready-made projects. In general, happy will be taken to their community. If you do on the contrary, get the opposite result. Friends Sishers entertain you who decided to study the assembler. Do not wait for help.

    Good AVR Programming Book It will help very well. Unfortunately, there are very few of them. If you in your hands got a book, and you think that everything is very available in it. - Try. I do not advise learn by e-books, as a last resort, print. Very uncomfortable to switch between the environment and text of the file file. Much more pleasant reading the book immediately try without being distracted by switching, in addition, you can make a mark on the fields, write the ideas that have arisen.

    Programming medium simpler. If there is a choice of several programs of your language programming - do not doubt, choose the one that is easier. Let it be less functional. Let it compile scary inflated code. The main thing is to just start working. After you are lean in a simple environment, you will easily go to a more advanced and "right" environment. And do not listen to those who say that you will lose more time - they are wrong. Pupils of junior classes are not asked to read "War and Peace" they give them books easier - with pictures.

    Libraries. The presence of libraries is controversial to learn language. Of course, later, they will greatly facilitate life, but at first "black boxes" are incomprehensible and not very helping the understanding of the language. On the other hand, it makes it easier to read the program and allow a newcomer, not particularly straining, build complex programs. So, their presence is not particularly bored. At least at first.

    Effective code. Selecting the programming environment to study programming only by how effective the code of the compile is a bad idea. You mainly comfortably start learning - that the tenth thing is "at the exit". Of course, you can later work on it.

    Vizard.Any device on board the crystal needs to be configured using ports. The procedure is pretty vigorous and datasheets are required. In addition, there are nuances in which the newcomer is not just to give. Therefore, in the medium it is very desirable for the presence of vizards. Releases are automatic SPI, I2C, USart, etc. automatic adjustments. The more devices are supported, the better. Expose the necessary peripheral parameters, and the Visard itself generates a code that will provide the specified parameters. Very simplifies life.


    General recommendations Such - programming at the initial stage should be as simple as possible (even if primitive). The programming environment should be easy to learn (as you need, to start, learn programming and not waste time on picking in the settings). It is advisable to Russify. Also does not prevent Russian manual and examples of programs. The possibility of firmware of the crystal from the medium is desirable. Next, when leaving the basics of programming, you can move on more complex shells.


    Another recommendation, finally, work with a real crystal. Do not be afraid to burn it. Improve practical experience. Working with emulators (for example Proteus), though it will free from the soldering iron, but will never be able to give the satisfaction that you will receive from the earned program, first mugs by the LED! Understanding what you did with your own hands the real working circuit will instill confidence and stimulus move on!

    (Visited 7 377 Times, 1 Visits Today)

    The programmer concept on the LPT port is shown in the figure. As a tire former, use the 74AC 244 or 74HC244 chip (K1564Ap5), 74ls244 (K5555Ap5) or 74Als244 (K1533Ap5).

    The VD1 LED indicates a microcontroller recording mode,

    vD2 LED - Reading,

    vD3 LED - the presence of a diagram.

    The voltage required for powering the scheme takes from the ISP connector, i.e. from the programmable device. This scheme is a recycled STK200 / 300 programmer (added LEDs for easy operation), so it is compatible with all PC programmer programs operating with the STK200 / 300 scheme. To work with this programmer, use a program Cvavr.

    The programmer can be performed on the printed circuit board and place it in the LPT connector housing, as shown in the pictures:




    To work with the programmer, it is convenient to use the LPT extensionnel of the port, which is easy to make yourself (for example, from the CableRonix cable for the printer), the main thing is "not to regret" the conductors for the Earth (18-25 legs of the connector) or buy. The cable between the programmer and the programmable microcircuit should not exceed 20-30 cm.

    Hello, dear habrarites!

    In this article, I want to tell about how one day I decided to start programming the microcontrollers, which was needed for this and that in the end it turned out.

    The topic of microcontrollers interested me for a long time, year in 2001. But then to get the programmer at the place of residence was problematic, and there was no purchase on the Internet and speech. I had to postpone this case until the best times. And so, one day I discovered that the best times came without leaving the house you can buy everything I needed. I decided to try. So, what we need:

    1. Programmer
    There are many options on the market - from the cheapest ISP (in-system programming) programmers for several dollars, to powerful debugger programmers for a couple of hundred. Without greater experience in this matter, first I decided to try one of the easiest and cheapest - usbasp. I bought at one time on eBay for $ 12, now you can find even for $ 3-4. In fact, this is the Chinese version of the programmer from Thomas Fischl. What can I say about him? Only one thing - it works. In addition, there are quite a lot of AVR controllers of the ATMEGA and ATTINY series. Under Linux does not require a driver.

    For firmware, you need to connect the VCC, GND, RESET, SCK, MOSI, MISO programmer outputs with the corresponding microcontroller outputs. For simplicity, I collected the auxiliary scheme right on the Male:

    Left on the board - the same microcontroller, which we are going to flash.

    2. Microcontroller
    With the choice of a microcontroller, I did not particularly bother and took ATmega8 from ATMEL - 23 I / O pine, two 8-bit timers, one 16-bit, frequency - up to 16 MHz, small consumption (1-3.6 mA), cheap ($ 2). In general, for a start - more than enough.

    Under Linux to compile and download the firmware on the controller, the AVR-GCC + AVRDEDE bundle works perfectly. Installation trivial. Following the instructions, you can install everything you need in a few minutes. The only NEANS, which should be paid to - AVRDUDE (software for recording on the controller) may require a super user right to access the programmer. Exit - Run through sudo (not very good idea), or register special UDEV rights. The syntax may differ in different versions of the OS, but in my case (Linux Mint 15) has been done by adding the following rule to the /etc/udev/rules.d/41-atmega.rules file:

    # USBASP PROGRAMMER Subsystem \u003d\u003d "USB", ATTR (IDVENDOR) \u003d\u003d "16C0", ATTR (IDPRODUCT) \u003d\u003d "05DC", group \u003d "plugdev", Mode \u003d "0666"

    After that, naturally, a restart of the service is needed.
    Service UDev Restart
    You can compile and flash without any problems directly from the command line (who would doubt), but if there are many projects, it is more convenient to put the plugin and do everything directly from the Eclipse environment.

    Under Windows will have to deliver the driver. There are no problems in the rest. For scientific interest, I tried the AVR Studio + Extreme Burner bundle in Windows. Again, everything works with a bang.

    We start programming

    Programming AVR controllers can be both on the assembler (AVR Assembler) and on C. Here, I think everyone has to make his choice itself, depending on the specific task and its preferences. Personally, I first started picking assembler. When programming on assembler, the architecture of the device becomes clearer and the feeling appears that they dig directly in the inside of the controller. In addition, I believe that in particularly critical programs, the knowledge of the assembler can be very useful. After familiarization with AVR Assembler, I am shifting on si.

    After acquaintance with architecture and basic principles, I decided to collect something useful and interesting. My daughter helped me, she was doing chess and one beautiful evening declared that he wants to have a timer watch for batches for a while. Batz! Here it is - the idea of \u200b\u200bthe first project! It was possible to order them on the same eBay, but I wanted to make your own clock, with black ... uh ... with indicators and buttons. No sooner said than done!

    As a display, it was decided to use two 7-segment diode indicator. To control it was enough 5 buttons - "Player 1", "Player 2", "Reset", "Setting" and "Pause". Well, do not forget about the sound indication of the game. Look like that's it. The figure below shows the general diagram of connecting the microcontroller to indicators and buttons. She will need when parsing the source code of the program:

    Colcessing flight

    Let's start, as it should be, from the entry point of the program - the Main functions. In fact, nothing remarkable in it is not - setting up ports, data initialization and an infinite button of pressing buttons. Well, the SEI () call is the resolution of the processing of interrupts, about them a little later.

    Int Main (Void) (init_io (); init_data (); Sound_off (); SEI (); while (1) (handle_buttons ();) Return 0;)
    Consider each function separately.

    Void init_io () (// Set Output DDRB \u003d 0xFF; DDRD \u003d 0xFF; // Set Input DDRC \u003d 0B11100000; // Pull-Up Resistors Portc | \u003d 0b00011111; // Timer Interrupts Timsk \u003d (1<

    Setting the I / O ports is very simple - into the DDRX register (where X is the letter, denoting port) the number, each bit of which means whether the corresponding PIN will be the input device (corresponds to 0) or output (corresponds to 1). Thus, seasushal in DDRB and DDRD number 0xFF, we made B and D output ports. Accordingly, the DDRC \u003d 0B11100000 command; turns the first 5 ports of the port C into input pins, and the remaining on the weekend. Team portc | \u003d 0b00011111; Includes internal tightening resistors on 5 inputs of the controller. According to the scheme, the buttons are connected to these inputs, which when pressed are closed them to the Earth. Thus, the controller understands that the button is pressed.

    Next, you follow the setting of two timers, Timer0 and Timer1. We use the first to update indicators, and the second - for the countdown of the time, after setting it to the triggering every second. A detailed description of all constants and the timer setting method to a certain interval can be found in the documentation for the ATMEGA8.

    Processing interrupt

    ISR (DISPLAY (); if (_Buzzer\u003e 0) (_BuzZer--; if (_buzzer \u003d\u003d 0) Sound_OFF ();)) ISR (Timer1_Compa_Vect) (if (ActiveTimer \u003d\u003d 1 && Timer1\u003e 0) ( Timer1--; if (Timer1 \u003d\u003d 0) process_timeoff ();) if (ActiveTimer \u003d\u003d 2 && Timer2\u003e 0) (Timer2--; if (Timer2 \u003d\u003d 0) Process_timeoff ();))

    When the timer is triggered, the control is transmitted to the corresponding interrupt handler. In our case, this is the Timer0_OVF_VECT processor, which causes the time output procedure to indicators, and Timer1_Compa_Vect, which processes the countdown.

    Conclusion to indicators

    Void Display () (Display_Number ((Timer1 / 60) / 10, 0B00001000); _delay_ms (0.25); display_number ((Timer1 / 60)% 10, 0B00000100); _delay_ms (0.25); display_number (((Timer1% 60) / 10 , 0B00000010); _delay_ms (0.25); display_number ((Timer1% 60)% 10, 0B00000001); _delay_ms (0.25); Display_Number ((Timer2 / 60) / 10, 0B10000000); _delay_ms (0.25); display_number ((Timer2 / 60)% 10, 0B01000000); _delay_ms (0.25); display_number ((Timer2% 60) / 10, 0b00100000); _delay_ms (0.25); display_number (((Timer2% 60)% 10, 0b00010000); _delay_ms (0.25); portd \u003d 0;) Void Display_Number (Int Number, Int Mask) (PortB \u003d Number_Mask (Number); PortdD \u003d Mask;)

    The Display feature uses a dynamic indication method. The fact is that each individual indicator has 9 contacts (7 for segments control, 1 for point and 1 for power supply). To control 4 digits it would take 36 contacts. Too wasteful. Therefore, the output of discharges to a multi-digit indicator is organized according to the following principle:

    The voltage is alternately fed to each of the shared contacts, which allows you to highlight the desired figure in the corresponding indicator using the same 8 control contacts. With a sufficiently high output frequency it looks like a static picture. That is why all 8 supply contacts of both indicators on the diagram are connected to 8 ports of port D, and 16 contact control segments are connected in pairs and connected to 8 ports of port B. Thus, the DISPLAY function with a delay of 0.25 ms alternately displays the desired number to each of the indicators . Under the end, all outputs that feed the voltage on the indicators are turned off (command portdd \u003d 0;). If this is not done, then the last display digit will continue to burn until the next call is called the DISPLAY function, which will lead to its brighter luminescence compared to the rest.

    Treatment of presses

    Void handle_buttons () (handle_button (KEY_SETUP); handle_button (KEY_RESET); handle_button (KEY_PAUSE); handle_button (KEY_PLAYER1); handle_button (KEY_PLAYER2);) void handle_button (int key) (int bit; switch (key) (case KEY_SETUP: bit \u003d Setup_bit; Break; Case key_reset: Bit \u003d reset_bit; break; case key_pause: bit \u003d pause_bit; break; case key_player1: bit \u003d player1_bit; break; case key_player2: bit \u003d player2_bit; break; default: return;) if (bit_is_clear ( Button_pin, bit)) (if (_pressed \u003d\u003d 0) (_delay_ms (Debounce_Time); if (bit_is_clear (button_pin, bit)) (_pressed | \u003d key; // Key Action Switch (key_setup: process_setup (); Break; Case key_reset: process_reset (); break; case key_pause: process_pause (); break; case key_player1: process_player1 (); break; case key_player2: process_player2 (); break;) Sound_on (15);))) ELSE (_Pressed & \u003d ~ Key;))

    This feature in turn polls all 5 buttons and processes press, if such happened. Pressing is registered by checking Bit_is_Clear (Button_pin, Bit), i.e. The button is pressed if the input corresponding to it is connected to the ground, which will happen according to the scheme, when you press the button. Delayed delay duration_time and re-checking is needed to avoid multiple unnecessary responses due to the rattles of contacts. Saving the press status in the appropriate variable bits _PRessed is used to eliminate re-triggering with a long press button.
    Pressing functions are quite trivial and believe that in additional comments do not need.

    Full text program

    #Define F_CPU 4000000L #Include #Include. #Include. #define DEBOUNCE_TIME 20 #define BUTTON_PIN PINC #define SETUP_BIT PC0 #define RESET_BIT PC1 #define PAUSE_BIT PC2 #define PLAYER1_BIT PC3 #define PLAYER2_BIT PC4 #define KEY_SETUP 0b00000001 #define KEY_RESET 0b00000010 #define KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volatile int ActiveTimer \u003d 0; Volatile int Timer1 \u003d 0; Volatile int Timer2 \u003d 0; volatile int _buzzer \u003d 0; Volatile int _pressed \u003d 0; // Function Declarations void init_io (); void init_data (); INT NUMBER_MASK (INT NUM); void handle_buttons (); void handle_button (int key); Void Process_Setup (); Void Process_reset (); void process_pause (); void process_timeoff (); Void Process_Player1 (); Void Process_Player2 (); void display (); void display_number (Int Mask, Int Number); Void Sound_on (int interval); void sound_off (); // Interrupts ISR (DISPLAY (); if (_Buzzer\u003e 0) (_Buzzer--; if (_buzzer \u003d\u003d 0) Sound_OFF ();)) ISR (Timer1_Compa_Vect) (if (ActiveTimer \u003d\u003d 1 && Timer1\u003e 0) (Timer1--; if (Timer1 \u003d\u003d 0) process_timeoff ();) if (ActiveTimer \u003d\u003d 2 && Timer2\u003e 0) (Timer2--; if (Timer2 \u003d\u003d 0) Process_Timeoff ();)) int Main (void) (init_io (); init_data (); sound_off (); sei (); while (1) (handle_buttons ();) Return 0;) void_io () (// set output ddrb \u003d 0xff; ddrd \u003d 0xFF ; // Set Input DDRC \u003d 0B11100000; // Pull-Up Resistors Portc | \u003d 0b00011111; // Timer Interrupts Timsk \u003d (1< 5940 || Timer2\u003e 5940) (Timer1 \u003d 0; Timer2 \u003d 0;)) void process_reset () (init_data ();) void process_timeoff () (init_data (); sound_on (30);) void process_pause () (ActiveTimer \u003d 0;) void process_player1 () (ActiveTimer \u003d 2;) void process_player2 () (active )_player2 () (ActiveTimer \u003d 1;) void handle_button (int key) (key_setup: bit \u003d setup_bit; break; Case key_reset: bit \u003d reset_bit ; Break; Case Key_Pause: Bit \u003d Pause_bit; Break; Case Key_Player1: Bit \u003d Player1_bit; Break; Case Key_Player2: Bit \u003d Player2_bit; Break; Default: Return;) if (bit_is_clear (button_pin, bit)) (if (_pressed \u003d\u003d 0) (_delay_ms (Debounce_Time); if (bit_is_clear (button_pin, bit)) (_pressed | \u003d key; // key_setup: process_setup (); break; Case Key_reset: Process_reset (); Break; Case Key_Pause: process_pause (); break; case key_player1: process_player1 (); break; case key_player2: process_player2 (); break;) Sound_on (15);))) ELSE (_PRE Ssed & \u003d ~ Key; )) Void handle_buttons () (handle_button (KEY_SETUP); handle_button (KEY_RESET); handle_button (KEY_PAUSE); handle_button (KEY_PLAYER1); handle_button (KEY_PLAYER2);) void display () (display_number ((Timer1 / 60) / 10, 0b00001000) ; _delay_ms (0.25); display_number ((Timer1 / 60)% 10, 0B00000100); _delay_ms (0.25); Display_Number ((Timer1% 60) / 10, 0B00000010); _delay_ms (0.25); display_number (((Timer1% 60)% 10, 0B00000001); _delay_ms (0.25); display_number ((Timer2 / 60) / 10, 0B10000000); _delay_ms (0.25); display_number ((Timer2 / 60)% 10, 0B01000000); _delay_ms (0.25); display_number ((Timer2 % 60) / 10, 0b00100000); _delay_ms (0.25); display_number (((Timer2% 60)% 10, 0b00010000); _delay_ms (0.25); portdd \u003d 0;) void display_number (int Number_Mask) (PortB \u003d Number_Mask (Number); portd \u003d mask;) void sound_on (int interval) (_buzzer \u003d interval; // PUT Buzzer Pin High Portc | \u003d 0b00100000;) void Sound_off () (// PUT Buzzer Pin Low Portc & \u003d ~ 0b00100000;)

    The prototype was assembled on a dumping board.