Please help me write the code (ATmega16) - Page 1
Forum section: electronics / general

author: Deadloop
author_rank: Newbie
timestamp: May 18, 2021, 12:55:52 pm
content: Hello, please help me write the code, the teacher gave the assignment, but after a long time searching for information on the Internet and trying to understand, I could not do anything. I don't need to flash anything, I just need the code to match the task.Assignment: Create a schematic diagram and annotated C ++ program for an Atmel AVR ATmega16 8-bit microcontroller that implements the following algorithm:1) MCU is clocked from the built-in generator, the clock frequency is 4 MHz.2) The 10 kΩ potentiometer is connected to the ADC input (ADC3), operating in 8-bit mode, powered by the microcontroller voltage Vcc (5 V).3) When the timer T0 interrupts with the same time period, the ADC conversion result is read and displayed on a strip of 8 LEDs connected to the C ports (time period 0.2 seconds).4) When the button is pressed once (connected to PD3), the last measured value in the USART is displayed at 9600 baud without parity.That is, the number of LEDs illuminated depends on the voltage, the higher the voltage, the more LEDs light up, if the voltage is 0, then the LEDs are off, if 5 - all the LEDs are on. It should look like an equalizer.I made a diagram (I will attach it below), it seems to be correct, but I don’t know how to write the code, please help (preferably with comments).A small clarification, maybe this is important, I am writing a project "GCC C ++ Executable Project" in Atmel studio.Thanks

author: HB9EVI
author_rank: Frequent Contributor
timestamp: May 18, 2021, 03:25:19 pm
content: first: you're supposed to do your homework assignment yourself; my tip is to read the datasheet to the ATmegasecond: there is no native c++ implementation for the avr family due to the missing libstdc++, only libc exists, so only c is availablethird: split the work in smaller pieces and build one step on the successfully accomplished previous step; don't try to do all at oncefourth: what you mean is a led bargraph, not an equalizer; keep in mind if you copy the 8-bit adc output to portc you'll have a binary coding of the leds too; it won't look like you're maybe used to from a bargraph vu meterif you have a particular problem one of the single steps you might ask, but don't expect, that somebody does your whole homework for you

author: rstofer
author_rank: Super Contributor
timestamp: May 18, 2021, 04:45:34 pm
content: This is a fairly large project so I'm not going to even attempt to code it. But...I have always subscribed to the concept of 'top down design' and 'bottom up coding'. I would decompose the project into blocks of either hardware or code and just draw them out on a piece of paper. I would show lines connecting the various blocks. This is the time to clean up the block diagram.When it came time to code, I would start at the bottom. I would always get the UART and serial IO running first. This allows me to put printf() statements in my code for debugging purposes. Always get the UART running first!When I write the code, I usually scribble down some pseudocode that describes what I am trying to accomplish. Finally, I write the actual C code.Since I am doing one block at a time, I have the opportunity to test each block before I interconnect it to higher level blocks.As to the bar graph, there are only 8 possible patterns and this only requires 3 bits to address. You can shift the ADC output 5 places to the right (leaving just the high 3 bits) and index into an array of 8 LED patterns. The code for this is trivial once you have read the ADC value.In any event, break the project up into small pieces.

author: rstofer
author_rank: Super Contributor
timestamp: May 18, 2021, 04:52:15 pm
content: You can find sample code all over the Internet. Here is some UART codehttps://www.kanda.com/AVR-C-Code-UART.phpLike most code you find, there will be assumptions made about which libraries you are using. This code uses WinAVR and AVR Studio.Here is some ADC codehttps://www.electronicwings.com/avr-atmega/atmega1632-adcEverything you need is on the Internet and Google knows where it is.

author: TomS_
author_rank: Frequent Contributor
timestamp: May 19, 2021, 07:03:24 am
content: Asking someone to write the code and comment it for you is basically just asking someone to do all of your work. If you dont understand it, how will you even know it is correct and the comments dont make you look like a fool to your teacher?You need to be asking more specific questions, like "I tried to do X and it didnt work, here's what I tried, what have I done wrong".So do as others have suggested: break the project down into smaller more manageable and easier to understand tasks, learn how to work each individual component that has been mentioned and ask questions when you get stuck, and then you will be able to glue them all together into something more complex. This stuff isnt rocket surgery or brain science and I find it hard to believe you havent found examples of each of them... there must be millions of them out there...And if you really dont understand how to do something, asking the teacher for help is probably a better idea than just finding someone to cover your ass. Your lack of understanding will become apparent eventually and then you'll have to explain why you were able to put this project together so flawlessly but cant answer some other simple question - thats the oldest academic red flag in the book. One thing is for sure, people arent going to cover you like that in the real world when you get a job, so learning how to find information and connect the dots now is a skill you are going to need andwilluse, and is probably one of the less obvious objectives of this assignment.

author: Nominal Animal
author_rank: Super Contributor
timestamp: May 19, 2021, 08:23:41 am
content: I normally completely ignore those looking for others to do their homework, but decided to make an exception today.First, you need to take a look at the Atmel (now Microchip) ATmega16 datasheet,https://ww1.microchip.com/downloads/en/DeviceDoc/doc2466.pdf.In the System Clock and Clock Options chapter, it describes the different ways the chip can be clocked. (All microcontrollers need some kind of a clock. Some, or in some cases, you may need to connect an external oscillator or a crystal of specific frequency; for example, microcontrollers that connect via USB usually require a crystal of specific frequency (12 MHz is typical) because the USB timings are rather tight.) On page 29, the Calibrated Internal Oscillator part in this chapter, tells us there indeed is a 4 MHz internal oscillator (with 3% accuracy at room temperature; pretty good) that does not need external components, only the CKSEL3 through CKSEL0 fuses programmed to 0011B; note that this is not the default (1 MHz, 0001Bis), so you do need to remember to do that at programming time.That takes care of the first point, and we also know we don't need external components (say, connected to the XTAL pins). Oh, we should remember to check the datasheet what it says about unconnected pins, especially XTAL pins; fortunately, immediately the illustration we looked at above it says"when [the internal oscillator is used], the XTAL pins should be left unconnected (NC).". I don't know about you, but I prefer to mark explicitly-unconnected pins with a left-disconnected mark (X over the pin).ADC3 is connected to a 10k potentimeter. As you've drawn, the ADC3 pin is to the wiper, and the other ends/pins of the pot to VCC and GND. Let's go back to the datasheet to see how the ADC is configured.. ah yes, the Analog to Digital Converter section starts at page 203.Here we see that the hardware is actually 10-bit, but does have a 8-bit mode, so we do need to remember to set that up correctly in the code. Also, since ADC3 can also be used as half of a differential pair (with ADC2), we need to remember to select single-ended operation for ADC3.But ah-ha! The very first page says that the ADC has a separate analog voltage supply, AVCC, that must be within 0.3V of VCC. We can just tie it to VCC because we will do ratiometric measurements on a voltage divider connected to VCC – but do read the ADC Noise Canceling Techniques section referred to, to see how one might get less noise on the ADC line. Since ATmega16 is able to choose between different voltage references (AVCC, internal 2.5V reference, AREF), we don't need to connect AREF to anything; we just need to remember to choose AVCC as the reference.(Now, the assignment says that we use timer T0 at 0.2 second intervals – that is 5 Hz rate – to read the ADC and update the LED state. I don't like that, because single sample conversion time is so short that noise (on VCC) may affect the reading. I'd much rather use an averaged ADC reading, say 16 samples over 0.2 seconds, in which case the rate would be 5×16 Hz = 300 Hz, but only one every 16th one would update the LEDs. Oh well, it doesn't matter, really.)At these time scales, I think it is better to use the single conversion mode (by setting ADSC to 1). After some time, the 8-bit conversion result is available in the ADCH register. (To get the full 10-bit result, we read the low bits from the ADCL first). If use the ADC completion interrupt, then that one only needs to read ADCH, and set port C output based on the reading. I'd be tempted to be lazy, and use a 256-byte conversion table in Flash. Then, the timer interrupt only needs to trigger the conversion, assuming the interrupts etc. have been set at initialization time in the code. I like this simplicity, although it can feel scary to rely on interrupts for a new programmer.The eight pins on the port C pins will have LEDs on them. The voltage over each LED will drop (depending on the LED, between 1.7V and 2.1V for most, but between 3.4V and 3.6V for blue or white LEDs. Because the operating voltage is 5V, we need to limit the current to each via a resistor. If we useVffor the voltage drop andIfor the desired current, we need a resistorR=(5-Vf)/I. You've chosen 270Ω, so assuming a 1.7V forward drop on the LED, the current is 12mA, which seems reasonable to me.Let's check the Electrical Characteristics chapter. Each pin should be able to source or sink 20 mA safely in "steady state conditions", as long as the sum total over ports B, C, D, and XTAL2 is kept under 100mA. 8×12mA = 96mA, and the internal pull-up for the button being over 20kΩ means that pin adds at most 0.25mA, so we should be good there. (If not, then we'd needed additional hardware, probably some kind of transistors in IC package. For seven LEDs, ULN2003A Darlington transistor arrays would be a good choice. They typically have series input resistors, so it'd just be a matter of whacking one in between the microcontroller and the LEDs.) Of course, there are dedicated LED controller chips and whatnot too, but fortunately, we don't need any of those here.Also note that for ATmega16, I/O pins seem to have symmetric source and sink capabilities. That is not always true; sometimes it is better to sink instead of source, connecting the LED cathodes to the I/O pin, and anodes to ground (with resistors on either side, usually the ground side). Progamming-wise, output LOW then enables the LED, and high disables. The shown circuit sources current from each I/O pin, so output HIGH enables the LED, and low disables. Either way works, it's just a matter of keeping track of the details.Also, physical switches tend to have what is called "contact bounce". Instead of changing from one state to another, it can "flicker" between the two states for a few milliseconds during the change. This can be countered using an RC filter, for example, but then we'd need more components; I think it is easier to deal with in software, especially for such a simple device as this. (More details on this after the hardware side is cleared.)The fourth point also says we need to set up the USART for 9600 baud, no parity, and I guess the standard 1 stop bit (two is also possible); often shortened as "9600N1", which you'll see often if you do a web search on devices with UART connections. The ATmega16 has only one USART, and to allow connecting to it, we'd need to expose the RX (PD0) and TX (PD1) pins. They don't need any passives (resistors, bypass capacitors), but we might draw them into a three-pin connector in the schematic (the third being ground; often a fourth for the VCC is also exposed).Next, let's look at the datasheet for recommended applications, especially how to power it. As it is, your microcontroller would be powered through the AVCC, AVREF, and /RESET pins, which might work in practice, but isn't something I'd like to do... The datasheet itself does not mention anything, and the Application Notes show just standard supply bypass capacitors, so I'd put an 1µF and a 100nF cap to ground from the VCC pin as usual, and mark them "supply bypass".So, aside from some small changes – leave AREF disconnected, connect VCC properly to a 5V supply (optionally with the supply bypass capacitors as mentoned above, although technically they are not required; they are only required for the circuit to work well in the real world), explicitly expose the pins to be used for the UART, and mark the XTAL pins not connected – your circuit should work.Above, we also encountered most of the things we need to do in software. Our code will take control of the microcontroller when it gets power or gets reset. We first need to calibrate the internal oscillator to 4 MHz and then select it (see the System Clock and Clock Options chapter in the datasheet). We also need to set up the I/O pin states for the LED pins (outputs) and the button (input with internal pull-up enabled). The USART must be properly setup, as does the timer T0 interrupt and period. Since PD3 (the button input) is also INT1, an external input source, we could technically use an interrupt for the button too; but, for simplicity and robustness, it is easier to have the code loop around the button state – with a software debouncing scheme on the button! – and emit the numeric value to the USART for each press. The ADC must be set up, including the conversion completion interrupt, if you use the simple scheme I described much earlier.It seems to me the programming task is pretty clear at the design level here. There are three main tasks: initialization, interrupts, and main loop. Initialization starts with the clock stuff, then sets up the I/O pins (both LED and button), the USART. The timer T0 interrupt handler and the ADC conversion completion handlers are set, then the timer and ADC initialized. The timer interrupt then only needs to set the single-shot conversion bit by setting the ADSC bit to 1; and the conversion complete interrupt reads ADCH, looks up the corresponding "LED pattern" in a 256-byte look up table in Flash, and writes the pattern byte to PORTC. Very straightforward.(Technically, the T0 interrupt can also just wait in a loop for the ADSC bit to become zero again, indicating the conversion is ready, and not use the completion interrupt; then it reads the ADCH register and sets the LEDs itself. But, since you are already usingoneinterrupt, why not use two instead, so that interruptions to the "main" code stay minimal? During the time the interrupt would wait in that loop, no code would be running; that time is better used running the "main" code instead. That's why interrupts exist, after all.)The only web references you should need, is the ATmega16 full datasheet, and whatever documentation you need for your development environment (I don't use Atmel Studio myself; I'd use avr-gcc and avr-libc – the latter is not a standard C library, but a minimal set of basic functions and a full set of header files describing the hardware and registers on various AVRs); it's all there, but expect to spend most of your time looking at the datasheet.It might even be time well spent to spend 1-3 hours to skim through the datasheet, to see what the datasheet describes, so later on, you can remember you saw something about that in the datasheet, and look it up (I search keywords and register names OFTEN!); overall, you may be able to save time by having a better idea where to look for answers.To be honest, I suspect the number of people reading this post in its entirety, will forever remain in the single digits.. but dammit, at least I tried to help others by describing a logical development process via example in a single post, in the hopes that others would realize that even when a task may feel insurmountable, logically nibbling at it until it can be chopped into logical pieces and attacked piecewise, works.