Reading and Writing Ports:
WRITING TO PORTS:
PORTA = 0xaf;
PORTA = 0b10101111;
PORTA = 175;
If you want to write to all eight bits of a port, you may explicitly write the byte out. This is accomplished by using the single equal sign “=”. Note you may use any of the three number systems. All three examples above write decimal 175 to port A of the microcontroller.
PORTA = (PORTA | 0b00010001);
The OR operator “|” is used to set a particular bit. In this case, bits zero and four are being set. This type of convention is useful when you do not want to change the other bits of the port.
PORTA = (PORTA & 0b11101110);
The AND operator “&” is used to clear a particular bit. In this case, bits zero and four are being cleared. This type of convention is useful when you do not want to change the other bits of the port.
READING FROM PORTS:
x=PINA;
To read the signal levels on a port, you must use PINx where “x” is the port (A, B, C, D, etc.).
x=(PINA & 0b00000001);
To only look at a particular set of bits, use the AND operator and a bit mask. Everywhere a zero is, the bit position will be forced to zero (by the definition of AND). Everywhere a one is, the bit value will be retained. In this example, “x” is assigned the value whatever bit zero is. This is useful when pins are unconnected. You do not know the state of the unused pins, but you must read them in as part of the PINA read. By ANDing with zeros, you know the pin states will be zero.
Note: you may want to change only certain bits of an output port. In this case, you may read the value of the output port latch and perform ANDing or ORing. This is done by reading PORTx where “x” is the output port of interest. Note that by reading PORTx, you are reading the values which are supposed to be outputting. If you actually read PINx of an output port, you are reading the value which is forced on the port from the outside world. Ideally PINx and PORTx should be identical (for output ports), but if a short circuit (or low impedance connection) is present on the pin, you may force the wrong value on the pin.
Flow Control:
IF STATEMENTS:
if(x == 1)
{
Your code here
}
Check for a true condition in the parenthesis. If the argument is true, execute the code between the braces once. When checking for equality, use the double equal signs “==”. Note to check for multiple conditions use “&” for “and” and “||” for “or”. So if you wanted to execute your code when “x” is equal to one and when “y” is equal to two, you would type
“if(x==1 & y==2)”. This convention of checking for multiple conditions also applies to “while” and “for” loops.
WHILE STATEMENTS:
while(x < 10)
{
Your code here
}
Check for a true condition in the parenthesis. If the argument is true, continue executing the code between the braces until the argument goes false. Note this statement only checks the argument at the beginning of each loop. So if you have already started executing code between the braces and the argument goes false, all your code will finish executing before rechecking the argument.
FOR STATEMENTS:
for(i=0; i<4; i=i+1)
{
Your code here
}
Set the incrementing variable (“i" in this case) to an initial value of zero. Loop through the code between the braces as long as the center argument is true (“i” is less than 4). After each run of the code, increment “i" by one. The for loop automatically changes “i” so you do not have to explicitly increment it after each run. If you wanted to increment “i” by two instead of one, change the final argument to “i=i+2”. You can use “i” as a normal variable inside the for loop for operations such as array indexing.
Useful C Operators:
+ Addition Operator: y = x+1;
Logical Bitwise AND: y = 0b01010101 & 0b00001111; (y equals 0b00000101)
~ Bitwise Complement: y = ~0b01010101; (y equals 0b10101010)
^ Bitwise XOR: y = 0b01010101 ^ 0b00001111; (y equals 0b01011010)
/ Division Operator: y = x / 3;
== Equality Query 3 == 3; (returns true; returns 1)
3 == 4; (returns false; returns 0)
!= Inequality Query 3!=4; (returns true; returns 1)
3!=3; (returns false; returns 0)
Greater Than Query 3 > 2; (returns true; returns 1)
2 > 3; (returns false; returns 0)
Left Shift Operator y = 0b00001111 < 2; (y equals 0b00111100)
Less Than Query 2 < 3; (returns true; returns 1)
3 < 2; (returns false; returns 0)
AND Query 0b00001111 & 0b00001111; (returns true; returns 1)
0b00001111 & 0b00001010; (returns false; returns 0)
! Negation Operator !(something not zero) (returns false; returns 0)
!(something zero or false) (returns true; returns 1)
|| OR Query 3==3 || 1==0; (returns true; returns 1)
3==2 || 1==0; (returns false; returns 0)
* Multiplication y = 2 * 4; (y equals 8)
% Remainder Operator y = 9 % 4; (y equals 1)
Right Shift Operator y = 0b00001100 > 2; (y equals 0b00000011)
= Assignment Operator y = 2; (y equals 2)
- Subtraction operator y = 4 - 3; (y equals 1)
// Comment Line Allows comments to be used in code. They are ignored.
Manipulating Character Strings:
CONSTANT UNCHANGING STRING:
char string1[] = “This is a test.”;
This string is called “string1” and will always have the value of “This is a test.”. This is suitable for outputting to an LCD or sending as a serial string to a host PC. If you have changing values in the string (such as ADC readings), this method will not work; you must use the “sprint()” command.
DYNAMIC STRING FORMATTING:
NOTE: to use the “sprintf” command, you must type (without quotes) “#include <string.h>” at the start of your code.
sprintf(string2, “The ADC reading is %d.”, x);
The “sprintf()” function writes a string to the “string2” variable. Note that “string2” must be a character array of N+1 length (or greater). You can declare the “string2” variable with
“char string2[30];”. There are over 20 characters in the output string so a good number to use in declaring the variable is 30 (to allow for 9 numbers).
The output string is formatted exactly by what is in the quotes (there must be quotes). Each time there is a “%d” present, the compiler knows a decimal number will be placed there. If there were multiple “%d” then the variables being outputted must be placed in the proper order of occurrence. In this example, the only variable being output is “x”.
First Argument: The string variable being written to.
Second Argument: The general form of the string with variable placement.
Other common forms of variable formatting are:
%d decimal signed integer
%u decimal unsigned integer
%X hexadecimal digits
%f floating point number
Third Argument: The list of variables being inserted into the string in the same order as the %’s.
EXAMPLE:
sprintf(string3, “The ADC1 reading is %d in Decimal, The ADC2 reading is %X in Hex.”, x, y)
“string3” is the character string being written to.
The second argument “The ADC1….” Is the general form of the output string.
“x” is the variable associated with the “%d”.
“y” is the variable associated with the “%X”.
Other Considerations:
DELAY FUNCTIONS:
You must type this at the beginning of your code: #include <util\delay.h>
Limited to 768 ms:
Call a delay in ms: _delay_ms(number);
Limited to 768 us:
Call a delay in us: _delay_us(number);
MATH FUNCTIONS:
You must type this at the beginning of your code: #include <math.h>
Functions supported:
M_PI Constant of Pi
M_SQRT2 Constant square root of two
cos() Cosine of the argument
sin() Sine of the argument
fabs() Absolute value of the argument
tan() Tangent of the argument
sqrt() Square root of the argument
exp() Computes the exponential of the argument (e^argument)
log() Computes the natural log of the argument
log10() Computes the base 10 log of the argument
and many others…
FLOATING POINT NUMBERS:
To enable floating point string formatting, you must enable floating point operations in the
compiler. Normal number crunching works fine without any modifications to the compiler. To
enable floating point string formatting follow the given procedure below:
In the “Project” menu click “Configuration Options”.
On the left click “Libraries”
Add “libm.a” and “libprintf_flt.a”.
On the left click “Custom Options”
On “[Linker Options]” insert the following options:
-Wl,-u,vfprintf -lprintf_flt –lm
Click OK, the rebuild your project.
PROGRAM TEMPLATE:
All your programs should start like this:
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
Functions and subroutines here
int main(void)
{
Your code here
}
HOW TO WRITE FUNCTIONS AND SUBROUTINES:
All functions and subroutines must have a return type. If the function does not return anything the return type is “void”. Other return types are integers (“int”), floating point numbers (“float”), and characters or bytes (“char”). The value to be returned is the variable following “return”.
In addition, you must specify the arguments and their types to the function. This is provided in parenthesis following the function name. If no arguments are required, put “void” in the argument list. This is seen in the “main” function of your program.
To return an integer example:
int AddTwoNumbers(int x, int y)
{
return x+y;
}
To return nothing (void) example:
void SetPortA(char x)
{
PORTA=x;
return;
}
To return nothing with no input arguments example:
void ClearPortA(void)
{
PORTA=0;
return;
}