One thing is great about microcontroller ICs, these are available almost in all parts of the globe and electronic retailers.
- 1 Introduction
- 2 Pinout Details
- 3 How to Create an SPI Connector from the Programmer to the Microcontroller
- 4 Making a Simple Programming Code for an MCU
- 5 How to Transfer a Program into a Microcontroller chip
- 6 How to Install a Programming Environment and Investigate WinAVR
Fundamentally microcontroller devices are popularly used in applications involving assessments of the surrounding environment and in similar electronics.
You could find these devices being used for displaying a certain parameter, in motor control applications, LED lighting, sensors of various types such tilt sensor, accelerometer, velocity meter, data loggers, temperature controllers, keyboards etc.
The primary understanding regarding microcontrollers could be obtained by referring to AVR Amega32 microcontroller which is so advanced that sometimes it’s called a computer within a chip.
This device is assigned to carry out series of commands to form a program.
The language of the program that you would be seeing here is C++. You’ll get to learn this language in greater depths in the course here.
When it comes to MCUs, you get the facility of having the option of controlling and configuring all of its pinouts.
If you are getting a bit tired with this, just chill cause it's nothing complex at all, you will be eased through all the aspects steadily but firmly as we move ahead.
In an MCU chip all pins except the Vdd and Vss which are the power pins of the chip, can be assigned with exclusive designations.
If you glance the chip from the top, you would find a little triangular notch which indicates the starting the point from where the pinouts begins it count that’s the #1 pin of the chip begins just under this notch.
Starting from this pin you would find 20 pins upto the bottom on that side (left), and another 20 pins on the other side (right), continuing from bottom to top on the right hand side.
The first 8 pins starting from the notch are the PBO-7 which form the index pins of the IC since all program here begin with the index zero.
The above series of pinouts is termed PORT B, while there are other identical sets of ports assigned A to D.
These ports could be assigned to accept and recognize a fed data called INPUT, and also to transmit data in some specified form called OUTPUT.
Two of the pins which come in the general category are the (+)/(-) pins which are also referred to as Vdd and GND.
One pin from PORT D (PDO-6) may be seen located on the left side of the chip at the bottom area.
PD7 which is pin#7 of PORT D could be traced standing alone and commencing the right hand side series of pinouts.
Now moving on from the right hand side of the chip where PORT D ends, PORT C begins its count upward in the order.
These contribute to the many interesting pins of the MCU right from analog to the digital ones.
These pins are featured to become the sensing inputs for detecting the many parameters through externally configured analog circuit stages.
The above pins constitute the PORT A.
The analog to digital conversion across the above pins could be understood with the help of an example wherein an analog temperature level detected using an ordinary sensor such as a thermister is applied to one of the PORT A pins which is readily accepted and converter by the MCU to produce a digital readout from zero to 255 degree F (an 8-bit figure which could be upgraded for achieving a 10-bit output).
Another feature which could be witnessed in MCUs additionally is the available programming space or the memory which determines the space for the variables and program specified for the microcontroller.
Furthermore to this, the MCUs have a built-in clock assigned for counting the relevant parameters.
The clock features enables the MCU to apply itself for many different counting processes which could be rapid in the range of microseconds depending upon the specification of the particular device, and also could be slower to any desired extents.
By now you might have understood the microcontroller concept to some extent and regarding its ports and pins.
How to Create an SPI Connector from the Programmer to the Microcontroller
Now it’s time to go a little deeper into the subject and investigate the world of programming.
Having said that, before indulging into a program loading procedure into the chip we need to find a proper way to integrate the SPI (Serial Peripheral Interface) connector with the MCU.
However even after this we can’t just push the SPI into the MCU pinouts, can we? Neither can we allow the extended wires from the SPI to directly get inserted into the bread board. This might also cause incorrect wires setting connected with the incorrect pins making bad connections.
Therefore in order to make things absolutely impeccable, we do the procedures over a tiny veroboard wherein we get the required connecting metal pins also called the “header” soldered. These header pins could now be used for connecting with the SPI connector. The connections from this header may be terminated to another parallel header pins which may be used for the breadboard connections.
Thus the above assembly now forms a snug and reliable intermediate connecting platform for the SPI to the MCU.
Uptil now everything looks nice ad perfect, so let’s move on to earn regarding the programmer which is required between your PC and the MCU.
There could a host of companies who make and sell these programmer units, so procuring these shouldn’t be a problem to you, such as Adafruit Industries, USBtinyISP or Sparkfun etc.
A few of these could look entirely different to the conventional types, but basically have everything identical and follow the standard programming rules and may be used as an interface between your PC and the AVR microcontroller.
However make sure of one think, if you are using some other MCU and not an AVR Atmega32, you may have to check for a correspondingly compatible programmer for that particular MCU chip.
It may be observed that quite a few of these programmers employ identical drivers, something tat must be taken care of and we’ll learn more about it in our subsequent chapters.
Connecting your PC with the microcontroller chip is truly basic, and you would be delighted to know how simple the proceedings are required for this. So let’s hit the button right awayJ
Making the above explained SPI interface board is not difficult, it’s all about getting your solder iron working through all the connections across the shown two header rows of pins on a small general purpose board.
The figure above shows the connection details that you would have to follow while interconnecting the wires between the headers.
To make things even simpler, let’s go through the following connection details for the same by referring to the image above:
SPI pin starting from top left goes to the “Master IN, Slave OUT” (MISO)
SPI pin from center left connects with the clock pin (SCK)
SPI pin at the bottom left joins with the Reset. (We’ll learn elaborately about this pin in the following tutorials)
SPI relevant to bottom right hooks up with the GND pin of the MCU, GND refers to the pin which forms the zero supply line or the negative (relative) rail of the supply.
SPI terminating from middle right header links up with “Master Out, Slave IN” (MOSI) pin of the MCU.
SPI coming out of the top right header is wired up with the (+) of the MCU which is quite obviously the Vdd or the positive supply pin of the MCU.
Connect the two connectors as explained and your SPI interface board is ready for the required actions.
For further help you may consult the figure that shown above, your final interface board should look like this after all the wire connections are appropriately done with the help of the above discussion.
I hope you might have already constructed the SPI interface as explained in the previous tutorial, and now it’s time to ensure that our computer accepts the programmer that we need to integrate in between the PC and the MCU.
Making a Simple Programming Code for an MCU
We take a USBTinyISP unit available from Sparkfun, for linking the computer with the microcontroller.
We know that any computer operating system such as Windows will require drivers without which it would be useless to load anything into the computer, thus our programmer will need drivers in order to load into your computer.
Let’s peek into the procedures required for installing the drivers in your computer OS, here we take the example of Windows 7 OS with either 32-bit or 64-bit specs.
Open sparkfun.com and click on “pocket AVR programmer page”. The link can be readily visualized within the page.
Next, find ”Windows driver” under documents and simply click on it.
This will provide you with the pocketprog-driver.zip file in your computer.
Go to your computer, find the download location and just unzip the downloaded file into a folder.
In case your computer is a 64-bit OS, you need to follow a few more steps as given under, with a 32-bit OS, you may directly begin the installation from the unzipped file.
For a 64-bit follow these, for 32-bit simply ignore:
Google “libusb sourceforge” and click on this links latest version.
You would come across a few additional files, however you would be interested to find the bib file, that is: libusb-win32-bin-#.#.#.#.zip
Now, go and find this download location in your computer, unzip it and save it in one of the folders.
Into this folder, navigate over the bin folder, proceeding on to the amd64 folder.
You would see a couple of folders here as: ghcalled libusb0.dll and libusb0.sys.
You would want to rename these as: libusb0_x64.dll and libusb0_x64.sys.
Now you will need to copy the above files into pocketprog-driver folder, simply overwrite the files on the existing version.
To install the above drivers, the following method which is rather a non-conventional in its type would interest you:
It’s a “add legacy hardware” mode.
Click on “Start Menu”
Then proceed by right clicking on “computer”
Click on “Manage”, and finally click on “device manager”
Next, inside the menu, choose “Add Legacy Hardware”
Go on to press “next”, until the wizard get inserted
Following the instructions, click on “Install the hardware which you would need to select from an Advanced list” this will prompt the radio button icon into that particular selection. It’s actually a windows control button that would now appear like a tiny circle having a roundish blue filing inside.
Now simply click “Next”
This will show you “Show all Devices” menu which you will need to click.
After this proceed to click on the “Have Disk” Icon.
With the help of the “Browse” icon, go ahead to the location of pocketprog-driver folder. If the selection was correctly done by you, you would visualize the pocketprog.inf file placed in that particular folder.
Double click over this file and you would certainly witness the driver getting installed into your PC.
Over and Out!! Let’s get on with our next tutorial on the next page.
By now you might have installed the required software and built the SPI interface.
How to Transfer a Program into a Microcontroller chip
The next step will call for a few components such as a breadboard, an LED and a calculated resistor for the intended application.
In this section we’ll learn the testing method of the programmer and confirm the installation of the relevant drivers and the software.
In order to verify if the drivers and the software were installed correctly we’ll implement a simple program known as avrdude.
The AVRdude is program associated with the latest WinAVR installation without which the actual transfer of the file into the MCU cannot be possible.
This program is a .hex file format which essentially becomes understandable to the MCU for the required executions.
In case the verification does not succeed, the programmer will be incapable of doing the transfer of the file.
Let’s quickly see how we can implement the testing procedure with the help of the following instructions:
Open the DOS (Disk operating system) prompt by clicking “start menu” and typing cmd.exe in the given search box.
Now the carrying out the AVRdude may be done by simply typing avrdude –c usbtiny –p m32 over the DOS prompt. As soon as this is implemented, the DOS will instantly acknowledge whether the connection was a success.
In the above command, the “-c” is a notifying flag which includes the “usbtiny” programmer parameter specification, while the “-p” tag identifies the microcontroller device (“m32 indicating Atmega32).
In case you have used a different MCU, you would need to include the relevant prefixes for the implementation.
Once the above procedure is finished, you may type “exit” over the DOS prompt, and that will move you out of the window.
If you are seriously wondering regarding the actual programming details, well for that we would first need to solder and construct the external analogue LED circuit over which the program could be implemented, because unless there’s a system to acknowledge the response from the MCU, the programming and running of the microcontroller would be quite meaningless.
Making the LED board is very simple, it’s all about soldering the two leads of the LED over a piece of veroboard and connect the resistor with one of the lead of the LED. The role of this LED is only to limit the current to the LED so that it doesn't burn of due to the excess voltage ad current from the MCU output.
The value of the resistor may be calculated by using the following simple formula:
R = (Ub – LEDfwd)/I
Where Ub is the supply voltage, LEDfwd is the optimal operating voltage of the LED used, and I is its optimal amps.
Suppose we use a RED LED which has a LED forward voltage = 2.5V and current I = 20mA, the above equation can be solved as follows:
Since the voltage from MCU would be 5V, it may be expressed as:
R = (5 – 2.5)/.02 = 125 ohms, ¼ watt, the nearest value being 120 ohms will do.
Now we have the LED, a 120 ohm resistor and a veroboard, simply interconnect the above components as given in the diagram with the microcontroller.
Once this is done, the MCU could be programmed for the intended response on the above LED set up.
Next up, the programming of the MCU.
In order to allow the microcontroller to perform some meaningful implementations, it’s imperative to write appropriate instructions into the MCU.
How to Install a Programming Environment and Investigate WinAVR
For this we could probably use our very own “text editor” in our PC, although may of us would appreciate the use of a more professional “programming environment” instead of an ordinary text editor, simple because this approach would allow you to enjoy some in-built interesting features within this “programming environment” package.
It would support creating and editing programs through different languages and also compile them into an deliverable mode easily understood and accepted by a microcontroller chip.
Ultimately this would be supported by WinAVR and transferred into the concerned MCU chip.
WinAVR could be also equipped to do execute many other operations such as troubleshooting the programs and warning us about possible syntax and compiling mistakes and errors. We’ll discuss these I our later tutorials.
You would the installation course of WinAVR to be extremely rapid and snappy. Let’s dive into the details with the following points:
You’ll need to download the latest versions from the WinAVR source forge files folder. You would come across some useful info related to this download from its official website.
You would be prompted across a security query, so that you can answer if you wanted the download to take place, this is enquired the file to be downloaded is a executable file.
Download the file and begin the execution process by clicking on it. Let the installation begin.
The process will guide you with some answerable questions so that you may be able to streamline the installation as per your comfort. You would want to ignore many of these to their default forms, it would all upto you to select the ones which you feel are best suited for the actions.
Until now you would find everything quite normal and easy going and find a few options I the start menu being thrown at you. No worries, only some of these would be actually using just one of tem named “programmers notepad”.
Once clicked on this icon, would initiate the user interface so that you may be able to apply the writing of the programs (such as creating and editing). You would also witness the program consisting of menu commands for aiding you to compile the codes and embed them into the microcontroller.
The fundamental job of the above programmer notepad is to transform a human readable code that you would be writing into a series of instructions understandable only to the MCU.
The next tutorial will cover the testing of the above programmer so that we can be sure regarding its compatibility with Windows and whether it perfectly “shakes hand” with your microcontroller IC.
How to Program an MCU for Turning ON an LED
Once this is confirmed we would proceed on to create a small “do nothing” code, just to ensure that the procedure of code transfer does not encounter errors.
Of course we are now ready to implement our first program inside the MCU, but before that it would be interesting to summarize quickly what we did in the course of our previous tutorials:
We procured the AVR Atmel microcontroller as per our required specification; here we have used the ATMega32 for the illustrations.Next, we learned about microcontroller basics and the programmer unit which is responsible for transferring a program into the MCU chip.
Further on, we built the SP interface connector which is essential so that your computer could be linked with the microcontroller for the programming actions.
After this we confirmed whether the drivers were installed correctly in the computer for a 32-bit as well as a 64-but operating system.
Next, we installed the programming environment called Win AVR for facilitating easy writing ad transferring of the codes into the microcontroller, followed by the implementation of the avrdude for verifying the programmer with your PC and the microcontroller interconnected.
Finally in the previous chapter we finished building the LED/ resistor circuit and connected it with the relevant MCU outputs.
That’s a lot of work indeed; nevertheless it’s time to head right away into some real programming stuff!
To begin with we would want to divide the microcontroller into three categories; this would simplify our understanding a lot:
Control, Detection, and Communication
It would be interesting know that the above functions could be programmed in many different ways.
In our first program we would try to order the microcontroller to “control” an external parameter, yes you are right it would be the LED that we built recently.
To be precise, we’ll tell the MCU to switch ON the connected LED, yep I know this looks quite primitive, but the starting phase always needs to be easy.
Moving ahead with the present job, making the MCU control the LED is actually pretty simple:
For this we instruct pin#0 on PORT B to produce the required 5V for the LED.
Recall from the previous tutorial, we connected the anode of the LED to the above mentioned pin of the MCU.
There are two essential things required to be addressed to this pin of the MCU: 1) output and 2) 5 volts
We’ll learn a way through which we ca instruct the particular pin to become the output of the MCU.
Once it’s set to be the output of the chip, we may instruct it to be either “high” (5V) or “low” (0V) as desired for an application.
Since the any logic circuit such as a MCU the pins could be wither an output or an input and could be configured to produce either a logic high or logic low, the pins only need to be assigned either to be a logical high or a logical low, there aren’t any intermediate or undefined states other than these couple of states for microcontrollers or for any digital IC for that matter. Also the same applies for each and every pin of the MCU.
As for the input and output pin assignments, the inputs would be positioned to accept signals from external analogue stages, while the outputs would be responsible for interpreting these into the specified logical states, or a frequency.
Although the above assignments could be done in many different methods, we would be discussing one of them for the sake of simplicity. However it must be noted that although the one which would presented right now looks easy and interesting, it’s not so viable and not a recommended type for all MCU applications, for the same reason you would be introduced to more popular programming methods later in the course. These programs will allow only the desired pins to be assigned as per the specs without affecting the other adjoining which could be possibly already assigned to do some other functions.
However right now we won’t be bothering about the other pins so much and would use only the relevant pins of interest, avoiding complications to some extents.
For assigning a pin as an output we need to employ the Data Direction Register (DDR). If you are wondering what register here means, it’s simply a space in the MCU that enables the microcontroller to respond in some specified manner.
Using the DDR we can set the pin to either send a data that is like an “output”, or accept data that is in the form of an “input”.
However you may be confused regarding the word, what does this imply? A data adds a third dimension to the pins which may be assigned to be continuously at logic zero (0V) or logic high (5V), but what about the signals which could vary quickly such as a frequency of pulses. A frequency would be accompanied with high and low logics (5V and 0V) oscillating with some specified intervals or periods, thus it becomes time oriented and may be adjusted with respect to time, that’s why we identify as “data” meaning a parameter which indicates a function relative to another function (logic states and time).
One method of assigning pin0 as an output is by writing the following code:
DDRB = 0b00000001;
In the above program, DDRB signifies Data Direction Register for PORT B; 0b instructs the compiler regarding the following binary expression of a number; while the “1” at the end of the expression indicates the position of the pin0, that is it’s location in the form of the first pin of PORT B.
If you remember we learned that PORT B associates 8 pins with it (from 0 to pin7), and if you notice the above code also has 8 digits in it, meaning each digit signifies these 8 pins of PORT B.
Now the next procedure would be to assign 5V to this pin (pin0). Again the principle of operation is identical to DDR as above expressed through the following binary code:
PORTB = 0b00000001;
As can be seen, the only difference between the above code and the earlier one is that in this code we have made use of the PORT register. This register specifically handles the pin assignments of that particular port for which it’s been positioned inside te MCU. Thus it enables us to assign the real data logics (0 or 1) for those pinouts.
Now we may be interested to discuss some regarding the approximate details of our program. As we know all programs require a particular space to initiate the execution, this can be compared to a chef who knows all the ingredients regarding a particular recipe but is not instructed from where to begin.
The “main” function here is the location where each of the C/C++ programs initiates the execution. Therefore the main may be created as:
However to enable the program to interpret the DDR and PORT register details and their functioning inside the MCU chip, an additional statement needs to be included which may consist of all the data regarding the AVR MCU. Perhaps we would want to add this inclusion in all of our programs.
As soon as the compilation initiates, the pre-processor section of the compiler focuses on the AVR directory to identify the “io.h” file. The extension “.h” here indicates it to be a header file, and that this code inside the file would be introduced at the start (head) of the source file that’s being created, hence the name “header”.
Here on we can introduce the DDR and PORT statements into our code, because the addition of the io.h header file would have directed the compiler regarding them.
DDRB = 0b00000001; //Data Direction Register setting pin0 to output and the remaining pins as input
PORTB = 0b00000001; //Set pin0 to 5 volts
The above fixes the orientation of the pin0 as the output, having a magnitude of 5V. However there’s still one issue which isn’t determined for this pin, that is this pin is yet to be instructed to be switched ON indefinitely as long as the MCU is powered. This infinite feedback loop would ensure that this pin from the MCU does not switch OFF, rather continues with the 5V output indefinitely.
Although there are many different methods of applying a loop instruction for a pin, we would try employing the “while” loop here. As the name suggest, the “while” loop tells the microcontroller that “while” the power is available you need to stay activated with the assigned 5V for the assigned pinout.
DDRB = 0b00000001; //Data Direction Register setting pin0 to output and the remaining pins as input
PORTB = 0b00000001; //Set pin0 to 5 volts
//Code would be in here if it needed to execute over and over and over ... endlessly
You might want to note that, here we have used ‘1’ in the form of an argument for the “while” loop, since everything except ‘0’ could be considered a logical “true”.
That implies, the “while” loop consideration would never be responsible for anything except a logical “true”, which means that the particular pin would latch on with the specified state indefinitely.
The LED can be witnessed to be ON across the assigned pin permanently as long as the MCU received power across its Vdd and Vss.
That’s it, now we have the result that we desired to get and finally can see it happening after so much of hard work, but nevertheless to view the sweet result of our hard work is so satisfying.
Within the next tutorials we’ll learn how to add a “time” dimension to the above LED, that is how to make it blink at certain specified rate.
Actually, in the above implementation, the LED is actually blinking but the loop rate is so quick that it’s almost like a permanent switch ON over the LED illumination.
We’ll see how this loop can be added with a delay as desired in order to make the LED blink at that delayed rate.
In the last discussion, we learned how to make an LED switch ON through a microcontroller, it was outstanding wasn't it? May be not so much!
Here we will learn how to spice-up the above LED illumination by attributing a bi-directional functionality, that is we’ll try to make it flash or blink at some specified frequency or rate. We’ll also see how this rate could be increased or decreased as desired by the user.
Let’s have a look into this:
DDRB |= 1 << PINB0;
PORTB ^= 1 << PINB0;
If you are feeling baffled with those strange symbols (&, ^, | etc) used in the above expression (& is not there but could be used in other similar codes), here are the related information you would be interested to know about these:
It includes many standard logical algorithms such AND, OR, NOT and XOR which are typically used with the above code.
These logical functionality specifically compare the two bits “1” and “0” according to their assigned truth tables.
We’ll get an idea by analyzing the following bit arrangement:
In the above code & refers to AND as used in C programming.
Reading the rows vertically, it suggests that 0 and 1 equals 0, 1 and 0 also equals 0, 0 and 0 equals 0, 1 and 1 equals 1. Reading it is as simple as that. These are as per the truth table of a AND operator.
If we assess the following table, it indicates the symbol “|” denoting the use of “OR” functionality, the “|” could be found just on the left of “backspace” in your computer keyboard:
Identically this truth table of an OR logic functionality indicates that bits 0 or 1 equals 1, 1 or 0 also equals 1, 0 or 0 equals 0, while 1 or 1 equals 1.
The following bit combination is for XOR logic operator denoted by ^ and may be studied just as we did with the AND, OR truth tables:
Now let’s continue with the first program and learn what the following line in it signifies:
Through our previous tutorials we know how the expression <avr/io.h> functions, so we won’t be reiterating it however their seems to be a new “include” expressed by #include which needs to be investigated.
In this “include” the delay.h allows us with some easy methods of implementation.
As the name suggests the delay.h enables us to induce a delay in the particular program.
The next expression int main (void) could be omitted from the ongoing discussion since we have already covered this in our earlier posts.
Next comes the altered DDRB.
The following shows the earlier form which is not a better way of assigning the pins since all the pins from 0 to 7 were switched to form the inputs. But just imagine what would be the situation if we wanted to create a lengthier program requiring those pins for some other functionality? For instance pin2 could be needed for applying a remote switching of an appliance. In that case we wouldn’t appreciate assigning the same as an input just through trial and error. That could mean incorrect response from the remote transmitter to the appliance receiver.
DDRB = 0b00000001;
We rather want to influence just one bit, hat pin0 bit, glancing at the “OR” functionality this could be executed through a binary masking.
DDRB = DDRB | 0b00000001;
Here it’s veiled with an “OR” mask: 0b00000001, although it quite appears to be an authentic binary number, in case the earlier DDRB for instance: 0b01001010, then applying an OR to this through masking could give: 0b01001010 | 0b00000001 = 0b01001011.
The resultant difference as could be witnessed is only with the pin0, whose bits have changed!
Compressing the above statement even further via C++ gives:
DDRB |= 0b00000001;
However we find that there’s even more in the given program. Although it may look quite legit and obvious we ought to take the benefit of some of the statements from the io.h header file especially when it’s fundamentally created for our convenience?
So if “DDRB |= 1 < < PINBO, why it’s like that?
1 < < PINBO is implemented for applying the masking effect. The “1” indicates what may be introduced inside the mask, while the < < is simply the left shift functionality. It executes exactly as it’s named, and PINBO is the number of locations that the “1” would sequence across the left hand side. To be precise PINBO may be equivalent of a 0.
So we begin with a 0b00000000, and put a “1” to produce 0b0000001 and then we transfer it to left 0 positions, which gives a exactly identical 0b00000001 as above.
Now, if supposing it was PINB4, the statement could be expressed as 1 < < PINB4. I this case the “1” would be pushed to the left 4 locations producing: 0b00010000.
Beware we are employing a zero index meaning there are four zeros after the “1”.
Now proceeding on to the “while” loop we had noting across the “infinite loop” earlier. But perhaps now we want the microcontroller to implement some of the desired executions. This may be only feasible inside the given loop. It’s the loop where the particular sequence is repeated again and again.
In case the execution would be placed prior to the loop, it would have implemented just once.
However in order to make the LED blink indefinitely it would required to switch the PINB0 alternately ON/OFF within the loop. Here we also find the delays being introduced, without which the blinking of the LED would be impossible. But this would force the LED to blink at a very rapid rate difficult to recognize with the naked eye, it would need to slow down a bit to become identifiable with our eyes.
We are aware the setting up procedure of a particular bit in the binary number, but not sure the method of applying a specific bit “0” in case it’s a “1” yet.
The following program could be seen doing this but we’ll also find that it may not be visible in the program.
The initial two statements changes the bit to “1” (5V, LED lights), then a pause is introduced for 100 ms.
The next couple of lines turns the PINB0 bit into “0” (zero voltage, LED shut off), but sorry the AND compare won’t be able to execute a “0” from the bit, but if we use NOT “~” for the binary mask it could switch all 0s into 1s and vice versa.
This will enable us to influence only the PINB0 bit and flip it to “0”. The parenthesis was included in order to contain the masking execution such that the NOT operation could be applied for the whole masks and not simply over the “1” prior to the left shift “< <”.
PORTB |= 1 << PINB0;
PORTB &= ~(1 << PINB0);
In order to create the ON OFF delays or the periods of equal duration, we may cut-short the previous four lines to two and apply XOR functionality in our benefit. It must be noted tat an XOR execution an assigned pin to a 1 in case it’s 0 and vice versa. This execution would only influence the PINB0. As may times the command is applied, it would simply turn the bit into the opposite of the existing logic.
PORTB ^= 1 << PINB0;
DONE! Your LED would be blinking now as per the set rate….Simple, wasn't that?