Sample BASCOM Program
Getting familiar with BASCOM
I have always learned best by looking at examples and modifying them to suit my purposes. That is how we will show you the basics of programming the AVR microcontroller. As you go through the book, feel free to experiment with the program to get various results. Some will work and some will not. Typically you will learn more from the trials that fail because of the time you spend troubleshooting the reason for the failure. This entire program is listed in the appendix under 'Programs' and also on my website under downloads as project1.bas if you would like to just load the program and continue to the next section.
We will start by opening the BASCOM software you downloaded and installed. Instructions on downloading and installing the software is located in the Appendix under “Software” as well as on MCS Electronic's website.
Comments, chip files and clocks
Now, start a new project and let's start typing some code. Click the blank page button to start a new project. After you have entered a line or two, click File -> Save As and choose a name and location for the project. Saving in the default location is fine, but it is best to create a folder specifically for each project and save the project in that folder.
Figure 5.1
The above figure shows the beginning portion of our program. The lines with a ' in front of them are remarks. They are shown in green by default and are ignored by BASCOM. They are there only for our reference. It is a good idea to put as many comments in the program as possible to insure you know what it was you were doing when you return to the program to debug or modify the code.
The last line specifies the type of chip to BASCOM. The command is the $regfile = and is in dark blue followed by “m16def.dat” in light blue which is the file. If you are using a chip other than the Atmega 16, you can locate the available reg files by going to Options -> Compiler -> and clicking on Chip. It will bring up a screen for you to see the names of the reg files for the chips as you can see in figure 4.2.
Figure 5.2
Next, you will see the line $crystal = 1000000. This tells the software what frequency the chip is using. This is important for any application that times any event, such as communication or waiting 2 seconds before turning an LED on or off. If the line in the code is set incorrectly, for instance if you told the software the frequency was 8000000, instead of waiting 2 seconds to turn an LED on or off, it would wait 16 seconds because it thinks the system clock is ticking 8000000 times per second instead of 1000000 times per second so it will wait until 16000000 ticks have passed before carrying out the command.
The Atmega 16 comes set from the manufacturer to use the internal RC oscillator (system clock) set at 1000000 (1mhz). It can be changed to 8mhz with the STK500, but the line in the code would have to be changed to 8000000 to match the actual clock frequency. Directions on changing the internal oscillator is in the appendix under 'Programming the Fuse Bits.'
Setting ports and pins
Now we need to configure the individual input/output pins to do perform the correct functions. First, we tell the microcontroller if the pins are going to be input (receive information) or output (send information) pins. You can choose to set an entire port (group of pins with the same letter prefix, i.e. A.0, A.1, etc), you can set one pin at a time, or you can do a combination of the two. We will do a combination of the two to illustrate how each is done.
Figure 5.3
Figure 5.3 shows the command Config Portb = Input. Config is the command given to the compiler, Portb is the set of pins (b) being addressed, and Input determines the direction of the pins (receive). That is how you set an entire port of pins to one direction.
However, we wanted to of the pins in Portb to be output pins to drive the LEDs. So, the next two lines changes just the two pins Portb.0 and Portb.1 to output pins to drive the LEDs. After the pins are configured as output pins, the next two lines sets the pins to positive 5 volts (this chip's operating voltage) to insure the LEDs are off as the negative side of the LEDs will be tied to the microcontroller through a resistor (the negative side must be tied to a ground source with the positive side tied to a positive voltage for the LED to illuminate. If the positive side is tied to a positive source and the negative side is tied to a positive source, the LED will not illuminate). The command SET drives the pin high – positive – while the RESET command drives the pin low – negative.
Watchdog timers, subroutines and do loops
Figure 5.4
This section of code illustrates five functions you will likely use in most of your programs. The first is the watchdog timer. The lines pertaining to the timer are obvious as they all have watchdog in the statement. As you can see, you need to initialize the timer with the config statement along with the length of time you want it to wait until it resets the microcontroller. After that you start the timer with the start command. Finally, you will place reset commands throughout your code to reset the timer preventing it from resetting your chip.
It seems like a lot of hassle to add a function you do not want to engage. However, without the watchdog timer, if your program locks up due to software, hardware, static electricity, or whatever, you don't want it to stay locked up or for the user to have to reset the product. That is the function of the watchdog timer. If your program locks up, the reset command for the watchdog will not reset the timer and it will count down to zero. At this point, the chip completely resets itself and starts running the program from the beginning. Just make sure when you are programming the time delay for the watchdog timer and inserting reset statements, you have enough of a delay and reset statements to keep from resetting the chip during normal operation (if we have a 2 second delay on the LED command, you would not set the timer at 1 second – 1000 milliseconds – or the chip would reset every time the LED started its cycle.
Following the watchdog timer you see several declare sub commands. We will be using subroutines to carry out functions in the event a button is pressed. As you can see, the subroutines are named according to the corresponding buttons we will assign for the function. This enables easier reading of the code at a later date. Every subroutine must be declared before it can be called.
After the declare sub commands, you see the Do command. This is half of a whole command. The other half goes at the end of our main body of the program to keep the program looping, waiting for a button to be pressed.
If then statements
Following the Do command, you see the first of many reset watchdog commands. After that command is an if-then statement. Each if-then statement has at least three parts. The first part is the condition. In this case, the condition is Pinb.2 = 0 which means button a is pressed and the pin is tied to ground.
If the button is pressed, the program executes the commands inside of the if-then statement (all commands before the matching end-if command as you can see in the example code in figure 4.4). The command executed in this case is to execute the subroutine Buttona with the command Gosub Buttona. At that point, the program jumps to subroutine Buttona and executes the commands in that portion of the program. You will see the subroutine soon.
If button A is not pressed, Pinb.2 = 1 and the program skips to the end of the if-then statement which is the end-if statement and begins executing the next line of code following the if-then group.
Figure 5.5
In figure 5.5 we see the last three if-then – end-if statements, each calling the subroutine for the button assigned to each pin for a total of four statements responding to four buttons. That takes care of the input portion of our product in the software.
The last statement you see is the other half of the Do-Loop statement, Loop. The microcontroller will continue to go in circles within this loop unless power is removed, one of the if-then statements is executed, or the watchdog timer resets the chip and the whole process starts over again.
Subroutines (continued)
Figure 5.6
In figure 5.6 we see the first subroutine for button A. When the if-then statement calls this subroutine, the microcontroller jumps to this point and starts with the first line of code, reset watchdog, and continues through until it reaches the Return statement which causes the microcontroller to return to the point in the program it jumped from to get to this subroutine.
After the reset watchdog command, you see another reset command for Portb.1. That makes Portb.1 go low or negative, allowing electricity to flow through the LED causing the LED to illuminate.
The next statement makes the program pause for 1500 milliseconds, or 1.5 seconds. It is a waitms command. Another command to create a pause in your programs is the wait command. If you typed wait 3 , the program would pause 3 seconds before continuing to the next command.
After the waitms 1500 command, you see another reset watchdog command. It is important to insure the watchdog timer is continually reset before it resets the microcontroller or your program will not function properly.
Following the watchdog reset, Portb.1 is once again set high, positive, stopping the flow of electricity.
The next line you see is Return which instructs the microcontroller to return to the main loop at the point it left. The last line is the End Sub line, letting BASCOM know the subroutine is finished.
So the order of the subroutine is pretty simple.
enter the subroutine
reset the watchdog
make portb.1(LED1) negative so the LED shines
wait 1.5 seconds
reset the watchdog
make portb.1(LED1)positive so the LED goes dark
return to the main program
let BASCOM know the subroutine is over
Figure 5.7
The order of Buttonb subroutine in figure 5.7 is similar.
enter the subroutine
reset the watchdog
make portb.1(LED1) negative so the LED shines
wait 1.5 seconds
reset the watchdog timer
make portb.0(LED2) negative so the LED shines
wait 1.5 seconds
reset the watchdog
make portb.1(LED1) and portb.0(LED2)positive so the LEDs goes dark
return to the main program
let BASCOM know the subroutine is over
Figure 5.8
Subroutine Buttonc is shown in figure 5.8 with the following order.
enter the subroutine
reset the watchdog
make portb.1(LED1) negative so the LED shines
wait 1.5 seconds
reset the watchdog timer
make portb.1(LED1) positive so the LED goes dark
make portb.0(LED2) negative so the LED shines
wait 1.5 seconds
reset the watchdog timer
make portb.0(LED2) positive so the LED goes dark
return to the main program
Let BASCOM know the subroutine is over
Figure 5.9
So the order of the subroutine is pretty simple.
enter the subroutine
reset the watchdog
make portb.0(LED2) negative so the LED shines
wait 1.5 seconds
reset the watchdog
make portb.0(LED2)positive so the LED goes dark
return to the main program
let BASCOM know the subroutine is over
Compiling
When you have typed in all of the code (or copied it from my website), compile the code in BASCOM. To do that, just press the compile button as shown in figure 5.10.
Figure 5.10
If you happen to have the simulator active, a new screen simulating the chip running with the program in the background will appear. To exit that screen, just close out the simulator window.
If the program does not successfully compile, you will get a list of errors at the bottom of the BASCOM window. You can get an idea of what you did wrong by looking at the errors and then finding the corresponding lines in your code. Many errors you encounter will be typing errors. Check your program against the copy in this book's appendix and try compiling the program again until you are successful.