Skip to content

DIO 라이브러리 사용법

1. DIO 개요

하나의 장비가 구동되는 데에는 수많은 신호 입출력이 필요하다. 일반적으로 이러한 신호들은 디지털 신호가 주류를 이룬다. 이러한 디지털 신호를 입력받고, 출력하기 위한 제어 모듈이 DIO (Digital Input Output) 모듈이다.

디지털 입출력에 대해서는 개별적인 비트들의 입출력 상태를 검출하고 사용하는 함수 뿐만 아니라, 8비트, 16비트, 32비트 단위로의 입출력을 지원하는 함수들도 포함하고 있다. 게다가, 각각의 입력 비트에 대해서 상승 및 하강 에지에서의 인터럽트를 사용할 수도 있다. DIO 모듈에 대한 라이브러리 함수는 크게 다음과 같이 나누어진다.

• 초기화: 모듈을 초기화 시키는 데 관련된 함수.
• 모듈 정보 확인: 모듈의 각종 정보를 확인하는 함수.
• 신호 입출력: 각각의 접점을 비트/바이트/워드/더블워드 단위로 입력을 확인하고 출력에 관한 함수.
• 인터럽트: 입력 비트들에서 상승 또는 하강에지에 대해 인터럽트를 설정 및 확인 함수.

본 User’s Guide에서는 여러 디지털 입출력 모듈 중 16개의 입력 비트와 16개의 출력 비트를 가지는 SIODB32P 모듈을 기준으로 설명한다.

AXD 라이브러리에서 지원하는 제품 내역은 다음과 같다.

이름 설명 인터럽트 지원 여부 비고
SIO-DB32 입/출력 각 16 점 지원 Local Board 제품
SIO-DI32 입력 32 점 지원 Local Board 제품
SIO-DO32 출력 32 점 미지원 Local Board 제품
PCI-DB64R 입/출력 각 32 점 지원 Local Board 제품
PCI-DI64R 입력 64점 지원 Local Board 제품
PCI-DO64R 출력 64점 미지원 Local Board 제품
SIO-RDI32 입력 32 점 미지원 RTEX 제품
SIO-RDO32 출력 32 점 미지원 RTEX 제품
JEPMC-IO2310 입/출력 각 32 점 미지원 MLII 제품
N3RTEX-DB32T 입/출력 각 16 점 미지원 RTEX 제품
N3RTEX-DI32 입력 32 점 미지원 RTEX 제품
N3RTEX-DO32T 출력 32 점 미지원 RTEX 제품
N3MLIII-DB32 입/출력 각 16 점 미지원 MLIII 제품
N3MLIII-DI32 입력 32 점 미지원 MLIII 제품
N3MLIII-DO32 출력 32 점 미지원 MLIII 제품
N3SIIIH-DB32T 입/출력 각 16 점 미지원 SSCNETIII/H 제품
N3SIIIH-DI32 입력 32 점 미지원 SSCNETIII/H 제품
N3SIIIH-DO32T 출력 32 점 미지원 SSCNETIII/H 제품

2. DIO 함수의 기본 규칙

모든 AXL함수의 기본적인 규칙이기도 하지만, DIO 함수군인 AXD 에서도 각각의 함수들은 기본적으로 함수의 수행 결과를 리턴한다. 리턴 값은 아래의 표에서와 같이 해당 함수가 정상적으로 수행되었는지, 아니면 어떠한 이유로 실행되지 못했는지를 알려준다. 함수의 리턴 값을 확인하고자 한다면, 다음과 같이한다.

DWORD Code = AxdInfoIsDIOModule(&uStatus);

if(Code == AXT_RT_SUCCESS)
    printf("정상적으로 실행 되었습니다.”);
else
    printf("AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n",Code);

또한, 함수들은 매개변수를 통해 필요한 인자들을 입력받고, 출력 또한 변수의 포인터를 넘겨받아 처리 결과를 저장하여 사용자에게 전달한다. 아래에서와 같이 특정 함수 AxdExFunction을 실행시키는 데, inPara1, inPara2 의 값이 필요하고, 결과 값은 outPara1, outPara2 에 받아온다고 하면, 아래와 같이 한다.

double inPara1, inPara2;
double outPara1, outPara2;

AxdExFunction(inPara1, inPara2, &outPara1, &outPara2);

3. Axd 사용 접두어별 그룹

DIO 함수는 다음과 같은 함수 접두어 그룹으로 나뉜다.

이름 설명
AxdInfo 보드 및 모듈 정보 확인 함수
Axdi Digital 입력 관련 대분류
Axdo Digital 출력 관련 대분류
AxdiInterrupt 입력 인터럽트 설정 확인
AxdiInterruptEdge 입력 인터럽트 상승 / 하강 에지시 인터럽트 발생 설정 확인
AxdiLevel 입력 신호 레벨 설정 확인
AxdiRead 입력 신호 읽기
AxdoRead 출력 신호 읽기
AxdoWrite 출력 신호 쓰기
AxdoLevel 출력 신호 레벨 설정 확인

4. 초기화 및 종료

AXL 라이브러리의 초기화 작업은 AxlOpen 함수를 실행함으로써 이루어진다. AxlOpen 함수를 실행하면, 내부적으로 라이브러리의 초기화뿐만 아니라 설치되어 있는 보드 및 보드에 존재하는 모듈을 모두 초기화하게 된다. 그러므로 사용자는 DIO 라이브러리를 사용하기 전에 반드시 DIO 모듈이 존재 하는가를 확인하여야 한다.

라이브러리 초기화

라이브러리의 초기화

AxlOpen: AxlOpen 함수는 라이브러리를 초기화 하는 함수이다. 사용자가 인터럽터를 사용할 경우 인터럽터를 처리할 IRQ 번호를 등록한다. 특히 PCI타입의 베이스보드에서는 IRQ 번호를 자동으로 생성하므로 라이브러리 초기화 시 입력한 IRQ 번호는 무시된다. 이 함수는 리턴 값으로 에러코드가 아닌 BOOL 값을 리턴하므로 아래에서처럼 사용할 수 있다.

// 라이브러리를 초기화한다.
// 7은 IRQ를 뜻한다. PCI에서는 자동으로 IRQ가 설정된다.
if(AxlOpen(7) == AXT_RT_SUCCESS)
    printf(라이브러리가 초기화되었습니다.);

라이브러리 초기화 여부의 확인

AxlIsOpened: AxlIsOpened 함수는 라이브러리의 초기화 여부를 확인하는 함수이다. 이 함수 또한 에러코드가 아닌 BOOL 값을 리턴한다. 라이브러리가 초기화되어 있다면 TRUE를 반환하고, 초기화되어 있지 않다면 FALSE를 반환한다.

// 라이브러리가 초기화되어 있는지 확인한다.
if(AxlIsOpened())
    printf(라이브러리가 초기화되어 있습니다.);
else
    printf(라이브러리가 초기화되지 않았습니다.);

DIO모듈의 존재 여부 확인

AxdInfoIsDIOModule: AxdInfoIsDIOModule 함수는 실제 DIO 모듈이 존재하는가 여부를 확인하는 함수이다. DIO 관련 함수를 사용하기 전에 DIO 모듈이 있는지를 먼저 확인하기 위해 사용한다. 모듈이 존재하는지를 확인하기 위해 아래와 같이 한다.

// DIO 모듈이 있는지 확인한다.
DWORD uStatus;
AxdInfoIsDIOModule(&uStatus);

if(uStatus == STATUS_EXIST)
    printf("DIO 모듈이 존재합니다.");
else
    printf("DIO 모듈이 존재하지 않습니다.");

입출력 모듈 및 채널의 개수 확인

AxdInfoGetModuleCount: AxdInfoGetModuleCount 함수는 전체 시스템에 장착되어 있는 DIO 모듈의 개수를 확인하는 함수이다.

// DIO 모듈의 개수를 확인한다.
long lCount;
AxdInfoGetModuleCount(&lCount);
printf(DIO 모듈의 개수는 %d개 입니다., lCount);

AxdInfoGetInputCount: AxdInfoGetInputCount함수는 지정한 DIO 모듈에서 입력 채널의 개수를 확인하는 함수이다.

// 0번째 모듈의 입력 채널 개수를 확인한다.
long lCount;
AxdInfoGetInputCount(0, &lCount);
printf(0번째 DIO모듈의 입력 채널 개수는 %d개 입니다., lCount);

AxdInfoGetOutputCount: AxdInfoGetOutputCount 함수는 지정한 DIO 모듈에서 출력 채널의 개수를 확인하는 함수이다.

// 0번째 모듈의 출력 채널 개수를 확인한다.
long lCount;
AxdInfoGetOutputCount(0, &lCount);
printf(0번째 DIO모듈의 출력 채널 개수는 %d개 입니다., lCount);

AxdInfoGetModuleNo: 초기화되어 있는 전체 DIO 모듈 번호를 확인한다.

// 0번 보드, 0번째 모듈에의 모듈 번호를 확인
long lBoardNo=0, lModulePos=0, lModuleNo;
Code = AxdInfoGetModuleNo(lBoardNo, lModulePos, & lModuleNo);
printf(0 보드, 0번째 모듈의 모듈 번호 : %d\n, lModuleNo);

라이브러리 종료

AxlClose: AxlClose 함수는 라이브러리를 종료하는 함수이다. 라이브러리를 사용한 후에는 마지막에 반드시 종료시켜서 할당된 메모리를 반환하여야 한다. 함수가 정상 실행되어 라이브러리가 종료되면 TRUE를 반환하고, 그렇지 않은 경우에는 FALSE를 반환한다.

// 라이브러리를 종료한다.
if(AxlClose())
printf(라이브러리가 종료되었습니다.);
// Ex1_AXD_InitAndClose.cpp : Defines the entry point for the console application.
// 라이브러리를 초기화하고, 입출력 정보를 확인한 후 종료한다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은 IRQ를 뜻한다. PCI에서는 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);

        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                printf(DIO 모듈이 존재 합니다.\n);
                // DIO 모듈의 개수를 확인
                long lModuleCounts;
                Code = AxdInfoGetModuleCount(&lModuleCounts);

                if (Code == AXT_RT_SUCCESS)
                    printf(DIO 모듈의 개수 : %d\n,lModuleCounts);
                else
                    printf(AxdInfoGetModuleCounts() : ERROR code 0x%x\n,Code);

                // 입력 및 출력 접점의 개수를 확인
                long lInputCounts;
                long lOutputCounts;

                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    Code = AxdInfoGetInputCount(ModuleNo,&lInputCounts);
                    if(Code == AXT_RT_SUCCESS)
                    {
                        DWORD Code2 = AxdInfoGetOutputCount(ModuleNo,&lOutputCounts);
                        if(Code2 == AXT_RT_SUCCESS)
                        {
                            printf(%d번째 모듈 : 입력 접점 %d개, 출력 접점 %d개\n, ModuleNo,
                            lInputCounts, lOutputCounts);
                        }
                        else
                            printf(AxdInfoGetOutputCounts() : ERROR code 0x%x\n,Code);
                    }
                    else
                        printf(AxdInfoGetInputCounts() : ERROR code 0x%x\n,Code);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(라이브러리가 종료되었습니다.\n);
    else
        printf(라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

5. 입출력 포트의 신호 레벨 설정

입출력 포트를 사용하기 위해서는 먼저 각각의 입출력 접점의 신호 레벨을 설정해 주어야 한다. 이는 프로그램상에서 1이라는 값이 High인지 Low인지를 설정해주는 것이며, 입출력 접점의 신호 레벨을 설정하기 위해 아래 그림에서와 같이 여러 접두어를 이용하여 총 20가지의 함수를 제공한다.

Offset의 설명

Offset은 DIO 모듈의 입출력 접점들의 일련 번호를 의미하며 입력과 출력 각각 독립적인 일련번호를 가진다. 예를 들어, SIO-DB32 모듈의 경우 입력과 출력이 하나의 모듈에 16개씩 총 32개의 접점이 존재하는데, 각 인덱스는 Bit 단위로 신호를 접근 할 경우 입력 offset이 0~15의 범위를 가지며 출력 offset이 0~15의 Offset을 가진다.
만약, 시스템에 SIO-DB32 / SIO-DI32 / SIO-DO32 모듈이 하나씩 장착되어 있고 할당된 Module No가 각각 0,1,2 로 순차적이라면 각 모듈별 할당 Offset의 범위와 각 함수의 연관성은 아래 표와 같다.

입력 Offset

SIO-DB32
(In 16/Out 16)
SIO-DI32
(In 32)
Data Size 비고
AxdiLevelSetInport
AxdiLevelGetInport
0 ~ 15 16 ~ 47 1 전체 모듈에서 Offset 적용됨
AxdiLevelSetInportBit
AxdiLevelGetInportBit
0 ~ 15 0 ~ 31 1 각각의 모듈에 Offset 적용
AxdiLevelSetInportByte
AxdiLevelGetInportByte
0 ~ 1 0 ~ 3 8 각각의 모듈에 Offset 적용
AxdiLevelSetInportWord
AxdiLevelGetInportWord
0 0 ~ 1 16 각각의 모듈에 Offset 적용
AxdiLevelSetInportDword
AxdiLevelGetInportDword
0 0 32 각각의 모듈에 Offset 적용

출력 Offset

SIO-DB32
(In 16/Out 16)
SIO-DO32
(Out 32)
Data Size 비고
AxdoLevelSetInport
AxdoLevelGetInport
0 ~ 15 16 ~ 47 1 전체 모듈에서 Offset 적용됨
AxdoLevelSetInportBit
AxdoLevelGetInportBit
0 ~ 15 0 ~ 31 1 각각의 모듈에 Offset 적용
AxdoLevelSetInportByte
AxdoLevelGetInportByte
0 ~ 1 0 ~ 3 8 각각의 모듈에 Offset 적용
AxdoLevelSetInportWord
AxdoLevelGetInportWord
0 0 ~ 1 16 각각의 모듈에 Offset 적용
AxdoLevelSetInportDword
AxdoLevelGetInportDword
0 0 32 각각의 모듈에 Offset 적용

함수 설명

AxdiLevelSetInport: 전체 입력 접점 모듈의 offset 번지에서 bit 단위로 해당 bit의 신호 레벨을 설정한다. 만약 PC에 여러 개의 DIO 모듈이 장치되어 있다고 하면, 모듈 인덱스 순서대로 번호가 매겨진다.
예를 들어 SIO-DB32 모듈이 2개 장착되어 있다면, 첫 번째 모듈에 있는 32개의 접점 중 입력 접점 16개가 먼저 0번부터 15번까지 번호가 매겨지고, 다음 모듈에 있는 32개의 접점 중 입력 접점 16개가 16번부터 31번까지 번호가 매겨진다. 이 offset 번지를 이용하여 해당 입력 접점의 신호 레벨을 설정하는 함수가 AxdiLevelSetInport 함수이다.
전체 입력 접점 중에 20번 비트의 신호 레벨을 HIGH로 설정하고자 한다면 다음과 같이 한다.

// 전체 모듈, Offset 20번지에서 bit 단위로 데이터 레벨을 HIGH로 설정한다.
AxdiLevelSetInport(20, 1);

AxdoLevelSetOutport: 출력 접점 신호 레벨을 설정하는 함수로써 사용 방법은 입력 함수인 AxdiLevelSetInport 와 동일하다.

AxdiLevelSetInportBit: 사용자가 지정한 DIO 모듈의 입력 점점 offset번지에서 bit단위로 해당 bit의 신호 레벨을 설정한다. 입력 점점 offset 번지는 앞에서 설명한 바와 같이 입력 접점에 해당하는 일련 번호인데, 특정 모듈을 지정하는 함수에서의 경우 하나의 모듈 내에서 입력 접점들에 붙여진 일련번호를 뜻한다.
예를 들어 ‘2’개의 SIO-DB32 모듈이 장착되어 있다고 할 때, ‘0’번 모듈에 ‘0’번부터 ‘15’번까지의 입력 offset값이 있고, ‘1’번 모듈에 0번부터 15번까지의 개별적인 번호가 붙는다.
‘0’번 모듈에서 1번 비트의 신호 레벨을 설정하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 0번지에서 bit 단위로 데이터 레벨을 HIGH로 설정한다.
AxdiLevelSetInportBit(0, 0, 1);

AxdoLevelSetOutportBit: 출력 접점 신호 레벨을 설정하는 함수로써 사용 방법은 입력 접점 신호 레벨을 설정하는 함수인 AxdiLevelSetInportBit 와 동일하다.

AxdiLevelSetInportByte: 사용자가 지정한 DIO 모듈의 입력 offset번지에서 byte단위(동시 8개 접점)로 해당 bit의 신호 레벨을 설정한다. offset번지는 해당 입력 접점이 속해있는 포트 번호와 같고, 순차적으로 ‘0’ 부터 ‘3’까지의 offset 값이 있으며, 8bit의 byte 단위로 신호 레벨을 설정할 수 있다. SIO-DB32 모듈의 경우, 하나의 모듈에 유효한 Offset의 범위는 0 ~ 1이 된다. ‘0’번 모듈에서 ‘0’번 offset의 신호 레벨을 설정하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 0번지에서 byte 단위로 데이터 레벨을 모두 HIGH로 설정한다.
AxdiLevelSetInportByte(0, 0, 0xFF);

AxdoLevelSetOutportByte: 출력 접점 신호 레벨을 설정하는 함수로써 사용 방법은 입력 접점 신호 레벨을 설정하는 함수인 AxdiLevelSetInportByte 와 동일하다.

AxdiLevelSetInportWord: AxdiLevelSetInportWord 함수는 앞에서 설명한 AxdiLevelSetInportByte 함수와 유사한데, 차이점이라면 word단위(16개 접점)로 점점의 신호 레벨을 설정 한다는 것이다.
16개의 접점을 한 단위로 묶어 사용하므로 offset 값은 ‘0’번과 ‘1’번 밖에 없다. SIO-DB32모듈의 경우 하나의 모듈에 유효한 Offset은 0번 밖에 없다. AxdSetPortLevelWord 함수에서도 마찬가지로 어느 특정 offset의 신호 레벨을 설정하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 0번지에서 word 단위로 데이터 레벨을 모두 HIGH로 설정한다.
AxdiLevelSetInportWord(0, 0, 0xFFFF);

AxdoLevelSetOutportWord: 출력 접점 신호 레벨을 설정하는 함수로써 사용 방법은 입력 접점 신호 레벨을 설정하는 함수인 AxdiLevelSetInportWord 와 동일하다.

AxdiLevelSetInportDword: AxdiLevelSetInportDword 함수는 앞에서 설명한 AxdiLevelSetInportWord 함수와 유사한데, 차이점이라면 Dword단위(32개 접점)로 입력 접점의 신호 레벨을 설정 한다는 것이다. 32개의 접점을 한 단위로 묶어 사용하므로 offset 값은 0번 밖에 없다. AxdiLevelSetInportDword 함수에서도 마찬가지로 어느 특정 offset의 신호 레벨을 설정하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 0번지에서 dword 단위로 데이터 레벨을 모두 HIGH로 설정한다.
AxdiLevelSetInportDword(0, 0, 0xFFFFFFFF);

AxdoLevelSetOutportDword: 출력 접점 신호 레벨을 설정하는 함수로써 사용 방법은 입력 함수인 AxdiLevelSetInportDword 와 동일하다.

6. 입출력 포트 읽기

함수 설명

특정 DIO 모듈에 있는 입출력 포트의 현재 상태를 확인하기 위해서 입력과 출력 각각 5개씩의 함수가 있다.
AxdiReadInport: 시스템에 장착된 전체 DIO 모듈의 입력 접점 offset번지에서 bit단위로 해당 bit의 정보를 읽어와서 1 또는 0을 반환한다. 0번 모듈에서 1번 비트의 값을 확인하고자 한다면 다음과 같이 한다.

// 0번째 모듈에서 Offset 1번지에 데이터를 bit 단위로 읽는다.
DWORD uValue;
AxdiReadInport(0, 1, &uValue);

AxdoReadOutport: 출력 접점의 상태를 읽는 함수로써 사용 방법은 입력 함수인 AxdiReadInport 와 동일하다.

AxdiReadInportBit: 사용자가 지정한 DIO 모듈의 입력 offset번지에서 bit단위로 해당 bit의 정보를 읽어와서 1 또는 0을 반환한다.
0번 모듈에서 1번 비트의 값을 확인하고자 한다면 다음과 같이 한다.

// 0번째 모듈에서 Offset 1번지에 데이터를 bit 단위로 읽는다.
DWORD uValue;
AxdiReadInportBit(0, 1, &uValue);

AxdoReadOutportBit: 출력 접점의 상태를 읽는 함수로써 사용 방법은 입력 함수인 AxdiReadInportBit 와 동일하다.

AxdiReadInportByte: 사용자가 지정한 모듈의 입력 offset 번지에서 byte 단위로 데이터를 읽는다. offset 번지는 0, 1, 2, 3의 값을 가진다. AxdiReadInportByte 함수는 byte 단위의 값을 리턴하므로 만약 특정 비트의 신호를 확인하고자 한다면 다음과 같이 비트연산을 하면 된다.

// 0번째 모듈의 Offset 0번지에서 byte 단위로 데이터를 읽는다.
DWORD uValue;
AxdiReadInportByte(0, 0, &uValue);
// 0번 모듈의 0번 Input bit의 정보를 bit연산을 이용하여 확인한다.
BOOL Bit0 = uValue&0x01 ? 1 : 0 ;
BOOL Bit1 = uValue&0x02 ? 1 : 0 ;
BOOL Bit2 = uValue&0x04 ? 1 : 0 ;
BOOL Bit3 = uValue&0x08 ? 1 : 0 ;

AxdoReadOutportByte: 출력 접점의 상태를 읽는 함수로써 사용 방법은 입력 함수인 AxdiReadInportByte와 동일하다.

AxdiReadInportWord: 사용자가 지정한 모듈의 입력 offset 번지에서 word 단위로 데이터를 읽는다. offset번지는 0, 1의 값을 가진다. AxdiReadInportWord함수는 word 단위의 값을 리턴하므로 만약 특정 비트의 신호를 확인하고자 한다면 다음과 같이 비트연산을 하면 된다.

// 0번째 모듈의 Offset 0번지에서 word 단위로 데이터를 읽는다.
DWORD uValue;
AxdiReadInportWord(0, 0, &uValue);

// 0번 모듈의 1번 Input bit의 정보를 bit연산을 이용하여 확인한다.
BOOL Bit1 = uValue&0x0002 ? 1 : 0 ;

AxdoReadOutportWord: 출력 접점의 상태를 읽는 함수로써 사용 방법은 입력 접점의 상태를 읽는 함수인 AxdiReadInportWord 와 동일하다.

AxdiReadInportDword: 사용자가 지정한 모듈의 입력 offset 번지에서 dword 단위로 데이터를 읽는다. offset번지는 0의 값을 가진다. AxdiReadInportDword 함수는 dword 단위의 값을 리턴하므로 만약 특정 비트의 신호를 확인하고자 한다면 다음과 같이 비트연산을 하면 된다.

// 0번째 모듈의 Offset 0번지에서 dword 단위로 데이터를 읽는다.
DWORD uValue;
AxdiReadInportDword(0, 0, &uValue);
// 0번 모듈의 2번 Input bit의 정보를 bit연산을 이용하여 확인한다.
BOOL Bit3 = uValue&0x00000004 ? 1 : 0 ;

AxdoReadOutportDword: 출력 접점의 상태를 읽는 함수로서 사용 방법은 입력 접점의 상태를 읽는 함수인 AxdiReadInportDword 와 동일하다.

// Ex2_AXD_ReadPort.cpp : Defines the entry point for the console application.
// DIO 모듈의 입력 포트에 대한 정보를 확인한다.
// 0 번 모듈이 32 입력 접점 모듈로 가정한다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은 IRQ를 뜻한다. PCI의 경우 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);

        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCounts;
                AxdInfoGetModuleCount(&lModuleCounts);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    if(AxdInfoGetInputCount(ModuleNo) > 0)
                    {
                        AxdiLevelSetInportDword(ModuleNo,0,0xffffffff );
                    }

                    if(AxdInfoGetOutputCount(ModuleNo) > 0)
                    {
                        AxdoLevelSetOutportDword(ModuleNo,0,0xffffffff );
                    }
                }

                // 무한 루프를 돌면서 Port의 현재 상태를 반환한다.
                printf(INFORMATION*****************\n);
                printf(아무키나 누르면 종료 합니다. \n);
                printf(****************************\n);
                printf(“\n\n0번 모듈의 입력 포트의 현재 상태\n);

                BOOL fExit = FALSE;
                DWORD Status_Module0[32];

                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면 무한 루프를 빠져나간다.
                    fExit = TRUE;

                    // bit 단위로 해당 offset 상태 확인
                    AxdiReadInportBit(0,0,&Status_Module0[0]);
                    AxdiReadInportBit(0,1,&Status_Module0[1]);

                    // byte 단위로 해당 offset 상태 확인
                    AxdiReadInportByte(0,0,&Status_Module0[2]);
                    AxdiReadInportByte(0,0,&Status_Module0[3]);

                    // word 단위로 해당 offset 상태 확인
                    AxdiReadInportWord(0,0,&Status_Module0[4]);
                    AxdiReadInportWord(0,0,&Status_Module0[5]);

                    // double word 단위로 해당 offset 상태 확인
                    AxdiReadInportDword(0,0,&Status_Module0[16]);
                    AxdiReadInportDword(0,0,&Status_Module0[17]);

                    // byte 단위로 해당 offset 상태 확인
                    AxdiReadInportByte(0,3,&Status_Module0[18]);
                    AxdiReadInportByte(0,3,&Status_Module0[19]);

                    // word 단위로 해당 offset 상태 확인
                    AxdiReadInportWord(0,1,&Status_Module0[20]);

                    // Input Port의 현재 상태를 반환한다.
                    printf(“\r0[%d],1[%d],2[%d],3[%d],4[%d].. 18[%d],19[%d],20[%d]...,
                    Status_Module0[0],Status_Module0[1], Status_Module0[2]&0x04 ? 1 : 0,
                    Status_Module0[3]&0x08 ? 1 : 0, Status_Module0[4]&0x0010 ? 1 : 0,
                    Status_Module0[5]&0x0020 ? 1 : 0, Status_Module0[16]&0x00010000 ? 1 : 0,
                    Status_Module0[17]&0x00020000 ? 1 : 0, Status_Module0[18]&0x04 ? 1 : 0,
                    Status_Module0[19]&0x08 ? 1 : 0, Status_Module0[20]&0x0010 ? 1 : 0);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(라이브러리가 종료되었습니다.\n);
    else
        printf(라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

7. 출력 포트 쓰기

Output Port는 모듈에서부터 신호를 출력하는 포트로써 SIO-DO32 모듈에는 32개의 출력 접점이 존재하고, SIO-DB32 모듈에는 16개의 출력 접점이 존재한다. Output Port를 이용하여 신호를 출력하기 위하여 다음과 같이 5가지의 함수가 제공된다. 각 함수의 할당 Offset의 의미와 범위는 단위 별로 1.4.1 항에 설명된 Level 설정 함수와 동일하다.

함수 설명

AxdoWriteOutportBit: 사용자가 지정한 DIO 모듈의 출력 offset번지에서 해당 출력 접점으로부터 bit단위로 출력을 내보낸다. 0번 모듈에서 1번 출력 접점을 통해 출력을 내보내고자 한다면 다음과 같이 한다.

// 0번째 모듈에서 1번 출력 접점(Offset : 1)에 데이터를 bit 단위로 출력한다.
AxdoWriteOutportBit(0, 1, 1);

AxdoWriteOutportByte: 사용자가 지정한 모듈의 출력 offset 번지에서 byte 단위로 데이터를 출력한다. offset 번지는 0 ~ 3의 값을 가진다. ‘0’번째 모듈의 출력 Offset 2번지(16번째 접점부터 8개접점 출력) 에서 byte 단위로 데이터를 출력하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 2번지에서 byte 단위로 데이터를 출력한다.
AxdoWriteOutportByte(0, 2, 0xFF);

AxdoWriteOutportWord: 사용자가 지정한 모듈의 출력 offset 번지에서 word 단위로 데이터를 출력한다. offset번지는 0 ~ 1의 값을 가진다. 0번째 모듈의 출력 Offset 0번지(0번째 접점부터 16개 접점 출력)에서 word 단위로 데이터를 출력하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 1번지에서 word 단위로 데이터를 읽는다.
AxdWritePortWord(0, 0, 0xFFFF);

AxdoWriteOutportDword: 사용자가 지정한 모듈의 offset 번지에서 Dword 단위로 데이터를 출력한다. offset번지는 0의 값을 가진다. 32개의 출력 접점을 한번에 출력한다. ‘0’번째 모듈의 Offset ‘0’번지에서 Dword 단위로 데이터를 출력하고자 한다면 다음과 같이 한다.

// 0번째 모듈의 Offset 0번지에서 dword 단위로 데이터를 출력한다.
AxdWritePortDword(0, 0, 0xFFFFFFFF);

AxdoWriteOutport: 시스템에 장착된 전체 출력 접점 모듈의 offset 번지에서 해당 bit에 bit단위로 출력을 내보낸다. 전체 출력 접점 중에 15번째 출력 점점에 Bit 단위로 데이터를 출력하고자 한다면 다음과 같이 한다.

// 전체 출력 접점 중에서 15번째 출력 접점에 ‘1’을 출력한다.
AxdoWriteOutport(15,1);
// Ex4_AXD_WriteOutput.cpp : Defines the entry point for the console application.
// DIO 모듈의 출력 포트에 출력을 내보내고 현재 상태를 확인한다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은 IRQ를 뜻한다. PCI에서는 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);
        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCounts;
                AxdInfoGetModuleCount(&lModuleCounts);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    if(AxdInfoGetInputCount(ModuleNo) > 0)
                    {
                        AxdiLevelSetInportDword(ModuleNo,0,0xffffffff );
                    }

                    if(AxdInfoGetOutputCount(ModuleNo) > 0)
                    {
                        AxdoLevelSetOutportDword(ModuleNo,0,0xffffffff );
                    }
                }

                // 무한 루프를 돌면서 Output Port의 현재 상태를 반환한다.
                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf([0 ~ 4] : 0 ~ 4 출력 접점(0 모듈의 0~4 출력 접점) On / Off \n);
                printf([5 ~ 9] : 16 ~ 20 출력 접점(1 모듈의 0~4 출력 접점) On / Off \n);
                printf(**************************** \n);
                printf(“\n\nOutput Port의 현재 상태\n);

                BOOL fExit = FALSE;
                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        DWORD OutPort;
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;

                            // 전체 출력 비트에서 해당 offset번지를 On/Off
                            case 0:
                            AxdoReadOutport(0,&OutPort);
                            if(OutPort) AxdoWriteOutport(0,0);
                            else AxdoWriteOutport(0,1);
                            break;

                            case 1:
                            AxdoReadOutport (1,&OutPort);
                            if(OutPort) AxdoWriteOutport(1,0);
                            else AxdoWriteOutport(1,1);
                            break;

                            case 2:
                            AxdoReadOutport (2,&OutPort);
                            if(OutPort) AxdoWriteOutport(2,0);
                            else AxdoWriteOutport (2,1);
                            break;

                            case 3:
                            AxdoReadOutport (3,&OutPort);
                            if(OutPort) AxdoWriteOutport (3,0);
                            else AxdoWriteOutport (3,1);
                            break;

                            case 4:
                            AxdoReadOutport (4,&OutPort);
                            if(OutPort) AxdoWriteOutport (4,0);
                            else AxdoWriteOutport (4,1);
                            break;

                            case 5:
                            AxdoReadOutport (16,&OutPort);
                            if(OutPort) AxdoWriteOutport (16,0);
                            else AxdoWriteOutport (16,1);
                            break;

                            case 6:
                            AxdoReadOutport (17,&OutPort);
                            if(OutPort) AxdoWriteOutport (17,0);
                            else AxdoWriteOutport (17,1);
                            break;

                            case 7:
                            AxdoReadOutport (18,&OutPort);
                            if(OutPort) AxdoWriteOutport (18,0);
                            else AxdoWriteOutport (18,1);
                            break;

                            case 8:
                            AxdoReadOutport (19,&OutPort);
                            if(OutPort) AxdoWriteOutport (19,0);
                            else AxdoWriteOutport (19,1);
                            break;

                            case 9:
                            AxdoReadOutport (20,&OutPort);
                            if(OutPort) AxdoWriteOutport (20,0);
                            else AxdoWriteOutport (20,1);
                            break;
                        }
                    }

                    // Output Port의 현재 상태를 반환한다.
                    DWORD Status_Output[32];
                    for(int OffsetNo=0;OffsetNo<32;OffsetNo++)
                    {
                        Status_Output[OffsetNo] = 0;
                        AxdoReadOutport (OffsetNo,&Status_Output[OffsetNo]);
                    }

                    printf(“\r0[%d],1[%d],2[%d],3[%d],..... 17[%d],18[%d],19[%d],20[%d]..., Status_Output[0], Status_Output[1], Status_Output[2], Status_Output[3], Status_Output[4], Status_Output[16], Status_Output[17], Status_Output[18], Status_Output[19], Status_Output[20]);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

8. 인터럽트

AXD에서는 입력 접점에 대해서 Rising Edge(Up Edge) 와 Falling Edge(Down Edge)에 대해 각각 인터럽트를 설정하여 활용할 수 있도록 하는 함수들을 제공한다.
인터럽트를 사용하기 위해서는 먼저 Interrupt Rising Edge Register와 Interrupt Falling Edge Register를 이용하여 인터럽트를 발생시킬 위치를 설정하고, 인터럽트를 어떤 방식으로 처리할 것인가를 설정한다.

AXD 에서는 인터럽트를 처리하는 방식으로 콜백함수 방식, 윈도우 메시지 방식, 이벤트 방식의 3가지 방식을 지원하므로 사용자의 개발 환경에 맞추어 선택하면 된다.
마지막으로 해당 모듈의 인터럽트 사용 유무를 ENABLE로 설정하고, AXL 전체 인터럽트 사용 유무를 ENABLE(AxlInterruptEnable 함수 사용) 하면 된다.
인터럽트 결과는 메시지 핸들러 및 콜백함수 내에서 리턴값으로 확인하며, Event 방식에서는 해당 이벤트 발생 후 AxdiInterruptRead 함수를 사용하여 확인할 수 있다.

Interrupt Rising / Falling Edge 설정

Interrupt Rising / Falling Edge Register는 해당 입력 접점의 Rising Edge 또는 Falling Edge에서 인터럽트를 발생시킬지를 설정하는 레지스터이다. 이 레지스터의 해당 비트를 1로 설정하면, 해당 Edge가 발생할 때 인터럽트가 발생된다. 예를 들어 offset번지 ‘0’번의 Interrupt Rising Edge Register를 1로 설정하였다면, 0번 입력 접점에 Rising Edge가 발생할 때 인터럽트가 발생하게 된다. Rising Edge와 Falling Edge는 상대적인 개념으로 만약 신호 레벨을 HIGH로 설정해두었다면, 신호가 없을 때는 LOW였다가 신호가 들어올 때 HIGH로 바뀌면서 Rising Edge가 발생하고, 다시 신호가 사라지면 LOW가 되면서 Falling Edge가 발생하게 된다. 만약 신호 레벨이 LOW로 설정되었다면, 이와 반대로 신호가 들어올 때 Falling Edge가 발생하고, 신호가 사라질 때 Rising Edge가 발생한다. 이러한 레지스터를 설정하거나 설정된 값을 확인하는 함수로는 전체 입력 접점에서 특정 offset 주소에 해당하는 비트를 설정 또는 확인하는 함수와 특정 모듈에서의 특정 offset번지에 해당하는 입력 접점을 bit단위, byte단위, word단위, dword단위로 설정 또는 확인 하는 함수로 구성된다.

intro1

AxdiInterruptEdgeSet: AxdiInterruptEdgeSet 함수는 전체 입력 접점에서 특정 offset번지에 있는 입력 접점에서 Rising 또는 Falling Edge가 발생할 때, 인터럽트가 발생하도록 레지스터를 설정하는 함수이다. offset번지는 ‘0’번부터 ‘전체 입력 접점의 수 – 1’까지 있는데, 예를 들어 2개의 SIO-DB32 모듈이 설치되어 있다면 0번 모듈의 16개 입력 접점들은 차례로 0 ~ 15까지의 offset 값을 갖고, 1번 모듈에 있는 16개의 입력 접점들은 차례로 16 ~ 31까지의 offset 값을 가지게 된다. 설정하고자 하는 Edge에 따라 UP_EDGE 또는 DOWN_EDGE를 입력하고 설정 값은 ‘1’로 하면 인터럽트를 발생시키고, ‘0’으로 하면 인터럽트를 발생시키지 않는다. 전체 입력 접점 중에 2번째 입력 접점의 Rising Edge에서 인터럽트를 발생시키고자 한다면 다음과 같이 한다.

// 전체 입력 접점 중에 2번째 입력 접점의 UpEdge에 인터럽트를 설정한다.
AxdiInterruptEdgeSet(2,UP_EDGE,1);

AxdiInterruptEdgeSetBit: AxdiInterruptEdgeSetBit 함수는 특정 모듈에서 특정 offset번지에 있는 입력 접점에서 Rising 또는 Falling Edge가 발생할 때 인터럽트가 발생하도록 레지스터를 설정하는 함수이다. offset번지는 ‘0’번부터 ‘해당 모듈의 입력 접점의 수 – 1’까지 있는데, 예를 들어, 2개의 SIO-DB32 모듈이 설치되어 있다면, ‘0’번 모듈의 16개 입력 접점들은 차례로 0 ~ 15까지의 offset 값을 갖고, 1번 모듈에 있는 16개의 입력 접점들 또한 차례로 0 ~ 15까지의 offset 값을 가지게 된다. 앞에서와 마찬가지로 설정하고자 하는 Edge에 따라 UP_EDGE 또는 DOWN_EDGE를 입력하고, 설정 값을 ‘1’로 하면 인터럽트를 발생시키고, ‘0’으로 하면 인터럽트를 발생시키지 않는다. ‘0’번 모듈에서 ‘2’번째 입력 접점의 Falling Edge에서 인터럽트를 발생시키고자 한다면 다음과 같이 한다.

// 0번 모듈의 입력 접점 중에 2번째 입력 접점의 UpEdge에 인터럽트를 설정한다.
AxdiInterruptEdgeSetBit(0,2,DOWN_EDGE,1);

특정 모듈에서 특정 offset번지에 해당하는 입력 접점들의 인터럽트 설정을 bit단위로 할 수도 있지만, 8개의 접점으로 구성된 byte 단위, 16개의 접점으로 구성된 word 단위, 32개의 접점으로 구성된 dword 단위로도 설정할 수 있다. Default 값은 ‘0’으로 설정되어 있으므로 사용할 비트들만 1로 설정하여 사용하면 된다. 만약 0번 모듈이 SIO-DB32 모듈이고, 홀수 번호의 입력 접점에서 Rising Edge가 발생할 때만 인터럽트를 발생시키고자 한다면 다음과 같이 한다.

// 0번 모듈의 입력 접점 중에 홀수 번호 입력 접점의 UpEdge에 인터럽트를 설정한다.
AxdiInterruptEdgeSetWord(0,0,UP_EDGE,0xAAAA);

Interrupt Rising / Falling Edge의 설정 값 확인

인터럽트 상승/하강 에지 레지스터에 설정된 값을 확인하기 위해서 제공되는 함수도 위에서 설명한 것과 같이 전체 입력 비트에서 특정 offset번지에 해당하는 입력 접점의 Rising Edge에 대한 설정을 확인하는 AxdiInterruptEdgeGet 함수와 특정 모듈에서의 특정 offset번지에 해당하는 값을 bit단위로 확인하는 AxdiInterruptEdgeGetBit 함수, 8개의 접점으로 구성된 byte단위로 확인하는 AxdiInterruptEdgeGetByte 함수, 16개의 접점으로 구성된 word단위로 확인하는 AxdiInterruptEdgeGetWord 함수, 32개의 접점으로 구성된 dword단위로 확인하는 AxdiInterruptEdgeGetDword 함수들이 있다.

AxdiInterruptEdgeGet: 전체 입력 접점 중에 2번째 입력 접점의 Rising Edge Register의 설정 값을 확인하고자 한다면 다음과 같이 한다. offset값은 AxdiInterruptEdgeSet 함수에서와 마찬가지로 ‘0’부터 ‘전체 접점 수 – 1’까지의 값을 순서대로 가진다.

// 전체 입력 접점 중에 2번째 입력 접점의 RisingEdge Register의 설정 값을 확인한다.
DWORD uEdge;
AxdiInterruptEdgeGet(2,UP_EDGE,&uEdge);

AxdiInterruptEdgeGetBit: 0번 모듈의 입력 접점 중에 2번째 입력 접점의 Falling Edge Register의 설정 값을 bit단위로 확인하고자 한다면 다음과 같이 한다. offset값은 AxdiInterruptEdgeSetBit 함수에서와 마찬가지로 ‘0’부터 ‘해당 모듈의 접점 수 - 1’까지의 값을 순서대로 가진다.

// 0번 모듈의 입력 접점 중에 2번째 입력 접점의 FallingEdge Register의 설정 값을 확인한다.
DWORD uEdge;
AxdiInterruptEdgeGetBit(0,2,DOWN_EDGE,&uEdge);

그 외 AxdiInterruptEdgeGetByte, AxdiInterruptEdgeGetWord, AxdiInterruptEdgeGetDword 함수들의 offset값들은 각각 Set함수와 동일하므로 참고하여 사용하면 된다.

인터럽트 사용 여부의 설정

인터럽트의 사용 여부는 Default로 사용하지 않음(DISABLE)으로 설정되어 있다. 그러므로 사용함(ENABLE)으로 설정을 해주어야 상승/하강에지 레지스터에 설정한대로 인터럽트가 발생한다. 인터럽트의 사용 여부를 설정하는 함수는 AxdiInterruptSetModuleEnable 함수이다. 만약 ‘0’번 모듈에서 인터럽트를 사용함으로 설정하고자 한다면 다음과 같이 한다.

// 0번 모듈에서 인터럽트를 사용함으로 설정
AxdiInterruptSetModuleEnable(0,ENABLE);

인터럽트 처리 방식의 설정

인터럽트가 발생했을 때 이를 처리하는 방법으로 AXD에서는 콜백함수 방식, 윈도우 메시지 방식, 이벤트 방식의 3가지를 제공한다. 콜백함수 방식은 이벤트 발생 시점에 즉시 콜백함수가 호출 됨으로 가장 빠르게 이벤트를 통지받을 수 있는 장점이 있으나, 콜백함수가 완전히 종료 될 때까지 메인 프로세스가 정체되어 있게된다. 즉, 콜백함수 내에 부하가 걸리는 작업이 있을 경우에는 사용에 주의를 요한다. 그러나, 이벤트 방식은 이벤트의 발생 여부를 감시하는 특정 스레드를 사용하여 메인 프로세스와 별개로 동작되므로 MultiProcessor 시스템 등에서 자원을 가장 효율적으로 사용할 수 있게 되어 특히 권장하는 방식이다. 이벤트 처리 방식을 설정하기 위해서는 AxdiInterruptSetModule 함수를 사용하여 다음과 같이 설정해주면 된다.

콜백 함수 방식

콜백함수 방식을 사용하기 위해서는 아래와 같이 설정한다.

// 0번 모듈의 이벤트 처리 방식을 콜백함수 방식으로 설정한다.
AxdiInterruptSetModule(0,NULL,NULL,OnDIOInterruptCallback,NULL);

OnDIOInterruptCallback은 인터럽트를 처리할 콜백함수의 포인터이다. 콜백함수는 전역 함수로 다음과 같이 설정하면 된다. 인터럽트가 발생하면 자동으로 인터럽트를 처리할 콜백함수를 호출하게 된다.

void CExDIOInterruptDlg::OnBtnStartInterruptCallback()
{
    // 인터럽트 처리 방식 설정
    AxdiInterruptSetModule(MODULE_NO,NULL,NULL,OnDIOInterruptCallback,NULL);
    // 특정 모듈에서 Dword 단위로 인터럽트 마스크를 설정
    AxdiInterruptEdgeSetDword(MODULE_NO,0,UP_EDGE,0xFFFFFFFF);
    // 인터럽트 허용 여부 설정
    AxdiInterruptSetModuleEnable(MODULE_NO,ENABLE);
}

// 인터럽트를 처리할 콜백함수
void OnDIOInterruptCallback(long nModuleNo, DWORD uFlag)
{
    // nModuleNo : 인터럽트 발생 모듈 번호, uFlag : 인터럽트 발생 Flag
    DWORD uValue;
    CString IntMessage;
    Int InputCounts = 32; // 전체 입력 접점의 수

    for(int ChkBit=0; ChkBit<InputCounts; ChkBit++)
    {
        if((uFlag >> ChkBit) & 0x01)
        {
            AxdiReadInportBit(nModuleNo, ChkBit, &uValue);

            if(uValue)
                printf(INTERRUPT(MESSAGE) :\n %d번 모듈의 %d번째 입력 Bit에서 Rising 인터럽트 발생,   nModuleNo,ChkBit);
            else
                printf(INTERRUPT(MESSAGE) :\n %d번 모듈의 %d번째 입력 Bit에서 Falling 인터럽트 발생, nModuleNo,ChkBit);
        }
    }
}

윈도우 메시지 방식

윈도우 메시지 방식을 사용하기 위해서는 아래와 같이 설정한다. C에서는 윈도우 메시지방식을 사용하지 못하므로 이부분은 VC++을 사용하여 설명한다. 윈도우 메시지 방식을 사용하기 위해서는 메시지를 받을 윈도우 핸들과 윈도우 메시지를 입력해야한다. 윈도우 메시지를 사용하지 않거나 디폴트 값을 사용하고자 한다면 0을 입력한다.

// 0번 모듈의 이벤트 처리 방식을 윈도우 이벤트 방식으로 설정한다.
AxdiInterruptSetModule(lModuleNo,this->m_hWnd,WM_DIO_INTERRUPT,NULL,NULL);

사용방법을 전체적으로 살펴보면 아래와 같으며, OnDIOInterruptMessage 함수에서 인터럽트를 처리한다.

#define WM_DIO_INTERRUPT 1011 // 인터럽트 메시지를 받아오기 위한 메세지 정의
#define MODULE_NO 0 // DIO 모듈 번호

//…(중략)…

// 메시지와 함수를 연결
BEGIN_MESSAGE_MAP(CExDIOInterruptDlg, CDialog)
    //{{AFX_MSG_MAP(CExDIOInterruptDlg)
    ON_MESSAGE(WM_DIO_INTERRUPT,OnDIOInterruptMessage)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//…(중략)…

void CExDIOInterruptDlg::OnBtnStartInterruptMessage()
{
    // 인터럽트 처리 방식 설정 (윈도우 메세지 방식)
    AxdiInterruptSetModule(MODULE_NO,this->m_hWnd,WM_DIO_INTERRUPT,NULL,NULL);

    // 0번 모듈에서 Dword 단위로 인터럽트 마스크를 설정
    AxdiInterruptEdgeSetDword(MODULE_NO,0,UP_EDGE,0xFFFFFFFF);

    // 인터럽트 허용 여부 설정
    AxdiInterruptSetModuleEnable(MODULE_NO,ENABLE);
}

void CExDIOInterruptDlg::OnDIOInterruptMessage(WPARAM nModule, LPARAM nIntrFlag)
{
    // nModule : 인터럽트 발생 모듈 번호 ( 0, 1, 2, 3)
    // nIntrFlag : 인터럽트 발생 Flag ( Input Port에서 인터럽트 발생 확인 )
    DWORD uValue;
    CString IntMessage;
    int InputCounts = 16; // 입력 Bit의 총 개수

    for(int ChkBit=0; ChkBit<InputCounts; ChkBit++)
    {
        if((nIntrFlag >> ChkBit) & 0x01)
        {
            AxdiReadInportBit(nModule, ChkBit, &uValue);
            if(uValue)
                IntMessage.Format(INTERRUPT(MESSAGE) : %d번 모듈의 %d번째 입력 Bit에서 Rising 인터럽트 발생, nModule,ChkBit);
            else
                IntMessage.Format(INTERRUPT(MESSAGE) : %d번 모듈의 %d번째 입력 Bit에서 Falling 인터럽트 발생, nModule,ChkBit);

            m_LIST_Message.InsertItem(0,IntMessage);
        }
    }
}

이벤트 방식

이벤트 방식을 사용하기 위해서는 아래와 같이 설정한다. 이벤트 방식은 이벤트의 발생 여부를 감시하는 특정 스레드를 사용하여 메인 프로세스와 별개로 동작되므로 MultiProcessor 시스템 등에서 자원을 가장 효율적으로 사용할 수 있게 되어 특히 권장하는 방식이다. 이 부분 또한 VC++을 사용하여 설명한다. 이벤트 방식을 사용하기 위해서는 이벤트 ID를 받을 HANDLE형 멤버변수인 m_hInterruptEvent 를 미리 선언해두고 사용하여야 한다.

// 0번 모듈의 이벤트 처리 방식을 윈도우 이벤트 방식으로 설정한다.
AxdiInterruptSetModule(0,NULL,NULL,NULL,&m_hInterruptEvent);

사용 방법을 전체적으로 살펴보면 아래와 같으며, ThreadProc함수에서 인터럽트를 처리한다. 여기서 주의 할점은 반드시 AxdiInterruptSetModule 함수를 스레드가 실행되기 전에 호출하여야 한다는 것이다. 인터럽트가 발생하면 인터럽트 이벤트가 발생하게 되고, 스레드는 이 이벤트를 감지하여 인터럽트가 발생했다는 것을 알게 된다. 그리고 스레드 내부에서 AxdReadInterrupt 함수를 호출하여 현재 인터럽트가 발생한 모듈 번호와 인터럽트 플래그 정보를 확인하여 어느 모듈의 어느 입력 Bit에 인터럽트가 발생하였는지를 확인한다.

// 이벤트 방식 인터럽트 사용에 필요한 변수
HANDLE m_hThreadHandle;
BOOL m_bThread;
HANDLE m_hInterruptEvent;

void CExDIOInterruptDlg::OnBtnStartInterruptEvent()
{
    // 인터럽트 처리 방식 설정
    AxdiInterruptSetModule(0,NULL,NULL,NULL,&m_hInterruptEvent); // 이벤트 방식

    // 특정 모듈에서 Dword 단위로 인터럽트 마스크를 설정
    AxdiInterruptEdgeSetDword(MODULE_NO,0,UP_EDGE,0xFFFFFFFF);

    // 인터럽트 허용 여부 설정
    AxdiInterruptSetModuleEnable(MODULE_NO,ENABLE);

    // 이벤트 방식을 사용하기 위해서 스레드를 만든다.
    m_bThread = TRUE;
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, this, NULL, NULL);
}

void ThreadProc(LPVOID lpData)
{
    CExDIOInterruptDlg *pDlg = (CExDIOInterruptDlg *)lpData;
    long lModuleNo;
    DWORD uFlag;
    DWORD uValue;
    CString IntMessage;
    int InputCounts = 32; // 입력 Bit의 총 개수

    while(pDlg->m_bThread)
    {
        if(WaitForSingleObject(pDlg->m_hInterruptEvent, 0) == WAIT_OBJECT_0)
        {
            // 이벤트 방식일 경우 인터럽트 정보를 읽어온다.
            AxdiInterruptRead(&lModuleNo, &uFlag);
            for(int ChkBit=0; ChkBit<InputCounts; ChkBit++)
            {
                if((uFlag >> ChkBit) & 0x01)
                {
                    AxdiReadInportBit(lModuleNo, ChkBit, &uValue);

                    if(uValue)
                        IntMessage.Format(INTERRUPT(MESSAGE) : %d번 모듈의 %d번째 입력 Bit에서 Rising 인터럽트 발생, lModuleNo,ChkBit);
                    else
                        IntMessage.Format(INTERRUPT(MESSAGE) : %d번 모듈의 %d번째 입력 Bit에서 Falling 인터럽트 발생, lModuleNo,ChkBit);

                    pDlg->m_LIST_Message.InsertItem(0,IntMessage);
                }
            }
        }
    }
}
// Ex5_AXD_InterruptUsing.cpp : Defines the entry point for the console application.
// 인터럽트를 발생시키고, 현재 상태를 확인한다.
#include “stdafx.h”
#include “stdio.h”
#include <conio.h>
#include “AXL.h”

// 인터럽트를 처리할 콜백함수
void OnDIOInterruptCallback(long nModuleNo, DWORD uFlag)
{
    // nModuleNo : 인터럽트 발생 모듈 번호, uFlag : 인터럽트 발생 Flag
    DWORD uValue;
    int InputCounts = 32; // 전체 입력 접점의 수

    for(int ChkBit=0; ChkBit<InputCounts; ChkBit++)
    {
        if((uFlag >> ChkBit) & 0x01)
        {
            AxdiReadInportBit(nModuleNo, ChkBit, &uValue);

            if (uValue)
                printf(“\n %d번 모듈의 %d번째 입력 Bit에서 Rising 인터럽트 발생, nModuleNo,ChkBit);
            else
                printf(“\n %d번 모듈의 %d번째 입력 Bit에서 Falling 인터럽트 발생, nModuleNo,ChkBit);
        }
    }
}

void main()
{
    // 라이브러리를 초기화한다.
    // 7은IRQ를 뜻한다. PCI에서 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);
        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCounts;
                int ModuleNo;

                AxdInfoGetModuleCount(&lModuleCounts);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(ModuleNo=0; ModuleNo < lModuleCounts; ModuleNo++)
                    AxdSetPortLevelDword(ModuleNo,0,0xffffffff );

                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf(**************************** \n\n);

                // 인터럽트 설정
                for(ModuleNo=0; ModuleNo < lModuleCounts; ModuleNo++)
                {
                    // 인터럽트 처리 방식 설정 (콜백함수 방식)
                    AxdiInterruptSetModule(ModuleNo,NULL,NULL, OnDIOInterruptCallback, NULL);

                    // 특정 모듈에서 Dword 단위로 인터럽트 마스크를 설정 (상승/하강 모두1)
                    AxdiInterruptEdgeSetDword(ModuleNo,0,UP_EDGE,0xFFFFFFFF);

                    // 인터럽트 허용 여부 설정
                    AxdiInterruptSetModuleEnable(ModuleNo,ENABLE);
                }

                BOOL fExit = FALSE;
                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;
                        }
                    }
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

9. 고급 DIO함수

AXL 라이브러리에서 위에서 언급한 기본적인 입출력뿐만 아니라 현장에서 빈번히 사용되는 몇가지 고급 DIO 기능 함수들을 제공한다.

신호의 변화 여부 확인

AxdiIsPulseOn: 지정한 모듈의 특정 입력 offset 번호에 해당하는 입력 접점에서 들어오는 신호가 off에서 on으로 바뀌었는지를 확인하는 함수이다. AxdiIsPulseOn 함수를 이용하여 신호의 변화 여부를 확인하기 위해서는 AxdiIsPulseOn 함수를 최소한 두 번 이상 호출하여야 한다. 이 함수는 이전에 호출되었을 때의 신호 레벨이 Off 이면서 현재 호출될 때 On 이면 TRUE를 반환하고, 아니면 FALSE를 반환한다. 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 Off에서 On으로 바뀌었는지 확인하고자 한다면 다음과 같이 한다.

// 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 Off에서 On으로 바뀌었는지를 확인한다.
DWORD uValue;
AxdiIsPulseOn(0,0,&uValue);

if(uValue)
    printf(0 모듈의 0 offset에 해당하는 입력 접점의 신호가 Off에서 On으로 바뀌었습니다.);

AxdiIsPulseOff: 지정한 모듈의 특정 offset 번호에 해당하는 입력 접점에서 들어오는 신호가 On에서 Off로 바뀌었는지를 확인하는 함수이다. 이 함수는 이전에 호출되었을 때의 신호 레벨이 On이면서 현재 호출될 때 Off이면 TRUE를 반환하고, 아니면 FALSE를 반환한다. 0번 모듈의 1번 offset에 해당하는 입력 접점의 신호가 Off에서 On으로 바뀌었는지 확인하고자 한다면 다음과 같이 한다.

// 0번 모듈의 1번 offset에 해당하는 입력 접점의 신호가 On에서 Off로 바뀌었는지 확인한다.
DWORD uValue;
AxdiIsPulseOff(0,1,&uValue);

if(uValue)
    printf(0 모듈의 1 offset에 해당하는 입력 접점의 신호가 On에서 Off로 바뀌었습니다.);
// Ex6_AXD_IsPulseOnOff.cpp : Defines the entry point for the console application.
// 특정 입력 포트에서 신호의 변화 유무를 확인한다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은IRQ를 뜻한다. PCI에서 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);

    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);
        // DIO 모듈이 있는지 검사.
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCount;
                AxdInfoGetModuleCount(&lModuleCount);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCount;ModuleNo++)
                AxdSetPortLevelDword(ModuleNo,0,0xffffffff );

                // 무한 루프를 돌면서 Output Port의 현재 상태를 반환한다.
                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf(**************************** \n);

                BOOL fExit = FALSE;

                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;
                        }
                    }

                    // Input Port의 현재 상태를 반환한다.
                    DWORD Status_Input;
                    DWORD uValue;
                    AxdiReadInport(0,&Status_Input);

                    printf(“\r0번 모듈의 0 offset의 현재 상태 : %d,Status_Input);

                    // 0번 모듈의 0번 offset에 해당하는 입력 접점 신호가 Off에서 On으로 바뀌었는지 확인
                    AxdiIsPulseOn(0,0,&uValue);

                    if(uValue)
                        printf(“\n0번 모듈의 0 offset 해당하는 입력 접점 신호가 Off에서 On으로 바뀌었습니다.\n);

                    // 0번 모듈의 0번 offset 해당하는 입력 접점 신호가 On에서 Off로 바뀌었는지 확인한다.
                    AxdiIsPulseOff(0,0,&uValue);

                    if(uValue)
                        printf(“\n0번 모듈의 0 offset에 해당하는 입력 접점의 신호가 On에서 Off로 바뀌었습니다.\n);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

신호의 지속 여부 확인

AxdiIsOn: 지정한 모듈의 특정 offset 번호에 해당하는 입력 접점에서 들어오는 신호가 AxdiIsOn 함수를 n번만큼 호출할 동안 On을 유지하고 있는지를 확인하는 함수이다. 이 함수는 설정한 횟수만큼 AxdiIsOn 함수를 호출하는 동안에 지속적으로 해당 입력 접점의 신호가 On이면 마지막 n번째부터의 호출에서 TRUE를 반환하고, 아니면 FALSE를 반환한다. N - 1번째 호출까지의 반환 값은 FALSE이다. 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 10회 호출될 동안에 지속적으로 On을 유지하는지 확인하고자 한다면 다음과 같이 한다.

// 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 10회 호출될 동안 On을 유지하는지 확인
DWORD uValue;
AxdiIsOn(0,0,10,&uValue, 1); // 최초 시작

for(int i = 0; i < 9; i++)
{
    // 실제 프로그램에서는 Timer 나 Thread 를 통한 일정 주기를 가진 호출 루틴이 사용됨
    AxdiIsOn(0,0,10,&uValue, 0);
}

if(uValue)
    printf(0 모듈의 0 offset에 해당하는 입력 접점의 신호가 On을 유지하였습니다.);

AxdiIsOff: 지정한 모듈의 특정 offset 번호에 해당하는 입력 접점에서 들어오는 신호가 AxdiIsOff 함수를 n번만큼 호출할 동안 Off를 유지하고 있는지를 확인하는 함수이다. 이 함수는 설정한 횟수만큼 AxdiIsOff 함수를 호출하는 동안에 지속적으로 해당 입력 접점의 신호가 Off이면 마지막 n번째부터의 호출에서 TRUE를 반환하고, 아니면 FALSE를 반환한다. n-1번째 호출까지의 반환 값은 FALSE이다. 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 10회 호출될 동안에 지속적으로 Off를 유지하는지 확인하고자 한다면 다음과 같이 한다.

// 0번 모듈의 0번 offset에 해당하는 입력 접점의 신호가 10회 호출될 동안 Off를 유지하는지 확인
DWORD uValue;
AxdiIsOff(0,0,10,&uValue, 1); // 최초 시작

for(int i = 0; i < 9; i++)
{
    // 실제 프로그램에서는 Timer 나 Thread 를 통한 일정 주기를 가진 호출 루틴이 사용됨
    AxdiIsOff(0,0,10,&uValue, 0);
}

if(uValue)
    printf(0 모듈의 0 offset에 해당하는 입력 접점의 신호가 Off를 유지하였습니다.);
// Ex7_AXD_IsOnOff.cpp : Defines the entry point for the console application.
// 특정 입력 접점에서 신호의 지속 여부를 확인
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은 IRQ를 뜻한다. PCI는 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);

        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCount;
                AxdInfoGetModuleCount(&lModuleCount);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    if(AxdInfoGetInputCount(ModuleNo) > 0)
                    {
                        AxdiLevelSetInportDword(ModuleNo,0,0xffffffff );
                    }

                    if(AxdInfoGetOutputCount(ModuleNo) > 0)
                    {
                        AxdoLevelSetOutportDword(ModuleNo,0,0xffffffff );
                    }
                }

                // 무한 루프를 돌면서 Output Port의 현재 상태를 반환한다.
                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf([1] : 0 모듈의 0 offset 입력 접점이 100 호출될 동안 On을 유지하는지 확인\n);
                printf([2] : 0 모듈의 0 offset 입력 접점이 100 호출될 동안 Off를 유지하는지 확인\n);
                printf(**************************** \n);

                BOOL fExit = FALSE;
                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        DWORD OutPort;
                        DWORD uValue;
                        int nCount;
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;

                            case 1:
                            // 0번 모듈의 0번 offset의 입력 접점의 신호가 100회 호출될 동안 On을 유지하는지 확인
                            AxdiIsOn(0,0,100,&uValue, 1); //최초 시작
                            for(nCount = 0; nCount < 99; nCount++)
                            {
                                AxdiIsOn(0, 0, 100, &uValue, 0);
                            }

                            if(uValue)
                                printf(“\n0번 모듈의 0 offset의 입력 접점의 신호가 On을 유지하였습니다.\n);
                            else
                                printf(“\n0번 모듈의 0 offset의 입력 접점의 신호가 On을 유지하지 못했습니다.\n);
                            break

                            case 2:
                            // 0번 모듈의 0번 offset의 입력 접점의 신호가 100회 호출될 동안 Off를 유지하는지 확인
                            AxdiIsOff(0, 0, 100, &uValue, 1); // 최초 시작
                            for(nCount = 0; nCount < 99; nCount++)
                            {
                                AxdiIsOff(0, 0, 100, &uValue, 0);
                            }

                            if(uValue)
                                printf(“\n0번 모듈의 0 offset의 입력 접점의 신호가 Off를 유지하였습니다.\n);
                            else
                                printf(“\n0번 모듈의 0 offset의 입력 접점의 신호가 Off를 유지하지 못했습니다.\n);
                            break;
                        }
                    }

                    // Input Port의 현재 상태를 반환한다.
                    DWORD Status_Input;
                    DWORD uValue;
                    AxdiReadInport(0,&Status_Input);
                    printf(“\r0번 모듈의 0 offset의 현재 상태 : %d,Status_Input);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

일정 시간 동안 신호 유지

AxdoOutPulseOn: 지정한 모듈의 특정 offset 번호에 해당하는 출력 접점에 mSec 단위로 일정 시간 동안 On 상태를 유지하다가 Off 시키는 함수이다. Offset 값은 출력 접점들만 ‘0’부터 시작하는 것이 아니고, 전체 비트에서 사용자가 출력 접점의 위치를 확인하여 사용해야 한다. 예를 들어, SIO-DB32 모듈이라고 하면, 0~15까지는 입력 접점이고, 16~31까지가 출력 접점이므로 offset 값은 16~31까지의 값을 사용하여야 한다는 것이다. 0번 모듈의 0번째 출력 접점(offset 16)의 신호를 1초 동안 On 상태를 유지하다가 Off 시키고자 한다면 다음과 같이 한다.

// 0번 모듈의 16번 offset에 해당하는 출력 접점의 신호를 1초(1000ms)동안 On 시킨 후 Off 시킨다.
AxdoOutPulseOn(0,16,1000);

AxdoOutPulseOff: 지정한 모듈의 특정 offset 번호에 해당하는 출력 접점에 mSec 단위로 일정 시간 동안 Off 상태를 유지하다가 On 시키는 함수이다. Offset 값은 위에서와 마찬가지로 전체 비트에서 사용자가 출력 접점의 위치를 확인하여 사용해야 한다. 0번 모듈의 0번째 출력 접점(offset 16)의 신호를 1초 후에 On 시키고자 한다면 다음과 같이 한다.

// 0번 모듈의 16번 offset에 해당하는 출력 접점의 신호를 1초(1000ms) 후에 On 시킨다.
AxdoOutPulseOff(0,16,1000);
// Ex8_AXD_OutPulseOnOff.cpp : Defines the entry point for the console application.
// 특정 출력 포트에서 신호를 일정 시간 On 으로 유지 또는 일정 시간 후 신호를 On 시킨다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은IRQ를 뜻한다. PCI는 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);

    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);
        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);
        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCount;
                AxdInfoGetModuleCount(&lModuleCount);

                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    if(AxdInfoGetInputCount(ModuleNo) > 0)
                    {
                        AxdiLevelSetInportDword(ModuleNo,0,0xffffffff );
                    }
                    if(AxdInfoGetOutputCount(ModuleNo) > 0)
                    {
                        AxdoLevelSetOutportDword(ModuleNo,0,0xffffffff );
                    }
                }

                // 무한 루프를 돌면서 Output Port의 현재 상태를 반환한다.
                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf([1] : 신호를 일정 시간 후에 OFF 시킨다. \n);
                printf([2] : 신호를 일정 시간 후에 ON 시킨다. \n);
                printf(**************************** \n);

                BOOL fExit = FALSE;
                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        long nDelay = 1000; // [ms단위]
                        int lOffset;
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;

                            case 1:
                            // 0번 모듈의 출력 접점 신호를 순차적으로 Off 시킨다.
                            for(lOffset=0;lOffset<32;lOffset++)
                                AxdoOutPulseOn(0,lOffset,nDelay*(lOffset-16));
                            break;

                            case 2:
                            // 0번 모듈의 출력 접점 신호를 순차적으로 Off시킨다.
                            for(lOffset=0;lOffset<32;lOffset++)
                                AxdoOutPulseOff(0,lOffset,nDelay*(lOffset-16));
                            break;
                        }
                    }

                    // Output Port의 현재 상태를 반환한다.
                    DWORD Status_Output[32];
                    for(int OffsetNo=0; OffsetNo < 32; OffsetNo++)
                        AxdoReadOutport(OffsetNo,&Status_Output[OffsetNo]);

                    printf(“\r16[%d],17[%d],18[%d],19[%d],20[%d],21[%d],22[%d]..., Status_Output[0], Status_Output[1], Status_Output[2], Status_Output[3], Status_Output[4], Status_Output[5], Status_Output[6], Status_Output[7], Status_Output[8]);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

신호의 토글

AxdoToggleStart: 지정한 모듈의 특정 출력 offset 번호에 해당하는 출력 접점에 설정한 횟수 및 간격(mSec)으로 신호를 토글한 후 원래의 출력 상태를 유지하는 함수이다. 0번 모듈의 0번째 출력 접점(offset 0)의 신호를 지정된 On/Off 시간(mSec) 간격으로 10회 토글한 후 원래의 상태로 돌아가고자 한다면 다음과 같이 한다. 무한대 반복을 하고자 하면 반복 횟수에 -1을 기입한다.

// 0번 모듈의 16번 offset에 해당하는 출력 접점의 신호를 초기 시작을 On으로 100 + 200mSec 간격으로 10회 토글한다. (On time 100mSec , Off Time 200 mSec)
AxdoToggleStart(0, 0, 1, 100, 200, 10);

AxdoToggleStop: 지정한 모듈의 특정 출력 offset 번호에 해당하는 출력 접점에 토글 중인 신호를 정지시키고 특정 신호로 고정시키는 함수이다. Offset 값은 위에서와 같다. 토글 중인 0번 모듈의 0번째 출력 접점(offset 0)의 신호를 정지시키고 신호 상태를 On으로 하고자 한다면 다음과 같이 한다.

// 토글 중인 0번 모듈의 0번 출력 offset에 해당하는 출력 접점의 신호를 정지시키고, On으로 유지한다.
AxdoToggleStop(0, 0, 1);
// Ex9_AXD_ToggleStartStop.cpp : Defines the entry point for the console application.
// 특정 출력 포트에서 신호를 토글시킨다.
#include “stdafx.h”
#include “AXL.h”
#include <conio.h>
#include “stdio.h”

void main(void)
{
    // 라이브러리를 초기화한다.
    // 7은IRQ를 뜻한다. PCI에서 자동으로 IRQ가 설정된다.
    DWORD Code = AxlOpen(7);
    if(Code == AXT_RT_SUCCESS)
    {
        printf(라이브러리가 초기화되었습니다.\n);

        // DIO 모듈이 있는지 검사
        DWORD uStatus;
        Code = AxdInfoIsDIOModule(&uStatus);

        if(Code == AXT_RT_SUCCESS)
        {
            if(uStatus == STATUS_EXIST)
            {
                // DIO 모듈의 개수를 확인
                long lModuleCount;
                AxdInfoGetModuleCount(&lModuleCount);
                // DIO 모듈의 입출력 신호 레벨을 High로 설정한다.
                for(int ModuleNo=0;ModuleNo<lModuleCounts;ModuleNo++)
                {
                    if(AxdInfoGetInputCount(ModuleNo) > 0)
                    {
                        AxdiLevelSetInportDword(ModuleNo,0,0xffffffff);
                    }

                    if(AxdInfoGetOutputCount(ModuleNo) > 0)
                    {
                        AxdoLevelSetOutportDword(ModuleNo,0,0xffffffff);
                    }
                }

                // 무한 루프를 돌면서 Output Port의 현재 상태를 반환한다.
                printf([INFORMATION]*************** \n);
                printf([ESC] : Exit \n);
                printf([1] : 1 간격으로 신호를 10 동안 토글시킨다. \n);
                printf([2] : 토글 중인 신호를 정지하고 Off로 고정한다. \n);
                printf(**************************** \n);

                BOOL fExit = FALSE;
                while(!fExit) // 무한 루프
                {
                    if(kbhit()) // 아무 키나 누르면
                    {
                        int ch = getch();
                        long nDelay = 1000; // [ms단위]
                        int lOffset;
                        switch(ch)
                        {
                            case 27: // Esc key
                            fExit = TRUE;
                            break;

                            case 1:
                            // 0번 모듈의 출력 접점 신호를 1초 간격으로 10회 토글시킨다.
                            for(lOffset=0;lOffset<32;lOffset++)
                                AxdoToggleStart(0,lOffset,nDelay,10);
                            break;

                            case 2:
                            // 토글 중인 신호를 정지시키고 Off로 유지한다.
                            for(lOffset=0;lOffset<32;lOffset++)
                                AxdoToggleStop(0,lOffset,0);
                            break;
                        }
                    }

                    // Output Port의 현재 상태를 반환한다.
                    DWORD Status_Output[32];
                    for(int OffsetNo=0;OffsetNo<32;OffsetNo++)
                        AxdoReadOutport(OffsetNo,&Status_Output[OffsetNo]);

                    printf(“\r16[%d],17[%d],18[%d],19[%d],20[%d],21[%d],22[%d]..., Status_Output[0], Status_Output[1], Status_Output[2], Status_Output[3], Status_Output[4], Status_Output[5], Status_Output[6], Status_Output[7], Status_Output[8]);
                }
            }
            else
                printf(AxdInfoIsDIOModule() : ERROR ( NOT STATUS_EXIST ) code 0x%x\n,Code);
        }
        else
            printf(AxdInfoIsDIOModule() : ERROR ( Return FALSE ) code 0x%x\n,Code);
    }
    else
        printf(AxlOpen() : ERROR code 0x%x\n,Code);

    // 라이브러리를 종료한다.
    if(AxlClose())
        printf(“\n라이브러리가 종료되었습니다.\n);
    else
        printf(“\n라이브러리가 정상적으로 종료되지 않았습니다.\n);
}

10. 신규 입출력 포트 읽기/쓰기 함수

신규 DIO API 리스트와 해당 API에서 사용되는 Parameter들의 선정 방법은 아래와 같다.

Function Description
AxdiReadInportByBitOffset 지정한 입력 접점 모듈의 bit Offset 위치에서 bit Length 단위로 데이터를 읽는다.
AxdoWriteOutportByBitOffset 지정한 출력 모듈의 Bit Offset 위치에서 Bit Length 단위로 데이터를 출력한다.
AxdoReadOutportByBitOffset 지정한 출력 접점 모듈의 bit Offset 위치에서 bit Length 단위로 데이터를 읽는다.

Parameters

[in/out] Name [Init Value] Explanation
[>>]lModuleNo 모듈 번호
[>>]uBitOffset 접점에 대한 bit Offset 위치
[>>]uBitLength 접점들의 총 bit 길이
[>>]pbyData 접점 값 (uBitLength 값의 크기와 같음)

uBitOffset & uBitLength

intro

EzConfig에서 해당 DIO 모듈의 Process Image 탭을 참조하면 위와 같은 그림을 확인할 수 있다. 여기서 BitOffset은 전체 모듈에 대한 BitOffset이므로 해당 값을 참조하면 안되며, BitLength만을 사용하여 uBitOffset과 uBitLength를 구할 수 있다.

예를 들면,
Slave_001. Transmit PDO mapping 1. Error code 의 경우 [ uBitOffset : 0, uBitLength : 16 ]이며,
Slave_001. Transmit PDO mapping 1. StatusWord 의 경우 [ uBitOffset : 16, uBitLength : 16]으로 Parameter를 결정 할 수 있다.
여기서 Input과 Output은 별개의 ubitOffset으로 계산 하면 된다. pbyData의 경우 AxdiReadInportByBitOffset, AxdoReadOutportByBitOffset의 경우 입력 받을 uBitLength의 bit 크기보다 큰 배열의 포인터를 넘겨주면 해당 배열로 데이터를 읽어 온다. AxdoWriteOutportByBitOffset의 경우 출력할 데이터가 담긴 배열의 포인터를 넘겨주면 uBitLength 만큼 해당 접점 위치부터 데이터를 출력한다.

11. DIO Command 매뉴얼 정보

본 매뉴얼은 SIO-DI32/SIO-DO32P/SIO-DB32P/SIO-DO32T/SIO-DB32T 모듈과 PCI-DB64R, PCI-DI64R, PCIDO64R 보드 제품 및 NETWORK으로 구성된 RTEX, MECHATROLINK II의 제품을 Windows 98, Windows NT, Windows 2000 또는 Windows XP의 OS환경에서 Microsoft VC++6.0, Visual Basic, Borland C-Builder, Delphi등의 언어에서 구동하기 위해 필요한 매뉴얼이며, 포함된 라이브러리 함수를 기능별로 분류하여 설명하였다.

헤더 파일
C++: AXD.h
C#: AXD.cs
Visual Basic: AXD.bas
Delphi: AXD.pas

12. 함수 용어

본 매뉴얼의 함수 이름

본 매뉴얼에서 사용된 함수 이름들은 접두어(Prefix)에 의해 동작을 구분할 수 있도록 되어있다.

라이브러리 함수 Prefix

Prefix/Suffix 설명
AxdInfo 보드 및 모듈 정보 확인 함수
Axdi Digital 입력 관련 대분류
Axdo Digital 출력 관련 대분류
AxdiInterrupt 입력 인터럽트 설정 확인
AxdiInterruptEdge 입력 인터럽트 상승 / 하강 에지시 인터럽트 발생 설정 확인
AxdiLevel 입력 신호 레벨 설정 확인
AxdiRead 입력 신호 읽기
AxdoRead 출력 신호 읽기
AxdoWrite 출력 신호 쓰기
AxdoLevel 출력 신호 레벨 설정 확인
Get 레지스터 값 확인
Set 레지스터 값 설정
Inport 입력 접점과 관련된 함수
Outport 출력 점점과 관련된 함수
Bit 1개의 접점 단위
Byte 8개의 접점 단위
Word 16개의 접점 단위
Dword 32개의 접점 단위

본 매뉴얼의 인자 이름

본 매뉴얼에서 사용된 함수들의 공통적인 인자들은 다음과 같은 의미를 가진다.

long lBoardNo: 초기화 된 베이스 보드(Base Board)의 첫 번째 보드부터 오름차순으로 자동 정렬된다. 보드번호는 ‘0’부터 시작한다.
long lModuleNo: DIO 모듈 초기화 시에 첫 번째 보드의 모듈부터 오름차순으로 자동 정렬된다. 모듈 번호는 ‘0’부터 시작한다.
DWORD uLevel: uLevel은 ReadPort 및 WriteOutport 관련 함수들을 사용 시 Level을 설정하고 확인한다.
DWORD uOffset: uOffset은 사용 모듈과 사용 함수에 따라 유효 범위가 달라지는데 아래의 Table을 참조하여 설정한다.

Data Type Offset Value or Return Related
All 0 ~ n-1 0(Off ), 1(On)
Bit 0 ~ 31 0(Off ), 1(On) Bit 계열 함수군
Byte 0, 1, 2, 3 00h ~ FFh Byte 계열 함수군
Word 0, 1 0000h ~ FFFFh Word 계열 함수군
Dword 0 00000000h ~ FFFFFFFFh Dword 계열 함수군

만약, 시스템에 SIO-DB32 / SIO-DI32 / SIO-DO32 모듈이 하나씩 장착되어 있고 할당된 Module No가 각각 0,1,2 로 순차적이라면, 각 모듈별 할당 Offset의 범위와 각 함수의 연관성은 아래 표와 같다.

입력 Offset

SIO-DB32
(In32/Out32)
SIO-DI32
(In32)
Data Size 비고
AxdiLevelSetInport
AxdiLevelGetInport
AxdiReadInport
0 ~ 15 16 ~ 47 1 전체 모듈에서 Offset 적용됨
AxdiLevelSetInportBit
AxdiLevelGetInportBit
AxdiReadInportBit
0 ~ 15 0 ~ 31 1 각각의 모듈 Offset 적용
AxdiLevelSetInportByte
AxdiLevelGetInportByte
AxdiReadInportByte
0 ~ 1 0 ~ 3 8 각각의 모듈 Offset 적용
AxdiLevelSetInportWord
AxdiLevelGetInportWord
AxdiReadInportWord
0 0 ~ 1 16 각각의 모듈 Offset 적용
AxdiLevelSetInportDword
AxdiLevelGetInportDword
AxdiReadInportDword
0 0 32 각각의 모듈 Offset 적용

출력 Offset

SIO-DB32
(In32/Out32)
SIO-DO32
(Out32)
Data Size 비고
AxdoLevelSetInport
AxdoLevelGetInport
AxdoReadInport
0 ~ 15 16 ~ 47 1 전체 모듈에서 Offset 적용됨
AxdoLevelSetInportBit
AxdoLevelGetInportBit
AxdoReadInportBit
0 ~ 15 0 ~ 31 1 각각의 모듈 Offset 적용
AxdoLevelSetInportByte
AxdoLevelGetInportByte
AxdoReadInportByte
0 ~ 1 0 ~ 3 8 각각의 모듈 Offset 적용
AxdoLevelSetInportWord
AxdoLevelGetInportWord
AxdoReadInportWord
0 0 ~ 1 16 각각의 모듈 Offset 적용
AxdoLevelSetInportDword
AxdoLevelGetInportDword
AxdoReadInportDword
0 0 32 각각의 모듈 Offset 적용

Interrupt Rising / Falling Edge Register

Interrupt Rising(Up) Edge는 사용자가 원하는 해당 입력 비트의 Rising Edge에서 인터럽트를 검출하기 위해 설정하는 레지스터이다. 해당 비트를 ‘1’로 셋팅하면 Rising Edge시에 인터럽트가 발생한다. Interrupt Falling(Down) Edge는 사용자가 원하는 해당 입력 비트의 Falling Edge에서 인터럽트를 검출하기 위해 설정하는 레지스터이다. 해당 비트를 ‘1’로 셋팅하면 Falling Edge시에 인터럽트가 발생한다. 단, 인터럽트가 Enable일 경우에 인터럽트가 발생한다.