RS485를 제어하려면 Receive, Drive Enable Pin을 제어해야 합니다. Polling 방식이나 제어주기에 제약이 없는 상황에서는 문제가 없지만 능동적인 제어일때는 여러가지 문제가 발생합니다 따라서 인터럽트를 이용해 송수신을 하면 delay함수를 쓰지 않고도 제어할 수 있어 효율적인 송,수신을 할 수 있습니다.
※ 485 드라이버를 2개 사용해서 송 수신 라인이 다르게 설계했다면 해당 내용은 유효하지 않습니다.
예제는 USART3으로 되어있으니 참고하시기 바랍니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#include <io.h> #include <stdio.h> #include "MCU_Initialize.h" //MCU Setting Header File #define TOGGLE(x,y) ((x)^=(unsigned char)(1 << y)) // Toggle Bit Function #define HIGH(x,y) ((x)|=(unsigned char)(1 << y)) // Bit On Function #define LOW(x,y) ((x)&=(unsigned char)~(1<< y)) // Bit Off Function #define CHKBIT(x,y) ((x) & (1<<(y))) // Bit Check #define LED PORTL #define TIMER_CALLTASK1 int_timer[0] // TX Periode Timer #define CALLTASK1TIME 5 // TX Periode Time #define TIMER_COMMERR3 int_timer[1] // Usart3 Communication Error Reset Timer #define COMMERR3TIME 20 // Usart3 Communication Error Reset Time volatile unsigned int int_timer[10]; volatile unsigned char uart3Txbuffer[50], uart3Txindex=0; volatile unsigned char uart3Rxbuffer[50], uart3Rxindex=0, uart3Endcode=0x0D; volatile bit u3Rxcomplet,u3Txcomplet; // USART3 Dataempty interrupt service routine interrupt [USART3_UDRE] void usart3_empty_isr (void) { if(uart3Txbuffer[uart3Txindex]==0xFF) // ProtocolSet 말미에 저장된 0xFF를 만나면 Empty Interrupt 종료 { uart3Txindex=0; UCSR3B &= ~(1<<UDRIE3); // UDRI Disable } else { UDR3=uart3Txbuffer[uart3Txindex++]; // Data 전송 } LOW(LED,6);TOGGLE(PORTJ,4); // TX Complet LED On } // USART3 Transmitter interrupt service routine interrupt [USART3_TXC] void usart3_tx_isr(void) { HIGH(LED,6);TOGGLE(PORTJ,4); // TX Complet LED Off LOW(PORTJ,2); // Uart3 TX Disable UCSR3B |=(1<<RXCIE3)|(1<< RXEN3); // 전송완료되면 RX Interrupt Routine Enable u3Txcomplet=1; // TX Flag On } // USART3 Receiver interrupt service routine interrupt [USART3_RXC] void usart3_rx_isr(void) { unsigned char dummy; dummy=UDR3; uart3Rxbuffer[uart3Rxindex++]=dummy; // 데이터가 수신되면 버퍼에 저장 if(dummy==uart3Endcode) // Endcode를 만나면 { uart3Rxindex=0; u3Rxcomplet=1; // RX Flag On LOW(LED,7);TOGGLE(PORTJ,4); // RX Complet LED On } } // Timer0 Over Flow Timer interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0=0x94; TOGGLE(LED,0);TOGGLE(PORTJ,4); if(++TIMER_CALLTASK1>CALLTASK1TIME){TIMER_CALLTASK1=CALLTASK1TIME; } // TX Periode Timer if(++TIMER_COMMERR3>COMMERR3TIME){TIMER_COMMERR3=COMMERR3TIME; } // USART3 Communication Error Timer } // Watchdog Timer interrupt service routine interrupt [WDT] void wdt_timeout_isr(void) { TOGGLE(LED,1); } void main(void) { mcuinitialize(); // MCU Initialize HIGH(PORTH,2); // Port2,3,4 TX Enable while (1) { #asm("sei"); // All Interrupt Allway On if(TIMER_CALLTASK1>=CALLTASK1TIME) { TIMER_CALLTASK1=0; #asm("wdr"); // Watchdog Timer Reset uart3Txbuffer[0]=0x02; uart3Txbuffer[1]=0x30; uart3Txbuffer[2]=0x31; uart3Txbuffer[3]=0x32; uart3Txbuffer[4]=0x33; uart3Txbuffer[5]=0x34; uart3Txbuffer[6]=0x35; uart3Txbuffer[7]=0x36; uart3Txbuffer[8]=0x37; uart3Txbuffer[9]=0x38; uart3Txbuffer[10]=0x39;uart3Txbuffer[11]=0x41;uart3Txbuffer[12]=0x42;uart3Txbuffer[13]=0x43;uart3Txbuffer[14]=0x44; uart3Txbuffer[15]=0x45;uart3Txbuffer[16]=0x46;uart3Txbuffer[17]=0x30;uart3Txbuffer[18]=0x31;uart3Txbuffer[19]=0x32; uart3Txbuffer[20]=0x33;uart3Txbuffer[21]=0x34;uart3Txbuffer[22]=0x35;uart3Txbuffer[23]=0x36;uart3Txbuffer[24]=0x37; uart3Txbuffer[25]=0x38;uart3Txbuffer[26]=0x39;uart3Txbuffer[27]=0x41;uart3Txbuffer[28]=0x42;uart3Txbuffer[29]=0x43; uart3Txbuffer[30]=0x44;uart3Txbuffer[31]=0x45;uart3Txbuffer[32]=0x46;uart3Txbuffer[33]=0x0D;uart3Txbuffer[34]=0xFF; if(u3Rxcomplet==0 && u3Txcomplet==0) // TX, RX Flag가 Off 일 때 { HIGH(PORTJ,2); // RS485 TX Enable Pin Active High UCSR3B &=~(1<<RXCIE3)&~(1<< RXEN3); // 송신전 인터럽트 중첩을 피하기 위해 RX Interrupt Routine Disable TIMER_COMMERR3=0; // 통신에러감지 타이머 리셋 uart3Txindex=0; // 송신인덱스 초기화 UCSR3B |= (1<<UDRIE3); // Empty Interrupt Enable } if(u3Rxcomplet==1 && u3Txcomplet==1) // TX, RX Falg가 전부 On 일 때 { TIMER_COMMERR3=0; // Communication Error Timer Clear u3Txcomplet=0; u3Rxcomplet=0; // TX, RX Flag Clear HIGH(LED,7);TOGGLE(PORTJ,4); // RX Lamp Off } if(u3Rxcomplet==1 || u3Txcomplet==1) // TX, RX Flag가 On되어 있는 상태에서 { if(TIMER_COMMERR3>=COMMERR3TIME) //Communication Error Timer가 Set되면 통신에러로 간주하고 { TIMER_COMMERR3=0; u3Txcomplet=0; u3Rxcomplet=0; // TX, RX Flag Clear UCSR3B &=~(1<<RXCIE3)&~(1<< RXEN3);// RX 관련 Registor Clear UCSR3B &=~(1<<UDRIE3); // Empty Interrupt Off } } } } } |