The last part is the code that is to be executed and belongs to the main function. Curly brackets { } define the beginning and end of the function. This example contains only one print statement to be executed. Note how the code within the curly brackets is indented (using a tab or spaces) to show that it belongs to the main function block. This indentation is not required but helps readers see the program structure. Instructions must end with a semicolon ';'. Double forward slashes allow comments to be added at the end of an instruction. The include statement has a # symbol in front of it.
<pre class="brush:c"><span style="color: #000000;">#include "KMotionDef.h"</span>
main()
{
}</pre>
Note: You can use our Code Indent and Beautifier in our latest Test Version 4.35a. See detailed [http://www.dynomotion.com/Help/ProgramScreen/ShowContextMenu.htm help] or our [https://www.youtube.com/watch?v=CsIijoLMq8U C Code Indent and Code Beautifier video].
.
===<span id="C Variables" class="mw-headline">C Variables</span>===
C Programs can declare and use various types of variables. Variables are used to store information. A variable '''must be declared''' to tell the compiler what type it is '''before''' it can be used.
3 common types of variables are:
'''int''' - 32 bit signed integer (whole numbers only)
'''float''' - 32 bit floating point number (~7 digits of precision)
'''double''' - 64 bit floating point number (~16 digits of precision)
Variables can be declared to be '''local''' or '''global'''. "Local" variables are declared inside of any function (including main). Their "scope" is limited to the function they are declared within. They are allocated into stack memory and are created when the function is entered and discarded when the function exits.
The Add function below declares a local variable c as an integer.
<pre class="brush:c">// Example to add 2 integer numbers
void Add(int a, int b)
{
int c; // declare a local integer variable
c = a + b; // add the integer numbers
printf("sum = %d\n", c); // print the sum
}</pre>
"Global" variables are declared outside of any function usually toward the beginning of the program after any included files. Their "scope" is the entire C Program. They are allocated into static memory and are created when the Program begins and discarded when the Program exits.
The code below declares a global integer variable c outside the Add Function
<pre class="brush:c">int c; // declare a global integer variable
// Example to add 2 integer numbers
void Add(int a, int b)
{
c = a + b; // add the integer numbers
printf("sum = %d\n", c); // print the sum
}</pre>
The advantage of Local variables is that the same name can be used in different functions for different purposes without conflict.
The advantage of Global variables is that the value persists for the life of the program and the scope of the entire program and so its value can be read/written from multiple functions or multiple executions of the same function.
Below is a program with duplicated code. It performs the same 3 similar operations on 3 different axes to Enable, Move, and Wait an Axis. Notice the same operations are performed each time with only two differences: the Axis and the distance moved. So by using a function with two parameters we can replace the 3 instructions with a single function call. The first parameter is which Axis which is an integer value. The second parameter is the distance to move which is a double precision value.
<pre class="brush:c">#include "KMotionDef.h"
main()
{
Now declaring a function named EnableMoveWait with 2 parameters (and void return value) we can simplify the C Program, lessen the number of total instructions in the program, and most importantly guarantee that the exact same operations are performed for each axis.
<pre class="brush:c">#include "KMotionDef.h"
// define function to Enable, Move, and wait with two parameters
It is often desirable to place the functions toward the end of file with the main starting point of the program toward the beginning. This tends to make the program more readable and logical. This is not necessary but more a personal preference. Because the C Compiler only reads the program one time from beginning to end it is good to place at the beginning a description of any Functions that exist in the program. The allows the compiler to know the names of any functions and what parameter and return value types they have before they are used in the program. It is critical that the parameters passed in the call to the function are the exact correct number and type that are defined to be used by the function itself. So to inform the compiler of what function to expect a "function prototype" is specified. This is exactly the same as the function declaration itself except with no body of instructions. It consists of only one line followed by a semicolon to indicate it is only a prototype and not the entire function. See the Program below that has the function moved below the main function and with a function prototype at the beginning:
<pre class="brush:c">#include "KMotionDef.h"
// define function prototype of function to expect later
===<span id="Simple_DiskReadWrite.c_example" class="mw-headline">Simple DiskReadWrite.c example</span>===
include "KMotionDef.h"<br /><br />main()<br />{<br /> FILE *f;<br /> char s[256];<br /> double a=123.456,b=999.999,c=0.001;<br /> double x=0,y=0,z=0;<br /> int result;<br /> <br /> // write 3 comma separated values to a disk file<br /> f=fopen("c:\\Temp\\KFlopData.txt","wt");<br /> fprintf(s,"%f,%f,%f\n",a,b,c);<br /> fclose(f);<br /> <br /> // read them back in<br /> f=fopen("c:\\Temp\\KFlopData.txt","rt");<br /> if (!f)<br /> {<br /> printf("Unable to open file\n");<br /> return;<br /> }<br /> <br /> // read a line and convert 3 doubles<br /> result=fscanf(f,"%lf,%lf,%lf",&x,&y,&z);<br /> fclose(f);<br /> <br /> printf("# values converted = %d, x=%f, y=%f, z=%f\n",result,x,y,z);<br />}
==Data/Motion Capture with a C Program==
A C Program can be used to capture real-time data to KFLOP's gather buffer, then upload the data to a PC Disk File, and then be analyzed using a PC App such as Microsoft Excel. This can be a very powerful method used to troubleshoot problems such as those involving complex GCode trajectories. See the many Capture examples (Whose names begin with "Capture").
Here is a [https://www.dynomotion.com/wiki/index.php?action=ajax&title=-&rs=SecureFileStore::getFile&f=/4/44/CaptureXYZMotionToFileWithHeader.c CaptureXYZMotionToFileWithHeader.c] example which captures the xyz trajectory:
<pre class="brush:c">#include "KMotionDef.h"
#define N 5000
extern double CS0_TimeExecuted;
main()
{
int i,k;
double X0,Y0,Z0,T0,*p=gather_buffer;
CS0_TimeExecuted=0.0;
while (CS0_TimeExecuted==0.0) ; // wait till we Start
*p++ = 0.0;
X0 = *p++ = ch0->Dest;
Y0 = *p++ = ch1->Dest;
Z0 = *p++ = ch2->Dest;
T0 = Time_sec();
// Capture Data
for (i=0; i<N-1; i++)
{
for (k=0; k<2; k++) WaitNextTimeSlice(); *p++ = Time_sec() - T0; *p++ = ch0->Dest;
*p++ = ch1->Dest;
*p++ = ch2->Dest;
}
p=gather_buffer;
FILE *f=fopen("C:\\temp\\kflopdata.txt","wt");
fprintf(f,"T,X,Y,Z\n"); // Header
for (i=0; i<N; i++)
{
// round times to nearest servo tick
p[0] = ((int)(p[0]/TIMEBASE + 0.5))*TIMEBASE;
fprintf(f,"%16.9f,%16.6f,%16.6f,%16.6f\n",p[0],p[1],p[2],p[3]);
p += 4;
}
fclose(f);
}
</pre>
Note the data is written to the file C:\temp\kflopdata.txt. So the folder C:\temp must exist.
Note double backslashes are used in C Programs to insert a single slash as a slash operates as a means of inserting special characters such as the newline character \n.
N determines how many samples are saved.
The gather_buffer is 8MBytes so is limited to 1 million doubles. This program captures 4 doubles per sample x 5000 samples = 20000 doubles.
The 2 in this line sets the number of Time Slices occur between samples. The number must be 1 or more.
<pre class="brush:c"> for (k=0; k<2; k++) WaitNextTimeSlice(); </pre>
The C Program can be assigned to an MCode so it can be executed from GCode
[[File:M100_Capture.png|none|link=]]
This GCode Executes the C Program then moves in a square
'''M100 (Trigger Capture)'''<br />'''G4 P0.1 (Wait till loaded)'''<br />'''G0 G20 X0 Y0 Z0'''<br />'''F100'''<br />'''G1 X0 Y1'''<br />'''G1 X1 Y1'''<br />'''G1 X1 Y0'''<br />'''G1 X0 Y0'''<br />'''M2'''
This is an example Microsoft Excel spreadsheet to Import (refresh) the data from a file, compute velocities and acceleration from the time/posistions, and chart the data.
[https://www.dynomotion.com/wiki/index.php?action=ajax&title=-&rs=SecureFileStore::getFile&f=/b/b6/PlotCaptureXYZwithHeader.xlsx PlotCaptureXYZwithHeader.xlsx]
Here is an example of charted data
[[File:XY_Vel_plot_example_from_Excel.png|none|link=]]
int PC_comm[N_PC_COMM_PERSIST];// 8 persist Variables constantly uploaded to send misc commands/data to PC
==Threads and KMotion.exec C Programs Screen==
==C Program Size and Stack Limitations==
Each of the first 6 User Thread Memory Spaces in KFLOP are limited to 64KBytes (65536 Bytesbytes). Kogna's Thread Spaces are 256KBytes (262,144Bytes). Thread 7 in KFLOP is larger and limited to 5x64KBytes (327680Bytes327680 bytes). Kogna's Thread 7 is 1MByte (1,048,576 bytes).
If subsequent Threads are unused it is possible permitted to overflow into their Thread Spaces. For example, in KFLOP if Threads #2 and #3 are not used it is permissible to load a program of size 3 x 64KBytes (196608 bytes) into Thread #1. If you later want to use Threads #2 or #3 then Thread #1 should be halted before using them.
Each User Thread Stack is located in precious single cycle (5ns) internal memory and is 2 KBytes in length. Care should be used to limit stack usage. Overflowing the stack will likely cause KFLOP to crash. Local variables (defined within functions) and passed function parameters reside on the stack. Large variables should be defined as Global Variables or in the 8 MByte [http://www.dynomotion.com/wiki/index.php?title=KFLOP_C_Programs#Gather_Buffer Gather Buffer]
==Axis Homing and Indexing==
KFLOP doesn't provide any built in mechanism for homing. Instead a homing sequence can be performed in any manner desired using a KFLOP C Program. A number of examples are included. A typical sequence might be to:
# Jog in some direction
# wait for an input to change
# stop
# wait until fully stopped
# Zero
For standard homing the example function '''SimpleHomeIndexFunction.c''' can be used. The example moves to a proximity sensor, optionally reverses to an Index Pulse, moves a fixed distance, then zeros the Axis. Specify -1 for the Index Bit number if no Index pulse exists or is not desired to be used. Below is an example call to the Function showing the parameters to be specified:
<pre class="brush:c"> result = SimpleHomeIndexFunction(2, // axis number to home
1000.0, // speed to move toward home
-1, // direction to move toward home (+1 or -1)
138, // limit bit number to watch for
0, // limit polarity to wait for (1 or 0)
100.0, // speed to move while searching for index
-1, // index bit number to watch for (use -1 for none)
1, // index polarity to wait for (1 or 0)
5000); // amount to move inside limits
</pre>
The example '''SimpleHomeIndexFunctionTest.c''' shows an example of homing 3 axes sequentially.
Note that because homing is all performed in software any IO bits can be used. Some of the documentation lists IO bits to be used but these are only suggestions.
Index pulses from encoders are typically differential signals. The differential index pulse signal can be connected to any unused A or B differential input. Or one of the + or - differential signals can be connected to a single ended digital input. Note that KFLOP's 3.3V inputs should not be driven hard (> 10ma) above 3.8V. Most 5V differential drivers do not do this.
KFLOP User C Programs are given [http://dynomotion.com/Help/Multitasking.htm CPU Time Slices] to execute so they are guaranteed to execute on a periodic basis. With only 1 User Thread running they are guaranteed to execute every 180us. So any index pulse longer that this time period will never be missed. Also with a proximity sensor the change in state will be guaranteed to be detected within this time period.
==Gather Buffer==
[http://www.dynomotion.com/Help/Cmd.htm#GetGatherDec GetGatherDec] [http://www.dynomotion.com/Help/Cmd.htm#SetGatherDec SetGatherDec] [http://www.dynomotion.com/Help/Cmd.htm#GetGatherHex GetGatherHex] [http://www.dynomotion.com/Help/Cmd.htm#SetGatherHex SetGatherHex]
}
</pre>
==Common C Programming Mistakes==
A common programming mistake is to forget to add the '()' for a function call. It might not be obvious why this isn't flagged as an error. In some programming languages such as Basic a subroutine with no parameters can be called by coding the name with no parenthesis. In C the name of a function represents the address of the function. Adding the () is required to make a function call to that address.
Furthermore in C any valid expression is allowed. For example:
2+2;
is a valid C expression. The compiler computes 4 and does nothing with it (sometimes computing things have side effects and therefore have purpose).
2;
is a valid C expression. The compiler computes 2 and does nothing with it.
ClearStopImmediately;
is a valid expression. The compiler computes the address of the function ClearStopImmediately and does nothing with it.
'''Note:''' You can use our Code Validator in our latest Test Version 4.35a. See detailed [http://www.dynomotion.com/Help/ProgramScreen/ShowContextMenu.htm help] or our [https://www.youtube.com/watch?v=N2KSdYuag1U Validate C Programs video].