Menu:

Arduino AVR assignment 1

Original by B.J.D. Vermulst for AVR Studio with WinAVR. April 2010.

We start with the most simple microcontroller project: a flashing LED. At the board, there is a LED available: it is connected with a 470 ohm resistor (or another value in this range) to pin B5 of the microcontroller.

flash1.c
The program of the flashing LED:
#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
    // set B5 for output
    DDRB = 1 << PB5;

    while (1){
        _delay_ms(500);
        PORTB ^= 1 << PB5;
    }
return 1;
}

The first line enables the use of the IO (input/output) functionality of the microcontroller. The second line tells the compiler that the library ‘delays.h’ has to be used. In this library, several delay routines are preprogrammed.

The first line of the main function makes PB5 output. If you look in the datasheet of the Atmel microcontroller, you’ll see that there are also data direction registers (DDRx) available for all the other ports. Without this line, we can send signals to this pin in our program without noticing anything on the outside. For each pin, it has to be specified if it is an input or output.

The other lines are a loop that is repeated over and over again. First, a delay of 500 milliseconds. After the delay, we toggle the output level of pin B5. Then the loop starts over again.

The result: a flashing LED with a frequency of 3 Hz (the LED flashes three times per second).

Adapt the delay functions as you like, to increase of decrease the flashing frequency, or to change the ratio between on and off (some additional code needed, try to create it!).


Connect the board and program the AVR.

flash2.c
Adapt the program in such a way that the LED flashes with a frequency of 1/5 Hz (one flash takes 5 seconds), with the LED turned off for 4 seconds and on for 1 second. Also create a function _delay_s to call _delay_ms(1000) one time for each second of delay desired.

flash3.c
Add 2 LEDs and resistors (in total 1 red, 1 orange and 1 green LED). The resistors should have a value around 470 ohms. This is calculated with Ohm’s law. The maximum current that a LED can handle is 20mA. The AVR board can supply only 100mA when powered with USB (5 LEDs using 20 mA each, or 10 LEDs with a current of 10mA, and so on…). Using an external power supply, the board can deliver up to 1A. Use the following pins: B0 (green), B1 (orange) and B2 (red). Now make a traffic light with the following cycle:
• 3 seconds green
• 1 second orange
• 10 seconds red
flash4.c
The use of 1 and 0 can be quite confusing. With the following lines of code, ON and OFF are defined. This part of code is inserted directly below the defines:
#define ON    1
#define OFF     0
Create a new function to set a certain port pin on port B to ON or OFF.

flash5.c
The traffic light that you’ve made is Dutch. Now, make an English traffic light which has the following cycle:
• 4 seconds green
• 1 second orange
• 9 seconds red
• 1 second orange + red
In England, the combination of red and orange indicates that the traffic light becomes green very soon.

flash6.c
Add 3 extra LEDs and resistors. Use the pins B3 (green), B4 (orange) and B5 (red). Make two traffic lights that are at a crossing. First, write down the total cycle of the traffic lights. Be careful, some car drivers pass through a red light, so if one traffic light turns red you have to wait to turn the other traffic light to green. If you use the English system, orange + red should not be at the same time the other traffic light is green! This is because there could be drivers that pass a traffic light at the red + orange light. Furthermore, you have to adapt some delay times.

flash7.c
The previous program is not very clear and easy to read. We can make the program much more clear by calling a function for each step in the cycle. In the function, we adapt all the lights so they are at the right color, and we wait for a certain number of seconds.

#define RED    0
#define ORANGE    1
#define GREEN    2

void phase(int seconds, int mainroad, int secroad)
{
    PORTBset(PB0, mainroad == GREEN);
    PORTBset(PB1, mainroad == ORANGE);
    PORTBset(PB2, mainroad == RED);
    PORTBset(PB3, secroad == GREEN);
    PORTBset(PB4, secroad == ORANGE);
    PORTBset(PB5, secroad == RED);
    _delay_s(seconds);
}

The first line of the function is called header. In the header is stated in which way the function should be called, in this case with 3 parameters:
• the delay time after setting the lights
• the color of the traffic light of the main road
• the color of the traffic light of the secondary road
In the while loop, for each step of the cycle we call this function.

while (1)
{
    phase(1, RED, RED);
    phase(5, GREEN, RED);
    phase(1, ORANGE, RED);
    phase(1, RED, RED);
    phase(3, RED, GREEN);
    phase(1, RED, ORANGE);
    phase(1, RED, RED);
}

flash8.c
Add two more LEDs, connect them to the pins D2 and D3. These LEDs are the traffic light for the pedestrians (a traffic light for pedestrians doesn’t contain an orange light). Adapt the function and the while loop in such a way that also the pedestrian lights are working right. You can chose to make the light for the pedestrians green at each change in green for the main and secondary road, or only once in the total cycle.

flash9.c
The traffic lights we just made, always turn the pedestrian light to green, even if there are no pedestrians. Most of the traffic lights contain buttons for pedestrians. Connect a button between pin D5 and the ground. For a pedestrian, it is nice to see that his push on the button has been recorded. So, add a yellow LED with resistor and connect it to pin D4. This LED is lit when the button is pushed, and is switched off when the pedestrian light is turned to green.

Now, somewhere in our program we have to check is the button is pushed. At first sight, this is not very difficult. We can run a few lines of code with an IF statement, under a certain condition (e.g. only when pin D4 is low).

if(PIND & (1 << PD5)){
PORTDset(PD4,1);
}

To check inputs, PIN registers should be used and to drive outputs PORT registers should be used.

With these few lines of code, we succeeded in lighting the yellow LED whenever the button is pressed. However, the problem is to execute this part continuously. The current program is once in a while stuck in a delay function for a few seconds.

We can solve this by using a custom delay function, instead of the previously mentioned delay functions. This new delay function is a function that checks if the button is pressed, wait for a very short time, checks the button again, wait, etc. etc. This continues until the total delay time has passed. If the waiting between two button checks is short enough (e.g. 10 mS), it seems like checking the button continuously. For clarity, we use two functions.

void button(void){
    if(PIND & (1 << PD5)){
        PORTDset(PD4,1);
        pressed = YES;
    }
}

In the first function we check if the button is pressed. If this is true, we turn on the LED and give the variable pressed the value YES, so we know in the main function we have to change the pedestrian light.



int pressed = 0;

void _delay_s(int t){
    int i;

    for(i=0;i<(t*100);i++){
        button();
        _delay_ms(10);
    }
        
}

The second function contains a FOR loop. A FOR loop is executed as many times as specified. Calling a FOR loop, there are three input parameters: the initialization value (i = 0) , the condition to execute the loop (i < 100), and the step size for each loop (i++, this is a kind of short notation of i = i + 1). In this loop we call the first function, button and we wait 10 milliseconds. We have to wait for a specified number of seconds, so we loop as many times as we want to wait 10 milliseconds.

In the main function, we only have to take the pedestrians into account if the function button has detected that the button has been pressed.

while (1)
{
phase(1, RED, RED, RED);
    phase(5, GREEN, RED, RED);
    phase(1, ORANGE, RED, RED);
    phase(1, RED, RED, RED);
    phase(3, RED, GREEN, RED);
    phase(1, RED, ORANGE, RED);
    phase(1, RED, RED, RED);
        
    if(pressed == YES){
        PORTDset(PD4,0);
        phase(5, RED, RED, GREEN);
        pressed = NO;
        phase(1, RED, RED, RED);
    }
}
Most of the times, the pedestrian lights are red, so this is set as default.

Add the LEDs for the pedestrian lights and add the button. Edit the program and test it.