You are on page 1of 24

Call Us +33 555 358 028

Products

o





o





o


o
o


Software

Blog

o
o
o
o
o
o

Forum

Contact us

o
o
o

Online store

Part 2: C programming for 8051 using KEIL IDE
Posted on May 8, 2008, by Ibrahim KAMAL, in Micro-controllers, tagged

If not simpler, the version of the C programming language used for the microcontroller environment is not very
different than standard C when working on mathematical operations, or organizing your code. The main difference is
all about the limitations of the processor of the 89S52 microcontroller as compared to modern computers.

however. it takes several steps depending on the tool you are using.A shows that to convert a C program to machine language.A There are several types of HEX files. you will have to refer to the following table: Data Type bit signed char unsigned char signed int unsigned int Bits 1 8 8 16 16 Bytes – 1 1 2 2 Value Range 0 to 1 -128 to +127 0 to 255 -32768 to +32767 0 to 65535 .1.Even if you’re not very familiar with the C language. Logically. the main idea is to produce a HEX file at the end. that why they are called HEX files. Variables and constants Variables One of the most basic concepts of programming is to handle variables. This machine language is basically just zero’s and one’s and is written in Hexadecimal format. a variable that occupies a big number of registers in RAM will be more slowly processed than a small variable that fits on a single register. knowing the exact type and size of a variable is a very important issue for microcontroller programmers. figure 2. From the C program to the machine language The C source code is very high level language. There are two main design considerations to be taken in account when choosing the variables types: the occupied space in ram and the processing speed. meaning that it is far from being at the base level of the machine language that can be executed by a processor. because the RAM is usually limited is size. we are going to produce machine code in the INTEL HEX-80 format. Figure 2. since this is the output of the KEIL IDE that we are going to use. this tutorial will introduce all the basic programming techniques that will be used along this tutorial. It will also show you how to use the KEIL IDE. This HEX file will be then used by the ‘burner’ to write every byte of data at the appropriate place in the EEPROM of the 89S52. For you to chose the right variable type for each one of your applications.1.

but both will occupy the same exact space in memory. the program is trying to store ‘-100 ′ in ‘c’. the results can be sometimes totally un-expected. from ’255 + 1′ giving ’156′. signed char d. any code line is ended with a semicolon ‘. example: display[0] = 100. On the other hand. Note that in the C programming language. d = a . because it is a ‘signed’ variable. noting that each byte will fit into a register. and the major difference between the two types is the range.’.175494E-38 to ±3. The names of the variables shown in the table are the same that are going to be used in the program for variables declarations. Each one of them is accessible by its number.c. its range of values is from ’0 to 255′ so. b = 200. any variable have to be declared to be used. and one ‘signed char’ and then perform some simple operations: unsigned char a. each one can be called by a specific number. c = a . will attribute a specific location in the RAM or FLASH memory to that variable. and when a the value to be stored in a variable is bigger than the maximum value range of this variable. for example an array can be declared this way: char display[10]. the concept of a variables ‘array’ can also be used for microcontrollers programming. will cause the the variable to overfow. This will create a group of 10 variables. trying to store a value below zero.402823E+38 This table shows the number of bits and bytes occupied by each types of variables. Like in any programming language. To understand the difference between those types. it overfows and rolls back to the other limit. because sometime. but since ‘c’ is unsigned. The size of that location will depend on the type of the variable that have been declared. even if the compiler doesn’t halt on that error. Generally. You will notice that most variables can be either ‘signed’ or unsigned ‘unsigned’. Back to our example. .b. because the variable ‘c’ is an unsigned type. Declaring a variable. except for the lines ending with brackets ‘{‘ ‘}’. Note that in C programming language. and the compiler will subtract the ‘-100′ from the other limit plus 1.b. consider the following example source code where we start by declaring three ‘unsigned char’ variables. We add 1 to the range because the overfow and roll back operation from 0 to 255 counts for the subtraction of one bit.signed long unsigned long float 32 32 32 4 4 4 -2147483648 to 2147483647 0 to 4294967295 ±1. we try to avoid storing value that are out of range.b. an array is like a table or a group of variables of the same type. a = 100. In that program the values of ‘c’ will be equal to ’155′! and not ‘-100′ as you though. the value of ‘d’ will be equal to ‘-100′ as expected.

you cannot change a constant's value in code. P1. There are four ports. meaning that the compiler will use this directive to read and understand the code. each time you write led_on_time. especially when the new names you give make more sense. You could also define a numeric constant value like this: #define led_on_time 184 Then. you could define the following: #define LED1 P1_0 With the definition above. This can be interesting for displaying messages on an LCD screen. as you shall see later) that dramatically simplifies that task. This line would cause this huge array to be stored in the FLASH memory. and using it will cause an error in the compiler. . where X takes a value between 0 and 3. you want to store a very large amount of constant values. you can access a single pin of a port using the bit type variables PX_0 to PX_7. using the ‘#define’ directive. 32 times bigger than the RAM memory. For example. You can also define your own names. To specify that a variable is to be stored in the FLASH memory. there are a number of pre-defined variables (defined in the header file. Note that this is compiler directive. //That's wrong. P2 and P3 respectively. Note that ‘display’ contains 10 different variables. you cannot write something like: led_on_time = 100. that wouldn’t fit in the RAM or simply would take too much space. In those char types variables. but it wont be editable. This makes your code much more easier to read. In that previous example. Where ‘display[1]‘ will be equal to ’40′. there is not such variable location as ‘display[10]‘. we use exactly the same variable types names but we add the prefix ‘code’ before it. once the program is burned on your chip. noting that the FLASH memory of the 89S52 is 8K bytes. display[1] = display[0] . Constants Sometimes. it will be replaced by 184. To access the pins and the ports through programming.display[3]. the compiler will replace every occurrence of LED1 by P1_0. but it is not a statement or command that can be translated to machine language. each one of the 8 bits represents a pin on the port. Port 0 to Port 3. Additionally. Note that this is not a variable and accordingly. your responsibility to distribute this memory between your program and your DATA. For example P1_3 is the pin number 3 of port 1. It is.display[3] = 60. each one of them can be accessed using the char variables P0. Example: code unsigned char message[500]. numbered from 0 to 9. The advantage of this technique is that it can be used to store a huge amount of variables. according to the variable declaration. you can store this DATA in the FLASH memory reserved for the code. depending on the port being accessed. however.

that’s for sure apart from the fact that a word like led_on_time is much more comprehensive than simply ‘184‘! Along this tutorial you will see how port names. it is time to know how to handle them in your program using mathematical and logic operations.'-’. the cosine function. Mathematical & logic operations Now that you know how to declare variables. for example. and you can read the line: extern foat cos (foat val). you will be able to use more advanced functions in your equations like Sin. To be able to successfully use those functions in your programs.h’ file itself. you have to know the type of variables that those functions take as parameter and return as a result. You can usually know those data types from the ‘math.'*’ and ‘/’. You can then perform all kind of mathematical operations. using the operators ‘+’. from this line you can deduce that the ‘cos’ function returns a foat data type. you only change it’s value once.). Cos and Tan trigonometric functions. If you include ‘math. is the ‘=’ operator which is used to store the content of the expression at its right. absolute values and logarithmic calculations like in the following example: a =(c*cos(b))+sin(b). and takes as a parameter a foat too. Since 5 in a constant. Example: a =(5*b)+((a/b)*(a+b)). You can also use brackets ‘( )’ when needed. the following table shows a short description of those functions: .The utility of using defined constants. appears when you want to adjust some delays in your code. For example a Cosine function takes an angle in radians whose value is a foat number between -65535 and 65535 and it will return a foat value as a result. And subsequently. (the parameter is always between brackets. trying to store the content of ‘b’ in it will cause an error. counters and interrupts. and it’s applied to the whole code. you can easily know how to deal with the rest of the functions of the math header file. Using the same technique. For example the following code will store the value of ‘b’ into ‘a’ : a = b. into the variable at its left. to control input/output operations and other features of the microcontroller like timers. or some constant variables that are re-used many times within the code: With a predefined constant. like all the others is declared in the top of the math header file. the following expression in totally invalid: 5 = b. and special function registers are used exactly as variables.h’ header file. Mathematical operations The most basic concept about mathematical operations in programming languages.

Function char cabs (char val). NOT (byte level) Example: P1 = ~P1. float log (float val). float pow (float x. For example. Those logic operators can be used in many ways to merge different bits of different registers together. It is required in that example to clear the four lower bits of that register without changing the state of the four other which may be used by other equipment. float acos (float val). using the following operators: Operator ! ~ & | Description NOT (bit level) Example: P1_0 = !P1_0. Calculates the smallest integer that is bigger than val. Returns the value of the Euler number ‘e’ to the power of val Returns the natural logarithm of val Returns the common logarithm of val A set of standard trigonometric functions. Description Return an the absolute value of a char variable. Return an the absolute value of a int variable. int abs (int val). Returns the square root of a float variable. Actually P1 is an SFR. For example. float asin (float val). float sin (float val). float exp (float val). float fmod (float x. float sqrt (float val). This can be done using logical operators according to the following code: . float atan (float val). float floor (float val). Returns the remainder of x / y. float log10 (float val). This function calculates the arc tan of the ratio y / x. OR and NOT operations. Return an the absolute value of a float variable. consider the variable ‘P1′. a NOT operation will invert all the bit of a register. They all take angles measured in radians whose value have to be between -65535 and 65535. and hence stored in an 8-bit register. Example: ceil(4. float cos (float val).0. long labs (long val). float fabs (float val). For example: fmod(15. Return an the absolute value of a long variable. float tanh (float val).8) = 4. float y). To understand the effect of such operation on registers. using the signs of both x and ytodetermine the quadrant of the angle and return a number ranging from -pi to pi. float cosh (float val). Returns x to the power y. float y). Logical operations You can also perform logic operations with variables. like AND. Calculates the largest integer that is smaller than val. which is of type ‘char’. AND OR Note that those logic operation are performed on the bit level of the registers. float tan (float val). Example: ceil(4.0) = 3. whose 8 bits represents the 8 I/O pins of Port 1. it’s easier to look at the bits of a variable (which is composed of one or more register).4. float x). float sinh (float val). float ceil (float val).3) = 5. float atan2 (float y.

in binary. By the way. It can be useful the shift the bit of a register the right or to the left in various situations. in binary P1 = 1000 0000 You can clearly notice that the content of P1 have been shifted 8 steps to the left. note that you could also perform the same operation using a decimal variable instead of a hexadecimal one. the value of P1 is ANDed with the variable 0xF0. Recalling the two following relations: 1 OR 0 OR (where ‘X’ can be any binary value) X X = = 1 X You can deduce that the first and last pins of P1 will be turned on. while the four lower bits will be cleared to 0. for example. the following code will have exactly the same effect than the previous one (because 240 = F0 in HEX): P1 = P1 & 240. //Adding '0x' before a number indicates that it is a hexadecimal one Here. without affecting the state of the other pins of port 1. Logic operators can also be used to define very specific conditions. as you shall see in the next section. without affecting the other. for example: P1 = 0x01. P1 = 0000 0001 P1 = (P1 << 7) // After that operation. // After that operation. P1 is ORed with the value 0×81. the following source code can be used: P1 = P1 | 0x81. which in the binary base is ’11110000 ′. Recalling the two following relations: 1 AND 0 AND (where ‘X’ can be any binary value) X X = = X 0 You can deduce that the four higher bits of P1 will remain unchanged. which is ’10000001′ in binary. to set the first and last bit of P1. Here. Those are just a few example of the manipulations that can be done to registers using logical operators. A similar types of operations that can be performed on a port. is to to set some of its bits to 1 without affecting the others.P1 = P1 & 0xF0. For example. The last types of logic operation studied in this tutorial is the shifting. this can be done using the following two operators: Operator >> << Description Shift to the right Shift to the left The syntax is is quite intuitive. Conditions and loops .

Not equal to The ‘If’ code block can get a little more sophisticated by introducing the ‘else’ and ‘else if’ statement. so pay attention.. >= != Description Equal to Smaller than. and otherwise execute another code block or continue with the fow of the program. to differentiate between different situations. it is required at a certain time. All the above situation describe an indispensable aspect of programming: ‘conditions’. it can save you lot of debugging time. the code block is only executed if both the two expressions are true. this error wont generate any alert from the compiler and is very hard to identify in a big program. } It is important to see how the code is organized in this part. In other words. would cause the the compiler to store 0 in P1. Otherwise it is clear that in that previous example. writing this expression with only one equal sign. as you can see in the following example: if ( (P1 == 0) & (a <= 128) ){ . or to direct the fow of the code depending on some criteria. to make decision according to specific input.. bigger than or equal to. } Notice the use of the two equal signs (==) between two variables or constants.. the code block is all delimited by the two brackets ‘{‘ and ‘}’. The ‘expression’ is the condition that shall be valid for the ‘code block’ to be executed.. The most famous way to do that is to use the ‘if’ statement. all the code between those two brackets will be executed if and only if the expression is valid.. code to be executed . bigger than. This issue is a source of logical error for many beginners in C language.. In C language.. according to the following syntax.. The expression can be any combination of mathematical and logical expressions. if (expression) { . this feature allows to execute a block of code only under certain conditions. In other words.. > <=. code block 1 .In most programs. Smaller than or equal to. Observe the following example source code: if (expression_1) { .. this means that you are asking whether P1 equals 0 or not. code to be executed . Here is a list of all the operators you can use to write an expression describing a certain condition: Operator == <.

Another very important tool in the programming languages is the loop. The code will keep looping as long as the . which is completely logical. }else if(expression_3) { . code block 3 ... } Here. Let’s start with the ‘for’ code block. There are some other alternatives to the ‘if…else’ code block.. }else if(expression_2) { .. it is enough to understand the ‘if…else’ code block. consider the following example source code: for(i=0.. each time with the counting variable ‘i’ increasing by 1 according to the statement ‘i++’... which is a highly controllable and configurable loop. loops are usually restricted to certain number of loops like in the ‘for’ code block or restricted to a certain condition like the ‘while’ block. whose performance is quite fair and have a wide range of applications. The last code block will only be executed if none of the previous expression is valid. that can provide faster execution speeds. but also have some limitations and restrictions like the ‘Select…case’ code block. only one shall be executed if and only if the corresponding condition is true... In C language like in many others.i<10... } Here the code between the the two brackets ‘{‘ ‘}’ will be be executed a certain number of times.. }else{ . code block 4 . However you can chose not to have and ‘else’ block at all if you want. code block 2 .. For now.. each one with its corresponding condition.. There are four different code blocks.i++){ P0 = i. BUT you can only have one ‘else’ block. Note that you can have as many ‘else if’ blocks as you need.

reducing its size... The second type of loop that we are going to study is the ‘while’ loop. it can be any statement that changes its value.. which is the condition to keep this loop alive. The ‘for’ loop functioning can be recapitulated by the following syntax: for(start.. that is equivalent to the previous method: while(i < 10){ P0 = i. as long as this conditions is satisfied.. } Where start represents the start value assigned to the count value before the loop begins.condition. it is the responsibility of the programmer to design the software carefully to provide an exit for that loop. return value //optional . which makes the particularity of this loop. step is the increase or decrease of the counting variable. Parameter_3){ ... Then. Finally.. or to make it an infinite loop. and increasing its overall performance. } . as you shall see later on along this tutorial.. code block . whether by an addition or subtraction. i = i +1. by grouping relatively small parts of code to be reused many times in the same program.step){ . Parameter_2.. the syntax of this one is simpler than the previous one. The condition is the expression that is is to remain true for the loop to continue. the code will keep looping. function body . Usually the counting value ‘i’ is reused in the body of the loop.condition ‘i<10′ is true. which is ‘i < 10 ′ in our example. A new function can be created according to the following syntax: Function_name(parameter_1. Both techniques are commonly used in microcontroller programs. as you can observe in the following example source code. Functions Functions are way of organizing your code. } Here there is only one parameter to be defined.

as all the trigonometric functions that are included by default take angles in radians. The function’s body is usually a sub program that implies the parameters to produce the required result. retrun rad. is a function that will calculate the angle in radian of a given angle in degrees.14)/180. } } In this last piece of code a function named ‘delay’ is created.18° . this line of code would cause the program to pause for approximately one second on a 12 MHz clock on a 8051 microcontroller. A common example of a function with a return value.This is the general form of a function. This function can be as the following: deg_to_rad(float deg){ float rad. the function will repeat a loop for a couple hundreds or thousand of times to generate precise delays in a program. and implying a locally defined unsigned int ‘i’. like the cos() function. rad = (deg * 3. through the ‘return’ command.i++){ . } This function named ‘deg_to_rad’ will take as a parameter an angle in degrees and output an angle in radians. A very common use of functions without return value is to create delays in a software. and where will be stored the value returned by the function.18). Usually the ‘return’ command is used at the end of the function. as it can be zero. which will output the value next to it. It can be called in your program according to this syntax: angle = deg_to_rad(102. consider the following function: delay(unsigned int y){ unsigned int i. some functions will also generate an output. all depends on the type and use of the function. The number of parameters of the function can be more than the three parameters of the examples above.i<y. with an unsigned integer ‘y’ as a parameter. A function like this can be called from anywhere in the program according to the following syntax: delay(30000). which is the angle in radians equivalent to 102. Where angle should be already defined as a foat. for(i=0.

. D. Variables declared in this place can be used anywhere in the code. noting that is should be written in this order: A. and is written like this: main(){ . Variables declarations More precisely. Functions’ body Here you group all your functions. C. those headers files can be system headers to declare the name of SFRs.Another important note about functions in the ‘main’ function. as they can be called from an ‘interrupt vector’. but they consume more memory space. . Header files can also contain your own functions that would be shared by various programs. Any application can be divided into the following parts. B. This particularity makes it the perfect place in a program to initialize the values of some constants. interrupts. sometimes it’s not. root square calculations or numbers approximations. it were the execution will start after a reset operation. whose values will be lost each time you switch from a function to another. or to define the mode of operation of the timers. global variables as easier to use and implement than local variables. sometimes it’s followed. code of the main functions .. variables are declared as global variables instead of local variables. for microcontrollers. } Organization of a C program All C programs have this common organization scheme. to define new constants. more precisely. header files (. The ‘main’ function has no parameters. this part is dedicated to ‘Global Variables’ declarations. In other words. or when a microcontroller circuit is turned ON. the sub-programs to be executed when an interrupt occurs is also written in this place.h) are included into your source code.. then the processor continue executing the rest of the program but never executes this part again. so we use local variables. and other features of the microcontroller. Any C program must contain a function named ‘main’ which is the place where the program’s execution will start. To summarize. Headers Includes and constants definitions In this part. Usually in microcontroller programs. Initialization The particularity of this part is that it is executed only one time when the microcontroller was just subjected to a ‘RESET’ or when power is just switched ON. it is imperative for this category of programming that this organization scheme be followed in order to be able to develop your applications successfully. counters.. Those functions can be simple ones that can be called from another place in your program. however. or to include mathematical functions like trigonometric functions. unless your are running short of RAM memory and want to save some space.

the pin number 0 of port 1 is constantly turned ON and OFF with a delay of approximately one second.h> delay(unsigned int y){ unsigned int i. Infinite loop An infinite loop in a microcontroller program is what is going to keep it alive. Actually it is the source code of the example project that we are going to construct in the next part of the tutorial. You can can download an evaluation . delay(30000). P1_0 = 0. A simple circuit can be constructed and a LED can be connected to the pin P1_0 to see how software and hardware adjustments can affect the behavior of you circuits. a function named ‘delay’ is created. } } After including basic headers for the SFR definitions of the 8952 microcontroller (REGX52. with an infinite loop (the condition for that loop to remain will always be satisfied as it is ’1′). P1_0 = 1.h) and for mathematical functions (math. Inside that loop. because a processor have to be allays running for the system to function.i<y. Using the KEIL environment KEIL uVision is the name of a software dedicated to the development and testing of a family of microcontrollers based on 8051 technology. #include <REGX52.h). exactly like a heart have to be always beating for a person to live. for(i=0.} } main(){ while(1){ delay(30000). and its from here that all the other functions are called and executed. Usually this part is the core of any program.h> #include <math. which is simple a function to create a delay controlled via the parameter ‘y’. like the 89S52 which we are going to use along this tutorial. Then comes the main function. but for now it is important to concentrate on the programming to summarize the notions discussed above. Simple C program for 89S52 Here is a very simple but complete example program to blink a LED.i++){. As you will see in the next part.E.

chose a name and click save. this tutorial uses KEIL C51 uVision 3 with the C51 compiler v8.com/c51/.05a. Most versions share merely the same interface. follow the following steps:  Open Keil and start a new project: 2. where you will be asked to select a device for Target ‘Target 1′: . The following window will appear. write and test the previous example source code.8. Create a separate folder where all the files of your project will be stored.A  You will prompted to chose a name for your new project.version of KEIL at their website: http://www.keil. To create a project.

The AT89S52 will be called your ‘Target device’. select AT89S52.  Click File.B  From the list at the left. New. The box named ‘Text1′ is where your code should be written later. . and something similar to the following window should appear.figure 2. seek for the brand name ATMEL. which is the final destination of your source code. then under ATMEL. You will be asked whether to ‘copy standard 8051 startup code‘ click No. Leave the two upper check boxes unchecked and click OK.8. You will notice that a brief description of the device appears on the right.

and click save.C  Now you have to click ‘File.c’.figure 2.8. Then you have to add this file to your project work space at the left as shown in the following screen shot: . Save as’ and chose a file name for your source code ending with the letter ‘. You can name is ‘code.c’ for example.

then under the ‘output‘ tab. then you will be prompted to browse the file to add to ‘source group 1′. make sure it is turned ON. by checking the box ‘generate HEX file‘. eventually ‘code.  In some versions of this software you have to turn ON manually the option to generate HEX files. chose the file that you just saved. .8.figure 2. This step is very important as the HEX file is the compiled output of your project that is going to be transferred to the micro-controller. Options for target ‘target 1′. by right-clicking on target 1. click on ‘Add files to group…‘.D  After right-clicking on ‘source group 1‘. You will notice that the file is added to the project tree at the left.c’ and add it to the source group.

this step is called Debugging. If after rebuilding the targets. You can then start to write the source code in the window titled ‘code. and correct eventual syntax errors. the ‘output window’ shows that there is 0 error. and has this icon: . figure 2. then you are ready to test the performance of your code. In KEIL.8. After clicking on the debug icon. you will notice that some part of the user interface will change. like in most development environment. like the run icon circled in the following figure: .E  You can use the output window to track eventual syntax errors. but also to check the FLASH memory occupied by the program (code = 49) as well as the registers occupied in the RAM (data = 9).c’ then before testing your source code. In KEIL IDE. you have to compile your source code. this step is called ‘rebuild all targets’ and has this icon: . some new icons will appear.

but clicking on ‘peripherals.8.  You can also control the execution of the program using the following icons: which allows you to follow the execution step by step. and the more important of them will be presented along the rest of this tutorial. There are many other features to discover in the KEIL IDE. You will easily discover them in first couple hours of practice. you can see the behavior of the pin 0 or port one. you can always return to the programming interface by clicking again on the debug button ( ).F  You can click on the ‘Run’ icon and the execution of the program will start.figure 2. In our example. when you’re finished with the debugging. Then. You can always stop the execution of the program by clicking on the stop button ( ) and you can simulate a reset by clicking on the ‘reset’ button . . Port 1′. I/O ports.

2014 at 11:12 am Sir I want to make a Program in keil for seven segment by using a button ….This concludes this second part of the 89S52 tutorial. Required fields are marked * Name * Email * Website . REPLY Leave A Comment Connect with: Your email address will not be published. I now invite you to start building a real hardware project in the next part. Previous part: Introduction to 8051 micro-controllers  ← Previous Post  Comments Next part: Basic input/output operations Next Post → (1)  Akshay says: July 6.When i press button 1 digit should show and again if i press button 2 digit should show and so on can u tel me the programing code to how to use button as toggle….

Post Comment Search .

We’ve just released a native version of ScanaStudio for Mac OS X. As of version 2.304 have been out for a couple of days now.  ScanaStudio for Mac OS X Well. we hate spam too! Subscribe Unsubscribe Recent PostsVISIT THE BLOG  Introducing Bus View for ScanaStudio Scanastudio V2. and I didn’t get the time to properly highlight its top features. the title says it all.Newsletter Enter your email address below: GO It's cool. and I though i would share that with our  .303.000 of  Sniffing CMOS camera initialization sequence! Yesterday at work i did a really cool thing with the new Hex View feature of ScanaStudio.

co/dd079VA6Mf © 2012+ IKALOGIC S.  Home  Blog  Contact us  About IKALOGIC  Legal information . FFT analysis.co/4eGT6hEscV  Inviting you into the brainstorming of the oscilloscope of the futurehttps://t.Packet View & HEX View We are glad to announce our all new addition to ScanaStudio: The Packet view and HEX view. RT if your followers use oscilloscopes!  Scanastudio V2.A.co/VuiXOfOc3q.304 out! BUS view.co/oUkQoUnAuShttp://t.S. This feature is so useful that we Our lastest tweets @ikalogic  RT @simonmonk2: Review: Scana Plus Logic Analyzer from @ikalogichttp://t. and some bug fixes! http://t. Manual channel reordering.