PLC에서 같은 패턴의 데이터 처리를 여러 번 반복해야 하는 경우가 있습니다. 예를 들어 D100부터 D199까지 100개의 데이터를 검사하거나, 여러 개의 설정값을 순서대로 계산하거나, 일정 범위의 데이터를 비교하는 작업입니다. 이런 로직을 모두 한 줄씩 작성하면 프로그램이 길어지고 유지보수가 어려워집니다. FOR-NEXT와 인덱스 레지스터 Z를 함께 사용하면 반복 데이터 처리를 훨씬 간결하게 구성할 수 있습니다.
반복 로직을 줄여야 하는 이유
PLC 프로그램에서 같은 구조가 반복되면 처음 작성할 때는 단순해 보일 수 있습니다. 그러나 데이터 개수가 늘어나면 문제가 달라집니다.
예를 들어 데이터 100개를 하나씩 비교하려고 같은 비교 로직을 100줄 작성하면, 나중에 조건을 하나 수정할 때 100곳을 확인해야 합니다. 중간에 주소 하나가 잘못 들어가도 찾기가 어렵고, 프로그램 전체 가독성도 떨어집니다.
반복 로직이 길어지면 다음 문제가 자주 발생합니다.
| 문제 | 설명 |
|---|---|
| 로직 길이 증가 | 같은 패턴이 반복되어 프로그램이 길어짐 |
| 주소 오류 | D137, D173처럼 중간 주소를 잘못 입력하기 쉬움 |
| 수정 부담 | 조건 변경 시 여러 줄을 모두 수정해야 함 |
| 디버깅 어려움 | 몇 번째 데이터에서 문제가 생겼는지 찾기 어려움 |
| 유지보수성 저하 | 다른 작업자가 로직 구조를 파악하기 어려움 |
FOR-NEXT는 이런 반복 작업을 정리하는 데 사용됩니다. 특히 인덱스 레지스터 Z와 함께 사용하면 연속된 데이터 영역을 배열처럼 처리할 수 있습니다.
본 글은 미쓰비시 MELSEC Q/R 시리즈 및 GX Works2/3 기준의 일반적인 내용을 바탕으로 작성했습니다. FOR-NEXT 사용 가능 범위, 인덱스 레지스터 개수, 명령어 제한 조건은 CPU 모델과 프로젝트 설정에 따라 달라질 수 있으므로 실제 적용 전 매뉴얼을 확인해야 합니다.
FOR-NEXT의 기본 개념
FOR-NEXT는 지정한 횟수만큼 특정 구간의 로직을 반복 실행하는 구조입니다. FOR에서 반복 횟수를 지정하고, NEXT에서 반복 구간을 종료합니다.
예를 들어 100개의 데이터를 처리해야 한다면 FOR K100처럼 반복 횟수를 지정할 수 있습니다. 그러면 FOR와 NEXT 사이의 로직이 지정 횟수만큼 반복 실행됩니다.
FOR-NEXT의 기본 개념은 다음과 같습니다.
| 구분 | 설명 |
|---|---|
| FOR | 반복 시작 지점 |
| 반복 횟수 | 몇 번 반복할지 지정 |
| 반복 구간 | FOR와 NEXT 사이의 로직 |
| NEXT | 반복 종료 지점 |
| 실행 방식 | 지정 횟수만큼 반복 후 다음 로직으로 진행 |
FOR-NEXT는 반복 로직을 줄이는 데 효과적입니다. 다만 한 스캔 안에서 반복이 처리될 수 있으므로 반복 횟수와 내부 연산량을 신중하게 잡아야 합니다.
FOR만으로는 배열 처리가 어렵다
FOR-NEXT만 사용하면 같은 구간을 반복 실행할 수는 있지만, 주소가 자동으로 바뀌는 것은 아닙니다.
예를 들어 D100 값을 100번 읽는 구조라면 반복은 되지만 매번 같은 D100만 읽게 됩니다. 데이터 100개를 순서대로 처리하려면 D100, D101, D102처럼 주소가 반복마다 바뀌어야 합니다.
이때 필요한 것이 인덱스 레지스터 Z입니다.
인덱스 레지스터 Z의 역할
Z는 주소를 가변적으로 지정할 때 사용하는 인덱스 레지스터입니다. 고정 주소 뒤에 Z를 붙이면 실제 참조 주소가 Z 값만큼 이동합니다.
예를 들어 Z0 값이 5라면 D100Z0은 D105를 가리키는 방식으로 이해할 수 있습니다.
| Z0 값 | D100Z0이 가리키는 실제 주소 |
|---|---|
| 0 | D100 |
| 1 | D101 |
| 2 | D102 |
| 5 | D105 |
| 99 | D199 |
이 구조를 FOR-NEXT와 결합하면 연속된 데이터 영역을 순서대로 처리할 수 있습니다.
FOR-NEXT와 Z를 함께 사용하는 기본 패턴
FOR-NEXT와 Z를 함께 사용할 때는 보통 다음 흐름으로 구성합니다.
| 단계 | 처리 내용 |
|---|---|
| 1 | 루프 시작 전 Z 값을 초기화 |
| 2 | FOR로 반복 횟수 지정 |
| 3 | D100Z0처럼 인덱스 주소로 데이터 처리 |
| 4 | 반복마다 Z 값을 증가 |
| 5 | NEXT에서 지정 횟수만큼 반복 |
| 6 | 반복 완료 후 다음 로직 진행 |
예를 들어 D100부터 D199까지 100개 데이터를 순서대로 검사하려면, Z0을 0으로 초기화한 뒤 FOR K100을 실행하고, 반복마다 Z0을 1씩 증가시키는 방식으로 구성할 수 있습니다.
이때 중요한 것은 루프 시작 전에 Z 값을 반드시 초기화하는 것입니다. 이전 스캔이나 다른 로직에서 사용한 Z 값이 남아 있으면 의도하지 않은 주소를 참조할 수 있습니다.
데이터 배열 연산 예시
두 개의 데이터 배열을 더해서 결과 배열에 저장하는 구조를 예로 들 수 있습니다.
예를 들어 D100~D199와 D200~D299의 값을 순서대로 더해 D300~D399에 저장하는 구조입니다.
개념은 다음과 같습니다.
| 반복 순서 | 읽는 값 1 | 읽는 값 2 | 저장 위치 |
|---|---|---|---|
| 1회 | D100 | D200 | D300 |
| 2회 | D101 | D201 | D301 |
| 3회 | D102 | D202 | D302 |
| … | … | … | … |
| 100회 | D199 | D299 | D399 |
이런 구조를 개별 로직으로 작성하면 100줄 이상이 필요합니다. 하지만 FOR-NEXT와 Z를 사용하면 반복 패턴 하나로 처리할 수 있습니다.
인덱스는 반드시 초기화해야 한다
FOR-NEXT에서 Z를 사용할 때 가장 기본이 되는 작업은 인덱스 초기화입니다.
예를 들어 루프 시작 전에 Z0을 0으로 만들지 않으면, 이전에 사용하던 값이 남아 있을 수 있습니다. Z0 값이 50인 상태에서 D100Z0을 사용하면 D150부터 참조하게 됩니다.
따라서 반복 처리를 시작하기 전에는 MOV K0 Z0처럼 인덱스 값을 초기화하는 구조를 넣는 것이 일반적입니다.
인덱스 초기화가 필요한 이유는 다음과 같습니다.
| 이유 | 설명 |
|---|---|
| 주소 기준점 정리 | 항상 D100부터 시작하도록 보장 |
| 이전 값 영향 제거 | 이전 루프 또는 다른 로직의 Z 값 잔류 방지 |
| 디버깅 편의 | 반복 시작점이 명확해짐 |
| 메모리 침범 방지 | 예상보다 뒤쪽 주소를 참조하는 문제 방지 |
Z는 단순한 데이터가 아니라 주소를 바꾸는 값입니다. 따라서 일반 D 값보다 더 신중하게 관리해야 합니다.
Z를 증가시키는 방식
반복마다 다음 주소로 이동하려면 Z 값을 증가시켜야 합니다. 1워드씩 순서대로 처리하는 경우에는 Z0을 1씩 증가시키면 됩니다.
예를 들어 D100, D101, D102처럼 연속 주소를 처리할 때는 반복마다 Z0을 1씩 증가시키는 방식이 적합합니다.
반면 결과 저장 위치를 한 칸씩 띄워서 저장해야 한다면 Z 값을 2씩 증가시키는 구조도 사용할 수 있습니다. 예를 들어 D300, D302, D304처럼 저장해야 하는 경우입니다.
| 처리 방식 | 인덱스 증가 |
|---|---|
| D100, D101, D102 순서 | 1씩 증가 |
| D300, D302, D304 순서 | 2씩 증가 |
| 32비트 데이터 단위 처리 | 구조에 따라 2워드 단위 고려 |
| 고정 간격 데이터 처리 | 데이터 구조에 맞게 증가값 설정 |
32비트 데이터를 다룰 때는 한 데이터가 2워드를 사용하는 경우가 많으므로 인덱스 증가량을 반드시 확인해야 합니다. 32비트 위치값을 D100/D101, D102/D103처럼 저장했다면 다음 데이터로 이동할 때 2워드 단위 이동이 필요할 수 있습니다.
FOR-NEXT는 한 스캔 부하를 증가시킬 수 있다
FOR-NEXT는 반복 로직을 짧게 만들지만, 실행 부하가 사라지는 것은 아닙니다. 반복 횟수만큼 내부 로직이 실행되므로 한 스캔에서 처리해야 하는 연산량은 늘어날 수 있습니다.
예를 들어 FOR K100 내부에 단순 비교 한두 개만 있다면 큰 문제가 없을 수 있습니다. 하지만 내부에 문자열 처리, 대량 연산, 통신 데이터 가공, 여러 개의 BMOV, 복잡한 비교가 들어가면 스캔 타임이 늘어날 수 있습니다.
반복 횟수와 내부 연산량이 과도하면 WDT, 즉 Watchdog Timer 에러가 발생할 수 있습니다. WDT는 PLC가 정해진 시간 안에 한 스캔을 끝내지 못할 때 발생할 수 있으며, 경우에 따라 CPU STOP으로 이어질 수 있습니다.
WDT 에러를 피하기 위한 기준
FOR-NEXT를 사용할 때는 반복 횟수를 무조건 크게 잡지 말고 실제 필요한 만큼만 설정해야 합니다.
다음 기준을 확인하는 것이 좋습니다.
| 확인 항목 | 설명 |
|---|---|
| 반복 횟수 | 실제 필요한 데이터 개수만 반복하는지 확인 |
| 내부 연산량 | 루프 안에 무거운 연산이 과도하게 들어가지 않았는지 확인 |
| 실행 주기 | 매 스캔 실행해야 하는지, 조건부 실행이면 되는지 확인 |
| 스캔 타임 변화 | 적용 전후 스캔 타임을 확인 |
| 분할 처리 필요성 | 데이터가 많으면 여러 스캔으로 나누어 처리 검토 |
모든 데이터를 반드시 한 스캔에 처리할 필요가 없다면, 여러 스캔에 나누어 처리하는 방식도 검토할 수 있습니다. 예를 들어 한 스캔에 10개씩 처리하고 다음 스캔에서 이어서 처리하는 구조입니다.
CJ와 함께 사용하는 경우
FOR-NEXT는 매 스캔 실행할 필요가 없는 경우가 많습니다. 예를 들어 모델 변경 시에만 레시피 데이터를 검사하거나, 검사 완료 후에만 100개 데이터를 비교하는 구조라면 매 스캔 반복문을 실행할 필요가 없습니다.
이런 경우 CJ 같은 조건부 점프 구조를 이용해 필요한 시점에만 FOR-NEXT 구간을 실행하도록 구성할 수 있습니다.
다만 CJ를 사용할 때는 출력 HOLD나 RST 미실행 문제를 주의해야 합니다. FOR-NEXT 구간이 데이터 처리 전용인지, 출력 제어와 섞여 있는지 반드시 확인해야 합니다.
FOR-NEXT와 CJ를 함께 사용할 때의 기준은 다음과 같습니다.
| 항목 | 기준 |
|---|---|
| 실행 조건 | 데이터 처리 요청이 있을 때만 실행 |
| 출력 제어 | 루프 내부에서 실제 Y 출력 제어는 피함 |
| 완료 플래그 | 반복 처리 완료 후 별도 플래그 설정 |
| 재실행 방지 | 완료 후 요청 비트 초기화 |
| 스캔 타임 확인 | 조건부 실행 시에도 최대 부하 확인 |
CJ는 반복문 실행 시점을 제어하는 데 사용할 수 있지만, 안전 조건이나 최종 출력부를 건너뛰는 용도로 사용하면 안 됩니다.
루프 외부 간섭을 확인해야 한다
FOR-NEXT와 Z를 사용할 때 Z 값이 예상과 다르게 움직인다면, 루프 외부에서 같은 Z 레지스터를 사용하고 있는지 확인해야 합니다.
하나의 Z 레지스터를 여러 루틴에서 공유하면 다음 문제가 발생할 수 있습니다.
| 문제 | 설명 |
|---|---|
| 주소 참조 오류 | 다른 루틴에서 바꾼 Z 값으로 엉뚱한 주소 접근 |
| 간헐적 오류 | 특정 조건에서만 Z 값이 바뀌어 원인 추적 어려움 |
| 데이터 덮어쓰기 | 저장 위치가 밀려 다른 영역을 덮을 수 있음 |
| 디버깅 어려움 | 루프 내부에서는 정상처럼 보이지만 외부 조건이 간섭 |
가능하면 루틴별로 사용하는 Z 번호를 구분하고, 주석으로 용도를 명확히 남기는 것이 좋습니다.
예를 들어 Z0은 검사 데이터 루프, Z1은 결과 저장 루프, Z2는 레시피 복사 루프처럼 역할을 나누면 유지보수가 쉬워집니다.
처음 적용할 때는 반복 횟수를 줄여 검증한다
FOR-NEXT는 한 스캔 안에서 빠르게 실행되기 때문에 모니터링이 쉽지 않습니다. 따라서 처음부터 FOR K100으로 전체 데이터를 처리하기보다, FOR K1 또는 FOR K2처럼 작은 횟수로 동작을 검증하는 것이 안전합니다.
검증할 때는 다음 항목을 확인합니다.
| 확인 항목 | 설명 |
|---|---|
| 첫 번째 주소 | D100, D200, D300 등 시작 주소가 맞는지 확인 |
| 두 번째 주소 | Z 증가 후 D101, D201, D301로 이동하는지 확인 |
| 저장 결과 | 결과값이 의도한 위치에 들어가는지 확인 |
| 반복 종료 | 지정 횟수 후 루프가 종료되는지 확인 |
| 범위 초과 | 마지막 반복에서 지정 영역을 넘지 않는지 확인 |
검증 후 반복 횟수를 실제 데이터 개수로 늘리는 것이 좋습니다.
메모리 범위 초과를 주의해야 한다
Z 인덱스를 사용하면 주소가 자동으로 이동하기 때문에, 반복 횟수를 잘못 설정하면 할당하지 않은 영역까지 접근할 수 있습니다.
예를 들어 D100부터 D199까지 100개 데이터만 처리해야 하는데 FOR K120으로 설정하면 D200 이후 영역까지 참조할 수 있습니다. 그 영역이 다른 용도로 사용 중이라면 데이터 충돌이 발생합니다.
메모리 범위 초과를 막으려면 다음을 확인해야 합니다.
| 확인 항목 | 설명 |
|---|---|
| 시작 주소 | 배열의 첫 주소 확인 |
| 데이터 개수 | 실제 처리할 개수 확인 |
| 인덱스 증가량 | 1씩 증가인지, 2씩 증가인지 확인 |
| 마지막 주소 | 마지막 반복에서 접근하는 주소 계산 |
| 주변 영역 | 바로 뒤 주소가 다른 용도로 쓰이는지 확인 |
FOR-NEXT와 Z를 사용할 때는 시작 주소와 반복 횟수만 보는 것이 아니라, 마지막으로 접근하는 주소까지 계산해야 합니다.
반복 연산 설계 체크리스트
FOR-NEXT와 Z를 사용한 반복 연산을 설계할 때는 다음 항목을 점검하는 것이 좋습니다.
| 점검 항목 | 확인 내용 |
|---|---|
| 인덱스 초기화 | 루프 시작 전 Z 값을 0 또는 기준값으로 초기화했는지 확인 |
| 반복 횟수 | 실제 데이터 개수와 반복 횟수가 일치하는지 확인 |
| 인덱스 증가 | 데이터 구조에 맞게 1워드 또는 2워드 단위로 증가하는지 확인 |
| 메모리 범위 | 마지막 반복에서 할당 영역을 넘지 않는지 확인 |
| 외부 간섭 | 다른 로직에서 같은 Z를 변경하지 않는지 확인 |
| 스캔 타임 | 반복 처리로 스캔 타임이 과도하게 늘지 않는지 확인 |
| WDT 위험 | 루프 내부 연산량이 과도하지 않은지 확인 |
| 테스트 방법 | 처음에는 1~2회 반복으로 검증했는지 확인 |
이 체크리스트를 기준으로 보면 반복문 사용 시 발생하는 대부분의 주소 오류와 스캔 타임 문제를 줄일 수 있습니다.
FOR-NEXT와 Z 활용 정리
FOR-NEXT는 반복적인 로직을 줄이는 데 효과적인 구조입니다. 데이터 100개를 비교하거나, 여러 설정값을 순서대로 처리하거나, 연속된 영역을 검사해야 할 때 같은 로직을 반복해서 작성하지 않고 하나의 반복 구조로 정리할 수 있습니다.
하지만 FOR-NEXT만으로는 주소가 자동으로 바뀌지 않습니다. 인덱스 레지스터 Z를 함께 사용해야 D100, D101, D102처럼 연속된 데이터를 순서대로 처리할 수 있습니다. 그래서 미쓰비시 PLC에서 FOR-NEXT와 Z는 대량 데이터 처리의 기본 조합으로 볼 수 있습니다.
반복문은 로직을 짧게 만들지만, 한 스캔 안에서 여러 번 실행되므로 스캔 타임과 WDT 에러를 고려해야 합니다. 루프 시작 전에는 Z 값을 초기화하고, 반복 횟수와 마지막 접근 주소를 계산해야 하며, 다른 로직에서 같은 Z를 변경하지 않는지도 확인해야 합니다.
FOR-NEXT와 Z를 정확히 사용하면 반복 로직을 줄이고 데이터 처리 구조를 명확하게 만들 수 있습니다. 다만 반복문은 눈에 보이는 래더 줄 수를 줄이는 도구일 뿐, 메모리 안에서 어떤 주소를 읽고 쓰는지까지 계산되어야 안정적으로 사용할 수 있습니다.