[r16]: / trunk / gpiomod / GPIOMods.library.md  Maximize  Restore  History

Download this file

135 lines (117 with data), 3.3 kB


         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.

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
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.

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
(* 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