Keil Compiler Lecture Notes #2 We are going to look at, analyze and hopefully understand the structure of a Keil C program. Several basics we need to understand.
DATA TYPES The C51 supports the following data types: Data Type Bit Signed char Unsigned char Enum Signed short Unsigned short Signed int Unsigned int Signed long Unsigned long Float Sbit Sfr Sfr16
Bits 1 8 8 16 16 16 16 16 32 32 32 1 8 16
Bytes 1 1 2 2 2 2 2 4 4 4 1 2
Value Range 0 to 1 -126 to +127 0 to 256 -32768 to +32767 -32768 to +32767 0 to 65535 -32768 to +32767 0 to 65535 -2147483648 to +2147483647 0 to 4294967295 +/-1.7549E+38 to +/-3.402823E+38 0 to 1 0 to 256 0 to 65535
The sbit, sfr, and sfr16 data types are included to allow access to the special function registers that are available on the 8051. For example, the declaration: sfr P0 = 0x80, declares the variable p0 and assigns it the special function address of 0x80. This is the address of PORT 0 on the 8051. The C51 compiler automatically converts between data types when the result implies a different data type. For example, a bit variable used in an integer assignment is converted to an integer.
1
Memory Types The C51 compiler supports the architecture of the 8051 and its derivatives and provides access to all memory areas of the 8051. Each variable may be explicitly assigned to a specific memory space. Following are the memory types supported by the C51 compiler: Memory Type Code Data Idata Bdata Xdata Pdata
Description Program memory (64 Kbytes; accessed by opcode MOVC @A+DPTR Directly addressable internal data memory; fastest access to variables (128 bytes). Indirectly addressable internal data memory; accessed across the full internal address space (256 bytes). Bit-addressable internal data memory; allows bit and byte access (16 bytes). External data memory (64Kbytes); accessed by opcode MOVX @DPTR Paged (256 bytes) external data memory; accessed by opcode MOVX @Rn
Accessing the internal data memory is considerably faster than accessing the external data memory. For this reason, you should place frequently used variables in internal data memory and less frequently used variables in external data memory. By including a memory type specifier in the variable declaration, you can specify where variables are stored. As with the signed and unsigned attributes, you may include memory type specifiers in the variable declaration. For example: Char data var1; ; Data type char, memory type data Char code text [] = “Enter Parameter;”; Data type char, memory type code Unsigned long xdata array [100] Float idata x,y,z Uinsigned int pdata dimension Char bdata flags
2
If the memory type specifier is omitted in a variable declaration, the default or implicit memory type is automatically selected. Function arguments and automatic variables which cannot be located in registers are also stored in the default memory area.
MEMORY MODELS The memory model determines the default memory type used for function arguments, automatic variable, and variables declared with no explicit memory type. You specify the memory model on the command line using the SMALL, COMPACT, and LARGE control directives. SMALL: Total RAM 128 bytes Restricting with the 8051/31. Will support code sizes up to about 4K but a constant check must be kept on stack usage. The number of global variables must be kept to a minimum to allow the linker OVERLAYER to work to best effect. With the 8052/32 versions, the manual use of the 128 byte IDATA area above 80H can allow applications up to about 1012K but again stack position must be kept in mind. Compact Total RAM 256 bytes off-chip, or 128 or 256 bytes on-chip Suitable for programs where, for example, the on-chip memory is applied to an operating system. The compac5t model is rarely used on its own but more usually in combination with the SMALL switch reserved for interrupt routines. Especially useful for programs with a large number of medium speed 8 bit variables, for which the MOVX A, @R0 is very suitable. Large
Total RAM up to 64Kb, 128 or 256 on-chip Permits slow access to a very large memory space and is perhaps the easiest model to use. Again, not often used on its own but in combination with SMALL. As with COMPACT, register variables are still used and so efficiency remains reasonable.
Specify Model size with directive: #PragmaSMALL
3
REG51.H Header file for 8051. /* BYTE Register */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; sfr PSW = 0xD0; sfr ACC = 0xE0; sfr B = 0xF0; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99; sbit ET0 = 0xA9; sbit EX0 = 0xA8; /* IP */ sbit PS = 0xBC; sbit PT1 = 0xBB; sbit PX1 = 0xBA; sbit PT0 = 0xB9; sbit PX0 = 0xB8; /* P3 */ sbit RD = 0xB7; sbit WR = 0xB6; sbit T1 = 0xB5; sbit T0 = 0xB4; sbit INT1 = 0xB3;
/* SCON */ sbit SM0 = 0x9F; sbit SM1 = 0x9E; sbit SM2 = 0x9D; sbit REN = 0x9C; sbit TB8 = 0x9B; sbit RB8 = 0x9A; sbit TI = 0x99; sbit RI = 0x98; /* BIT Register */ /* PSW */ sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0; /* TCON */ sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88; /* IE */ sbit EA = 0xAF; sbit ES = 0xAC; sbit ET1 = 0xAB; sbit EX1 = 0xAA; sbit INT0 = 0xB2; sbit TXD = 0xB1; sbit RXD = 0xB0;
4
Example 1 Write a program that reads data in from 8 switches connected to P0, stores the readings in a 10-byte array, shows the most recent reading on 8 LEDs connected to P2, and waits 1/10 second to repeat the process. Write the program first in assembly language then in C.
Part 1 Assembly Language
EXTRN CODE (MSEC) MYCODE SEGMENT CODE MYDATA SEGMENT DATA RSEG MYDATA ARRAY: DS 10 RSEG MYCODE START: AGAIN:
END
MOV R0,#ARRAY ;SET ARRAY POINTER MOV ACC,P0 MOV P2,ACC MOV @R0,ACC ;STORE IN ARRAY MOV R2,#0 ;HIGH BYTE MOV R1,#100 ;LOW BYTE LCALL MSEC INC R0 ;POINT TO NEXT LOC. CJNE R0,#ARRAY+10, AGAIN ;END? SJMP START ;RESET TO START
Part 2 “C” #include void msec (unsigned int); void main() { unsigned char array [10]; unsigned char I; while (1) { for (I=0; I<=0; I++){ array[I]=p2=p0; msec(100) } } }
5
Example 2 This example counts up in binary and displays the result on eight LEDs connected to port 1. The data is displayed with about 1 second delay between each output. #include /* Function to wait about 1 second*/ void wait_a_second() { unsigned int x; for(x=0;x<3300;x++); } /* Start of main program */ main() { int LED=1 for(;;) { P1=~LED; LED++ Wait_a_second(); } }
/*initialize count to 1*/ /*start of endless loop*/ /*invert and output*/ /*increment the count*/ /*wait about a second*/
6
Example 3 This example is a dice simulator project. Seven LED’s are connected to port 1 of the microcontroller. A push-button switch is connected to bit 0 of port 3 and when this switch is depressed, a new number is obtained between 1 and 6 and the corresponding LED’s are turned on to simulate a dice. After 2 seconds delay, all LED’s are turned off and the user can throw a dice again. #include #define ALL_OFF 0xFF sbit button = P3.0
/*bit p3.0 is the push-button*/
/*function to delay about a second*/ void wait_a_second() { unsigned int x; for(x=0;x<33000;x++); } /*start of mian program*/ main() { int DICE=0 /*initialize to 0*/ int DICE_ARRAY[6]={0x08,0x14,0x1c,0x63,0x6b,0x77}; for(;;) {
}
/*start of loop*/ if(button==0) /*button pressed?*/ { P!=~DICE_ARRAY[DICE-1]; wait_a_second(); /*wait 2 seconds*/ wait_a_second(); P1=ALL_OFF; /*turn off LED’s*/ } else { DICE++; /*inc DICE*/ If(DICE==7)DICE=1; /*set to 0 if 7*/ }
}
7
Example 4: Implementing a 4 bit Counter using an 8051 and Interfacing it to an LCD (Modified from example from Prof. Frank Vahid’s web site)
Purpose: In this example, you will learn how to write a simple C program for 80X51 microcontroller, compile it using C51 compiler, and emulate it on an emulator. The program will be used to control a simple 4-bit up-down counter, capable of counting from 0 to 15. At each step the count should be displayed in decimal
format on the LCD. Assignment:
In this lab : • You will design a 4-bit Up-Down counter using the C programming language for the 8051 micro-controller and display the count on an LCD. • You will then test and run your program on the 8051. 1.The 4 bit counter has the following functionality: • The counter has the following input pins : a.Reset : when high resets the counter dataout to ``0000'' b.Updown : decides whether the counter counts up or down. c.Load : makes the counter count from the 4 bit input Datain d.Datain : which is a 4 bit input count • The counter has a 4 bit Dataout to reflect the count. • The count has to be sent to the LCD and displayed in decimal format.
Apparatus Required:
1.4.7k resistors(8) 2.1k resistor(1) 3.DIP switch 4.LCD 5.5V power supply 6.8051 Development system
8
Schematic:
9
10
Program: #pragma SMALL DB OE #include #include "io.h" /* P0, P1, P2 and P3 are predefined port names and are bit addressable */ sbit reset = P0^4; /* bit 4 of Port 0 */ sbit up_down = P0^5; sbit load = P0^6; sbit Start_LCD = P3^7; /* bit 7 of Port 3 */ /* Delay function */ void delay() { int i, j; for(i=0; i<1000; i++) for(j=0; j<100; j++) i = i + 0; } /* Function to output the decimal value of the count on the LCD */ void PrintInt(unsigned char i) { char ch[4]; /* Write code to convert the count to a string value and use the PrintString function provided in io.c */ PrintString(ch); } void main(void) { unsigned char count = 0; InitIO(); /* Initialize the LCD */ while (1) { if (Start_LCD == 1) { ClearScreen(); PrintString("Ready..."); delay(); 11
} else if (reset == 1) { /* Output 0 on the LCD */ } else if (load == 1) { /* Output the current value of Datain on the LCD */
}
} else { /* Check the Up/Down pin for 1 or 0 count up or down accordingly. Display each value on the LCD */ }
}
EXAMPLE 5 /* CIO.C */ /* PROGRAM TO LEARN THE KEIL C DEVELOPMENT ENVIRONMENT Program counts up Port-2 when any key is pressed. Then counts down when "00" is pressed. Then returns to counting up when "FF" is pressed. Program prints to screen using short ASCII input and output routines. */ #pragma DEBUG OBJECTEXTEND CODE #include /* #include <stdio.h> */ /***************************/ /* main program */ void delayloop(unsigned int); /* settable delay loop */ unsigned int getchr(void); /* read serial port */ void sndchr(unsigned int);
void main(void) /* execution begins here after stack init */ { unsigned int intvar, carvar; 12
unsigned int result = 0x41; unsigned int lch, rch = 0x41; SCON = 0x50; TMOD = 0x20; TH1 = 0xF3; TR1 = 1; TI = 1;
/* mode 1, 8-bit uart, enable receiver */ /* timer 1, mode 2, 8-bit reload */ /* reload value for 2400 baud */ /* timer 1 run */ /* set TI to send first char of uart */
while (1) /* main loop */ { intvar = 00; /* set P2 = 00 */ P2 = intvar; while (!RI) {} /* Wait for serial input */ carvar = getchr(); /* get char from serial port */ sndchr(carvar); while (1) { if(result == 0x41) intvar++; /* increment after first keystroke */ if(result == 0x46) intvar--; /* decrement P2 if "FF" */ if(result == 0x30) intvar++; /* increment P2 if "00" */ P2 = intvar; /* send intvar to I/O port */ delayloop(0xcc); delayloop(0x11); carvar = getchr(); /* get char from serial port */ if(carvar != 0x41) /* shift & save if new keystroke */ { lch = rch; rch = carvar; sndchr(carvar); } if((lch == 0x46)&&(rch == 0x46)) /* check for "FF" */ {result = 0x46;} if((lch == 0x30)&&(rch == 0x30)) /* check for "00" */ {result = 0x30;} } } } /* Delay loop */ void delayloop(x) 13
unsigned int x; { unsigned int loop1, loop2; for (loop1 = 01; loop1 <=x; loop1++) { for (loop2 = 01; loop2 <=0xff; loop2++) {} } } /* Read whatever is in serial port buffer */ /* Return "A" if re-entered before next keystroke */ unsigned int getchr(void) { unsigned int chr, ch1; ch1 = SBUF; /* get character */ chr = ch1 & 0x7f; /* mask off 8t bit */ if(!RI) {chr = 0x41;} /* return "A" if no new keystroke */ RI = 0; /* clear serial status bit */ if(chr == 0x0d) { sndchr(chr); chr = 0x0a; } return(chr); } /* Send a character to the serial port */ void sndchr(x) unsigned int x; { SM1 = 0; /* clear the tx buffer full flag */ SBUF = x; while (SM1){} }
14