Diff of /trunk/gpiomod/GPIOMods.library.md [000000] .. [r16]  Maximize  Restore

Switch to side-by-side view

--- a
+++ b/trunk/gpiomod/GPIOMods.library.md
@@ -0,0 +1,134 @@
+---
+
+             This FB can be used to sample analog data by using two
+ GPIO Pins:
+ - one digital input
+ - one digital output
+
+ There are also other circuits out there, which only
+ need one single GPIO. But they have the clear disadvantage
+ that they need to reconfigure this GPIO constantly. Additionally
+ you have to take care about the VRef, which you are using, as it
+ will be pulled to ground by the GPIO acting as an output.
+ You need to take care to not destroy your board with that. In the
+ Circuit, recommended here, it is to my understanding much safer,
+ as we simply use the digital output as our VRef. Therefore we can
+ easily and safely pull it to ground.
+
+ Wirering::
+   Digital Output (VRef)
+      v
+   R1 (2,2kOhm) 
+      v
+   Transistor / Poti / LDR / ...
+      |---> Input Pin
+   C1 (1uF)
+      v
+     GND
+
+ Scheduling:
+ The accuracy of the measurement relies in some aspects on the scheduling.
+ So it is recommended to schedule the task, which is driving this FB, as 
+ frequent as possible. It is generally OK to combine this FB with the SoftPWM.
+ Just the sampling accuracy will slightly vary, depending on the frequency
+ of the PWM. 
+
+~~~ST
+FUNCTION_BLOCK SoftAIN
+VAR_INPUT
+    xInput: BOOL;
+END_VAR
+VAR_OUTPUT
+    xOutput: BOOL;
+    rVal: REAL;
+END_VAR
+VAR
+    xSampling: BOOL;
+    tStart: SYSTIME;
+    tCurrent: SYSTIME;
+    xInit: BOOL;
+END_VAR
+VAR
+    ctDischarge: SYSTIME;
+    crScale: REAL;
+END_VAR
+
+~~~
+~~~ST
+SysTimeGetUs(tCurrent);
+IF xInit THEN
+	xInit := FALSE;
+	tStart := tCurrent;
+END_IF
+	
+
+IF xSampling THEN
+	// Reading the sampling pin, and measure the time
+	IF xInput THEN
+		/// capacitor is full, stop sampling, and discharge
+		xSampling := FALSE;
+		rVal := LWORD_TO_REAL(tCurrent - tStart) * crScale;
+		tStart := tCurrent;
+	END_IF
+ELSE
+	// Discharge the capacitor
+	IF tCurrent - tStart > ctDischarge THEN
+		// start sampling
+		tStart := tCurrent;
+		xOutput := TRUE;
+	END_IF
+END_IF
+~~~
+---
+
+             This FB can be used to implement a Soft PWM, based
+ on the scheduler of a Linux system.
+
+ Note, that this function block should be used in a
+ a high priority task. The interval of the task will
+ constantly change.
+
+~~~ST
+FUNCTION_BLOCK SoftPWM
+VAR_INPUT
+    dwFrequ: DWORD;
+    rDutyCycle: REAL;
+END_VAR
+VAR_OUTPUT
+    xPWM: BOOL;
+END_VAR
+VAR
+    hTask: SysTask.RTS_IEC_HANDLE;
+    ulInterval: DWORD;
+END_VAR
+VAR
+    cMinInterval: DWORD;
+END_VAR
+
+~~~
+~~~ST
+(* If current task is not, yet, determined, get it *)
+IF hTask = SysTask.RTS_INVALID_HANDLE THEN
+	SysTask.SysTaskGetCurrent(ADR(hTask));
+END_IF
+
+(* if task is determined, adjust next cycle *)
+IF hTask <> SysTask.RTS_INVALID_HANDLE THEN
+	IF xPWM THEN
+		ulInterval := LREAL_TO_DWORD((LREAL#1000000 / DWORD_TO_LREAL(dwFrequ)) * rDutyCycle);
+	ELSE
+		ulInterval := LREAL_TO_DWORD((LREAL#1000000 / DWORD_TO_LREAL(dwFrequ)) * (LREAL#1 - rDutyCycle));
+	END_IF
+	
+	(* if we are near the boundary values, we snap the output either to TRUE or FALSE *)
+	IF ulInterval < cMinInterval THEN
+		SysTask.SysTaskSetInterval(hTask, DWORD#1000000 / dwFrequ);
+	ELSE		
+		SysTask.SysTaskSetInterval(hTask, ulInterval);
+		xPWM := NOT xPWM;
+	END_IF
+END_IF
+
+
+
+~~~