테스트를 위하여 Queue에 임시로 명령을 저장한 후 데이터 전송하도록 프로그램을 구성할 것입니다.
ID 읽기와 데이터 읽기는 같은 명령을 사용해도 번지만 변경하게 되면 공용으로 사용 가능하여 하나의 함수로
구성하였습니다.
함수 호출하기
ID 읽기 : 주소 : 0xA0000 , 사이즈 : 4 ( ID 읽기는 주소 및 사이즈가 고정되어야 정상 데이터를 받을 수 있습니다. )
데이터 쓰기 :
데이터 읽기 : 주소 : 0 , 사이즈 : 4 ( 상황에 따라 수정 후 사용 가능합니다 )
// 큐에 명령어 저장
Queue<byte[]> quene = new Queue<byte[]>();
quene.Enqueue(CmdRead(0xA000, 4));// ID 읽기(번지=0xa000, 사이즈=4)
quene.Enqueue(CmdWrite(0, new byte[] { 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44 })); // 데이터 쓰기(번지=0, 데이터='1111222233334444')
quene.Enqueue(CmdRead(0, 4)); // 데이터 읽기(번지=0,사이즈=4)
ID 읽기 / 데이터 읽기 함수
주소와 데이터 사이즈를 받아서 명령어를 리턴하며 통신 구성은 아래와 같습니다.
static byte[] CmdRead(int register_No/*주소*/ , int word_count/*갯수*/) // 읽기
{
int fild_Length = 0x0006; // 고정
byte[] bytes = new byte[12];
//트랜젝선 식별자
bytes[0] = 0;
bytes[1] = 0;
//프로토콜 식별자
bytes[2] = 0;
bytes[3] = 0;
//필드 길이
bytes[4] = (byte)((fild_Length & 0xFF00) >> 8); //(H)
bytes[5] = (byte)(fild_Length & 0x00FF); //(L)
//유니트 식별자
bytes[6] = 0xFF;
//펑션 코드
bytes[7] = 0x3;
//레지스터 번호
bytes[8] = (byte)((register_No & 0xFF00) >> 8); //(H)
bytes[9] = (byte)(register_No & 0xFF); //(L)
//워드 카운터
bytes[10] = (byte)((word_count & 0xFF) >> 8); //(H)
bytes[11] = (byte)(word_count & 0x00FF); //(L)
return bytes;
}
데이터 쓰기 함수
데이터를 읽은 주소, 쓰고자 하는 데이터를 바이트 배열로 입력하여 전송하며, 데이터의 크기는 배열의 크기에 따라 동적으로 변경되도록 하였습니다.
static byte[] CmdWrite(int register_No/*주소*/, params byte[] WrData/*데이터*/) // 쓰기
{
byte[] bytes = new byte[12 + WrData.Length + 1];
int word_count = WrData.Length / 2;
int fild_Length = bytes.Length - 6;
//트랜젝선 식별자
bytes[0] = 0;
bytes[1] = 0;
//프로토콜 식별자
bytes[2] = 0;
bytes[3] = 0;
//필드길이
bytes[4] = (byte)((fild_Length & 0xFF00) >> 8); //(H)
bytes[5] = (byte)(fild_Length & 0x00FF); //(L)
//유니트 식별자
bytes[6] = 0xFF;
//펑션 코드
bytes[7] = 0x10;
//레지스터 번호
bytes[8] = (byte)((register_No & 0xFF00) >> 8); //(H)
bytes[9] = (byte)(register_No & 0xFF); //(L)
//레지스터 카운터
bytes[10] = (byte)((word_count & 0xFF) >> 8); //(H)
bytes[11] = (byte)(word_count & 0x00FF); //(L)
//바이트 카운터
bytes[12] = (byte)(word_count * 2);
//쓰기 데이터
for (int i = 0; i < WrData.Length; i++)
{
bytes[13 + i] = WrData[i];
}
return bytes;
}
데이터 수신 함수
장치로부터 받은 데이터를 각각의 배열 원소에 따라 구분토록 하였습니다.
최소 바이트 수는 6이며 6번째 값에 따라 에러 유무를 구분하고, 에러일 경우 6번째 이후의 값은 에러 번호로 리턴됩니다.
7번째의 값은 읽기/쓰기 구분이며, 읽은 경우 9번째부터 뒤의 데이터가 읽은 값이 되고, 주소는 리턴되지 않습니다.
쓰기의 경우 데이터 주소, 사이즈가 리턴되어 전송 성공을 판단할 수 있습니다.
static void ReceiveDataPaser(params byte[] bytes)//데이터 분석
{
if (bytes.Length > 6)
{
if (bytes[6] == 0xFF) /*유니트 식별자*/
{
if (bytes.Length == 9)// 에러인 경우
{
if (bytes[7] == 0x83 | bytes[7] == 0x90)
{
string err = "";
switch (bytes[8])
{
case 0x00: { err = "정상 종료"; break; }
case 0x01: { err = "잘못된 펑션"; break; }
case 0x02: { err = "잘못된 데이터 주소"; break; }
case 0x03: { err = "잘못된 데이터 값"; break; }
case 0x04: { err = "슬레이브 장치 실패"; break; }
case 0x06: { err = "슬레이브 장치 사용 중"; break; }
}
WriteLine("Err :{0}", err);
}
}
else
{
if (bytes[7] == 0x03 /*펑션 코드*/)
{
string hex = "";
// 9번째 부터가 데이터
for (int i = 9; i < bytes.Length; i++)
{
hex += bytes[i].ToString("X2");
}
// 아스키 확인용
string ascii = Encoding.Default.GetString(bytes, 9, bytes.Length - 9);
WriteLine("데이터 : {0}", hex);
}
else if (bytes[7] == 0x10 /*펑션 코드*/)
{
int no = ((bytes[8] & 0xFF00) << 8) + bytes[8];
int wordCnt = ((bytes[10] & 0xFF00) << 8) + bytes[11];
WriteLine("데이터 번지 : {0} , 데이터 사이즈 : {1}", no, wordCnt);
}
}
}
}
}
실행 결과
ID 읽기 4 워드(8바이트, 두 개씩 한 묶음)가 리턴되었고 쓰기 0번 주소에 4 워드로 입력되었습니다.
읽기는 앞에서 전송 한 값을 4 워드로 수신한 것을 확인할 수 있었습니다.
이전 포스트
2021.11.08 - [프로젝트/통신] - RFID 오므론 V608S IP 설정 및 통신 확인
2021.11.05 - [프로젝트/통신] - RFID 오므론 V608S 통신 프로토콜 확인
2021.11.05 - [프로젝트/통신] - RFID 오므론 V608S 선정 및 구성
'프로그래밍 > C Sharp' 카테고리의 다른 글
[ C# ] 엑셀파일 읽기 (0) | 2021.11.09 |
---|---|
[ C# ] 허니웰 스케너 시리얼 통신으로 On/Off 하기 (1) | 2021.11.08 |
[ C# ] 배열 생성시 초기값 넣기 (0) | 2021.11.08 |
[ C# ] 그래프 필터링 하기 : 이동 평균 필터(Move Average Filter) (2) | 2021.11.04 |
[ C# ] 스택(Stack) 과 큐(Queue) (0) | 2021.11.02 |
댓글