--- 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 + + + +~~~