Professional Documents
Culture Documents
Microcontroller:
A microcontroller (sometimes abbreviated C, uC or MCU) is a small computer on a single integrated circuit containing a processor core, memory, and programmable input/output peripherals. Program memory in the form of NOR flash or OTP ROM is also often included on chip, as well as a typically small amount of RAM. Microcontrollers are designed for embedded applications, in contrast to the microprocessors used in personal computers or other general purpose applications. Microcontrollers are used in automatically controlled products and devices, such as automobile engine control systems, implantable medical devices, remote controls, office machines, appliances, power tools, toys and other embedded systems. By reducing the size and cost compared to a design that uses a separate microprocessor, memory, and input/output devices, microcontrollers make it economical to digitally control even more devices and processes. Mixed signal microcontrollers are common, integrating analog components needed to control non-digital electronic systems. Some microcontrollers may use four-bit words and operate at clock rate frequencies as low as 4 kHz, for low power consumption (milliwatts or microwatts). They will generally have the ability to retain functionality while waiting for an event such as a button press or other interrupt; power consumption while sleeping (CPU clock and most peripherals off) may be just nanowatts, making many of them well suited for long lasting battery applications. Other microcontrollers may serve performance-critical roles, where they may need to act more like a digital signal processor (DSP), with higher clock speeds and power consumption.
However, the RISC strategy also brings Memory-to-memory: Register to register: some very important advantages. Because "LOAD" and "STORE" "LOAD" and "STORE" incorporated in instructions are independent instructions each instruction requires only one clock cycle to execute, the entire program will Small code sizes, Low cycles per second, execute in approximately the same amount high cycles per second large code sizes of time as the multi-cycle "MULT" command. These RISC "reduced Transistors used for storing Spends more transistors instructions" require less transistors of on memory registers complex instructions hardware space than the complex instructions, leaving more room for general purpose registers. Because all of the instructions execute in a uniform amount of time (i.e. one clock), pipelining is possible. Separating the "LOAD" and "STORE" instructions actually reduces the amount of work that the computer must perform. After a CISC-style "MULT" command is executed, the processor automatically erases the registers. If one of the operands needs to be used for another computation, the processor must re-load the data from the memory bank into a register. In RISC, the operand will remain in the register until another value is loaded in its place. The Performance Equation The following equation is commonly used for expressing a computer's performance ability:
The CISC approach attempts to minimize the number of instructions per program, sacrificing the number of cycles per instruction. RISC does the opposite, reducing the cycles per instruction at the cost of the number of instructions per program. RISC Roadblocks Despite the advantages of RISC based processing, RISC chips took over a decade to gain a foothold in the commercial world. This was largely due to a lack of software support. Although Apple's Power Macintosh line featured RISC-based chips and Windows NT was RISC compatible, Windows 3.1 and Windows 95 were designed with CISC processors in mind. Many companies were unwilling to take a chance with the emerging RISC technology. Without commercial interest, processor developers were unable to manufacture RISC chips in large enough volumes to make their price competitive. Another major setback was the presence of Intel. Although their CISC chips were becoming increasingly unwieldy and difficult to develop, Intel had the resources to plow through development and produce powerful processors. Although RISC chips might surpass Intel's efforts in specific areas, the differences were not great enough to persuade buyers to change technologies. The Overall RISC Advantage Today, the Intel x86 is arguable the only chip which retains CISC architecture. This is primarily due to advancements in other areas of computer technology. The price of RAM has decreased dramatically. In 1977, 1MB of DRAM cost about $5,000. By 1994, the same amount of memory cost only $6 (when adjusted for inflation). Compiler technology has also become more sophisticated, so that the RISC use of RAM and emphasis on software has become ideal.
Hybrids As memory technology has matured in recent years, the line between RAM and ROM has blurred. Now, several types of memory combine features of both. These devices do not belong to either group and can be collectively referred to as hybrid memory devices. Hybrid memories can be read and written as desired, like RAM, but maintain their contents without electrical power, just like ROM. Two of the hybrid devices, EEPROMand flash, are descendants of ROM devices. These are typically used to store code. EEPROMs are electrically-erasable-and-programmable. Internally, they are similar to EPROMs, but the erase operation is accomplished electrically, rather than by exposure to ultraviolet light. Any byte within an EEPROM may be erased and rewritten. Once written, the new data will remain in the device forever--or at least until it is electrically erased. The primary tradeoff for this improved functionality is higher cost, though write cycles are also significantly longer than writes to a RAM. So you wouldn't want to use an EEPROM for your main system memory. Flash memory combines the best features of the memory devices described thus far. Flash memory devices are high density, low cost, nonvolatile, fast (to read, but not to write), and electrically reprogrammable. These advantages are overwhelming and, as a direct result, the use of flash memory has increased dramatically in embedded systems. From a software viewpoint, flash and EEPROM technologies are very similar. The major difference is that flash devices can only be erased one sector at a time, not byte-by-byte. Typical sector sizes are in the range 256 bytes to 16KB. Despite this disadvantage, flash is much more popular than EEPROM and is rapidly displacing many of the ROM devices as well. The third member of the hybrid memory class is NVRAM (non-volatile RAM). Nonvolatility is also a characteristic of the ROM and hybrid memories discussed previously. However, an NVRAM is physically very different from those devices. An NVRAM is usually just an SRAM with a battery backup. When the power is turned on, the NVRAM operates just like any other SRAM. When the power is turned off, the NVRAM draws just enough power from the battery to retain its data. NVRAM is fairly common in embedded systems. However, it is expensive--even more expensive than SRAM, because of the battery--so its applications are typically limited to the storage of a few hundred bytes of system-critical information that can't be stored in any better way. Table 1 summarizes the features of each type of memory discussed here, but keep in mind that different memory types serve different purposes. Each memory type has its strengths and weaknesses. Side-by-side comparisons are not always effective. Erase Size Byte Byte Max Erase Cycles Unlimited Unlimited
Type
No
No
n/a
n/a
Inexpensive
Fast
PROM
No
n/a
n/a
Moderate
Fast
EPROM
No
Entire Chip
Moderate
Fast
EEPROM
No
Yes
Byte
Expensive
Flash
No
Yes
Sector
Moderate
NVRAM
No
Yes
Byte
Unlimited
Fast
Table 1. Characteristics of the various memory types When working with microcontrollers, many of the tasks usually consist of controlling the peripherals that are connected to the device, respectively programming the subsystems that are contained in the controller (which by itself communicate with the circuitry connected to the controller). The AVR series of microcontrollers offers two different ways to perform this task: There's a separate I/O address space available that can be addressed with specific I/O instructions that are applicable to some or all of the I/O address space (in, out, sbi etc.), known as I/O mapping. The entire I/O address space is also made available as memory-mapped I/O, i. e. it can be accessed using all the MCU instructions that are applicable to normal data memory. The I/O register space is mapped into the data memory address space with an offset of 0x20 since the bottom of this space is reserved for direct access to the MCU registers. (Actual SRAM is available only behind the I/O register area, starting at either address 0x60, or 0x100 depending on the device.).
This is why there are two sets of addresses in the AVR data sheets. The first address is using I/O mapping and the second address in brackets is the memory mapped approach.
Registers Registers are special storages with 8 bits capacity and they look like this: 7 6 5 4 3 2 1 0
Note the numeration of these bits: the least significant bit starts with zero (20 = 1). A register can either store numbers from 0 to 255 (positive number, no negative values), or numbers from -128 to +127 (whole number with a sign bit in bit 7), or a value representing an ASCII-coded character (e.g. 'A'), or just eight single bits that do not have something to do with each other (e.g. for eight single flags used to signal eight different yes/no decisions). The special character of registers, compared to other storage sites, is that they can be used directly in assembler commands, operations with their content require only a single command word, they are connected directly to the central processing unit called the accumulator,
they are source and target for calculations. There are 32 registers in an AVR. They are originally named r0 to r31. However certain instructions will not work in registers r0 to r15 e.g. ldi will only work on registers r16 to r31.
Keil Limitations
There are several very important limitations in the evaluation version of Keil's Developer's Kit that users need be aware of when writing software for the 8051. Object code must be less than 2 Kbytes The compiler will compile any-sized source code file, but the final object code may not exceed 2 Kbytes. If it does, the linker will refuse to create a final binary executable (or HEX file) from it. Along the same lines, the debugger will refuse any files that are over 2Kbytes, even if they were compiled using a different software package. Program code starts at address 0x4000 All C code compiled and linked using the Keil tools will begin at address 0x4000 in code memory. Such code may not be programmed into devices with less than 16Kbytes of Read-Only Memory. Code written in assembly may circumvent this limitation by using the "origin" keyword to set the start to address 0x0000. No such work-around exists for C programs, though. However, the integrated debugger in the evaluation software may still be used for testing code. Once tested, the code may be compiled by the full version of the Keil software, or by another compiler that supports the C extensions used by Keil.
C Modifications The Keil C compiler has made some modifications to an otherwise ANSI-compliant implementation of the C programming language. These modifications were made solely to facilitate the use of a higher-level language like C for writing programs on micro controllers. Variable Types The Keil C compiler supports most C variable types and adds several of its own. Standard Types
The evaluation version of the Keil C compiler supports the standard ANSI C variable types, with the exception of the floating-point types. These types are summarized below.
Type Char unsigned char enum short unsigned short int unsigned int long unsigned long
Bits 8 8 16 16 16 16 16 32 32
Bytes 1 1 2 2 2 2 2 4 4
Range -128 to +127 0 to 255 -32,768 to +32,767 -32,768 to +32,767 0 to 65,535 -32,768 to +32,767 0 to 65,535 -2,147,483,648 to +2,147,483,647 0 to 4,294,697,295
In addition to these variable types, the compiler also supports the struct and union data structures, as well as type redefinition using typedef. Keil Types To support a micro controller and embedded systems applications, Keil added several new types to their compiler. These are summarized in the table below Type Bit Sbit Sfr sf16 Bits 1 1 8 16 Bytes 0 0 1 2 Range 0 to 1 0 to 1 0 to 255 0 to 65,535
Of these, only the bit type works as a standard variable would. The other three have special behavior that a programmer must be aware of. bit This is a data type that gets allocated out of the 8051's bit-addressable on-chip RAM. Like other data types, it may be declared as either a variable. However, unlike standard C types, if may not be used as a pointer. An example of its usage follows.
/* declare two bit variables - the compiler will decide which */ /* addresses they are at. Initialize them to 0 and 1. */ bit testbit1 = 0; bit testbit2 = 1; /* set testbit1 to the value in testbit2 */
testbit1 = testbit2; /* clear testbit2 */ testbit2 = 0; /* testbit1 is now a 1, and testbit2 is now a 0 */ /* Note that the assignment of testbit2 to testbit1 only copied */ /* the contents of testbit2 into testbit1. It did *not* change */ /* the location of testbit1 to be the same as testbit2. */ sbit, sfr, and sf16 These are special types for accessing 1-bit, 8-bit, and 16-bit special function registers. Because there is no way to indirectly address registers in the 8051, addresses for these variables must be declared outsite of functions within the code. Only the data addressed by the variable may be manipulated in the code. An example follows: /* create an sbit variable that points to pin 0 of port 1 */ /* note that this is done outside of any functions! */ sbit P10 = 0x90; /* now the functions may be written to use this location */ void main (void) { /* forever loop, toggling pin 0 of port 1 */ while (1==1) { P10 = !P10; delay (500); /* wait 500 microseconds */ } }
Conveniently, the standard special function registers are all defined in the reg51.h file that any developer may include into their source file. Only registers unique to the particular 8051-derivative being used for the project need have these variable declared, such as registers and bits related to a second on-chip serial port Keil Variable Extensions In writing applications for a typical computer, the operating system handles manages memory on behalf of the programs, eliminating their need to know about the memory structure of the hardware. Even more important, most computers having a unified memory space, with the code and data sharing the same RAM. This is not true with the 8051, which has separate memory spaces for code, on-chip data, and external data. To accommodate for this when writing C code, Keil added extensions to variable declarations to specify which memory space the variable is allocated from, or points to. The most important of these for student programmers are summarized in the following table.
Memory Type Directly-addressable data memory (data memory addresses 0x00-0x7F) Indirectly-addressable data memory (data memory addresses 0x00-0xFF) External data memory Program memory
Related ASM MOV A, 07Fh MOV R0, #080h , MOV A, R0 MOVX @DPTR MOVC @A+DPTR
These extensions may be used as part of the variable type in declaration or casting by placing the extension after the type, as in the example below. If the memory type extension is not specified, the compiler will decide which memory type to use automatically, based on the memory model (SMALL, COMPACT, or LARGE, as specified in the project properties in Keil). /* This is a function that will calculate and return a checksum of */ /* a range of addresses in code memory, using a simple algorithm */ /* that simply adds each consecutive byte together. This could be */ /* useful for verifying if the code in ROM got corrupted (like if */ /* the Flash device were wearing out). */ unsigned int checksum (unsigned int start, unsigned int end) { /* first, declare pointers to the start and end of */ /* the range in code memory. */ unsigned int code *codeptr, *codeend;
/* now declare the variable the checksum will be */ /* calculated in. Because direct-addressable data */ /* is faster to access than indirect, and this */ /* variable will be accessed frequently, we will */ /* declare it in data memory (instead of idata). */ /* In reality, if left unspecified, the compiler */ /* would probably leave it in the accumulator for */ /* even faster access, but that would defeat the */ /* point of this example. */ unsigned int data checksum = 0;
/* the addresses passed into the function as params. */ /* because start and end are passed in as values, */ /* not pointers, they must be cast to the correct */ /* pointer type */ codeptr = (unsigned int code *)start; codeend = (unsigned int code *)end;
/* Now perform the checksum calculation, looping */ /* until the end of the range is reached. */ while (codeptr <= codeend) { checksum = checksum + (unsigned int data)*codeptr; codeptr++; /* go to the next address */ }
return (checksum); } Keil Function Extensions As in most other C compilers, functions may be declared in one of two fashions: unsigned int functionname (unsigned int var) { .... return (var); } functionname (var)
Most modern programmers use the first syntax, as do the examples in this document.
Keil provides two important extensions to the standard function declaration to allow for the creation of interrupt handlers and reentrant functions. interrupt In writing applications for a typical computer, the operating system provides system calls for setting a function, declared in the standard manner, as the handler for an interrupt. However, in writing code for an 8051 without an operating system, such a system would not be possible using solely C code. To eliminate this problem, the Keil compiler implements a function extension that explicitly declares a function as an interrupt handler. The extension is interrupt, and it must be followed by an integer specifying which interrupt the handler is for. For example:
/* This is a function that will be called whenever a serial */ /* interrupt occurs. Note that before this will work, interrupts */ /* must be enabled. See the interrupt example in the appendix. */ void serial_int (void) interrupt 4 { ... } In the example, a function called serial_int is set as the handler for interrupt 4, which is the serial port interrupt. The number is calculated by subtracting 3 from the interrupt vector address and dividing by 8. The five standard interrupts for the 8051 are as follows: Interrupt Reset External 0 Timer 0 External 1 Timer 1 Serial Flag IE0 TF0 IE1 TF1 RI/TI Vector Address 0000 0003h 000Bh 0013h 001Bh 0023h
Other interrupts are dependent on the implementation in the particular 8051-derivative being used in the project, but may be calculated in the same manor using the vector addresses specified by the manufacturer. using Since the processor only save the current program counter before executing an interrupt handler, the handler can potentially damage any data that was in the registers prior to the interrupt. This in turn would corrupt the program once the processor goes back to where it left off. To avoid this, the Keil compiler determines which registers will be used by the interrupt handler function, pushes them out to the stack, executes the handler, and then restores the registers from the stack, before returning to the interrupted code. However, this incurs extra time, especially if a lot of registers will be used. It is preferred that as little time be spent in interrupts as possible. To decrease this time, Keil provides an optional extension, using, to the interrupt extension that tells the compiler to simple change to a new register bank prior to executing the handler, instead of pushing the registers to the stack. /* This is a function that will be called whenever a serial */ /* interrupt occurs. Prior to executing the handler, the */
/* processor will switch to register bank 1 void serial_int (void) interrupt 4 using 1 { ... } In the 8051, interrupts have two possible priorities: high and lo. If, during the processing of an interrupt, another interrupt of the same priority occurs, the processor will continue processing the first interrupt. The second interrupt will only be processed after the first has finished. However, if an interrupt of a higher priority arrives, the first (low priority) interrupt will itself be interrupted, and not resume until the higher priority interrupt has finished. Because of this, all interrupts of the same priority may use the same register bank. The using extension should be used when quick execution time is of high importance, or when other functions are called from the interrupt handler, as it would otherwise push all of the registers on to the stack prior to calling the function, incurring more time penalties. Reentrant Similar to the case described for interrupts above, it is possible for a single function to be interrupted by itself. For example, in the middle of normal execution of the function, the interrupt occurs, and that interrupt makes a call to the same function. While the interrupt handler will save the registers before entering this function, no protective measures are taken from overwriting the contents of local variables allocated in data memory. When the interrupt is serviced and control is passed back to normal execution, the corrupted data in those variables could ruin the entire program. The general term for a function that may be called more than once simultaneously is "reentrant." Accordingly, the reentrant extension may be used in a function declaration to force the compiler to maintain a separate data area in memory for each instance of the function. While safe, this does have the potential to use large area of the rather limited data memory. An example of such a function follows. /* Because this function may be called from both the main program */ /* and an interrupt handler, it is declared as reentrant to */ /* protect its local variables. */
/* The handler for External interrupt 0, which uses somefunction() */ void external0_int (void) interrupt 0 { ... somefunction(0);
/* the main program function, which also calls somefunction() */ void main (void) { while (1==1) { ... somefunction(); } }
Apart from knowing Keil Software for programming a Microcontroller we have pre-defined functions and usage of variables for interfacing LEDs, switches and LCDs. LOOPS IN C: Loops are used to repeat one statement or set statements more than one time. Most real programs contain some construct that loops within the program, performing repetitive actions on a stream of data or a region of memory. There are several ways to loop in C. For Loop For loop is a counter loop. The for loop allows automatic initialization of instrumentation of a counter variable. The general form is for (initialization; condition; increment/decrement) { statements block } If the statement block is only one statement, the braces are not necessary. Although the for allows a number of variations, generally the initialization is used to set a counter variable to its starting value. The condition is generally a relational statement that checks the counter variable against a termination value, and the increment increments (or decrements) the counter value. The loop repeats until the condition becomes false. Example Main(){ int i;
While Loop The while loop repeats a statement until the test at the top proves false. The while loop has the general form: while(condition) { statement block }
The while tests its condition at the top of the loops. Therefore, if the condition is false to begin with, the loop will not execute at all. The condition may be any expression. An example of a while follows. It reads characters until end-of-file is encountered. Example main(){ int t = 0; while(t<=10) { printf(%d\n,t); t=t+1; } } do-while loop This is very similar to the while loop except that the test occurs at the end of the loop body. This guarantees that the loop is executed at least once before continuing. Such a setup is frequently used where data is to be read. The test then verifies the data, and loops back to read again if it was unacceptable. void main(void){ int val; do { printf("Enter 1 to continue and 0 to exit :"); scanf("%d\n", &val); } while (val!= 1 && val!= 0) } SWITCH BOUNCING & DEBOUNCING: Switch debounce and switch bounce are two different things. Switch Bounce happens when you close a mechanical switch. When you close a switch it tends to literally bounce upon the metal contact which connects the circuit. It's almost like dropping a basketball. The basketball will hit then ground (analogous to a closed switch) then bounce back up (analogous to a open switch) then bounce back down, then up, then down, etc... until it permanently stays on the ground (permanently closed). Usually switches take a few microseconds to a few milliseconds to completely close. What this means in terms of digital logic is that as the switch physically bounces your logic can switch back and forth low-to-high-to-low-etc... until your switch settles down. Switch Debounce is the process of getting rid of switch bounce. One solution to get rid of switch bounce is given above by dlgoff
Figure 1: The SR debouncer The SR latch is a rather funky beast, as confusing to non-EEs as recursion is to, well, just about everyone. With the switch in the position shown the upper gate's output will be a one, regardless of the value of the other input. That and the one created by the bottom pull-up resistor drives the lower NAND to a zero, which races around back into the other gate. If the switch moves between contacts and is for a while suspended in the nether region between terminals, the latch maintains its state because of the looped-back zero from the bottom gate. The switch moves a rather long way between contacts. It may bounce around a bit, but will never bang all the way back to the other contact. Thus, the latch's output is guaranteed bounce-free. The circuit suggests an alternative approach, a software version of the same idea. Why not skip the NAND pair and run the two contacts, with pull-ups, directly to input pins on the CPU? Sure, the computer will see plenty of bounciness, but write a trivial bit of code that detects any assertion of either pole, which means the switch is in that position, as follows: if(switch_hi())state=ON; if(switch_lo())state=OFF; The functions switch_hi and switch_lo each read one of the two poles. Other functions in the program examine variable stateto determine the switch's position. This saves two gates but costs one extra input pin on the processor. It's the simplestand most reliabledebounce code possible. (OK, so I slipped some code in after all). An RC debouncer The SR circuit is the most effective of all debouncing approaches but it's rarely used. Double-throw switches are bulkier and more expensive than the simpler single-pole versions. An awful lot of us use switches that are plated onto the circuit board, and it's impossible to make double-pole versions of these. So EEs prefer alternative designs that work with cheap single-pole switches.
Though complex circuits using counters and smart logic satisfy our longing for pure digital solutions to all problems, from signal processing to divorce, it's easier and cheaper to exploit the peculiar nature of a resistorcapacitor (RC) network. Charge or discharge a capacitor through a resistor and you'll find the voltage across the cap rises slowly; it doesn't snap to a new value like a sweet little logic circuit. Increase the value of either component and the time lag ("time constant" in EE lingo) increases. Figure 2 shows a typical RC debouncer. A simple circuit, surely, yet one that hides a surprising amount of complexity.
8051 Architecture:
LCD : The most commonly used Character based LCDs are based on Hitachi's HD44780 controller or other which are compatible with HD44580. In this tutorial, we will discuss about character based LCDs, their interfacing with various microcontrollers, various interfaces (8-bit/4-bit), programming, special stuff and tricks you can do with these simple looking LCDs which can give a new look to your application. The most commonly used LCDs found in the market today are 1 Line, 2 Line or 4 Line LCDs which have only 1 controller and support at most of 80 charachers, whereas LCDs supporting more than 80 characters make use of 2 HD44780 controllers. Most LCDs with 1 controller has 14 Pins and LCDs with 2 controller has 16 Pins (two pins are extra in both for back-light LED connections). Pin description is shown in the table below.
Pin No. Pin no. 1 Pin no. 2 Pin no. 3 Pin no. 4
Description Power supply (GND) Power supply (+5V) Contrast adjust 0 = Instruction input 1 = Data input 0 = Write to LCD module 1 = Read from LCD module Enable signal Data bus line 0 (LSB) Data bus line 1 Data bus line 2 Data bus line 3 Data bus line 4
Pin no. 5 Pin no. 6 Pin no. 7 Pin no. 8 Pin no. 9 Pin no. 10 Pin no. 11
R/W EN D0 D1 D2 D3 D4
D5 D6 D7
Data bus line 5 Data bus line 6 Data bus line 7 (MSB)
Pin No. Pin no. 1 Pin no. 2 Pin no. 3 Pin no. 4 Pin no. 5 Pin no. 6 Pin no. 7 Pin no. 8 Pin no. 9 Pin no. 10
Description Data bus line 7 (MSB) Data bus line 6 Data bus line 5 Data bus line 4 Data bus line 3 Data bus line 2 Data bus line 1 Data bus line 0 (LSB) Enable signal for row 0 and 1 (1stcontroller) 0 = Write to LCD module 1 = Read from LCD module 0 = Instruction input 1 = Data input Contrast adjust Power supply (GND) Power supply (+5V) Enable signal for row 2 and 3 (2ndcontroller) Not Connected
Pin no. 11 Pin no. 12 Pin no. 13 Pin no. 14 Pin no. 15 Pin no. 16
Designate LCD functions, such as display format, data length, etc. Set internal RAM addresses Perform data transfer with internal RAM Perform miscellaneous functions
Although looking at the table you can make your own commands and test them. Below is a breif list of useful commands which are used frequently while working on the LCD.
No. Instruction
Hex
Decimal
1 2 3 4
Function Set: 8-bit, 1 Line, 5x7 Dots Function Set: 8-bit, 2 Line, 5x7 Dots Function Set: 4-bit, 1 Line, 5x7 Dots Function Set: 4-bit, 2 Line, 5x7 Dots
48 56 32 40
5 6 7 8 9 10 12 13 14 15 16 17
Entry Mode Display off Cursor off (clearing display without clearing DDRAM content) Display on Cursor on Display on Cursor off Display on Cursor blinking Shift entire display left Shift entire display right Move cursor left by one character Move cursor right by one character Clear Display (also clear DDRAM content) Set DDRAM address or coursor position on display Set CGRAM address or set pointer to CGRAM location
0x06 0x08 0x0E 0x0C 0x0F 0x18 0x1C 0x10 0x14 0x01
6 8 14 12 15 24 30 16 20 1
Table 4: Frequently used commands and instructions for LCD * DDRAM address given in LCD basics section see Figure 2,3,4 ** CGRAM address from 0x00 to 0x3F, 0x00 to 0x07 for char1 and so on.. The table above will help you while writing programs for LCD. But after you are done testing with the table 4, i recommend you to use table 3 to get more grip on working with LCD and trying your own commands. In the next section of the tutorial we will see the initialization with some of the coding examples in C as well as assembly.