RF433 송수신기용 강력통신함수 개발

IMGP0469

 

인터넷 상의 통신 프로토콜을 사용하여 통신을 하고자 하는 경우 BAUD RATE를 높게 적용함에 의하여 조그만 노이즈에도 수신이 잘 되지 않습니다.

우리나라에서 433MHZ는 자동차 시동과문개폐용 과 타이어 압력 확인용으로 사용토록 되어 있어서  주변에서 작은 노이즈가 수시로 발생합니다.

BUAD RATE를 130 수준으로 낮추고 송신기의 주기와 정확한 싱크로를 이루어 다소의 노이즈가 있어도 메세지 수신에 성공하는 “강력통신함수”를 아래와 같이 소개합니다.


통신함수 자체는 문자열 (string) 을 송수신 할 수 있습니다.
스위치 개폐 자체만의 전송을 사용하고자 원하면 아래 전산올을 사용하십시요..

1.  하나의 스위치로 on/off 하는 경우

int SWpinnum = 5      //on 용 접점 스위치가 연결된 핀 번호
int ledPinnum = 6           // 스위치의 on/off 상태를 보여주는 led 핀번호
String  onCode = “AA”         // 스위치 on 됬을 때 송신할 문자code
String  offCode = “BB”         // 스위치 off 됬을 때 송신할 문자 code
bool SWonoff  = false;          //swith 의 기 요청된 on/off  상태
long SWconkeepTime;        // 스위치의 변경된 상태를 유지하는 시간 (밀리초)

//*****************************************************************
void setup () {
pinMode(SWpinnum , INPUT);
pinMode(ledPinnum,OUTPUT);

//*****************************************************************
void loop() {

if (millis()>SWconkeepTime){           //스위치 상태를 유지하는 기본 시간이 경과하면
bool  SWon = digitalRead(SWPinnum)  //핀의 상태를 읽고
if(SWon !=SWonoff){   //현재 의 상태와 다르면
if (Swon) {RF433Send(onCode);digitalWrite(ledPinnum, HIGH);}                                                                             //on이면 onCode전송 LED를 켜고
else {RF433Send(offCode);digitalWrite(ledPinnum,LOW);}
//off이면 offCode 전송 LED 끔
SWonoff = SWon ;        //SWonoff 를 변경된 상태로 바꾸고
SWconkeepTime = millis()+10000 ;  다시 10초간 상태 변경 정지
}
}
//*****************************************************************

수신기
//*****************************************************************

int ledPinnum = 6     ;      // 스위치의 on/off 상태를 보여주는 led 핀번호
String  onCode = “AA”  ;       // 스위치 on 됬을 때 송신할 문자code
String  offCode = “BB”   ;      // 스위치 off 됬을 때 송신할 문자 code

void setup(){

pinMode( ledPinnum, OUTPUT);

void loop() {

if (RF433_21S_Received()) {
if (RFString==onCode){digitalWrite(ledPinnum,HIGH);}
if (RFString==offCode){digitalWrite(ledPinnum,LOW);}
}

/*************************************************************************

1.  두개의 스위치로 on 과  off 하는 경우

int SWpinOnnum = 5      //on 용 접점 스위치가 연결된 핀 번호
int SWpinOffnum = 6      //off 용 접점 스위치가 연결된 핀 번호
int ledPinnum = 7           // 스위치의 on/off 상태를 보여주는 led 핀번호
String  onCode = “AA”         // 스위치 on 됬을 때 송신할 문자code
String  offCode = “BB”         // 스위치 off 됬을 때 송신할 문자 code
bool SWonoff  = false;          //swith 의 기 요청된 on/off  상태
long SWconkeepTime;        // 스위치의 변경된 상태를 유지하는 시간 (밀리초)

//*****************************************************************
void setup () {
pinMode(SWpinOnnum , INPUT);
pinMode(SWpinoffnum , INPUT);
pinMode(ledPinnum,OUTPUT);

//*****************************************************************
void loop() {
if (digitalRead( SWpinOnnum){SWon=true;}  //핀의 상태를 읽고
if (digitalRead( SWpinoffnum){SWon=false;}  //핀의 상태를 읽고
if (millis()>SWconkeepTime){           //스위치 상태를 유지하는 기본 시간이 경과하면
if(SWon !=SWonoff){   //현재 의 상태와 다르면
if (Swon) {RF433Send(onCode);digitalWrite(ledPinnum, HIGH);}                                                                             //on이면 onCode전송, LED를 켜고         else {RF433Send(offCode);digitalWrite(ledPinnum,LOW);}                                                                        //off이면 offCode 전송, LED 끔
SWonoff = SWon ;        //SWonoff 를 변경된 상태로 바꾸고
SWconkeepTime = millis()+10000 ;  다시 10초간 상태 변경 정지  이는 본함수가 2.5초 간격으로 동일 내용을 4회 전송하기 때문입니다)
}
}

//*****************************************************************

수신기 전산올   은  단일 접점 스위치 사용시와 동일
//*****************************************************************
//************************************************************************

내려받기판

RF433_order_1111   송신기용

RF433_RECEIVER_1110   수신기용


송신기 전산올 (스케치 내용)

수신기 전산올

/************************************************************************* RF433 송수신 강력함수 …… 작성자 : 21세기의봄 (대표 김창곤) *************************************************************************** 원리:
* 1) 1 Milli 초에 1 subbit를 송수신함   //나노 초를 사용하면 자체 계산 시간이 길어져서 잘 안됨
* 2) 8개의 subbit에서 앞2개는 버리고 뒤의 6개의 bit 군으로 8개의 sub bit 가 1 표시인지 0 표시인지 판정

* 3) 1 char 수신을 위한 8개의 bit후 2개의 bit를 check bit로 사용
* 4) 함수가 호출되고 시작주기 시간이 지나면 일단 수신 bit들을 buffer[200]에 저장
* 5) buffer[]에서 문자 수신 시작 점 검색하여 거의 정확한 시작 sub bit 파악
* – 시작문자열울 만족시키는 sub bit군을 우선 검색하고 만족하면 송신 글자수를 알려주는 첫 byte의 checkbit  일치 여부를 확인하여 만족시 나머지 문자열 수신…

6) 최대로 4bit로 표현되는 16 문자를 수신…
* 7)  송신 글자수의 50% 이상이 checkbit에서 오류를 보이면 문자열 수신 실패로 간주…
* 8) 수신 오류 문자는 앞선 수신 문자로 대체
* 9) buffer[]내에서 시작점이 있는 위치,i 값, 에 의하여 재 검색 주기의 시작점 조정하여 송신기의 시작시점과 최대한  synchro..  유지….*

* 본 ‘전산올’은 독자적으로 개발 되었으나 자유 공개합니다. (올 : 직물을 구성하는 실을 표현했던 말)
***************************************************************************************************************** */
int RFinputPin = 11; //수신기에 연결된 핀번호

long prevReceive ; //앞서 수신한 시간
byte buffer[200]; // RF433_21S_Recieved() sub bit 단위로 수신된 data 저장공간
int maxB=200; // RF433_21S_Recieved() buffer의 최대 index , 비 싱크로시 적용
int maxBsync = 160; //싱크로시 bit 수신 크기
int i = 0; // RF433_21S_Recieved() buffer[] 의 index
int8_t j ; // RF433_21S_Recieved() buffer 내 bit 단위 index 0~8 값
String RFString; // RF433_21S_Recieved() 함수의 결과물 string … 여기서는 사용안함…
String prevString = ” ” ; // RF433_21S_Recieved() 앞서 수신한 string ..초기값은 공백 20자 ..
long nextLooptime; // RF433_21S_Recieved() 함수 실행 시작 시간 주기 (송신기와 일치)
long loopInterval = 2500; // RF433_21S_Recieved() 함수 실행 주기
int8_t loopSynccount=0; // RF433_21S_Recieved() 싱크로 일치 회수 … 3회 이상이되면 rf433 receive 함수 시작 시간을 setting함
bool loopSyncset=0; // RF433_21S_Recieved() 함수 실행 주기 싱크로 여부 … 싱크로 되면 시작시간 고정됨…
bool preSyncset=0; // RF433_21S_Recieved() 에비 싱크로 여부 … 설정도 되면 confirm 실패시 주기를 변경하지 않음…
int iiii; // RF433_21S_Recieved() 실문자열이 시작한 buffer[]의 index
int8_t failCountinsyn = 0; // RF433_21S_Recieved()
int8_t failCount; // RF433_21S_Recieved() 연속 수신 실패한 회수
bool success=false; // RF433_21S_Recieved() 수신에 성공한 경우 – failCount 를 하기 위한 것

String synchSet =”” ; // 싱크로 되었는 지를 시리얼 문자열에 보여주기 위한 것 “S”자를 표시함

//*****************************************************************
void setup() {
//*****************************************************************
pinMode (RFinputPin, INPUT);
Serial.begin(9600);

nextLooptime=millis();
prevReceive = millis();
}
//*****************************************************************
void loop() {
//*****************************************************************

if (RF433_21S_Received()) {
Serial.print(RFString);Serial.print(” “); Serial.print(iiii);Serial.print(” “);Serial.print(synchSet);Serial.print(” “);Serial.println(millis()-prevReceive);
prevReceive=millis();
}
}
//******************************************
bool RF433_21S_Received(){
//*******************************************

if(millis()< nextLooptime){return false;} //문자열 주기 시작 시간까지 공회전

int8_t a[10]; // {1,0,1,0,1,0,1,0,0,0}} bit의 구성이면 문자열 수신 시작
unsigned long subInterval = 1; //sub-bit 를 reading하는 시간 간격.. millisecond
unsigned long subNext; //차기 bit를 digitalreading 하는 시간
int8_t incorCnum; // check bit가 일치하는 않는 수신 byte 수
byte c; // 수신 단위 글자
int16_t adjustBasic = 1200; // 수신함수 주기 시작점 조정 값 … 시작문자열 수신 실패시
int16_t adjustControl ; // 수신함수 주기 시작점 조정 값 … 시작문자열 수신 성공시
int16_t k1, k2,k3,n ; // 전산 진행을 위해 임시로 사용하는 변수
bool confirmed = 0; //data 수신 성공
bool correct; //수신 문자dhk check bit 가 일치하는 지
RFString = “”;

if(success){failCount=0;}
subNext = nextLooptime ; //최초 값 설정
if(loopSyncset){k1=maxBsync;} else {k1=maxB;} // 싱크로시는 buffer 읽는 값 최소화

for (i=0;i<k1 ;i ++) //buffer의 최대 index 까지 digital reading
{ for (int j=0;j<8;j +=1)
{ while(millis() <subNext){} //차기 digital reading 시까지 대기
subNext += subInterval; // 다음번 digital reading 시간 설정
bitWrite(buffer[i],j, digitalRead(RFinputPin)); // sub bit reading
}
}
// ****** i 반복구간 ***************************************************
int ii = 0;
if (loopSyncset){ if (iiii >= 35){ii=11;} if(iiii>15 && iiii<35){ii=iiii-12;}}
for( i=ii;(loopSyncset && i<40) || (! loopSyncset && i<maxB-30); i++) //index 60까지 시작 문자열을 찾음
{ int iii = i; int jjj; // 시작문자열 찾기 진행중 실패서 i 값 복원
// ****** j 반복구간 ***************************************************
for (j = 0;j <8 ;j ++) {
bool fail = false;
jjj=j; // 시작문자열 찾기 진행중 실패서 j 값 복원
int8_t failC=0; int8_t failCcrit=1;
for (int8_t jj=0;jj<10 && !fail;jj ++){ //시작문자열 10 bit에 대하여 진행
a[jj]=0;
for (int8_t kk=2;kk<8;kk ++){ // 8개의 sub bit 중 0,1 번째 bit는 버림
n = j+kk; if (n<8 ){if(bitRead(buffer[i+jj],n)){a[jj] ++;}} else { if(bitRead(buffer[i+jj+1],n-8)){a[jj] ++;}} }
if( (jj %2 ) ==0){if(a[jj]<3){failC ++;}}
else {if(a[jj]>3){failC ++;}}
if(failC>failCcrit ){fail=true;}
} //{1,0,1,0,1,0,1,0,1,0}의 bit 순열 탐색
if (!fail ) {
int8_t ia= 0;
int8_t ja= 0;
int8_t k, k1;
int8_t Mcount = 0;
i +=10; //실 data 시작점
iiii=i;
int8_t N=20;
confirmed = false; //수신하는 글자수, 우선은 20으로 시작
int8_t incorCnum = 0;
int8_t incorNcrit ;
for (k1=0 ;k1<N+1 && i<maxB-2;k1 ++){
if (k1>1 && !confirmed){ i=iii; j=jjj; goto bbb;}
c = B00000000;
bool checkBit0 =0;bool checkBit1 =0;
correct = 1;
for (int8_t jj=0; jj<8; jj ++) {
if (bit01()){ bitWrite(c,jj,1);if(jj%2==0){checkBit0=!checkBit0;} else {checkBit1=!checkBit1;}}
}
if (bit01() != checkBit0){correct =0;goto ccc;}
if (bit01() != checkBit1){correct =0;goto ccc;}
ccc:;
if (k1 ==0){ //수신 byte 0,1번재는 수신문자 수겸 수신 확인용
if (correct && c !=0){
for (int8_t k1=0;k1<4; k1 ++){
if (bitRead(c,k1) !=bitRead(c,k1+4)){i=iii; j=jjj;goto bbb;}
else {bitWrite(c,k1+4,0);}
}
N=c ;
confirmed = true;
incorNcrit=N/2;
}
else {i=iii; j=jjj;goto bbb;}
}
else {
if (!correct || c<32 || c>126 ){incorCnum +=1;c=4;}
if (incorCnum>incorNcrit ) {RFString=””;incorCnum=0;i=iii; j=jjj;goto bbb;} //오류 문자가 전송 문자수의 반 이상이면 not confirmed..
RFString += char(c);

}
}
success = true; //failCount를 작동하기 위한 것
if (iii<100){preSyncset = true;}
if (iii<20){adjustControl=0;} // 시작점이 확인된 i 값에 따라 syncro를 위한 주기 시작 시간 조절
if (iii <5){adjustControl= -60;} // i 값이 너무 적으면 시작시간 전진 하여 적정 i 값 유지
if (iii >= 25 ) {adjustControl= 160;iiii=15;}
if (iii > 40) {adjustControl=280;}
if (iii > 70) {adjustControl= 560;}
if (iii > 100) {adjustControl= 600;}
if(!loopSyncset && iii<25){loopSynccount ++; if (loopSynccount>0){loopSyncset=1;maxBsync=150;synchSet=”S”;preSyncset=false;}} else {loopSynccount=0;}
nextLooptime += loopInterval+adjustControl; //loop 시작 시점 조절을 위해 adjustControl 도입

for ( k2=0;k2<N;k2 ++){
if(RFString.charAt(k2)==4){RFString.setCharAt(k2,prevString.charAt(k2));} //오류글자는 이전 확인된 글자로
}
prevString = RFString; //이전 확인된 글자 최신으로 변경
return true;}
bbb:;
}
//*************** j 구간 종료 *********************
}
//*************** i 구간 종료 *********************
failCount ++;
if(loopSyncset || preSyncset ){
adjustBasic=0;
if (failCount==1){iiii -=5;}
if (failCount==2){loopSyncset=false;synchSet=” “;adjustBasic=-800;}
}
else {adjustBasic=-300;}

nextLooptime += loopInterval+adjustBasic;
success = false;
return false;
}

//****************************************
bool bit01(){
//****************************************
/* i = buffer[] 의 index 로 global 하게 지정
* j = buffer[i] 의 bit index 로 global 하게 지정
*/
int8_t bitVfor1 =13;
int8_t count1=0;
int bitValue =0;
int8_t vFactor = 5;
int8_t n;
bool bitA=0;
bool d;
for (int8_t k=2;k<8;k ++)
{ n = j+k;
if(k>4){vFactor=6;}
if(k>5){vFactor=7;}
if(k>6){vFactor=8;}
if (n<8) {d = bitRead(buffer[i],n);} else {d = bitRead(buffer[i+1],n-8);}
if(d){count1 ++;bitValue +=vFactor;}
}
if (bitValue >= bitVfor1){bitA=1;} // 1이 4개 인경우 처리
i ++;
return bitA;
}


송신기 전산올

//*************************************************************
//시리얼 포트로 입력되는 문자열을 RF송신기로 송신하는 기능을 갖고 있습니다.
//수신 실패를 대비하여 시리얼 문자열을 4회 송신합니다…
//문자열 송신 대기소 기능을 갖추어 RF송신중에 시리얼로 송신 문자열을 수신하는 경우 대기소에 저장하여두고 순차적으로 하나씩 송신합니다.

//****RF433_Send 함수용 선언 ******************************
int outPin = 12;
bool startCode[10]={1,0,1,0,1,0,1,0,1,0};
bool readStringset = false;
long nextLooptime;
long loopInterval = 2500;
int interval = 8;
long millisNext=0;
long prevRFsent ;
String quie[20] ; // RF 송신할 문자 대기소
int8_t quieI = 0; //quie의 실행 index
int8_t quieL = 0; //quie의 추가되는 문자열 입력 위치

//********************************************************

//****Serial 입력용 선언 *********************************
String readString0; //serial1 또는 SoftwareSerial 에서 읽어온 문자를 저장함
String readStringA;
char c; //serial1에서 또는 SoftwareSerial에서 한자씩 읽어올 임시 저장소
String Str13= “\r”;

//********************************************************
void setup() {
//********************************************************
pinMode (outPin, OUTPUT);
nextLooptime = millis();
Serial.begin(9600);
}
//********************************************************
void loop() {
//********************************************************
while (Serial.available()) {
c = Serial.read();
if (c == char(10) ) { //읽은 글자가 줄의 긑임을 알리면
if (readString0.endsWith(Str13)){readString0.remove(readString0.length()-1,1);}
Serial.println(readString0 +”… Set”); // echo
readStringA=readString0;
readString0=””;
readStringset=true;
}
else {
readString0 += c; // 아니면 읽은 한 글자를 출력 줄에 추가
}
}
if (readStringset){RF433Send(readStringA); readStringset=false;}

// Serial.print(nextLooptime);Serial.print(” “);Serial.println(millis());
RF433Execute();
}
//*******************************************************
void RF433Send(String AAA) { //송신 문자열을 quie에 대기 시킴
//*******************************************************
for(int8_t k=0;k <4;k ++){
quie[quieL] = AAA;
quieL ++;
if (quieL>19){quieL=0;}
}
}
//*******************************************************
bool RF433Execute() { //퀴에 있는 문자열을 한개씩 송신
//*******************************************************
if (millis()<nextLooptime) {return false;} // 시간이 되기 전까지는 그냥 출소

String AAA = quie[quieI];
if (AAA==””) {AAA=”Good”;} // 퀴가 비어있으면 “G” 글자 송신
else {quie[quieI]=””; quieI ++; if(quieI>19 ){quieI=0;}}
int L = AAA.length(); if (L>15){L=15;} //15 글자까지만 처리
byte B = L; Serial.print(B);
for (int8_t k=0;k<4;k++){bitWrite(B,k+4,bitRead(B,k));} // 하위4개의 bit를 상위 4자리에 복제
char Chr[20];
AAA.toCharArray(Chr,L+1);
millisNext=nextLooptime+interval;
for (int i=0;i<10;i ++) //시작 code 전송
{while(millis()<millisNext){}
millisNext=millisNext+interval;
digitalWrite(outPin, startCode[i]);
}
SendByte(B); //글자 수 전송

for (int i=0;i <L;i++){ //주 문장 전송
SendByte(Chr[i]);
}
Serial.print(AAA+”….Sent “);Serial.println(millis()- prevRFsent); prevRFsent = millis();
nextLooptime +=loopInterval; //본 주기 다음 시간 설정
return true;
}
//******************************************************************
void SendByte(byte B) { // 한개의 byte를 전송하기
//******************************************************************
bool d;
bool checkBit[2]={0,0};
for (int8_t j=0; j<8; j++)
{ while(millis()<millisNext){}
millisNext +=interval;
d = bitRead(B,j);
digitalWrite(outPin,d);
if(d){if (j%2==0){checkBit[0]=!checkBit[0];} else {checkBit[1]=!checkBit[1];}}
}
for(int8_t k1=0;k1<2;k1 ++) {
while(millis()<millisNext){}
millisNext +=interval;
digitalWrite(outPin,checkBit[k1]);
}
}
//******************************************************************

댓글 남기기

이메일은 공개되지 않습니다.

다음의 HTML 태그와 속성을 사용할 수 있습니다: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>