brock

Friday, January 28, 2011

AVR Tutorial

CodeVisionAVR
CodeVisionAVR is a C cross-compiler, Integrated Development Environment and Automatic Program Generator designed for the Atmel AVR family of microcontrollers.

The program is a native 32bit application that runs under the Windows 95, 98, NT 4, 2000 and XP operating systems.

The C cross-compiler implements nearly all the elements of the ANSI C language, as allowed by the AVR architecture, with some features added to take advantage of specificity of the AVR architecture and the embedded system needs.

The compiled COFF object files can be C source level debugged, with variable watching, using the Atmel AVR Studio debugger.

The Integrated Development Environment (IDE) has built-in AVR Chip In-System Programmer software that enables the automatical transfer of the program to the microcontroller chip after successful compilation/assembly. The In-System Programmer software is designed to work in conjunction with the Atmel STK500/AVRISP, Kanda Systems STK200+/300, Dontronics DT006, Vogel Elektronik VTEC-ISP, Futurlec JRAVR and MicroTronics ATCPU/Mega2000 development boards.

For debugging embedded systems, which employ serial communication, the IDE has a built-in Terminal.

Besides the standard C libraries, the CodeVisionAVR C compiler has dedicated libraries for:
·   Alphanumeric LCD modules
·   Philips I2C bus
·   National Semiconductor LM75 Temperature Sensor
·   Philips PCF8563, PCF8583, Dallas Semiconductor DS1302 and DS1307 Real Time Clocks
·   Dallas Semiconductor 1 Wire protocol
·   Dallas Semiconductor DS1820/DS18S20 Temperature Sensors
·   Dallas Semiconductor DS1621 Thermometer/Thermostat
·   Dallas Semiconductor DS2430 and DS2433 EEPROMs
·   SPI
·   Power management

·   Delays
·   Gray code conversion
CodeVisionAVR also contains the CodeWizardAVR Automatic Program Generator, that allows you to write, in a matter of minutes, all the code needed for implementing the following functions:
·   External memory access setup
·   Chip reset source identification
·   Input/Output Port initialization
·   External Interrupts initialization
·   Timers/Counters initialization
·   Watchdog Timer initialization
·   UART initialization and interrupt driven buffered serial       communication
·   Analog Comparator initialization
·   ADC initialization
·   SPI Interface initialization
·   I2C Bus, LM75 Temperature Sensor, DS1621 Thermometer/Thermostat and PCF8563, PCF8583, DS1302, DS1307 Real Time Clocks initialization
·   1 Wire Bus and DS1820/DS18S20 Temperature Sensors initialization
·   LCD module initialization.


The author of the program wishes to thank Mr. Jack Tidwell for his great help in the implementation of floating point routines and to Mr. Yuri G. Salov for his excellent work in improving the Mathematical Functions Library  and beta testing CodeVisionAVR.

Opening an Existing Project

You can open an existing Project file using the File|Open menu command or by pressing the Open file button on the toolbar.
An Open dialog window appears.

You must select the file name of the Project you wish to open.
By pressing the Open button you will open the Project file and its source file(s).
You can configure the Project by using the Project|Configure menu command.





Creating a New Project

You can create a new Project using the File|New menu command or by pressing the Create new file button on the toolbar.
A dialog box appears, in which you must select File Type|Project and press the OK button.

A dialog will open asking you to confirm if you would like to use the CodeWizardAVR to create the new project.

If you select No then the Create New Project dialog window will open.
You must specify the new Project file name and its location.

The Project file will have the .prj extension.
You can configure the Project by using the Project|Configure menu command.

Adding or removing a File from the Project

To add or remove a file from the currently opened project you must use the Project|Configure menu command.
A Configure Project tabbed dialog window will open. You must select the Files tab.

By pressing the Add button you can add a source file to the project.
The first file added to the project is the main project file.
This file will always be Maked.
The rest of the files added to the project will be automatically linked to the main project file on Make.
Multiple files can be added by holding the Ctrl key when selecting in the Add File to Project dialog.

When the project is Open-ed all project files will be opened in the editor.
By clicking on a file, and then pressing the Remove button, you will remove this file from the project.

Changes can be saved, respectively canceled, using the OK, respectively Cancel buttons.

When creating a project with multiple files the following rules must be preserved:

·   only .C files must be added to the project's Files list
·   there's no need to #include the .C files from the Files list as they will be automatically linked
·   data type definitions and function declarations must be placed in header .H files, that will be #include -ed as necessary in the .C files
·   global variables declarations must be placed in the .C files where necessary
·   there's no need to declare global variables, that are not static, in header .H files, because if these files will be #include -ed more than once, the compiler will issue errors about variable redeclarations.

Setting the C Compiler Options

To set the C compiler options for the currently opened project you must use the Project|Configure menu command.
A Configure Project tabbed dialog window will open. You must select the C Compiler and Code Generation tabs.

You can select the target AVR microcontroller chip by using the Chip combo box.
You must also specify the CPU Clock Frequency in MHz, which is needed by the Delay Functions, 1 Wire Protocol Functions and Dallas Semiconductor DS1820/DS18S20 Temperature Sensors Functions .

The required memory model can be selected by using the Memory Model radio group box.

The compiled program can be optimized for minimum size, respectively maximum execution speed, using the Optimize for|Size, respectively Optimize for|Speed, settings.

For devices that allow self-programming the Program Type can be selected as:

·   Application
·   Boot Loader



If the Boot Loader program type was selected, a supplementary Boot Loader Debugging in AVR Studio option is available.




If this option is enabled, the compiler will generate supplementary code that allows the Boot Loader to be source level debugged in the AVR Studio simulator/emulator.

When programming the chip with the final Boot Loader code, the Boot Loader Debugging option must be disabled.

The (s)printf features option allows to select which versions of the printf and sprintf Standard C Input/Oputput Functions will be linked in your project:
·   int - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', no width or precision specifiers are supported, only the '+' and ' ' flags are supported, no input size modifiers are supported
·   int, width - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', the width specifier is supported, the precision specifier is not supported, only the '+', '-', '0' and ' ' flags are supported,  no input size modifiers are supported

·   long, width - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%' the width specifier is supported, the precision specifier is not supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported
·   long, width, precision - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', the width and precision specifiers are supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported

·   float, width, precision - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'e', 'E', 'f', 'x', 'X', '%', the width and precision specifiers are supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported.

The more features are selected, the larger is the code size generated for the printf and sprintf functions.



The (s)scanf features option allows to select which versions of the scanf and sscanf Standard C Input/Oputput Functions will be linked in your project:

·   int, width - the following conversion type characters are supported: 'c', 's', 'i', 'd', 'u', 'x', '%', the width specifier is supported, no input size modifiers are supported
·   long, width - the following conversion type characters are supported: 'c', 's', 'i', 'd', 'u', 'x',  '%' the width specifier is supported, only the 'l' input size modifier is supported.

The more features are selected, the larger is the code size generated for the printf and sprintf functions.

The Data Stack Size must be also specified.

Eventually you may also specify the External SRAM size (in case the microcontroller have external SRAM memory connected).

The External SRAM Wait State option enables the insertion of wait states during access to the external SRAM. This is useful when using slow memory devices.

If an Atmel AT94K05, AT94K10, AT94K20 or AT94K40 FPSLIC device will be used, than there will be the possibility to specify the Program SRAM size in Kwords.

The size of the bit variables, which are placed in registers R2 to R14, can be specified using the Bit Variables size list box.

Checking the Promote char to int check box enables the ANSI promotion of char operands to int.

This option can also be specified using the #pragma promotechar compiler directive.

Promoting char to int leads to increased code size and lower speed for an 8 bit chip microcontroller like the AVR.

If the char is unsigned check box is checked, the compiler treats by default the char data type as an unsigned 8 bit in the range 0…255.

If the check box is not checked the char data type is by default a signed 8 bit in the range  –128…127.

This option can also be specified using the #pragma uchar compiler directive.

Treating char as unsigned leads to better code size and speed.

If the 8 bit enums check box is checked, the compiler treats the enumerations as being of 8 bit char data type, leading to improved code size and execution speed of the compiled program. If the check box is not checked the enumerations are considered as 16 bit int data type as required by ANSI.

The Enhanced Instructions check box allows enabling or disabling the generation of Enhanced Core instructions for the ATmega128, ATmega16, ATmega161, ATmega162, ATmega163, ATmega32, ATmega323, ATmega64, ATmega8 and AT94K FPSLIC devices.

The rest of the registers in the range R2 to R14, not used for bit variables, can be automatically allocated to char and int global variables by checking the Compilation|Automatic Register Allocation check box.

An external startup file can be used by checking the Compilation|Use an External Startup File check box.

The generation of warning messages during compilation can be enabled or disabled by using the Compilation|Enable Warnings check box.

For debugging purposes you have the option Stack End Markers. If you select it, the compiler will place the strings DSTACKEND, respectively HSTACKEND, at the end of the Data Stack, respectively Hardware Stack areas.

When you debug the program with AVR Studio you may see if these strings are overwritten, and consequently modify the Data Stack Size.

When your program runs correctly you may disable the placement of the strings in order to reduce code size.

Using the File Output Format(s) list box you can select the following formats for the files generated by the compiler:

·   COFF (required by the Atmel AVR Studio debugger), ROM, Intel HEX and EEP (required by the In-System Programmer) ;
·   Atmel generic OBJ, ROM, Intel HEX and EEP (required by the In-System Programmer) ;

If the COFF file format is selected and the Use the Terminal I/O in AVR Studio check box is checked, special debugging information is generated in order to use the AVR Studio Terminal I/O window for communication with the simulated AVR chip’s UART.
If the Use the Terminal I/O in AVR Studio option is enabled, the UART or USART code will not run correctly on the real AVR chip. This option is only for debugging purposes.

The Globally #define tab allows to #define macros that will be visible in all the project files.

#define ABC 1234

in each project file.

The Paths tabs allows to specify additional paths for #include and library files.
These paths must be entered one per line in the appropriate edit controls.

Changes can be saved, respectively canceled, using the OK, respectively Cancel buttons.


Working with files

Creating a New File

You can create a new source file using the File|New menu command or by pressing the Create new file button on the toolbar.
A dialog box appears, in which you must select File Type|Source and press the Ok button.

A new editor window appears for the newly created file.
The new file has the name untitled.c. You can save this file under a new name using the File|Save As menu command.



Reserved Keywords

Following is a list of keywords reserved by the compiler.
These can not be used as identifier names.

break
bit
case
char
const
continue
default
do
double
eeprom
else
enum
extern
flash
float
for
funcused
goto
if
inline
int
interrupt
long
register
return
short
signed
sizeof
sfrb
sfrw
static
struct
switch
typedef
union
unsigned
void
volatile
while

Identifiers

An identifier is the name you give to a variable, function, label or other object.
An identifier can contain letters  (A...Z, a...z) and digits (0...9), as well as the underscore character (_).
However an identifier can only start with a letter or an underscore.
Case is significant; i.e. variable1 is not the same as Variable1.
Identifiers can have up to 32 characters.

Data Types

The following table lists all the data types supported by the CodeVisionAVR C compiler, their range of possible values and their size:

Type      Size (Bits)  Range
bit 1      0 , 1
char      8      -128 to 127
unsigned char 8      0 to 255
signed char    8      -128 to 127
int 16     -32768 to 32767
short int 16     -32768 to 32767
unsigned int   16     0 to 65535
signed int      16     -32768 to 32767
long int  32     -2147483648 to 2147483647
unsigned long int    32     0 to 4294967295
signed long int        32     -2147483648 to 2147483647
float      32     ±1.175e-38 to ±3.402e38
double   32     ±1.175e-38 to ±3.402e38

The bit data type is supported only for global variables.

If the Project|Configure|C Compiler|Code Generation|char is unsigned option is checked or #pragma uchar+ is used, then char has by default the range 0..255.






Constants

Integer or long integer constants may be written in decimal form  (e.g. 1234), in binary form with 0b prefix (e.g. 0b101001), in hexadecimal form with 0x prefix  (e.g. 0xff) or in octal form with 0-prefix (e.g. 0777).
Unsigned integer constants may have the suffix U (e.g. 10000U).
Long integer constants may have the suffix L (e.g. 99L).
Unsigned long integer constants may have the suffix UL (e.g. 99UL).
Floating point constants may have the suffix F (e.g. 1.234F).

Character constants must be enclosed in single quotation marks. 
String constants must be enclosed in double quotation marks. E.g. "Hello world".
If you place a string between quotes as a function parameter, this string will automatically be considered as constant and will be placed in FLASH memory.
Example:

/ * this function displays a string located in SRAM */
void display_ram(char *s) {

/* .......  */

}

/ * this function displays a string located in FLASH */

void display_flash(char flash *s) {

/* .......  */
}

void main(void) {
/* this will not work !!! */
/* because the function addresses the string as */
/* it is located in SRAM, but the string "Hello world" */
/* is constant and is placed in FLASH */
display_ram("Hello world");
/* this will work !!! */
/* the function addresses the string as it is located in FLASH */
display_flash("Hello world");  }

Constant can be grouped in arrays, which can have up to 8 dimensions.

Constants are stored in FLASH memory, to specify this you must use the flash or const keywords.
Constant expressions are automatically evaluated during compilation.
Example:

flash int  integer_constant=1234+5;
flash char char_constant=’a’;
flash long long_int_constant1=99L;
flash long long_int_constant2=0x10000000;
flash int  integer_array1[]={1,2,3};
/* The first two elements will be 1 and 2,
the rest will be 0 */
flash int  integer_array2[10]={1,2};
flash int  multidim_array[2,3]={{1,2,3},{4,5,6}};
flash char string_constant1[]=”This is a string constant”;
const char string_constant2[]=”This is also a string constant”;

Constants can’t be declared inside functions.


Variables

Program variables can be global (accessible to all the functions in the program) or local (accessible only inside the function they are declared).

If not specifically initialized, the global variables are automatically set to 0 at program startup.
The local variables are not automatically initialized on function call.
The syntax is:

[] ;

Example:

/* Global variables declaration */
char a;
int  b;
/* and initialization */
long c=1111111;


void main(void) {
/* Local variables declaration */
char d;
int  e;
/* and initialization */
long f=22222222;
}

Variables can be grouped in arrays, which can have up to 8 dimensions.
The first element of the array has always the index 0.
If not specifically initialized, the elements of global variable arrays are automatically set to 0 at program startup.
Example:

/* All the elements of the array will be 0 */
int  global_array1[32];

/* Array is automatically initialized */
int  global_array2[]={1,2,3};
int  global_array3[4]={1,2,3,4};
char global_array4[]=”This is a string”;

/* Only the first 3 elements of the array are        
initialized, the rest 29 will be 0 */
int  global_array5[32]={1,2,3};

/* Multidimensional array */
int multidim_array[2][3]={{1,2,3},{4,5,6}};

void main(void) {
/* local array declaration */
int  local_array1[10];

/* local array declaration and initialization */
int  local_array2[3]={11,22,33};
char local_array3[7]="Hello";
}




Local variables that must conserve their values during different calls to a function must be declared as static.
Example:

int alfa(void) {
/* declare and initialize the static variable */
static int n=1;
return n++;
}

void main(void) {
int i;

/* the function will return the value 1 */
i=alfa();

/* the function will return the value 2 */
i=alfa();
}

If not specifically initialized, static variables are automatically set to 0 at program startup.


Variables that are declared in other files must be preceded by the extern keyword.
Example:

extern int xyz;

/* now include the file which contains
the variable xyz definition */
#include

To instruct the compiler to allocate a variable to registers, the register modifier must be used.
Example:        register int abc;

The compiler may automatically allocate a variable to registers, even if this modifier is not used.


The volatile modifier must be used in order to prevent a variable to be allocated to registers and to warn the compiler that it may be subject to outside change during evaluation.
Example:    volatile int abc;

All the global variables, not allocated to registers, are stored in the Global Variables area of SRAM.

All the local variables, not allocated to registers, are stored in dynamically allocated space in the Data Stack area of SRAM.

Specifying the SRAM Storage Address for Global Variables

Global variables can be stored at specific SRAM locations at design-time using the @ operator.
Example:

/* the integer variable "a" is stored
in SRAM at address 80h */
int a @0x80;

/* the structure "alfa" is stored
in SRAM at address 90h */
struct x {
int a;
char c;
} alfa @0x90;


Bit Variables

The bit variables are special global variables located in the register R2 to R14 memory space.
These variables are declared using the bit keyword.
The syntax is:

bit ;

Example:

/* declaration and initialization */
bit alfa=1; /* bit0 of R2 */
bit beta; /* bit1 of R2 */

void main(void)
{
if (alfa) beta=!beta;

/* ........ */
}

Memory allocation for the bit variables is done, in the order of declaration, starting with bit 0 of R2, then bit 1 of R2 and so on, in ascending order.

A number of maximum 104 bit variables can be declared.
The size of the bit variables allocated to the program can be specified in the Project|Configure|C Compiler|Code Generation|Bit Variables Size list box.
This size should be as low as possible, in order to free registers for allocation to other global variables.
If not specifically initialized, the bit global variables are automatically set to 0 at program startup.
In expression evaluation bit variables are automatically promoted to unsigned char.

Allocation of Variables to Registers

In order to fully take advantage of the AVR architecture and instruction set, the compiler allocates some of the program variables to chip registers.
The registers from R2 up to R14 can be allocated for bit variables.
You may specify how many registers in this range are allocated using the Project|Configure|C Compiler|Code Generation|Bit Variables Size list box. This value must be as low as required by the program.
If the Project|Configure|C Compiler|Code Generation|Automatic Register Allocation option is checked or the #pragma regalloc+ compiler directive is used, the rest of registers in the R2 to R14 range, that aren’t used for bit variables, are allocated to char and int global variables. The allocation is realized in order of variable declaration until the R14 register is allocated.

If the automatic register allocation is disabled, you can use the register keyword to specify which global variable to be allocated to registers.
Example:
/* disable automatic register allocation */
#pragma regalloc-
/* allocate the variable ‘alfa’ to a register */
register int alfa;
/* allocate the variable ‘beta’ to the register pair R10, R12 */
register int beta @10;

The char and int local variables are automatically allocated, in order of declaration, to registers R16 up to R21.


Structures

Structures are user-defined collections of named members.
The structure members can be any of the supported Data Types, arrays of these data types or pointers to them.
Structures are defined using the struct reserved keyword.
The syntax is:

[] struct [] {
[ [,, ...]];
[ []:[,[]:, ...]];
...
} [];


Example:

/* Global structure located in SRAM */
struct ram_structure {
char a,b;
int  c;
char d[30],e[10];
char *pp;
} sr;

/* Global constant structure located in FLASH */
flash struct flash_structure {
int  a;
char b[30], c[10];
} sf;

/* Global structure located in EEPROM */
eeprom struct eeprom_structure
{
char a;
int  b;

char c[15];
} se;

void main(void) {
/* Local structure */
struct local_structure {
char a;
int  b;
long c;
} sl;

/* ............. */

}

The space allocated to the structure in memory is equal to sum of the sizes of all the members.

There are some restrictions that apply to the structures stored in FLASH.
Because with the Atmel AVRASM32 Assembler single bytes defined with .DB in FLASH occupy in reality 2 bytes, the CodeVisionAVR C compiler will replace the char members of structures stored in FLASH with int.

Also it will extend the size of the char arrays, members of such structures, to an even value.

Structures can be grouped in unidimensional arrays.
Example how to initialize and access an global structure array stored in EEPROM:

/* Global structure array located in EEPROM */
eeprom struct eeprom_structure {
char a;
int  b;
char c[15];
} se[2]={{'a',25,"Hello"},
{'b',50,"world"}};

void main(void) {
char k1,k2,k3,k4;
int i1, i2;

/* declare a pointer to the structure */
struct eeprom_structure eeprom *ep;

/* direct access to structure members */
k1=se[0].a;
i1=se[0].b;
k2=se[0].c[2];
k3=se[1].a;
i2=se[1].b;
k4=se[1].c[2];

/* same access to structure members using a pointer */
ep=&se; /* initialize the pointer with the structure address */
k1=ep->a;
i1=ep->b;
k2=ep->c[2];
++ep;   /* increment the pointer */
k3=ep->a;
i2=ep->b;

k4=ep->c[2];

}
Because some AVR devices have a small amount of SRAM, in order to keep the size of the Data Stack small, it is recommended not to pass structures as function parameters and use pointers for this purpose.
Example:

struct alpha {
int a,b, c;
} s={2,3};

/* define the function */
struct alpha *sum_struct(struct alpha *sp) {
/* member c=member a + member b */
sp->c=sp->a + sp->b;
/* return a pointer to the structure */
return sp;
}

void main(void) {
int i;
/* s->c=s->a + s->b */
/* i=s->c */
i=sum_struct(&s)->c;

}

Structure elements can be also declared as bit fields, having a width from 1 to 32.
Bit fields are allocated in the order of declaration starting from the least significant bit.
Example:

/* this structure will occupy 1 byte in SRAM
as the bit field data type is unsigned char */
struct alpha1 {
unsigned char a:1; /* bit 0 */
unsigned char b:4; /* bits 1..4 */

unsigned char c:3; /* bits 5..7 */
};

/* this structure will occupy 2 bytes in SRAM
as the bit field data type is unsigned int */
struct alpha2 {
unsigned int a:2; /* bits 0..1 */
unsigned int b:8; /* bits 2..9 */
unsigned int c:4; /* bits 10..13 */
/* bits 14..15 are not used */
};

/* this structure will occupy 4 bytes in SRAM
as the bit field data type is unsigned long */

struct alpha3 {
unsigned long a:10; /* bits 0..9 */
unsigned long b:8;  /* bits 10..17 */
unsigned long c:6;  /* bits 18..23 */
/* bits 24..31 are not used */
};


Unions

Unions are user-defined collections of named members that share the same memory space.
The union members can be any of the supported Data Types, arrays of these data types or pointers to them.
Unions are defined using the union reserved keyword.
The syntax is:

[] union [] {
[ [,, ...]];
[ :[,:, ...]];
...
} [];

Unions are always stored in SRAM.
The space allocated to the union in memory is equal to the size of the largest member.
Union members can be accessed in the same way as structure members.
Example:
/* union declaration */
union alpha {
unsigned char lsb;
unsigned int  word;
} data;

void main(void) {
unsigned char k;

/* declare a pointer to the union */
union alpha *dp;

/* direct access to union members */

data.word=0x1234;
k=data.lsb; /* get the LSB of 0x1234 */

/* same access to union members using a pointer */
dp=&data;  /* initialize the pointer with the union address */
dp->word=0x1234;
k=dp->lsb; /* get the LSB of 0x1234 */

}
Because some AVR devices have a small amount of SRAM, in order to keep the size of the Data Stack small, it is recommended not to pass unions as function parameters and use pointers for this purpose.
Example:

#include /* printf */

union alpha {
unsigned char lsb;
unsigned int  word;
} data;

/* define the function */
unsigned char low(union alpha *up) {
/* return the LSB of word */
return up->lsb;
}

void main(void) {
data.word=0x1234;
printf("the LSB of %x is %2x",data.word,low(&data));

}

Union elements can be also declared as bit fields, having a width from 1 to 32.
Bit fields are allocated in the order of declaration starting from the least significant bit.

Example:

/* this union will occupy 1 byte in SRAM
as the bit field data type is unsigned char */
union alpha1 {
unsigned char a:1; /* bit 0 */
unsigned char b:4; /* bits 0..3 */
unsigned char c:3; /* bits 0..2 */
};

/* this union will occupy 2 bytes in SRAM
as the bit field data type is unsigned int */
union alpha2 {
unsigned int a:2; /* bits 0..1 */
unsigned int b:8; /* bits 0..7 */

unsigned int c:4; /* bits 0..3 */
/* bits 8..15 are not used */
};

/* this union will occupy 4 bytes in SRAM
as the bit field data type is unsigned long */
union alpha3 {
unsigned long a:10; /* bits 0..9 */
unsigned long b:8;  /* bits 0..7 */
unsigned long c:6;  /* bits 0..5 */
/* bits 10..31 are not used */
};

Enumerations

The enumeration data type can be used in order to provide mnemonic identifiers for a set of char or int values.
The enum keyword is used for this purpose.
The syntax is:

[] enum [] {
[[[=constant-initializer],, ...]]}
[];

Example:

/* The enumeration constants will be initialized as follows:
sunday=0 , monday=1 , tuesday=2 ,..., saturday=6 */

enum days {
sunday, monday, tuesday, wednesday,
thursday, friday, saturday} days_of_week;

/* The enumeration constants will be initialized as follows:
january=1 , february=2 , march=3 ,..., december=12 */
enum months {
january=1, february, march, april, may, june,
july, august, september, october, november, december}
months_of_year;



void main {
/* the variable days_of_week is initialized with

the integer value 6 */
days_of_week=saturday;
}

Enumerations can be stored in SRAM or EEPROM.
To specify the storage in EEPROM, the eeprom keyword must be used.
Example:

eeprom enum days {
sunday, monday, tuesday, wednesday,
thursday, friday, saturday} days_of_week;


It is recommended to treat enumerations as having 8 bit char data type, by checking the 8 bit enums check box in Project|Configure|Compiler|Code Generation. This will improve the size and execution speed of the compiled program.

Global Variables Memory Map File

During compilation the C compiler generates a Global Variables Memory Map File, in which are specified the SRAM address location, register allocation and size of the global variables used by the program.
This file has the .map extension and can be viewed using the menu File|Open command or by pressing the Open button on the toolbar.
Structure and union members are listed individually along with their corresponding address and size.

This file is useful during program debugging using the AVR Studio debugger.







Type Conversions

In an expression, if the two operands of a binary operator are of different types, then the compiler will convert one of the operands into the type of the other.

The compiler uses the following rules:

If either of the operands is of type float then the other operand is converted to the same type.

If either of the operands is of type long int or unsigned long int then the other operand is converted to the same type.

Otherwise, if either of the operands is of type int or unsigned int then the other operand is converted to the same type.

Thus char type or unsigned char type gets the lowest priority.

Using casting you can change these rules.
Example:

void main(void) {
int  a, c;
long b;
/* The long integer variable b will be treated here as an        
integer */
c=a+(int) b;
}

It is important to note that if the Project|Configure|C Compiler|Code Generation|Promote char to int option isn't checked or the #pragma promotechar+ isn't used, the char, respectively unsigned char, type operands are not automatically promoted to int , respectively unsigned int, as in compilers targeted for 16 or 32 bit CPUs.

This helps writing more size and speed efficient code for an 8 bit CPU like the AVR.

To prevent overflow on 8 bit addition or multiplication, casting may be required.

The compiler issues warnings in these situations.





Example:

void main(void) {
unsigned char a=30;
unsigned char b=128;
unsigned int c;

/* This will generate an incorrect result, because the multiplication
is done on 8 bits producing an 8 bit result, which overflows.
Only after the multiplication, the 8 bit result is promoted to
unsigned int */

c=a*b;

/* Here casting forces the multiplication to be done on 16 bits,
producing an 16 bit result, without overflow */

c=(unsigned int) a*b;
}
The compiler behaves differently for the following operators:
+=
-=
*=
/=
%=
&=
|=
^=
<<=
>>=
For these operators, the result is to be written back onto the left-hand side operand (which must be a variable). So the compiler will always convert the right hand side operand into the type of left-hand side operand.









Operators

The compiler supports the following operators:

+    -   /
%   ++  =
==          ~
!     !=
<    >
<=          >=
&    &&
|     ||
^    ?
<<          >>
-=           +=
/=          %=
&=          *=
^=          |=
>>=        <<=


Functions

You may use function prototypes to declare a function.
These declarations include information about the function parameters.
Example:    int alfa(char par1, int par2, long par3);

The actual function definition may be written somewhere else as:
int alfa(char par1, int par2, long par3)
{
/* Write some statements here */
}

The old Kernighan & Ritchie style of writing function definitions is not supported.
Function parameters are passed through the Data Stack
Function values are returned in registers R30, R31, R22 and R23 (from LSB to MSB).




Pointers

Due to the Harvard architecture of the AVR microcontroller, with separate address spaces for data (SRAM), program (FLASH) and EEPROM memory, the compiler implements three types of pointers.
The syntax for pointer declaration is:

[] type * [] pointer_name;

or

type [] * [] pointer_name;

where type can be any data type.

Variables placed in SRAM are accessed using normal pointers.
For accessing constants placed in FLASH memory, the flash type storage modifier is used.
For accessing variables placed in EEPROM, the eeprom type storage modifier is used.
Although the pointers may point to different memory areas, they are by default stored in SRAM.
Example:


/* Pointer to a char string placed in SRAM */
char *ptr_to_ram=”This string is placed in SRAM”;


/* Pointer to a char string placed in FLASH */
flash char *ptr_to_flash1=”This string is placed in FLASH”;
char flash *ptr_to_flash2=”This string is also placed in FLASH”;


/* Pointer to a char string placed in EEPROM */
eeprom char *ptr_to_eeprom1="This string is placed in EEPROM";
char eeprom *ptr_to_eeprom2="This string is also placed in EEPROM";

In order to store the pointer itself in other memory areas, like FLASH or EEPROM, the flash or eeprom pointer storage modifiers must be used as in the examples below:

/* Pointer stored in FLASH to a char string placed in SRAM */
char * flash flash_ptr_to_ram=”This string is placed in SRAM”;


/* Pointer stored in FLASH to a char string placed in FLASH */
flash char * flash flash_ptr_to_flash=”This string is placed in FLASH”;


/* Pointer stored in FLASH to a char string placed in EEPROM */
eeprom char * flash eeprom_ptr_to_eeprom="This string is placed in EEPROM";

/* Pointer stored in EEPROM to a char string placed in SRAM */
char * eeprom eeprom_ptr_to_ram=”This string is placed in SRAM”;


/* Pointer stored in EEPROM to a char string placed in FLASH */
flash char * eeprom eeprom_ptr_to_flash=”This string is placed in FLASH”;


/* Pointer stored in EEPROM to a char string placed in EEPROM */
eeprom char * eeprom eeprom_ptr_to_eeprom="This string is placed in EEPROM";

For improving the code efficiency two memory models are implemented.
The TINY memory model uses 8 bits for storing pointers to the variables placed in SRAM. In this memory model you can only have access to the first 256 bytes of SRAM.
The SMALL memory model uses 16 bits for storing pointers the variables placed in SRAM. In this memory model you can have access to 65536 bytes of SRAM.

For improving program speed and size, you must always try to use the TINY memory model.
Pointers to the FLASH and EEPROM memory areas always use 16 bits.

Because pointers to the FLASH memory are 16 bits wide, the total size of the constant arrays and char strings can't exceed 64K for the ATmega103 or ATmega128. However the total size of the program can be 128K for these chips.

Pointers can be grouped in arrays, which can have up to 8 dimensions.
Example:
/* Declare and initialize a global array of pointers to strings 
placed in SRAM */

char *strings[3]={"One","Two","Three"};



/* Declare and initialize a global array of pointers to strings 
placed in FLASH  The pointer array itself is also stored in FLASH */

flash char * flash messages[3]={"Message 1","Message 2","Message 3"};



/* Declare some strings in EEPROM */

eeprom char m1[]="aaaa";
eeprom char m2[]="bbbb";

void main(void) {

/* Declare a local array of pointers to the strings placed in EEPROM
You must note that although the strings are located in EEPROM,
the pointer array itself is located in SRAM */

char eeprom *pp[2];

/* and initialize the array */
pp[0]=m1;
pp[1]=m2;
}



Pointers to functions are always 16 bits wide because they are used to access the FLASH memory area. There is no need to use the flash keyword for these types of pointers.

Example:
/* Declare a function */

int sum(int a, int b) {

return a+b;

}

/* Declare and initialize a global pointer to the function sum */

int (*sum_ptr) (int a, int b)=sum;
void main(void) {
int i;

/* Call the function sum using the pointer */
i=(*sum_ptr) (1,2);
}


Accessing the I/O Registers

The compiler uses the sfrb and sfrw keywords to access the AVR microcontroller’s I/O Registers, using the IN and OUT assembly instructions.

Example:
/* Define the SFRs */
sfrb PINA=0x19;  /* 8 bit access to the SFR */
sfrw TCNT1=0x2c; /* 16 bit access to the SFR */


void main(void) {
unsigned char a;
a=PINA;       /* Read PORTA input pins */
TCNT1=0x1111; /* Write to TCNT1L & TCNT1H registers */
}


The addresses of I/O registers are predefined in the following header files, located in the ..\INC subdirectory:


tiny13.h
tiny22.h
tiny26.h
90s2313.h
90s2323.h
90s2333.h
90s2343.h
90s4414.h
90s4433.h
90s4434.h
90s8515.h
90s8534.h
90s8535.h
mega103.h
mega128.h
mega16.h
mega161.h
mega162.h
mega163.h
mega169.h
mega32.h
mega323.h
mega603.h
mega64.h
mega8.h
mega8515.h
mega8535.h
43usb355.h
76c711.h
86rf401.h
94k.h

You may #include the corresponding file, for the processor that you use, at the beginning of your program.


Bit level access to the I/O Registers

The bit level access to the I/O registers is accomplished using bit selectors appended after the name of the I/O register.
Because bit level access to I/O registers is done using the CBI, SBI, SBIC and SBIS instructions, the register address must be in the 0 to 1Fh range for sfrb and in the 0 to 1Eh range for sfrw.


Example:

sfrb PORTA=0x1b;
sfrb DDRA=0x18;
sfrb PINA=0x19;

void main(void) {
/* set bit 0 of Port A as output */
DDRA.0=1;

/* set bit 1 of Port A as input */

DDRA.1=0;

/* set bit 0 of Port A output */
PORTA.0=1;

/* test bit 1 input of Port A */
if (PINA.1) { /* place some code here */ };

/* ....... */

}

To improve the readability of the program you may wish to #define symbolic names to the bits in I/O registers:

sfrb PINA=0x19;
#define alarm_input PINA.2

void main(void)
{
/* test bit 2 input of Port A */
if (alarm_input) { /* place some code here */ };

/* ....... */
}

It is important to note that bit selector access to I/O registers located in internal SRAM above address 5Fh (like PORTF for the ATmega128 for example) will not work, because the CBI, SBI, SBIC and SBIS instructions can’t be used for SRAM access.


Accessing the EEPROM

Accessing the AVR internal EEPROM is accomplished using global variables, preceded by the keyword eeprom.

Example:
/* The value 1 is stored in the EEPROM during chip programming */

eeprom int alfa=1;
eeprom char beta;
eeprom long array1[5];

/* The string is stored in the EEPROM during chip programming */
eeprom char string[]=”Hello”;

void main(void) {
int i;

/* Pointer to EEPROM */
int eeprom *ptr_to_eeprom;

/* Write directly the value 0x55 to the EEPROM */
alfa=0x55;

/* or indirectly by using a pointer */

ptr_to_eeprom=&alfa;

*ptr_to_eeprom=0x55;

/* Read directly the value from the EEPROM */
i=alfa;
/* or indirectly by using a pointer */
i=*ptr_to_eeprom;
}

Pointers to the EEPROM always use 16 bits.



Using Interrupts

The access to the AVR interrupt system is implemented with the interrupt keyword.
Example:

/* Vector numbers are for the AT90S8515 */
/* Called automatically on external interrupt */
interrupt [2] void external_int0(void) {
/* Place your code here */
}


/* Called automatically on TIMER0 overflow */
interrupt [8] void timer0_overflow(void) {
/* Place your code here */


}

Interrupt vector numbers start with 1.
The compiler will automatically save all the used registers when calling the interrupt functions and restore them back on exit.
A RETI assembly instruction is placed at the end of the interrupt function.
Interrupt functions can’t return a value nor have parameters.
You must also set the corresponding bits in the peripheral control registers to configure the interrupt system and enable the interrupts.

The automatic saving and restoring of registers R0, R1, R15, R22, R23, R24, R25, R26, R27, R30, R31 and SREG, during interrupts can be turned on or off using the #pragma savereg directive.

Example:


/* Turn registers saving off */
#pragma savereg-

/* interrupt handler */
interrupt [1] void my_irq(void) {
/* now save only the registers that are
affected by the routines in the handler,
for example R30, R31 and SREG */
#asm
push r30
push r31
in   r30,SREG
push r30
#endasm

/* place the C code here */
/* .... */

/* now restore SREG, R31 and R30 */
#asm
pop r30
out SREG,r30
pop r31
pop r30
#endasm
}
/* re-enable register saving for the other interrupts */

#pragma savereg+

The default state is automatic saving of registers during interrupts.


The Preprocessor

The Preprocessor directives allows you to:

·   include text from other files, such as header files containing library and user function prototypes
·   define macros that reduce programming effort and improve the legibility of the source code
·   set up conditional compilation for debugging purposes and to improve program portability
·   issue compiler specific directives


The #include directive may be used to include another file in your source.
You may nest as many as 16 #include files.
Example:


/* File will be looked for in the /inc directory of the compiler. */
#include
                                   or
/* File will be looked for in the current project directory.
If it's not located there, then it will be included from
the /inc directory of the compiler. */
#include "file_name"

The #define directive may be used to define a macro.
Example:
#define ALFA 0xff

This statement defines the symbol  ‘ALFA’ to the value 0xff.
The C preprocessor will replace 'ALFA' with 0xff in the source text before compiling.

Macros can also have parameters. The preprocessor will replace the macro with it's expansion and the formal parameters with the real ones.
Example:

#define SUM(a,b) a+b
/* the following code sequence will
be replaced with int i=2+3; */
int i=SUM(2,3);

When defining macros you can use the # operator to convert the macro parameter to a character string.

Example:

#define PRINT_MESSAGE(t)  printf(#t)

/* ...... */
/* the following code sequence will
be replaced with printf("Hello"); */
PRINT_MESSAGE(Hello);

Two parameters can be concatenated using the ## operator.
Example:
#define ALFA(a,b) a ## b


/* the following code sequence will
be replaced with char xy=1; */
char ALFA(x,y)=1;

A macro definition can be extended to a new line by using \ .

Example:
#define MESSAGE "This is a very \
long text..."

A macro can be undefined using the #undef directive.

Example:
#undef ALFA

The #ifdef, #ifndef, #else and  #endif directives may be used for conditional compilation.
The syntax is:

#ifdef macro_name
[set of statements 1]
#else
[set of statements 2]
#endif

If  'alfa' is a defined macro name, then the  #ifdef expression evaluates to true and the set of statements 1 will be compiled.
Otherwise the set of statements 2 will be compiled.
The #else and set of statements 2 are optional.
If 'alfa' is not defined, the #ifndef expression evaluates to true.
The rest of the syntax is the same as that for #ifdef.

The #if, #else and  #endif directives may be also used for conditional compilation.

The syntax is:

#if expression1
[set of statements 1]
#else
[set of statements 2]
#endif


If  expression1 evaluates to true, the set of statements 1 will be compiled.
Otherwise the set of statements 2 will be compiled.
The #else and set of statements 2 are optional.

The #elif directive is also useful in conditional compilation:

#if expression1
[set of statements 1]
#elif expression1
[set of statements 2]
#else
[set of statements 3]
#endif

If  expression1 evaluates to true, the set of statements 1 will be compiled.

If  expression2 evaluates to true, the set of statements 2 will be compiled.
Otherwise the set of statements 3 will be compiled.
The #else and set of statements 3 are optional.

There are the following predefined macros:

__CODEVISIONAVR__ the version and revision of the compiler represented as an integer, example for V1.23.8 this will be 1238
__LINE__ the current line number of the compiled file
__FILE__ the current compiled file

__TIME__ the current time in hh:mm:ss  format
__DATE__ the current date in mmm dd yyyy  format
_CHIP_ATXXXXX_ where ATXXXXX is the chip type, in uppercase letters, specified in the Project|Configure|C Compiler|Code Generation|Chip option
_MCU_CLOCK_FREQUENCY_ the AVR clock frequency specified in the Project|Configure|C Compiler|Code Generation|Clock option, expressed as an integer in Hz
_MODEL_TINY_ if the program is compiled using the TINY memory model

_MODEL_SMALL_ if the program is compiled using the SMALL memory model
_OPTIMIZE_SIZE_ if the program is compiled with optimization for size
_OPTIMIZE_SPEED_ if the program is compiled with optimization for speed
_UNSIGNED_CHAR_ if the char is unsigned compiler option is enabled or #pragma uchar+ is used
_8BIT_ENUMS_ if the 8 bit enums compiler option is enabled or #pragma 8bit_enums+ is used.

The #line directive can be used to modify the predefined __LINE__ and __FILE__ macros.
The syntax is:

#line integer_constant ["file_name"]

Example:

/* This will set __LINE__ to 50 and
__FILE__ to "file2.c" */
#line 50 "file2.c"

/* This will set __LINE__ to 100 */
#line 100

There #error directive can be used to stop compilation and display an error message.
The syntax is:

#error error_message

Example:

#error This is an error!

The #pragma directive allows compiler specific directives.
You can use the #pragma warn directive to enable or disable compiler warnings.
Example:


/* Warnings are disabled */
#pragma warn-

/* Write some code here */


/* Warnings are enabled */
#pragma warn+


The compiler’s code optimizer can be turned on or off using the #pragma opt directive. This directive must be placed at the start of the source file.

The default is optimization turned on.
Example:

/* Turn optimization off, for testing purposes */

#pragma opt-
                                or
/* Turn optimization on */
#pragma opt+

If the code optimization is enabled, you can optimize some portions or all the program for size or speed using the #pragma optsize directive.

The default state is determined by the Project|Configure|C Compiler|Code Generation|Optimization setting.
Example:

/* The program will be optimized for minimum size */
#pragma optsize+

/* Place your program functions here */

/* Now the program will be optimized for maximum execution speed */
#pragma optsize-

/* Place your program functions here */

The automatic saving and restoring of registers R0, R1, R15, R22, R23, R24, R25, R26, R27, R30, R31 and SREG, during interrupts can be turned on or off using the #pragma savereg directive.


Example:
/* Turn registers saving off */
#pragma savereg-

/* interrupt handler */
interrupt [1] void my_irq(void) {
/* now save only the registers that are
affected by the routines in the handler,
for example R30, R31 and SREG */
#asm
push r30
push r31
in   r30,SREG
push r30
#endasm

/* place the C code here */

/* now restore SREG, R31 and R30 */
#asm
pop r30
out SREG,r30
pop r31
pop r30
#endasm
}
/* re-enable register saving for the other interrupts */

#pragma savereg+

The default state is automatic saving of registers during interrupts.

The automatic allocation of global variables to registers can be turned on or off using the #pragma regalloc directive.
The default state is determined by the Project|Configure|C Compiler|Code Generation|Automatic Register Allocation check box.
Example:

/* the following global variable will be automatically
allocated to a register */
#pragma regalloc+

unsigned char alfa;

/* the following global variable will not be automatically
allocated to a register and will be placed in normal SRAM */
#pragma regalloc-
unsigned char beta;

The ANSI char to int operands promotion can be turned on or off using the #pragma promotechar directive.
Example:
/* turn on the ANSI char to int promotion */
#pragma promotechar+

/* turn off the ANSI char to int promotion */
#pragma promotechar-

This option can also be specified in the Project|Configure|C Compiler|Code Generation|Promote char to int menu.

Treating char by default as an unsigned 8 bit can be turned on or off using the #pragma uchar directive.
Example:

/* char will be unsigned by default */
#pragma uchar+

/* char will be signed by default */
#pragma uchar-

This option can also be specified in the Project|Configure|C Compiler|Code Generation|char is unsigned menu.

Treating enumerations as an 8 bit char data type can be turned on or off using the #pragma 8bit_enums directive.
Example:

/* enumerations will be 8 bit char */
#pragma 8bit_enums+

/* enumerations will be 16 bit int */
#pragma 8bit_enums-

This option can also be specified in the Project|Configure|C Compiler|Code Generation|char is unsigned menu.
It is recommended to treat enumerations as an 8 bit char, in order to improved the size and execution speed of the compiled program.


The #pragma library directive is used for specifying the necessity to compile/link a specific library file.
Example:

#pragma library mylib.lib

The #pragma glbdef+ directive is used for compatibility with projects, created with versions of CodeVisionAVR prior to V1.0.2.2, where the Project|Configure|C Compiler|Global #define option was enabled.
It signals the compiler that macros are globally visible in all the program modules of a project.

This directive must be placed in beginning of the first source file of the project.
By default this directive is not active, so macros are visible only in the program module where they are defined.

SRAM Memory Organization

A compiled program has the following memory map:

The Working Registers area contains 32x8 bit general purpose working registers.
The compiler uses the following registers: R0, R1, R15, R22, R23, R24, R25, R26, R27, R28, R29, R30 and R31.
Also some of the registers from R2 to R14 may be allocated by the compiler for global bit variables. The rest of unused registers, in this range, are allocated for global char and int variables.
Registers R16 to R21 are allocated for local char and int variables.

The I/O Registers area contains 64 addresses for the CPU peripheral functions as Port Control Registers, Timer/Counters and other I/O functions. You may freely use these registers in your assembly programs.


The Data Stack area is used to dynamically store local variables, passing function parameters and saving registers R0, R1, R15, R22, R23, R24, R25, R26, R27, R30, R31 and SREG during interrupt routine servicing.
The Data Stack Pointer is implemented using the Y register.
At start-up the Data Stack Pointer is initialized with the value 5Fh+Data Stack Size.
When saving a value in the Data Stack, the Data Stack Pointer decrements.

When the value is retrieved, the Data Stack Pointer in incremented back.
When configuring the compiler, in the Project|Configure|C Compiler|Code Generation menu, you must specify a sufficient Data Stack Size, so it will not overlap the I/O Register area during program execution.

The Global Variables area is used to statically store the global variables during program execution. The size of this area can be computed by summing the size of all the declared global variables.

The Hardware Stack area is used for storing the functions return addresses.
The SP register is used as a stack pointer and is initialized at start-up with value of last SRAM address.
During the program execution the Hardware Stack grows downwards to the Global Variables area.

When configuring the compiler you have the option to place the strings DSTACKEND, respectively HSTACKEND, at the end of the Data Stack, respectively Hardware Stack areas.

When you debug the program with AVR Studio you may see if these strings are overwritten, and consequently modify the Data Stack Size using the Project|Configure|C Compiler|Code Generation menu command.

When your program runs OK you may disable the placement of the strings in order to reduce code size.









Including Assembly Language in Your Program

You can include assembly language anywhere in your program using the #asm and #endasm directives.
Example:

void delay(unsigned char i) {
while (i--) {
/* Assembly language code sequence */
#asm
nop
nop
#endasm
};
}

Inline assembly may also be used.
Example:

#asm("sei") /* enable interrupts */

In order to use multiple instructions in inline assembly, the \ separator is required.

Example:

#asm("nop\nop\nop")

The registers R0, R1, R22, R23, R24, R25, R26, R27, R30 and R31 can be freely used in assembly routines.
However when using them in an interrupt service routine the programmer must save, respectively restore, them on entry, respectively on exit, of this routine.





Hints

In order to decrease code size and improve the execution speed, you must apply the following rules:

·   If possible use unsigned variables;
·   Use the smallest data type possible, i.e. bit and unsigned char;

·   The size of the bit variables, allocated to the program in the Project|Configure|C Compiler|Code Generation|Bit Variables Size list box, should be as low as possible, in order to free registers for allocation to other global variables;

·   If possible use the TINY memory model;
·   Treat enumerations as having 8 bit char data type, by checking the 8 bit enums check box in Project|Configure|Compiler;
·   Always store constant strings in FLASH by using the flash keyword;
·   After finishing debugging your program, compile it again with the Stack End Markers option disabled;
·   Write time critical portions of code using assembly language.


Character Type Functions

The prototypes for these functions are placed in the file ctype.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

unsigned char isalnum(char c)
returns 1 if c is alphanumeric.

unsigned char isalpha(char c)
returns 1 if c is alphabetic.

unsigned char isascii(char c)
returns 1 if c is an ASCII character (0..127).

unsigned char iscntrl(char c)
returns 1 if c is a control character (0..31 or 127).

unsigned char isdigit(char c)
returns 1 if c is a decimal digit.

unsigned char islower(char c)
returns 1 if c is a lower case alphabetic character.

unsigned char isprint(char c)
returns 1 if c is a printable character (32..127).



unsigned char ispunct(char c)
returns 1 if c is a punctuation character (all but control and alphanumeric).

unsigned char isspace(char c)
returns 1 c is a white-space character (space, CR, HT).

unsigned char isupper(char c)
returns 1 if c is an upper-case alphabetic character.

unsigned char isxdigit(char c)
returns 1 if c is a hexadecimal digit.

char toascii(char c)
returns the ASCII equivalent of character c.

unsigned char toint(char c)
interprets c as a hexadecimal digit and returns an usigned char from 0 to 15.

char tolower(char c)
returns the lower case of c if c is an upper case character, else c.

char toupper(char c)
returns the upper case of c if c is a lower case character, else c.



Standard C Input/Output Functions

The prototypes for these functions are placed in the file stdio.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

The standard C language I/O functions were adapted to work on embedded microcontrollers with limited resources.

The lowest level Input/Output functions are:

char getchar(void)
returns a character received by the UART, using polling.

void putchar(char c)
transmits the character c using the UART, using polling.

Prior to using these functions you must:
·   initialize the UART's Baud rate
·   enable the UART transmitter
·   enable the UART receiver.
Example:

#include <90s8515 .h=".h">
#include
/* quartz crystal frequency [Hz] */
#define xtal 4000000L

/* Baud rate */
#define baud 9600

void main(void) {
char k;

/* initialize the UART's baud rate */
UBRR=xtal/16/baud-1;

/* initialize the UART control register
RX & TX enabled, no interrupts, 8 data bits */
UCR=0x18;

while (1) {
/* receive the character */
k=getchar();
/* and echo it back */
putchar(k);
};
}

You can alternatively initialize the UART's Baud rate using the Project|Configure|C Compiler menu.
If you intend to use other peripherals for Input/Output, you must modify accordingly the getchar and putchar functions. The source code for these functions is available in the
file stdio.h .
All the high level Input/Output functions use getchar and putchar.
void puts(char *str)
outputs, using putchar, the null terminated character string str, located in SRAM, followed by a new line character.

void putsf(char flash *str)
outputs, using putchar, the null terminated character string str, located in FLASH, followed by a new line character.

void printf(char flash *fmtstr [ , arg1, arg2, ...])
outputs formatted text, using putchar, according to the format specifiers in the fmtstr string.
The format specifier string fmtstr is constant and must be located in FLASH memory.

The implementation of printf is a reduced version of the standard C function.
This was necessary due to the specific needs of an embedded system and because the full implementation would require a large amount of FLASH memory space.
The format specifier string has the following structure:


%[flags][width][.precision][l]type_char

The optional flags characters are:
'-' left-justifies the result, padding on the right with spaces. If it's not present, the result will be right-justified, padded on the left with zeros or spaces;
'+' signed conversion results will always begin with a '+' or '-' sign;
' ' if the value isn't negative, the conversion result will begin with a space. If the value is negative then it will begin with a '-' sign.

The optional width specifier sets the minimal width of an output value. If the result of the conversion is wider than the field width, the field will be expanded to accommodate the result, so not to cause field truncation.
The following width specifiers are supported:
n - at least n characters are outputted. If the result has less than n characters, then it's field will be padded with spaces. If the '-' flag is used, the result field will be padded on the right, otherwise it will be padded on the left;

0n - at least n characters are outputted. If the result has less than n characters, it is padded on the left with zeros.

The optional precision specifier sets the maximal number of characters or minimal number of integer digits that may be outputted.
For the 'e', 'E' and 'f' conversion type characters the precision specifier sets the number of digits that will be outputted to the right of the decimal point.
The precision specifier always begins with a '.' character in order to separate it from the width specifier.

The following precision specifiers are supported:
none - the precision is set to 1 for the 'i', 'd', 'u', 'x', 'X' conversion type characters. For the 's' and 'p' conversion type characters, the char string will be outputted up to the first null character;
.0 - the precision is set to 1 for the 'i', 'd', 'u', 'x', 'X' type characters;
.n - n characters or n decimal places are outputted.
For the 'i', 'd', 'u', 'x', 'X' conversion type characters, if the value has less than n digits, then it will be padded on the left with zeros. If it has more than n digits then it will not be truncated.

For the 's' and 'p' conversion type characters, no more than n characters from the char string will be outputted.
For the 'e', 'E' and 'f' conversion type characters, n digits will be outputted to the right of the decimal point.
The precision specifier has no effect on the 'c' conversion type character.

The optional 'l' input size modifier specifies that the function argument must be treated as a long int for the 'i', 'd', 'u', 'x', 'X' conversion type characters.


The type_char conversion type character is used to specify the way the function argument will be treated.
The following conversion type characters are supported:
'i' - the function argument is a signed decimal integer;
'd' - the function argument is a signed decimal integer;
'u' - the function argument is an unsigned decimal integer;
'e' - the function argument is a float, that will be outputted using the [-]d.ddddd e[-]dd  format
'E' - the function argument is a float, that will be outputted using the [-]d.ddddd E[-]dd  format

'f' - the function argument is a float, that will be outputted using the [-]ddd.ddddd  format
'x' - the function argument is an unsigned hexadecimal integer, that will be outputted with lowercase characters;
'X' - the function argument is an unsigned hexadecimal integer, that will be outputted with with uppercase characters;
'c' - the function argument is a single character;
's' - the function argument is a pointer to a null terminated char string located in SRAM;

'p' - the function argument is a pointer to a null terminated char string located in FLASH;
'%' - the '%' character will be outputted.

void sprintf(char *str, char flash *fmtstr [ , arg1, arg2, ...])

this function is identical to printf except that the formatted text is placed in the null terminated character string str.

In order to reduce program code size, there is the Project|Configure|C Compiler|Code Generation|(s)printf features option.

It allows linking different versions of the printf and sprintf functions, with only the features that are really required  by the program.

The following (s)printf features are available:

·   int - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', no width or precision specifiers are supported, only the '+' and ' ' flags are supported, no input size modifiers are supported

·   int, width - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', the width specifier is supported, the precision specifier is not supported, only the '+', '-', '0' and ' ' flags are supported,  no input size modifiers are supported
·   long, width - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%' the width specifier is supported, the precision specifier is not supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported

·   long, width, precision - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'x', 'X', '%', the width and precision specifiers are supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported
·   float, width, precision - the following conversion type characters are supported: 'c', 's', 'p', 'i', 'd', 'u', 'e', 'E', 'f', 'x', 'X', '%', the width and precision specifiers are supported, only the '+', '-', '0' and ' ' flags are supported,  only the 'l' input size modifier is supported.

The more features are selected, the larger is the code size generated for the printf and sprintf functions.

char *gets(char *str, unsigned char len)

inputs, using getchar, the character string str terminated by the new line character.
The new line character will be replaced with 0.
The maximum length of the string is len. If len characters were read without encountering the new line character, then the string is terminated with 0 and the function ends.
The function returns a pointer to str.

signed char scanf(char flash *fmtstr [ , arg1 address, arg2 address, ...])

formatted text input by scanning, using getchar, a series of input fields according to the format specifiers in the fmtstr string.
The format specifier string fmtstr is constant and must be located in FLASH memory.
The implementation of scanf is a reduced version of the standard C function.
This was necessary due to the specific needs of an embedded system and because the full implementation would require a large amount of FLASH memory space.

The format specifier string has the following structure:

%[width][l]type_char

The optional width specifier sets the maximal number of characters to read. If the function encounters a whitespace character or one that cannot be converted, then it will continue with the next input field, if present.

The optional 'l' input size modifier specifies that the function argument must be treated as a long int for the 'i', 'd', 'u', 'x' conversion type characters.

The type_char conversion type character is used to specify the way the input field will be processed.
The following conversion type characters are supported:

'd' - inputs a signed decimal integer in a pointer to int argument;
'i' - inputs a signed decimal integer in a pointer to int argument;
'u' - inputs an unsigned decimal integer in a pointer to unsigned int argument;
'x' - inputs an unsigned hexadecimal integer in a pointer to unsigned int argument;
'c' - inputs an ASCII character in a pointer to char argument;
's' - inputs an ASCII character string in a pointer to char argument;
'%' - no input is done, a '%' is stored.

The function returns the number of successful entries, or -1 on error.

signed char sscanf(char *str, char flash *fmtstr [ , arg1 address, arg2 address, ...])

this function is identical to scanf except that the formatted text is inputted from the null terminated character string str, located in SRAM.

In order to reduce program code size, there is the Project|Configure|C Compiler|Code Generation|(s)scanf features option.

It allows linking different versions of the scanf and sscanf functions, with only the features that are really required  by the program.

The following (s)scanf features are available:
·   int, width - the following conversion type characters are supported: 'c', 's', 'i', 'd', 'u', 'x', '%', the width specifier is supported, no input size modifiers are supported
·   long, width - the following conversion type characters are supported: 'c', 's', 'i', 'd', 'u', 'x',  '%' the width specifier is supported, only the 'l' input size modifier is supported.


The more features are selected, the larger is the code size generated for the scanf and sscanf functions.



Standard Library Functions

The prototypes for these functions are placed in the file stdlib.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

int atoi(char *str)
converts the string str to integer.     

long int atol(char *str)
converts the string str to long integer.

void itoa(int n, char *str)
converts the integer n to characters in string str.

void ltoa(long int n, char *str)
converts the long integer n to characters in string str.

void ftoa(float n, unsigned char decimals, char *str)
converts the floating point number n to characters in string str.
The number is represented with a specified number of decimals.


void ftoe(float n, unsigned char decimals, char *str)
converts the floating point number n to characters in string str.
The number is represented as a mantissa with a specified number of decimals and an integer power of 10 exponent (e.g. 12.35e-5).

float atof(char *str)
converts the characters from string str to floating point.

int rand (void)
generates a pseudo-random number between 0 and 32767.

void srand(int seed)
sets the starting value seed used by the pseudo-random number generator in the rand function.


Mathematical Functions

The prototypes for these functions are placed in the file math.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

unsigned char cabs(signed char x)
returns the absolute value of the byte x.

unsigned int abs(int x)
returns the absolute value of the integer x.

unsigned long labs(long int x)
returns the absolute value of the long integer x.

float fabs(float x)
returns the absolute value of the floating point number x.

signed char cmax(signed char a, signed char b)
returns the maximum value of bytes a and b.

int max(int a, int b)
returns the maximum value of integers a and b.

long int lmax(long int a, long int b)
returns the maximum value of long integers a and b.

float fmax(float a,float b)
returns the maximum value of floating point numbers a and b.

signed char cmin(signed char a, signed char b)
returns the minimum value of bytes a and b.

int min(int a, int b)
returns the minimum value of integers a and b.

long int lmin(long int a, long int b)
returns the minimum value of long integers a and b.


float fmin(float a, float b)
returns the minimum value of floating point numbers a and b.

signed char csign(signed char x)
returns -1, 0 or 1 if the byte x is negative, zero or positive.

signed char sign(int x)
returns -1, 0 or 1 if the integer x is negative, zero or positive

signed char lsign(long int x)
returns -1, 0 or 1 if the long integer x is negative, zero or positive.

signed char fsign(float x)
returns -1, 0 or 1 if the floating point number x is negative, zero or positive.

unsigned char isqrt(unsigned int x)
returns the square root of the unsigned integer x.

unsigned int lsqrt(unsigned long x)
returns the square root of the unsigned long integer x.

float sqrt(float x)
returns the square root of the positive floating point number x.

float floor(float x)
returns the smallest integer value of the floating point number x.

float ceil(float x)
returns the largest integer value of the floating point number x.

float fmod(float x, float y)
returns the remainder of x divided by y.

float modf(float x, float *ipart)
splits the floating point number x into integer and fractional components.
The fractional part of x is returned as a signed floating point number.
The integer part is stored as floating point number at ipart.

float ldexp(float x, int expn)
returns x * 2**expn.

float frexp(float x, int *expn)
returns the mantisa and exponent of the floating point number x.

float exp(float x)
returns e**x .

float log(float x)
returns the natural logarithm of the floating point number x.

float log10(float x)
returns the base 10 logarithm of the floating point number x.

float pow(float x, float y)
returns x**y .

float sin(float x)
returns the sine of the floating point number x, where the angle is expressed in radians.

float cos(float x)
returns the cosine of the floating point number x, where the angle is expressed in radians.

float tan(float x)
returns the tangent of the floating point number x, where the angle is expressed in radians.

float sinh(float x)
returns the hyperbolic sine of the floating point number x, where the angle is expressed in radians.

float cosh(float x)
returns the hyperbolic cosine of the floating point number x, where the angle is expressed in radians.

float tanh(float x)
returns the hyperbolic tangent of the floating point number x, where the angle is expressed in radians.

float asin(float x)
returns the arc sine of the floating point number x (in the range -PI/2 to PI/2).
x must be in the range -1 to 1.

float acos(float x)
returns the arc cosine of the floating point number x (in the range 0 to PI).  x must be in the range -1 to 1.

float atan(float x)
returns the arc tangent of the floating point number x (in the range -PI/2 to PI/2).

float atan2(float y, float x)
returns the arc tangent of the floating point numbers y/x (in the range -PI to PI).



String Functions

The prototypes for these functions are placed in the file string.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

The string manipulation functions were extended to handle strings located both in SRAM and FLASH memories.


char *strcat(char *str1, char *str2)
concatenate the string str2 to the end of the string str1.

char *strcatf(char *str1, char flash *str2)
concatenate the string str2, located in FLASH, to the end of the string str1.

char *strncat(char *str1, char *str2, unsigned char n)
concatenate maximum n characters of the string str2 to the end of the string str1.
Returns a pointer to the string str1.

char *strncatf(char *str1, char flash *str2, unsigned char n)
concatenate maximum n characters of the string str2, located in FLASH, to the end of the string str1.
Returns a pointer to the string str1.

char *strchr(char *str, char c)
returns a pointer to the first occurrence of the character c in the string str, else a NULL pointer.



char *strrchr(char *str, char c)
returns a pointer to the last occurrence of the character c in the string str, else a NULL pointer.

signed char strpos(char *str, char c)
returns the index to first occurrence of the character c in the string str, else -1.

signed char strrpos(char *str, char c)
returns the index to the last occurrence of the character c in the string str, else -1.

signed char strcmp(char *str1, char *str2)
compares the string str1 with the string str2.
Returns <0 0="0">0 according to str1str2.

signed char strcmpf(char *str1, char flash *str2)
compares the string str1, located in SRAM, with the string str2, located in FLASH.
Returns <0 0="0">0 according to str1str2.

signed char strncmp(char *str1, char *str2, unsigned char n)
compares at most n characters of the string str1 with the string str2.  Returns <0 0="0">0 according to str1str2.

signed char strncmpf(char *str1, char flash *str2, unsigned char n)
compares at most n characters of the string str1, located in SRAM, with the string str2, located in FLASH.
Returns <0 0="0">0 according to str1str2.

char *strcpy(char *dest, char *src)
copies the string src to the string dest.

char *strcpyf(char *dest, char flash *src)
copies the string src, located in FLASH, to the string dest, located in SRAM.
Returns a pointer to the string dest.

char *strncpy(char *dest, char *src, unsigned char n)
copies at most n characters from the string src to the string dest (null padding).
Returns a pointer to the string dest.

char *strncpyf(char *dest, char flash *src, unsigned char n)
copies at most n characters from the string src, located in FLASH, to the string dest, located in SRAM (null padding).
Returns a pointer to the string dest.

unsigned char strspn(char *str, char *set)
returns the index of the first character, from the string str, that doesn't match a character from the string set.
If all characters from set are in str returns the length of str.

unsigned char strspnf(char *str, char flash *set)
returns the index of the first character, from the string str, located in SRAM, that doesn't match a character from the string set, located in FLASH.
If all characters from set are in str returns the length of str.

unsigned char strcspn(char *str, char *set)
searches the string str for the first occurrence of a character from the string set.

If there is a match returns, the index of the character in str.
If there are no matching characters, returns the length of str.

unsigned char strcspnf(char *str, char flash *set)
searches the string str for the first occurrence of a character from the string set, located in FLASH.

If there is a match, returns the index of the character in str.
If there are no matching characters, returns the length of str.

char *strpbrk(char *str, char *set)
searches the string str for the first occurrence of a char from the string set.

If there is a match, returns a pointer to the character in str.
If there are no matching characters, returns a NULL pointer.

char *strpbrkf(char *str, char flash *set)
searches the string str, located in SRAM, for the first occurrence of a char from the string set, located in FLASH.

If there is a match, returns a pointer to the character in str.
If there are no matching characters, returns a NULL pointer.



char *strrpbrk(char *str, char *set)
searches the string str for the last occurrence of a character from the string set.

If there is a match, returns a pointer to the character in str.
If there are no matching characters, returns a NULL pointer.

char *strrpbrkf(char *str, char flash *set)
searches the string str, located in SRAM, for the last occurrence of a character from the string set, located in FLASH.

If there is a match, returns a pointer to the character in str.
If there are no matching characters, returns a NULL pointer.

char *strstr(char *str1, char *str2)
searches the string str1 for the first occurrence of the string str2.
If there is a match, returns a pointer to the character in str1 where str2 begins.
If there is no match, returns a NULL pointer.

char *strstrf(char *str1, char flash *str2)
searches the string str1, located in SRAM, for the first occurrence of the string str2, located in FLASH.

If there is a match, returns a pointer to the character in str1 where str2 begins.  If there is no match, returns a NULL pointer.

char *strtok(char *str1, char flash *str2)
scans the string str1, located in SRAM, for the first token not contained in the string str2, located in FLASH.
The function considers the string str1 as consisting of a sequence of text tokens, separated by spans of one or more characters from the string str2.
The first call to strtok, with the pointer to str1 being different from NULL, returns a pointer to the first character of the first token in str1. Also a NULL character will be written in str1, immediately after the returned token.

Subsequent calls to strtok, with NULL as the first parameter, will work through the string str1 until no more tokens remain. When there are no more tokens, strtok will return a NULL pointer.

unsigned char strlen(char *str)
for the TINY memory model.
returns the length of the string str (in the range 0..255).

unsigned int strlen(char *str)
for the SMALL memory model.
returns the length of the string str (in the range 0..65535).

unsigned int strlenf(char flash *str)
returns the length of the string str located in FLASH.

void *memcpy(void *dest,void *src, unsigned char n)
for the TINY memory model.

void *memcpy(void *dest,void *src, unsigned int n)
for the SMALL memory model.

Copies n bytes from src to dest. dest must not overlap src, else use memmove.
Returns a pointer to dest.

void *memcpyf(void *dest,void flash *src, unsigned char n)
for the TINY memory model.

void *memcpyf(void *dest,void flash *src, unsigned int n)
for the SMALL memory model.

Copies n bytes from src, located in FLASH, to dest. Returns a pointer to dest.

void *memccpy(void *dest,void *src, char c, unsigned char n)
for the TINY memory model.

void *memccpy(void *dest,void *src, char c, unsigned int n)
for the SMALL memory model.

Copies at most n bytes from src to dest, until the character c is copied.  dest must not overlap src.

Returns a NULL pointer if the last copied character was c or a pointer to dest+n+1.



void *memmove(void *dest,void *src, unsigned char n)
for the TINY memory model.

void *memmove(void *dest,void *src, unsigned int n)
for the SMALL memory model.

Copies n bytes from src to dest. dest may overlap src.
Returns a pointer to dest.

void *memchr(void *buf, unsigned char c, unsigned char n)
for the TINY memory model.

void *memchr(void *buf, unsigned char c, unsigned int n)
for the SMALL memory model.
Scans n bytes from buf for byte c.

Returns a pointer to c if found or a NULL pointer if not found.
signed char memcmp(void *buf1,void *buf2, unsigned char n)
for the TINY memory model.

signed char memcmp(void *buf1,void *buf2, unsigned int n)
for the SMALL memory model.

Compares at most n bytes of buf1 with buf2.
Returns <0 0="0">0 according to buf1buf2.

signed char memcmpf(void *buf1,void flash *buf2, unsigned char n)
for the TINY memory model.

signed char memcmpf(void *buf1,void flash *buf2, unsigned int n)
for the SMALL memory model.

Compares at most n bytes of buf1, located in SRAM, with buf2, located in FLASH.
Returns <0 0="0">0 according to buf1buf2.

void *memset(void *buf, unsigned char c, unsigned char n)
for the TINY memory model.

void *memset(void *buf, unsigned char c, unsigned int n)
for the SMALL memory model.
Sets n bytes from buf with byte c. Returns a pointer to buf.

Variable Length Argument Lists Macros

These macros are defined in the file stdarg.h, located in the ..\INC subdirectory. This file must be #include -ed before using the macros.

void va_start(argptr, previous_par)

This macro, when used in a function with a variable length argument list, initializes the argptr pointer of va_list type, for subsequent use by the va_arg and va_end macros.
The previous_par argument must be the name of the function argument immediately preceding the optional arguments.

The va_start macro must be called prior to any access using the va_arg macro.

type va_arg(argptr, type)

This macro is used to extract successive arguments from the variable length argument list referenced by argptr.
type specifies the data type of the argument to extract.
The va_arg macro can be called only once for each argument. The order of the parameters in the argument list must be observed.
On the first call va_arg returns the first argument after the previous_par argument specified in the va_start macro. Subsequent calls to va_arg return the remaining arguments in succession.

void va_end(argptr)

his macro is used to terminate use of the variable length argument list pointer argptr, initialized using the va_start macro.

Example:
#include

/* declare a function with a variable number of arguments */
int sum_all(int nsum, ...)
{
va_list argptr;
int i, result=0;
/* initialize argptr */
va_start(argptr,nsum);



/* add all the function arguments after nsum */

for (i=1; i <= nsum; i++)

/* add each argument */
result+=va_arg(argptr,int);

/* terminate the use of argptr */
va_end(argptr);
return result;
}

void main(void)
{
int s;
/* calculate the sum of 5 arguments */
s=sum_all(5,10,20,30,40,50);
}


Non-local Jump Functions

These functions can execute a non-local goto.
They are usually used to pass control to an error recovery routine.
The prototypes for the non-local jump functions are placed in the file setjmp.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

int setjmp(char *env)

This function saves the current CPU state (Y, SP, SREG registers and the current instruction address) in the env variable.
The CPU state can then be restored by subsequently calling the longjmp function.

Execution is then resumed immediately after the setjmp function call.
The setjmp function will return 0 when the current CPU state is saved in the env variable.
If the function returns a value different from 0, it signals that a longjmp function was executed.
In this situation the returned value is the one that was passed as the retval argument to the longjmp function.
In order to preserve the local variables in the function where setjmp is used, these must be declared with the volatile attribute.


void longjmp(char *env, int retval)

This function restores the CPU state that was previously saved in the env variable by a call to setjmp.
The retval argument holds the integer non-zero value that will be returned by setjmp after the call to longjmp. If a 0 value is passed as the retval argument then it will be substituted with 1.

In order to facilitate the usage of these functions, the setjmp.h header file also contains the definition of the jmp_buf data type, which is used when declaring the env variables.


Example:

#include <90s8515 .h=".h">
#include
#include

/* declare the variable used to hold the CPU state */
jmp_buf cpu_state;

void foo(void)
{
printf("Now we will make a long jump to main()\n\r");
longjmp(cpu_state,1);
}

void main(void)
{
/* this local variable will be preserved after a longjmp */
volatile int i;
/* this local variable will not be preserved after a longjmp */
int j;
/* init the AT90S8515 UART */
UCR=8;
/* Baud=9600 @ 4MHz */
UBRR=25;
if (setjmp(cpu_state)==0)
{
printf("First call to setjmp\n\r");
foo();
}

else
printf("We jumped here from foo()\n\r");
}

BCD Conversion Functions

The prototypes for these functions are placed in the file bcd.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

unsigned char bcd2bin(unsigned char n)
Converts the number n from BCD representation to it's binary equivalent.

unsigned char bin2bcd(unsigned char n)
Converts the number n from binary representation to it's BCD equivalent.
The number n values must be from 0 to 99.

Gray Code Conversion Functions

The prototypes for these functions are placed in the file gray.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

unsigned char gray2binc(unsigned char n)
unsigned char gray2bin(unsigned int n)
unsigned char gray2binl(unsigned long n)
Convert the number n from Gray code representation to it's binary equivalent.

unsigned char bin2grayc(unsigned char n)
unsigned char bin2gray(unsigned int n)
unsigned char bin2grayl(unsigned long n)
Convert the number n from binary representation to it's Gray code equivalent.


Memory Access Functions

The prototypes for these functions are placed in the file mem.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

void pokeb(unsigned int addr, unsigned char data)
this function writes the byte data to SRAM at address addr.

void pokew(unsigned int addr, unsigned int data)
this function writes the word data to SRAM at address addr.
The LSB is written at address addr and the MSB is written at address addr+1.

unsigned char peekb(unsigned int addr)
this function reads a byte located in SRAM at address addr.

unsigned int peekw (unsigned int addr)
this function reads a word located in SRAM at address addr.
The LSB is read from address addr and the MSB is read from address addr+1.

Delay Functions

These functions are intended for generating delays in C programs.
The prototypes for these functions are placed in the file delay.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
Before calling the functions the interrupts must be disabled, otherwise the delays will be
much longer then expected.
Also it is very important to specify the correct AVR chip clock frequency in the Project|Configure|C Compiler|Code Generation menu.

The functions are:
void delay_us(unsigned int n)
generates a delay of n mseconds. n must be a constant expression.

void delay_ms(unsigned int n)
generates a delay of n milliseconds.
This function automatically resets the watchdog timer every 1ms by generating the wdr instruction.

Example:

void main(void) {
/* disable interrupts */
#asm("cli")

/* 100ms delay */
delay_us(100);

/* ............. */

/* 10ms delay */
delay_ms(10);

/* enable interrupts */
#asm("sei")

/* ............. */
}

LCD Functions

The LCD Functions are intended for easy interfacing between C programs and alphanumeric LCD modules built with the Hitachi HD44780 chip or equivalent.
The prototypes for these functions are placed in the file lcd.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

Prior to #include -ing the lcd.h file, you must declare which microcontroller port is used for communication with the LCD module.
The following LCD formats are supported in lcd.h: 1x8, 2x12, 3x12, 1x16, 2x16, 2x20, 4x20, 2x24 and 2x40 characters.

Example:

/* the LCD module is connected to PORTC */
#asm
.equ __lcd_port=0x15
#endasm

/* now you can include the LCD Functions */
#include

The LCD module must be connected to the port bits as follows:


[LCD]    [AVR Port]
RS (pin4) ------       bit 0
RD (pin 5) ------      bit 1
EN (pin 6) ------      bit 2
DB4 (pin 11) ---      bit 4
DB5 (pin 12) ---      bit 5
DB6 (pin 13) ---      bit 6
DB7 (pin 14) ---      bit 7

You must also connect the LCD power supply and contrast control voltage, according to the data sheet.

The low level LCD Functions are:

void _lcd_ready(void)
waits until the LCD module is ready to receive data.
This function must be called prior to writing data to the LCD with the _lcd_write_data function.

void _lcd_write_data(unsigned char data)
writes the byte data to the LCD instruction register.
This function may be used for modifying the LCD configuration.
Example:

/* enables the displaying of the cursor */
_lcd_ready();
_lcd_write_data(0xe);

void lcd_write_byte(unsigned char addr, unsigned char data);
writes a byte to the LCD character generator or display RAM.

Example:

/* LCD user defined characters
Chip: AT90S8515
Memory Model: SMALL
Data Stack Size: 128 bytes
Use an 2x16 alphanumeric LCD connected
to the STK200+ PORTC header as follows:

[LCD]   [STK200+ PORTC HEADER]
1 GND- 9  GND
2 +5V- 10 VCC 
3 VLC- LCD HEADER Vo
4 RS - 1  PC0
5 RD - 2  PC1

6 EN - 3  PC2
11 D4 - 5  PC4
12 D5 - 6  PC5
13 D6 - 7  PC6
14 D7 - 8  PC7 */

/* the LCD is connected to PORTC outputs */
#asm
.equ __lcd_port=0x15 ;PORTC
#endasm

/* include the LCD driver routines */
#include

typedef unsigned char byte;

/* table for the user defined character
arrow that points to the top right corner */
flash byte char0[8]={
0b0000000,
0b0001111,
0b0000011,
0b0000101,
0b0001001,
0b0010000,
0b0100000,

0b1000000};

/* function used to define user characters */
void define_char(byte flash *pc,byte char_code)
{
byte i,a;
a=(char_code<<3 0x40="0x40" font="font">
for (i=0; i<8 a="a" font="font" i="i" lcd_write_byte="lcd_write_byte" pc="pc">
}

void main(void)
{
/* initialize the LCD for 2 lines & 16 columns */
lcd_init(16);

/* define user character 0 */
define_char(char0,0);

/* switch to writing in Display RAM */
lcd_gotoxy(0,0);
lcd_putsf("User char 0:");

/* display used defined char 0 */
lcd_putchar(0);


while (1); /* loop forever */
}


unsigned char lcd_read_byte(unsigned char addr);

reads a byte from the LCD character generator or display RAM.

The high level LCD Functions are:


void lcd_init(unsigned char lcd_columns)


initializes the LCD module, clears the display and sets the printing character position at row 0 and column 0. The numbers of columns of the LCD must be specified (e.g. 16).
No cursor is displayed.
This is the first function that must be called before using the other high level LCD Functions.

void lcd_clear(void)

clears the LCD and sets the printing character position at row 0 and column 0.

void lcd_gotoxy(unsigned char x, unsigned char y)
sets the current display position at column x and row y. The row and column numbering starts from 0.

void lcd_putchar(char c)
displays the character c at the current display position.

void lcd_puts(char *str)
displays at the current display position the string str, located in SRAM.

void lcd_putsf(char flash *str)
displays at the current display position the string str, located in FLASH.



LCD Functions for displays with 4x40 characters

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

The LCD Functions are intended for easy interfacing between C programs and alphanumeric LCD modules with 4x40 characters, built with the Hitachi HD44780 chip or equivalent.
The prototypes for these functions are placed in the file lcd4x40.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

Prior to #include -ing the lcd4x40.h file, you must declare which microcontroller port is used for communication with the LCD module.

Example:

/* the LCD module is connected to PORTC */
#asm
.equ __lcd_port=0x15
#endasm

/* now you can include the LCD Functions */
#include

The LCD module must be connected to the port bits as follows:


[LCD]    [AVR Port]
RS  (pin 11) ---       bit 0
RD  (pin 10) ---       bit 1
EN1 (pin 9) ----       bit 2
EN2 (pin 15) --        bit 3
DB4 (pin 4) ----       bit 4
DB5 (pin 3) ----       bit 5
DB6 (pin 2) ----       bit 6
DB7 (pin 1) ----       bit 7

You must also connect the LCD power supply and contrast control voltage, according to the data sheet.

The low level LCD Functions are:
void _lcd_ready(void)

waits until the LCD module is ready to receive data.
This function must be called prior to writing data to the LCD with the _lcd_write_data function.

void _lcd_write_data(unsigned char data)
writes the byte data to the LCD instruction register.
This function may be used for modifying the LCD configuration.

Prior calling the low level functions _lcd_ready and _lcd_write_data, the global variable _en1_msk must be set to LCD_EN1, respectively LCD_EN2, to select the upper, respectively lower half, LCD controller.

Example:
/* enables the displaying of the cursor on the upper half
of the LCD */
_en1_msk=LCD_EN1;
_lcd_ready();
_lcd_write_data(0xe);

void lcd_write_byte(unsigned char addr, unsigned char data);
writes a byte to the LCD character generator or display RAM.

unsigned char lcd_read_byte(unsigned char addr);
reads a byte from the LCD character generator or display RAM.
The high level LCD Functions are:

void lcd_init(void)
initializes the LCD module, clears the display and sets the printing character position at row 0 and column 0.
No cursor is displayed.
This is the first function that must be called before using the other high level LCD Functions.

void lcd_clear(void)
clears the LCD and sets the printing character position at row 0 and column 0.

void lcd_gotoxy(unsigned char x, unsigned char y)
sets the current display position at column x and row y. The row and column numbering starts from 0.

void lcd_putchar(char c)
displays the character c at the current display position.

void lcd_puts(char *str)
displays at the current display position the string str, located in SRAM.

void lcd_putsf(char flash *str)
displays at the current display position the string str, located in FLASH.
LCD Functions for displays connected in 8 bit memory mapped mode

These LCD Functions are intended for easy interfacing between C programs and alphanumeric LCD modules built with the Hitachi HD44780 chip or equivalent.
The LCD is connected to the AVR external data and address buses as an 8 bit peripheral.
This type of connection is used in the Kanda Systems STK200+ and STK300 development boards. For the LCD connection, please consult the documentation that came with your development board.
These functions can be used only with AVR chips that allow using external memory devices: AT90S4414, AT90S8515, ATmega603, ATmega103, ATmega128, ATmega161 and ATmega162.

The prototypes for these functions are placed in the file lcdstk.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The following LCD formats are supported in lcdstk.h: 1x8, 2x12, 3x12, 1x16, 2x16, 2x20, 4x20, 2x24 and 2x40 characters.
The LCD Functions are:

void _lcd_ready(void)
waits until the LCD module is ready to receive data.
This function must be called prior to writing data to the LCD with the _LCD_RS0 and _LCD_RS1 macros.
Example:

/* enables the displaying of the cursor */
_lcd_ready();
_LCD_RS0=0xe;

The _LCD_RS0, respectively _LCD_RS1, macros are used for accessing the LCD Instruction Register with RS=0, respectively RS=1.


void lcd_write_byte(unsigned char addr, unsigned char data);

writes a byte to the LCD character generator or display RAM.

Example:

/* LCD user defined characters

Chip: AT90S8515
Memory Model: SMALL
Data Stack Size: 128 bytes

Use an 2x16 alphanumeric LCD connected
to the STK200+ LCD connector */

/* include the LCD driver routines */
#include

typedef unsigned char byte;

/* table for the user defined character

arrow that points to the top right corner */
flash byte char0[8]={
0b0000000,
0b0001111,
0b0000011,
0b0000101,
0b0001001,
0b0010000,
0b0100000,
0b1000000};

/* function used to define user characters */
void define_char(byte flash *pc,byte char_code)
{
byte i,a;
a=(char_code<<3 0x40="0x40" font="font">
for (i=0; i<8 a="a" font="font" i="i" lcd_write_byte="lcd_write_byte" pc="pc">
}

void main(void)
{
/* initialize the LCD for 2 lines & 16 columns */
lcd_init(16);

/* define user character 0 */

define_char(char0,0);

/* switch to writing in Display RAM */
lcd_gotoxy(0,0);
lcd_putsf("User char 0:");

/* display used defined char 0 */
lcd_putchar(0);

while (1); /* loop forever */
}
unsigned char lcd_read_byte(unsigned char addr);
reads a byte from the LCD character generator or display RAM.

void lcd_init(unsigned char lcd_columns)
initializes the LCD module, clears the display and sets the printing character position at row 0 and column 0. The numbers of columns of the LCD must be specified (e.g. 16).
No cursor is displayed.
This is the first function that must be called before using the other high level LCD Functions.

void lcd_clear(void)
clears the LCD and sets the printing character position at row 0 and column 0.

void lcd_gotoxy(unsigned char x, unsigned char y)
sets the current display position at column x and row y. The row and column numbering starts from 0.

void lcd_putchar(char c)
displays the character c at the current display position.

void lcd_puts(char *str)
displays at the current display position the string str, located in SRAM.

void lcd_putsf(char flash *str)
displays at the current display position the string str, located in FLASH.







I2C Bus Functions

The I2C Functions are intended for easy interfacing between C programs and various peripherals using the Philips I2C bus.
These functions treat the microcontroller as a bus master and the peripherals as slaves.
The prototypes for these functions are placed in the file i2c.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

Prior to #include -ing the i2c.h file, you must declare which microcontroller port and port bits are used for communication through the I2C bus.

Example:
/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the I2C Functions */
#include

The I2C Functions are:

void i2c_init(void)
this function initializes the I2C bus.
This is the first function that must be called prior to using the other I2C Functions.


unsigned char i2c_start(void)
issues a START condition.
Returns 1 if bus is free or 0 if the I2C bus is busy.

void i2c_stop(void)
issues a STOP condition.



unsigned char i2c_read(unsigned char ack)
reads a byte from the bus.
The ack parameter specifies if an acknowledgement is to be issued after the byte was read.
Set ack to 0 for no acknowledgement or 1 for acknowledgement.

unsigned char i2c_write(unsigned char data)
writes the byte data to the bus.
Returns 1 if the slave acknowledges or 0 if not.

Example how to access an Atmel 24C02 256 byte I2C EEPROM:


/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */

#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the I2C Functions */
#include
/* function declaration for delay_ms */
#include
#define EEPROM_BUS_ADDRESS 0xa0
/* read a byte from the EEPROM */
unsigned char eeprom_read(unsigned char address) {
unsigned char data;
i2c_start();
i2c_write(EEPROM_BUS_ADDRESS);
i2c_write(address);
i2c_start();
i2c_write(EEPROM_BUS_ADDRESS | 1);
data=i2c_read(0);
i2c_stop();
return data;
}




/* write a byte to the EEPROM */
void eeprom_write(unsigned char address, unsigned char data) {

i2c_start();
i2c_write(EEPROM_BUS_ADDRESS);
i2c_write(address);
i2c_write(data);
i2c_stop();

/* 10ms delay to complete the write operation */
delay_ms(10);
}

void main(void) {
unsigned char i;

/* initialize the I2C bus */
i2c_init();

/* write the byte 55h at address AAh */
eeprom_write(0xaa,0x55);

/* read the byte from address AAh */
i=eeprom_read(0xaa);

while (1); /* loop forever */
}

National Semiconductor LM75 Temperature Sensor Functions

These functions are intended for easy interfacing between C programs and the LM75 I2C bus temperature sensor.
The prototypes for these functions are placed in the file lm75.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The I2C bus functions prototypes are automatically #include -ed with the lm75.h.

Prior to #include -ing the lm75.h file, you must declare which microcontroller port and port bits are used for communication with the LM75 through the I2C bus.

Example:

/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the LM75 Functions */
#include

The LM75 Functions are:

void lm75_init(unsigned char chip,signed char thyst,signed char tos, unsigned char pol)


this function initializes the LM75 sensor chip.
Before calling this function the I2C bus must be initialized by calling the i2c_init function.
This is the first function that must be called prior to using the other LM75 Functions.
If more then one chip is connected to the I2C bus, then the function must be called for each one, specifying accordingly the function parameter chip.
Maximum 8 LM75 chips can be connected to the I2C bus, their chip address can be from 0 to 7.

The LM75 is configured in comparator mode, where it functions like a thermostat.
The O.S. output becomes active when the temperature exceeds the tos limit, and leaves the active state when the temperature drops below the thyst limit.
Both thyst and tos are expressed in °C.
pol represents the polarity of the LM75 O.S. output in active state.
If pol is 0, the output is active low and if pol is 1, the output is active high.

Refer to the LM75 data sheet for more information.
int lm75_temperature_10(unsigned char chip)
this function returns the temperature of the LM75 sensor with the address chip.
The temperature is in °C and is multiplied by 10.

Example how to display the temperature of two LM75 sensors with addresses 0 and 1:


/* the LM75 I2C bus is connected to PORTB */

/* the SDA signal is bit 3 */

/* the SCL signal is bit 4 */

#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* include the LM75 Functions */
#include

/* the LCD module is connected to PORTC */
#asm
.equ __lcd_port=0x15
#endasm

/* include the LCD Functions */
#include



/* include the prototype for sprintf */

#include
/* include the prototype for abs */
#include
char display_buffer[33];

void main(void) {
int t0,t1;
/* initialize the LCD, 2 rows by 16 columns */
lcd_init(16);



/* initialize the I2C bus */
i2c_init();

/* initialize the LM75 sensor with address 0 */
/* thyst=20°C tos=25°C */
lm75_init(0,20,25,0);

/* initialize the LM75 sensor with address 1 */
/* thyst=30°C tos=35°C */
lm75_init(1,30,35,0);

/* temperature display loop */

while (1)
{
/* read the temperature of sensor #0 *10°C */
t0=lm75_temperature_10(0);

/* read the temperature of sensor #1 *10°C */
t1=lm75_temperature_10(1);

/* prepare the displayed temperatures */
/* in the display_buffer */
sprintf(display_buffer,
"t0=%-i.%-u%cC\nt1=%-i.%-u%cC",
t0/10,abs(t0%10),0xdf,t1/10,abs(t1%10),0xdf);

/* display the temperatures */
lcd_clear();
lcd_puts(display_buffer);
};
}










Dallas Semiconductor DS1621 Thermometer/Thermostat Functions

These functions are intended for easy interfacing between C programs and the DS1621 I2C bus thermometer/thermostat.
The prototypes for these functions are placed in the file ds1621.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The I2C bus functions prototypes are automatically #include -ed with the ds1621.h.

Prior to #include -ing the ds1621.h file, you must declare which microcontroller port and port bits are used for communication with the DS1621 through the I2C bus.

Example:

/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the DS1621 Functions */
#include

The DS1621 Functions are:

void ds1621_init(unsigned char chip,signed char tlow,signed char thigh, unsigned char pol)


this function initializes the DS1621 chip.
Before calling this function the I2C bus must be initialized by calling the i2c_init function.
This is the first function that must be called prior to using the other DS1621 Functions.
If more then one chip is connected to the I2C bus, then the function must be called for each one, specifying accordingly the function parameter chip.
Maximum 8 DS1621 chips can be connected to the I2C bus, their chip address can be from 0 to 7.

Besides measuring temperature, the DS1621 functions also like a thermostat.
The Tout output becomes active when the temperature exceeds the thigh limit, and leaves the active state when the temperature drops below the tlow limit.
Both tlow and thigh are expressed in °C.
pol represents the polarity of the DS1621 Tout output in active state.
If pol is 0, the output is active low and if pol is 1, the output is active high.

Refer to the DS1621 data sheet for more information.

unsigned char ds1621_get_status(unsigned char chip)

this function reads the contents of the configuration/status register of the DS1621 with  address chip.
Refer to the DS1621 data sheet for more information about this register.

void ds1621_set_status(unsigned char chip, unsigned char data)

this function sets the contents of the configuration/status register of the DS1621 with  address chip.

Refer to the DS1621 data sheet for more information about this register.

void ds1621_start(unsigned char chip)

this functions exits the DS1621, with address chip, from the power-down mode and starts the temperature measurements and the thermostat.

void ds1621_stop(unsigned char chip)

this functions enters the DS1621, with address chip, in power-down mode and stops the temperature measurements and the thermostat.


int ds1621_temperature_10(unsigned char chip)

this function returns the temperature of the DS1621 sensor with the address chip.

The temperature is in °C and is multiplied by 10.
Example how to display the temperature of two DS1621 sensors with addresses 0 and 1:


/* the DS1621 I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* include the DS1621 Functions */
#include

/* the LCD module is connected to PORTC */
#asm
.equ __lcd_port=0x15
#endasm

/* include the LCD Functions */
#include

/* include the prototype for sprintf */
#include

/* include the prototype for abs */
#include
char display_buffer[33];

void main(void) {
int t0,t1;

/* initialize the LCD, 2 rows by 16 columns */
lcd_init(16);



/* initialize the I2C bus */
i2c_init();

/* initialize the DS1621 sensor with address 0 */
/* tlow=20°C thigh=25°C */
ds1621_init(0,20,25,0);

/* initialize the DS1621 sensor with address 1 */
/* tlow=30°C thigh=35°C */
ds1621_init(1,30,35,0);

/* temperature display loop */

while (1)
{
/* read the temperature of DS1621 #0 *10°C */
t0=ds1621_temperature_10(0);

/* read the temperature of DS1621 #1 *10°C */
t1=ds1621_temperature_10(1);

/* prepare the displayed temperatures */
/* in the display_buffer */
sprintf(display_buffer,
"t0=%-i.%-u%cC\nt1=%-i.%-u%cC",
t0/10,abs(t0%10),0xdf,t1/10,abs(t1%10),0xdf);

/* display the temperatures */
lcd_clear();
lcd_puts(display_buffer);
};
}









Philips PCF8563 Real Time Clock Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the PCF8563 I2C bus real time clock (RTC).
The prototypes for these functions are placed in the file pcf8563.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The I2C bus functions prototypes are automatically #include -ed with the pcf8563.h.


Prior to #include -ing the pcf8563.h file, you must declare which microcontroller port and port bits are used for communication with the PCF8563 through the I2C bus.
Example:

/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the PCF8563 Functions */
#include

The PCF8563 Functions are:


void rtc_init(unsigned char ctrl2, unsigned char clkout, unsignedText Box: char timer_ctrl)

this function initializes the PCF8563 chip.
Before calling this function the I2C bus must be initialized by calling the i2c_init function.
This is the first function that must be called prior to using the other PCF8563 Functions.
Only one PCF8583 chip can be connected to the I2C bus.

The ctrl2 parameter specifies the initialization value for the PCF8563 Control/Status 2 register.
The pcf8563.h header file defines the following macros which allow the easy setting of the ctrl2 parameter:

·   RTC_TIE_ON sets the Control/Status 2 register bit TIE to 1
·   RTC_AIE_ON sets the Control/Status 2 register bit AIE to 1
·   RTC_TP_ON sets the Control/Status 2 register bit TI/TP to 1
These macros can be combined using the | operator in order to set more bits to 1.

The clkout parameter specifies the initialization value for the PCF8563 CLKOUT Frequency register.

The pcf8563.h header file defines the following macros which allow the easy setting of the clkout parameter:
·   RTC_CLKOUT_OFF disables the generation of pulses on the PCF8563 CLKOUT output
·   RTC_CLKOUT_1 generates 1Hz pulses on the PCF8563 CLKOUT output
·   RTC_CLKOUT_32 generates 32Hz pulses on the PCF8563 CLKOUT output
·   RTC_CLKOUT_1024 generates 1024Hz pulses on the PCF8563 CLKOUT output
·   RTC_CLKOUT_32768 generates 32768Hz pulses on the PCF8563 CLKOUT output.


The timer_ctrl parameter specifies the initialization value for the PCF8563 Timer Control register.
The pcf8563.h header file defines the following macros which allow the easy setting of the timer_ctrl parameter:
·   RTC_TIMER_OFF disables the PCF8563 Timer countdown
·   RTC_TIMER_CLK_1_60 sets the PCF8563 Timer countdown clock frequency to 1/60Hz
·   RTC_TIMER_CLK_1 sets the PCF8563 Timer countdown clock frequency to 1Hz

·   RTC_TIMER_CLK_64 sets the PCF8563 Timer countdown clock frequency to 64Hz
·   RTC_TIMER_CLK_4096 sets the PCF8563 Timer countdown clock frequency to 4096Hz.

Refer to the PCF8563 data sheet for more information.
unsigned char rtc_read(unsigned char address)
this function reads the byte stored in a PCF8563 register at address.

void rtc_write(unsigned char address, unsigned char data)
this function stores the byte data in the PCF8583 register at address.


unsigned char rtc_get_time(unsigned char *hour, unsigned char *min, unsigned char *sec)


this function returns the current time measured by the RTC .
The *hour, *min and *sec pointers must point to the variables that must receive the values of hour, minutes and seconds.
The function return the value 1 if the read values are correct.
If the function returns 0 then the chip supply voltage has dropped below the Vlow value and the time values are incorrect.
Example:


#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

#include
void main(void) {
unsigned char ok,h,m,s;

/* initialize the I2C bus */
i2c_init();

/* initialize the RTC,
Timer interrupt enabled,
Alarm interrupt enabled,
CLKOUT frequency=1Hz
Timer clock frequency=1Hz */
rtc_init(RTC_TIE_ON | RTC_AIE_ON,RTC_CLKOUT_1,RTC_TIMER_CLK_1);

/* read time from the RTC */
ok=rtc_get_time(&h,&m,&s);
/* ........ */
}

void rtc_set_time(unsigned char hour, unsigned char min, unsigned char sec)

this function sets the current time of the RTC .
The hour, min and sec parameters represent the values of hour, minutes and seconds.

void rtc_get_date(unsigned char *date, unsigned char *month, unsigned *year)

this function returns the current date measured by the RTC .
The *date, *month and *year pointers must point to the variables that must receive the values of day, month and year.

void rtc_set_date(unsigned char date, unsigned char month, unsigned year)
this function sets the current date of the RTC .

void rtc_alarm_off(void)
this function disables the RTC alarm function.

void rtc_alarm_on(void)
this function enables the RTC alarm function.

void rtc_get_alarm(unsigned char *date, unsigned char *hour, unsigned char *min)
this function returns the alarm time and date of the RTC.
The *date, *hour and *min pointers must point to the variables that must receive the values of date, hour and minutes.

void rtc_set_alarm(unsigned char date, unsigned char hour, unsigned char min)
this function sets the alarm time and date of the RTC.
The date, hour and min parameters represent the values of date, hours and minutes.
If date is set to 0, then this parameter will be ignored.
After calling this function the alarm will be turned off. It must be enabled using the rtc_alarm_on function.

void rtc_set_timer(unsigned char val)
this function sets the countdown value of the PCF8563 Timer.



Philips PCF8583 Real Time Clock Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the PCF8583 I2C bus real time clock (RTC).
The prototypes for these functions are placed in the file pcf8583.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The I2C bus functions prototypes are automatically #include -ed with the pcf8583.h.


Prior to #include -ing the pcf8583.h file, you must declare which microcontroller port and port bits are used for communication with the PCF8583 through the I2C bus.
Example:

/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the PCF8583 Functions */
#include

The PCF8583 Functions are:


void rtc_init(unsigned char chip, unsigned char dated_alarm)
this function initializes the PCF8583 chip.
Before calling this function the I2C bus must be initialized by calling the i2c_init function.
This is the first function that must be called prior to using the other PCF8583 Functions.
If more then one chip is connected to the I2C bus, then the function must be called for each one, specifying accordingly the function parameter chip.
Maximum 2 PCF8583 chips can be connected to the I2C bus, their chip address can be 0 or 1.

The dated_alarm parameter specifies if the RTC  alarm takes in account both the time and date (dated_alarm=1), or only the time (dated_alarm=0).
Refer to the PCF8583 data sheet for more information.
After calling this function the RTC  alarm is disabled.

unsigned char rtc_read(unsigned char chip, unsigned char address)
this function reads the byte stored in the PCF8583 SRAM.

void rtc_write(unsigned char chip, unsigned char address, unsigned char data)
this function stores the byte data in the PCF8583 SRAM.
When writing to the SRAM the user must take in account that locations at addresses 10h and 11h are used for storing the current year value.

unsigned char rtc_get_status(unsigned char chip)
this function returns the value of the PCF8583 control/status register.
By calling this function the global variables __rtc_status and __rtc_alarm are automatically updated.
The __rtc_status variable holds the value of the PCF8583 control/status register.

The __rtc_alarm variable takes the value 1 if an RTC alarm occurred.

void rtc_get_time(unsigned char chip, unsigned char *hour, unsigned char *min, unsigned char *sec, unsigned char *hsec)
this function returns the current time measured by the RTC.
The *hour, *min, *sec and *hsec pointers must point to the variables that must receive the values of hour, minutes, seconds and hundreds of a second.
Example:


#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

#include

void main(void) {
unsigned char h,m,s,hs;

/* initialize the I2C bus */
i2c_init();

/* initialize the RTC 0,
no dated alarm */
rtc_init(0,0);

/* read time from RTC 0*/
rtc_get_time(0,&h,&m,&s,&hs);

/* ........ */
}


void rtc_set_time(unsigned char chip, unsigned char hour, unsigned char min, unsigned char sec, unsigned char hsec)
this function sets the current time of the RTC.
The hour, min, sec and hsec parameters represent the values of hour, minutes, seconds and hundreds of a second.


void rtc_get_date(unsigned char chip, unsigned char *date, unsigned char *month, unsigned *year)
this function returns the current date measured by the RTC.
The *date, *month and *year pointers must point to the variables that must receive the values of day, month and year.


void rtc_set_date(unsigned char chip, unsigned char date, unsigned char month, unsigned year)
this function sets the current date of the RTC.


void rtc_alarm_off(unsigned char chip)
this function disables the RTC alarm function.

void rtc_alarm_on(unsigned char chip)
this function enables the RTC alarm function.

void rtc_get_alarm_time(unsigned char chip, unsigned char *hour, unsigned char *min, unsigned char *sec, unsigned char *hsec)
this function returns the alarm time of the RTC.
The *hour, *min, *sec and *hsec pointers must point to the variables that must receive the values of hours, minutes, seconds and hundreds of a second.


void rtc_set_alarm_time(unsigned char chip, unsigned char hour, unsigned char min, unsigned char sec, unsigned char hsec)
this function sets the alarm time of the RTC.
The hour, min, sec and hsec parameters represent the values of hours, minutes, seconds and hundreds of a second.


void rtc_get_alarm_date(unsigned char chip, unsigned char *date, unsigned char *month)
this function returns the alarm date of the RTC.
The *day and *month pointers must point to the variables that must receive the values of date and month.


void rtc_set_alarm_date(unsigned char chip, unsigned char date, unsigned char month)
this function sets the alarm date of the RTC.



Dallas Semiconductor DS1302 Real Time Clock Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the DS1302 real time clock (RTC).
The prototypes for these functions are placed in the file ds1302.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

Prior to #include -ing the ds1302.h file, you must declare which microcontroller port and port bits are used for communication with the DS1302.

Example:

/* the DS1302 is connected to PORTB */
/* the IO signal is bit 3 */
/* the SCLK signal is bit 4 */
/* the RST signal is bit 5 */
#asm
.equ __ds1302_port=0x18
.equ __ds1302_io=3
.equ __ds1302_sclk=4
.equ __ds1302_rst=5
#endasm

/* now you can include the DS1302 Functions */
#include

The DS1302 Functions are:

void rtc_init(unsigned char tc_on, unsigned char diodes, unsigned char res)


this function initializes the DS1302 chip.
This is the first function that must be called prior to using the other DS1302 Functions.
If the tc_on parameter is set to 1 then the DS1302’s trickle charge function is enabled.
The diodes parameter specifies the number of diodes used when the trickle charge function is enabled. This parameter can take the value 1 or 2.
The res parameter specifies the value of the trickle charge resistor:

·   0 for no resistor
·   1 for a 2kW resistor
·   2 for a 4kW resistor
·   3 for a 8kW resistor.

Refer to the DS1302 data sheet for more information.

unsigned char ds1302_read(unsigned char addr)
this function reads a byte stored at address addr in the DS1302 registers or SRAM.

void ds1302_write(unsigned char addr, unsigned char data)
this function stores the byte data at address addr in the DS1302 registers or SRAM.

void rtc_get_time(unsigned char *hour, unsigned char *min, unsigned char *sec)
this function returns the current time measured by the RTC.
The *hour, *min and *sec pointers must point to the variables that must receive the values of hours, minutes and seconds.
Example:

#asm
.equ __ds1302_port=0x18
.equ __ds1302_io=3
.equ __ds1302_sclk=4
.equ __ds1302_rst=5
#endasm

#include

void main(void) {
unsigned char h,m,s;

/* initialize the DS1302 RTC:
use trickle charge,
with 1 diode and 8K resistor */
rtc_init(1,1,3);

/* read time from the DS1302 RTC */
rtc_get_time(&h,&m,&s);

/* ........ */
}


void rtc_set_time(unsigned char hour, unsigned char min, unsigned char sec)
this function sets the current time of the RTC.
The hour, min and sec parameters represent the values of hour, minutes and seconds.


void rtc_get_date(unsigned char *date, unsigned char *month, unsigned char *year)
this function returns the current date measured by the RTC.
The *date, *month and *year pointers must point to the variables that must receive the values of date, month and year.


void rtc_set_date(unsigned char date, unsigned char month, unsigned char year)
this function sets the current date of the RTC.


Dallas Semiconductor DS1307 Real Time Clock Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the DS1307 I2C bus real time clock (RTC).
The prototypes for these functions are placed in the file ds1307.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The I2C bus functions prototypes are automatically #include -ed with the ds1307.h.

Prior to #include -ing the ds1307.h file, you must declare which microcontroller port and port bits are used for communication with the DS1307 through the I2C bus.
Example:

/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */
#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm

/* now you can include the DS1307 Functions */

#include

The DS1307 Functions are:

void rtc_init(unsigned char rs, unsigned char sqwe, unsigned char out)
this function initializes the DS1307 chip.
Before calling this function the I2C bus must be initialized by calling the i2c_init function.
This is the first function that must be called prior to using the other DS1307 Functions.
The rs parameter specifies the value of the square wave output frequency on the SQW/OUT pin:

·   0 for 1Hz
·   1 for 4096Hz
·   2 for 8192Hz
·   3 for 32768Hz.

If the sqwe parameter is set to 1 then the square wave output on the SQW/OUT pin is enabled.
The out parameter specifies the logic level on the SQW/OUT pin when the square wave output is disabled (sqwe=0).
Refer to the DS1307 data sheet for more information.

void rtc_get_time(unsigned char *hour, unsigned char *min, unsigned char *sec)
this function returns the current time measured by the RTC.
The *hour, *min and *sec pointers must point to the variables that must receive the values of hours, minutes and seconds.
Example:


/* the I2C bus is connected to PORTB */
/* the SDA signal is bit 3 */
/* the SCL signal is bit 4 */

#asm
.equ __i2c_port=0x18
.equ __sda_bit=3
.equ __scl_bit=4
#endasm


#include

void main(void) {
unsigned char h,m,s;

/* initialize the I2C bus */
i2c_init();

/* initialize the DS1307 RTC */
rtc_init(0,0,0);

/* read time from the DS1307 RTC */
rtc_get_time(&h,&m,&s);

/* ........ */
}


void rtc_set_time(unsigned char hour, unsigned char min, unsigned char sec)
this function sets the current time of the RTC.
The hour, min and sec parameters represent the values of hour, minutes and seconds.

void rtc_get_date(unsigned char *date, unsigned char *month, unsigned char *year)
this function returns the current date measured by the RTC.
The *date, *month and *year pointers must point to the variables that must receive the values of date, month and year.


void rtc_set_date(unsigned char date, unsigned char month, unsigned char year)
this function sets the current date of the RTC.









1 Wire Protocol Functions

The 1 Wire Functions are intended for easy interfacing between C programs and various peripherals using the Dallas Semiconductor 1 Wire protocol.
These functions treat the microcontroller as a bus master and the peripherals as slaves.
The prototypes for these functions are placed in the file 1wire.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.

Prior to #include -ing the 1wire.h file, you must declare which microcontroller port and port bit is used for communication through the 1 Wire protocol.

Example:

/* the 1 Wire bus is connected to PORTB */
/* the data signal is bit 2 */
#asm
.equ __w1_port=0x18
.equ __w1_bit=2
#endasm

/* now you can include the 1 Wire Functions */
#include <1wire .h=".h">

Because the 1 Wire Functions require precision time delays for correct operation, the interrupts must be disabled during their execution.
Also it is very important to specify the correct AVR chip clock frequency in the Project|Configure|C Compiler|Code Generation menu.


The 1 Wire Functions are:

unsigned char w1_init(void)
this function initializes the 1 Wire devices on the bus.
It returns 1 if there were devices present or 0 if not.

unsigned char w1_read(void)
this function reads a byte from the 1 Wire bus.

unsigned char w1_write(unsigned char data)
this function writes the byte data to the 1 Wire bus.
It returns 1 if the write process completed normally or 0 if not.

unsigned char w1_search(unsigned char cmd,void *p)
this function returns the number of devices connected to the 1 Wire bus.
If no devices were detected then it returns 0.
The byte cmd represents the Search ROM (F0h), Alarm Search (ECh) for the DS1820/DS18S20, or other similar commands, sent to the 1 Wire device.
The pointer p points to an area of SRAM where are stored the 8 bytes ROM codes returned by the device. After the eighth byte, the function places a ninth status byte which contains a status bit returned by some 1 Wire devices (e.g. DS2405).

Thus the user must allocate 9 bytes of SRAM for each device present on the 1 Wire bus.
If there is more then one device connected to the 1 Wire bus, than the user must first call the w1_search function to identify the ROM codes of the devices and to be able to address them at a later stage in the program.
Example:

#include <90s8515 .h=".h">

/* specify the port and bit used for the 1 Wire bus */
#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm

/* include the 1 Wire bus functions prototypes */
#include <1wire .h=".h">

/* include the printf function prototype */
#include

/* specify the maximum number of devices connected
to the 1 Wire bus */

#define MAX_DEVICES 8



/* allocate SRAM space for the ROM codes & status bit */

unsigned char rom_codes[MAX_DEVICES,9];


/* quartz crystal frequency [Hz] */
#define xtal 4000000L

/* Baud rate */
#define baud 9600

void main(void) {

unsigned char i,j,devices;


/* initialize the UART's baud rate */
UBRR=xtal/16/baud-1;

/* initialize the UART control register
TX enabled, no interrupts, 8 data bits */
UCR=8;

/* detect how many DS1820/DS18S20 devices
are connected to the bus and
store their ROM codes in the rom_codes array */

devices=w1_search(0xf0,rom_codes);

/* display the ROM codes for each detected device */

printf("%-u DEVICE(S) DETECTED\n\r",devices);
if (devices) {

for (i=0;i
printf("DEVICE #%-u ROM CODE IS:", i+1);
for (j=0;j<8 font="font" i="i" j="j" printf="printf" rom_codes="rom_codes">
printf("\n\r");
};
};
while (1); /* loop forever */
}



unsigned char w1_dow_crc8(void *p, unsigned char n)
this function returns the 8 bit DOW CRC for a block of bytes with the length n, starting from address p.

Dallas Semiconductor DS1820/DS18S20 Temperature Sensors Functions

These functions are intended for easy interfacing between C programs and the DS1820/DS18S20 1 Wire bus temperature sensor.
The prototypes for these functions are placed in the file ds1820.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The 1 Wire bus functions prototypes are automatically #include -ed with the ds1820.h.

Prior to #include -ing the ds1820.h file, you must declare which microcontroller port and port bits are used for communication with the DS1820/DS18S20 through the 1 Wire bus.

Example:
/* specify the port and bit used for the 1 Wire bus */

#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm

/* include the DS1820/DS18S20 functions prototypes */

#include










The DS1820/DS18S20 functions are:

int ds1820_temperature_10(unsigned char *addr)
this function returns the temperature of the DS1820/DS18S20 sensor with the ROM code stored in an array of 8 bytes located at address addr.

The temperature is in °C and is multiplied by 10. In case of error the function returns the value -9999.
If only one DS1820/DS18S20 sensor is used, no ROM code array is necessary and the pointer addr must be NULL (0).
If more several sensors are used, then the program must first identify the ROM codes for all the sensors. Only after that the ds1820_temperature_10 function may be used, with the addr pointer pointing to the array which holds the ROM code for the needed device.

Example:
#include <90s8515 .h=".h">
/* specify the port and bit used for the 1 Wire bus */

#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm

/* include the DS1820/DS18S20 functions prototypes */
#include
/* include the printf function prototype */
#include
/* include the abs function prototype */
#include
/* maximum number of DS1820/DS18S20 connected to the bus */
#define MAX_DEVICES 8

/* DS1820/DS18S20 devices ROM code storage area,
9 bytes are used for each device
(see the w1_search function description),
but only the first 8 bytes contain the ROM code
and CRC */
unsigned char rom_codes[MAX_DEVICES,9];



main()
{
unsigned char i,j,devices;
int temp;
/* initialize the UART's baud rate */
UBRR=xtal/16/baud-1;

/* initialize the UART control register
TX enabled, no interrupts, 8 data bits */
UCR=8;

/* detect how many DS1820/DS18S20 devices
are connected to the bus and
store their ROM codes in the rom_codes array */

devices=w1_search(0xf0,rom_codes);

/* display the number */
printf("%-u DEVICE(S) DETECTED\n\r",devices);

/* if no devices were detected then halt */
if (devices==0) while (1); /* loop forever */
/* measure and display the temperature(s) */      

while (1)

{

for (i=0;i

{

temp=ds1820_temperature_10(&rom_codes[i,0]);

printf("t%-u=%-i.%-u\xf8C\n\r",++i,temp/10,

abs(temp%10));        

};

};
}

unsigned char ds1820_set_alarm(unsigned char *addr,signed char temp_low,signed char temp_high)
this function sets the low (temp_low) and high (temp_high) temperature alarms of the DS1820/DS18S20.
In case of success the function returns the value 1, else it returns 0.
The alarm temperatures are stored in both the DS1820/DS18S20's scratchpad SRAM and its EEPROM.
The ROM code needed to address the device is stored in an array of 8 bytes located at address addr.

If only one DS1820/DS18S20 sensor is used, no ROM code array is necessary and the pointer addr must be NULL (0).
The alarm status for all the DS1820/DS18S20 devices on the 1 Wire bus can be determined by calling the w1_search function with the Alarm Search (ECh) command.
Example:


#include <90s8515 .h=".h">

/* specify the port and bit used for the 1 Wire bus */

#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm

/* include the DS1820/DS18S20 functions prototypes */

#include
/* include the printf function prototype */
#include
/* include the abs function prototype */
#include
/* maximum number of DS1820/DS18S20 connected to the bus */
#define MAX_DEVICES 8
/* DS1820/DS18S20 devices ROM code storage area,
9 bytes are used for each device
(see the w1_search function description),
but only the first 8 bytes contain the ROM code
and CRC */


unsigned char rom_codes[MAX_DEVICES,9];
/* allocate space for ROM codes of the devices
which generate an alarm */

unsigned char alarm_rom_codes[MAX_DEVICES,9];

main()
{
unsigned char i,j,devices;
int temp;
/* initialize the UART's baud rate */
UBRR=xtal/16/baud-1;

/* initialize the UART control register
TX enabled, no interrupts, 8 data bits */
UCR=8;

/* detect how many DS1820/DS18S20 devices
are connected to the bus and
store their ROM codes in the rom_codes array */

devices=w1_search(0xf0,rom_codes);

/* display the number */

printf("%-u DEVICE(S) DETECTED\n\r",devices);

/* if no devices were detected then halt */

if (devices==0) while (1); /* loop forever */

/* set the temperature alarms for all the devices

temp_low=25°C temp_high=35°C */

for (i=0;i
{
printf("INITIALIZING DEVICE #%-u ", i+1);
if (ds1820_set_alarm(&rom_codes[i,0],25,35))
putsf("OK"); else putsf("ERROR");
};



while (1)
{

/* measure and display the temperature */

for (i=0;i

{

temp=ds1820_temperature_10(&rom_codes[i,0]);

printf("t%-u=%-i.%-u\xf8C\n\r",++i,temp/10,

abs(temp%10));        

};



/* display the number of devices which

generated an alarm */      
printf("ALARM GENERATED BY %-u DEVICE(S)\n\r",
w1_search(0xec,alarm_rom_codes));
};
}

Refer to the DS1820/DS18S20 data sheet for more information.


















Dallas Semiconductor DS2430 EEPROM Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the DS2430 1 Wire bus EEPROM.
The prototypes for these functions are placed in the file ds2430.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The 1 Wire bus functions prototypes are automatically #include -ed with the ds2430.h.


Prior to #include -ing the ds2430.h file, you must declare which microcontroller port and port bits are used for communication with the DS2430 through the 1 Wire bus.
Example:


/* specify the port and bit used for the 1 Wire bus */

#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm

/* include the DS2430 functions prototypes */
#include
The DS2430 functions are:

unsigned char ds2430_read_block(unsigned char *romcode,unsigned char *dest,
unsigned char addr,unsigned char size);

this function reads a block of size bytes starting from the DS2430 EEPROM memory address addr and stores it in the string dest located in SRAM.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.


unsigned char ds2430_read(unsigned char *romcode,unsigned char addr, unsigned char *data);
this function reads a byte from the DS2430 EEPROM memory address addr and stores it in the SRAM memory location pointed by data.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.


unsigned char ds2430_write_block(unsigned char *romcode,
unsigned char *source,unsigned char addr,unsigned char size);
this function writes a block of size bytes, from the string source, located in SRAM, in the DS2430 EEPROM starting from memory address addr.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.


unsigned char ds2430_write(unsigned char *romcode,
unsigned char addr,unsigned char data);
this function writes the byte data at DS2430 EEPROM memory address addr.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.


unsigned char ds2430_read_appreg_block(unsigned char *romcode, unsigned char *dest,unsigned char addr,unsigned char size);
this function reads a block of size bytes starting from the DS2430 application register address addr and stores it in the string dest located in SRAM.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.





unsigned char ds2430_write_appreg_block(unsigned char *romcode, unsigned char *source,unsigned char addr,unsigned char size);
this function reads a block of size bytes starting from the DS2430 application register address addr and stores it in the string dest located in SRAM.
It returns 1 if successful, 0 if not.
The DS2430 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.

If only one DS2430 EEPROM is used, no ROM code array is necessary and the pointer romcode must be NULL (0).
If several 1 Wire device are used, then the program must first identify the ROM codes for all the devices. Only after that the DS2430 functions may be used, with the romcode pointer pointing to the array which holds the ROM code for the needed device.
Example:

/* specify the port and bit used for the 1 Wire bus
The DS2430 devices are connected to
bit 6 of PORTA of the AT90S8515 as follows:

[DS2430]      [STK200 PORTA HEADER]
1 GND         -   9  GND
2 DATA        -   7  PA6

All the devices must be connected in parallel
AN 4.7k PULLUP RESISTOR MUST BE CONNECTED
BETWEEN DATA (PA6) AND +5V !
*/
#asm
.equ __w1_port=0x1b
.equ __w1_bit=6
#endasm

// test the DS2430 functions
#include
#include <90s8515 .h=".h">
#include

/* DS2430 devices ROM code storage area,

9 bytes are used for each device
(see the w1_search function description),
but only the first 8 bytes contain the ROM code
and CRC */
#define MAX_DEVICES 8
unsigned char rom_code[MAX_DEVICES,9];

char text[]="Hello world!";
char buffer[32];
#define START_ADDR 2

main() {
unsigned char i,devices;
// init UART
UCR=8;
UBRR=25; // Baud=9600 @ 4MHz

// detect how many 1 Wire devices are present on the bus
devices=w1_search(0xF0,&rom_code[0,0]);
printf("%-u 1 Wire devices found\n\r",devices);

for (i=0;i
// make sure to select only the DS2430 types
// 0x14 is the DS2430 family code
if (rom_code[i,0]==DS2430_FAMILY_CODE)
{
printf("\n\r");
// write text in each DS2430 at START_ADDR
if (ds2430_write_block(&rom_code[i,0],
text,START_ADDR,sizeof(text)))
{
printf("Data written OK in DS2430 #%-u!\n\r",i+1);
// display the text written in each DS2430
if (ds2430_read_block(&rom_code[i,0],buffer,START_ADDR,sizeof(text)))
printf("Data read OK!\n\rDS2430 #%-u text: %s\n\r",
i+1,buffer);
else printf("Error reading data from DS2430 #%-u!\n\r",
i+1);
}
else printf("Error writing data to DS2430 #%-u!\n\r",i+1);
};// stop
while (1);
}
Refer to the DS2430 data sheet for more information.





Dallas Semiconductor DS2433 EEPROM Functions

This topic applies only to the commercial versions of the CodeVisionAVR C Compiler.

These functions are intended for easy interfacing between C programs and the DS2433 1 Wire bus EEPROM.
The prototypes for these functions are placed in the file ds2433.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The 1 Wire bus functions prototypes are automatically #include -ed with the ds2433.h.


Prior to #include -ing the ds2433.h file, you must declare which microcontroller port and port bits are used for communication with the DS2433 through the 1 Wire bus.
Example:


/* specify the port and bit used for the 1 Wire bus */

#asm
.equ __w1_port=0x18 ;PORTB
.equ __w1_bit=2
#endasm



/* include the DS2433 functions prototypes */

#include

The DS2433 functions are:

unsigned char ds2433_read_block(unsigned char *romcode,unsigned char *dest, unsigned int addr,unsigned int size);
this function reads a block of size bytes starting from the DS2433 EEPROM memory address addr and stores it in the string dest located in SRAM.
It returns 1 if successful, 0 if not.
The DS2433 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.


unsigned char ds2433_read(unsigned char *romcode,unsigned int addr, unsigned char *data);
this function reads a byte from the DS2433 EEPROM memory address addr and stores it in the SRAM memory location pointed by data.
It returns 1 if successful, 0 if not.
The DS2433 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.

unsigned char ds2433_write_block(unsigned char *romcode, unsigned char *source,unsigned int addr,unsigned int size);

this function writes a block of size bytes, from the string source, located in SRAM, in the DS2433 EEPROM starting from memory address addr.
It returns 1 if successful, 0 if not.
The DS2433 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.

unsigned char ds2433_write(unsigned char *romcode,unsigned int addr, unsigned char data);
this function writes the byte data at DS2433 EEPROM memory address addr.
It returns 1 if successful, 0 if not.
The DS2433 device is selected using it's ROM code stored in an array of 8 bytes located at address romcode.
If only one DS2433 EEPROM is used, no ROM code array is necessary and the pointer romcode must be NULL (0).
If several 1 Wire device are used, then the program must first identify the ROM codes for all the devices. Only after that the DS2433 functions may be used, with the romcode pointer pointing to the array which holds the ROM code for the needed device.
Example:

/* specify the port and bit used for the 1 Wire bus

The DS2433 devices are connected to
bit 6 of PORTA of the AT90S8515 as follows:

[DS2433]      [STK200 PORTA HEADER]
1 GND         -   9  GND
2 DATA        -   7  PA6

All the devices must be connected in parallel

AN 4.7k PULLUP RESISTOR MUST BE CONNECTED
BETWEEN DATA (PA6) AND +5V !
*/
#asm
.equ __w1_port=0x1b
.equ __w1_bit=6
#endasm

// test the DS2433 functions
#include
#include <90s8515 .h=".h">
#include

/* DS2433 devices ROM code storage area,

9 bytes are used for each device
(see the w1_search function description),
but only the first 8 bytes contain the ROM code
and CRC */
#define MAX_DEVICES 8
unsigned char rom_code[MAX_DEVICES,9];

char text[]="This is a long text to \
be able to test writing across the \
scratchpad boundary";
char buffer[100];
#define START_ADDR 2

main() {
unsigned char i,devices;
// init UART
UCR=8;
UBRR=25; // Baud=9600 @ 4MHz

// detect how many 1 Wire devices are present on the bus

devices=w1_search(0xF0,&rom_code[0,0]);
printf("%-u 1 Wire devices found\n\r",devices);
for (i=0;i
// make sure to select only the DS2433 types
// 0x23 is the DS2433 family code
if (rom_code[i,0]==DS2433_FAMILY_CODE)
{
printf("\n\r");
// write text in each DS2433 at START_ADDR
if (ds2433_write_block(&rom_code[i,0],
text,START_ADDR,sizeof(text)))
{
printf("Data written OK in DS2433 #%-u!\n\r",i+1);

// display the text written in each DS2433
if (ds2433_read_block(&rom_code[i,0],
buffer,START_ADDR,sizeof(text)))
printf("Data read OK!\n\rDS2433 #%-u text: %s\n\r",
i+1,buffer);
else printf("Error reading data from DS2433 #%-u!\n\r",i+1);
}
else printf("Error writing data to DS2433 #%-u!\n\r",i+1);
};
// stop
while (1);
}

Refer to the DS2433 data sheet for more information.




















SPI Functions

The SPI Functions are intended for easy interfacing between C programs and various peripherals using the SPI bus.
The prototypes for these functions are placed in the file spi.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The SPI functions are:

unsigned char spi(unsigned char data)
this function sends the byte data, simultaneously receiving a byte.

Prior to using the spi function, you must configure the SPI Control Register SPCR according to the Atmel Data Sheets.

Because the spi function uses polling for SPI communication, there is no need to set the SPI Interrupt Enable Bit SPIE.

Example of using the spi function for interfacing to an AD7896 ADC:

/*
Digital voltmeter using an
Analog Devices AD7896 ADC
connected to an AT90S8515
using the SPI bus
Chip: AT90S8515
Memory Model: SMALL
Data Stack Size: 128 bytes
Clock frequency: 4MHz
AD7896 connections to the AT90S8515
[AD7896]  [AT9S8515 DIP40]
1 Vin
2 Vref=5V
3 AGND  - 20 GND
4 SCLK  - 8  SCK
5 SDATA - 7  MISO
6 DGND  - 20 GND
7 CONVST- 2  PB1
8 BUSY  - 1  PB0
Use an 2x16 alphanumeric LCD connected
to PORTC as follows:
[LCD]   [AT90S8515 DIP40]


1 GND- 20 GND
2 +5V- 40 VCC
3 VLC
4 RS - 21 PC0
5 RD - 22 PC1
6 EN - 23 PC2
11 D4 - 25 PC4
12 D5 - 26 PC5
13 D6 - 27 PC6
14 D7 - 28 PC7 */

#asm
.equ __lcd_port=0x15
#endasm

#include // LCD driver routines
#include // SPI driver routine
#include <90s8515 .h=".h">
#include
#include

// AD7896 reference voltage [mV]
#define VREF 5000L

// AD7896 control signals PORTB bit allocation
#define ADC_BUSY PINB.0
#define NCONVST PORTB.1

// LCD display buffer
char lcd_buffer[33];

unsigned read_adc(void)
{
unsigned result;
// start conversion in mode 1
// (high sampling performance)
NCONVST=0;
NCONVST=1;
// wait for the conversion to complete
while (ADC_BUSY);
// read the MSB using SPI
result=(unsigned) spi(0)<<8 font="font">
// read the LSB using SPI and combine with MSB
result|=spi(0);

// calculate the voltage in [mV]
result=(unsigned) (((unsigned long) result*VREF)/4096L);
// return the measured voltage
return result;
}

void main(void)
{
// initialize PORTB
// PB.0 input from AD7896 BUSY
// PB.1 output to AD7896 /CONVST
// PB.2 & PB.3 inputs
// PB.4 output (SPI /SS pin)
// PB.5 input
// PB.6 input (SPI MISO)
// PB.7 output to AD7896 SCLK

DDRB=0x92;

// initialize the SPI in master mode
// no interrupts, MSB first, clock phase negative
// SCK low when idle, clock phase=0
// SCK=fxtal/4

SPCR=0x54;

// the AD7896 will work in mode 1
// (high sampling performance)
// /CONVST=1, SCLK=0

PORTB=2;

// initialize the LCD

lcd_init(16);
lcd_putsf("AD7896 SPI bus\nVoltmeter");
delay_ms(2000);
lcd_clear();


// read and display the ADC input voltage


while (1)
{
sprintf(lcd_buffer,"Uadc=%4umV",read_adc());
lcd_clear();
lcd_puts(lcd_buffer);
delay_ms(100);
};
}

Power Management Functions

The Power Management Functions are intended for putting the AVR chip in one of its low power consumption modes.
The prototypes for these functions are placed in the file sleep.h, located in the ..\INC subdirectory. This file must be #include -ed before using the functions.
The Power Management Functions are:

void sleep_enable(void)
this function enables entering the low power consumption modes.

void sleep_disable(void)
this function disables entering the low power consumption modes.
It is used to disable accidental entering the low power consumption modes.

void idle(void)
this function puts the AVR chip in the idle mode.
Prior to using this function, the sleep_enable function must be invoked to allow entering the low power consumption modes.
In this mode the CPU is stopped, but the Timers/Counters, Watchdog and interrupt system continue operating.
The CPU can wake up from external triggered interrupts as well as internal ones.

void powerdown(void)
this function puts the AVR chip in the powerdown mode.
Prior to using this function, the sleep_enable function must be invoked to allow entering the low power consumption modes.
In this mode the external oscillator is stopped.
The AVR can wake up only from an external reset, Watchdog time-out or external level triggered interrupt.



void powersave(void)
this function puts the AVR chip in the powersave mode.
Prior to using this function, the sleep_enable function must be invoked to allow entering the low power consumption modes.
This mode is similar to the powerdown mode with some differences, please consult the Atmel Data Sheet for the particular chip that you use.


void standby(void)
this function puts the AVR chip in the standby mode.
Prior to using this function, the sleep_enable function must be invoked to allow entering the low power consumption modes.
This mode is similar to the powerdown mode with the exception that the external clock oscillator keeps on running.
Consult the Atmel Data Sheet for the particular chip that you use, in order to see if the standby mode is available for it.



void extended_standby(void)
this function puts the AVR chip in the extended standby mode.
Prior to using this function, the sleep_enable function must be invoked to allow entering the low power consumption modes.
This mode is similar to the powersave mode with the exception that the external clock oscillator keeps on running.
Consult the Atmel Data Sheet for the particular chip that you use, in order to see if the standby mode is available for it.