MEGAWIN

MG82F6D Series UART0 TX RX 485

롬돌이 2022. 12. 5. 09:34
반응형

1. 프로그램 개요

P22Green 0 LED, P24 Red LED, P26Green 1 LED가 연결되어 있다.

UART0을 송신은 폴링 방식으로 사용하고, 수신은 인터럽트를 사용하도록 한다.

P17RS485DE/RE를 선택하는 핀으로 사용한다.

수신 시에는 송신하는 쪽에서 라인을 컨트롤하니까 상관은 없으나 송신 시에는 DR/RE 핀을 제어 해야 한다.

송신 전에 DE를 선택해 주고 일정 시간 뒤에 라인에 데이터를 전송하고, 전송이 끝나면 잠시 기다린 뒤에 DE신호를 RE신호로 바꾼다.

중간에 딜레이가 없으면 데이터가 깨지므로 주의해야한다.

 

 

2. 회로도

                         

 

 

 

 

3. Code

main routine

void main()

{

         u8 i;

         InitSystem();                                      // 시스템 초기화

         Uart0RxIn=0;                                     // 변수 초기화

         UartOvTime=0;

         bUartOvFlag=FALSE;

         Set485Rx();                                       // P17 Low로 하여 데이터를 수신할 수 있도록 한다.

         LED_G_0=0;LED_G_1=0;LED_R=0;             // LED ALL ON

         DelayXms(1000);                                 // 1초 딜레이

         LED_G_0=1;LED_G_1=1;LED_R=1;             // LED ALL OFF

 

         Set485Tx();                                        // P17 High로 하여 데이터를 송신할 수 있도록 한다.

         DelayXus(10);                                     // 송신 전 딜레이

         Uart0SendStr("Start!\n");                      // “Start!”를 송신한다.

         DelayXus(10);                                     // 송신 후 딜레이

         Set485Rx();                                       // P17 Low로 하여 데이터를 수신할 수 있도록 한다.

 

         while(1)

         {

                  if(LedTime==0)                         // 100ms마다 LED_G_0을 토글시킨다.

                  {

                           LedTime=100;

                           LED_G_0 = !LED_G_0;

                  }

                  if(bUartOvFlag)                                   // UART 수신 후 일정시간이 지나면

                  {

                           Set485Tx();                               // P17 High로 하여 데이터를 송신할 수 있도록 한다.

                           DelayXus(10);                            // 일정시간 기다린 뒤

                           for(i=0;i<Uart0RxIn;i++)

                           {

                                   Uart0SendByte(RcvBuf[i]);    // 수신 된 데이터를 전송한다.

                           }

                           Uart0RxIn=0;                            // 전송이 끝나면 수신 데이터의 수를 0으로 만들고

                           DelayXus(10);                            // 일정시간이 지난 뒤

                           Set485Rx();                               // P17 Low로 하여 데이터를 수신할 수 있도록 한다. 

                           bUartOvFlag=0;                         // 데이터 전송을 위한 플래그를 클리어 시킨다.

                  }

 

         }

 

}

 

 

 

⑵ 시스템 초기화 루틴

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

*Function:   void InitSystem(void)

*Description:           Initialize MCU

*Input:  

*Output:    

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

void InitSystem(void)

{

           InitPort();

           InitTimer0();

           InitUart0_S0BRG();

           InitInterrupt();

}

- 포트 설정을 수행한다.

- 타이머 0 초기화

- USR0S0BRG 초기화

- 인터럽트 동작 설정

 

 

Port 초기화

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

*Function:   void InitPort(void)

*Description:            Initialize IO Port

*Input:  

*Output:    

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

void InitPort(void)

{

           PORT_SetP2PushPull(BIT2|BIT4|BIT6);                                                   // Set P22,P24,P26 as Push-Pull,For LED.

è P22, P24, P26LED 구동을 위하여 Push-Pull type로 설정한다.

           PORT_SetP1OpenDrainPu(BIT7);                                                 // set P17 open-drain with pull-high, for 485 control

è P17Pull-Up을 가지고 있는 Open Drain 타입으로 설정해 준다.

}

 

*** 사용된 매크로함수는 “API_Macro_MG82FG6D16.H”에서 찾아볼 수 있다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\MG82F6D16_UART0_TXRX_485\code\include

 

 

 

 

⑷ 타이머 0 초기화

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

*Function:   void InitTimer0(void)

*Description:   Initialize Timer0

*Input:  

*Output:    

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

void InitTimer0(void)

{

           TM_SetT0Mode_1_16BIT_TIMER();                                                // TIMER0 Mode: 16-bit

           TM_SetT0Clock_SYSCLKDiv12();                                                 // TIMER0 Clock source: SYSCLK/12

           TM_SetT0Gate_Disable();                                                                      // TIMER0 disable gate

          

           TM_SetT0LowByte(TIMER_12T_1ms_TL);                                      // Set TL0 value

           TM_SetT0HighByte(TIMER_12T_1ms_TH);                                      // Set TH0 value

          

           TM_EnableT0();                                                                                              // Enable TIMER0

}

 

- 타이머 0의 모드 설정

#define TM_SetT0Mode_1_16BIT_TIMER()                           TMOD=(TMOD&(~(T0M0|T0M1)))|(T0M0)

T0M1=0, T0M0=1로하여 모드 116비트 타이머로 설정한다.

- 타이머 0의 클럭 설정

#define TM_SetT0Clock_SYSCLKDiv12()   AUXR3=(AUXR3&(~T0XL));AUXR2=(AUXR2&(~T0X12));TMOD=(TMOD&(~T0C_T))

T0XL = 0, T0X12 = 0, T0C/T = 0으로 저장하여 타이머 0의 클럭을 (SYSCLK/12)로 결정한다.

SYSCLK 12MHz이므로, 타이머 0의 클럭은 1MHz이다. 따라서 타이머 01us마다 1씩 증가한다.

 

- 게이트 사용하지 않음

#define TM_SetT0Gate_Disable()                                                TMOD=TMOD&(~T0GATE)

타이머 0Gate를 사용하지 않는 것으로 설정한다.

 

- 1ms 타이머로 설정

#define TM_SetT0HighByte(x)                               TH0=x

#define TM_SetT0LowByte(x)                               TL0=x

타이머 01ms 타이머가 되도록 TH0, TL0에 초기값을 저장한다.

 

- 타이머 0 시작

#define TM_EnableT0()                              TR0=1

TR0를 셋 시켜 타이머 0을 동작 시킨다.

 

UART0초기화 èS0를 이용해서 UART0Baud Rate를 설정한다.

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

*Function:              void InitUart0_S0BRG(void)

*Description:          Initialize Uart0, The source of baud rate was S0BRG

*Input:  

*Output:    

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

void InitUart0_S0BRG(void)

{       

         UART0_SetAccess_S0CR1();                    // Enable access S0CR1

         UART0_SetMode8bitUARTVar();              // UART0 Mode: 8-bit, Variable B.R.

         UART0_EnReception();                                   // Enable reception

         UART0_SetBRGFromS0BRG();                  // B.R. source:S0BRG

         UART0_SetS0BRGBaudRateX2();                       // B.R. x2

         UART0_SetS0BRGSelSYSCLK();                         // S0BRG clock source: SYSCLK

 

    // Sets B.R. value

         UART0_SetS0BRGValue(S0BRG_BRGRL_9600_2X_12000000_1T);

        

         UART0_EnS0BRG();                                       // Enable S0BRG

}

- UART0 MODE 설정

#define UART0_SetAccess_S0CR1()                            S0CFG=S0CFG|(SMOD3)

S0CFG 레지스터의 0번 비트인 SMOD3을 셋 시킴으로써 S0CR1을 제어가능하게 된다. CPU S0CR1을 읽고 쓰기 위해SFR어드레스 0xB9을 제어한다.

- UART0MODE 1으로 설정한다.

#define UART0_SetMode8bitUARTVar()                       S0CFG=S0CFG&(~SM30);SM00_FE=0;SM10=1

SM30 비트 클리어, SM00비트 클리어, SM10 비트 셋 시킴으로서 MODE 1으로 설정한다. Mode 18-bit UART이고, Baud Rate는 가변이 된다.

 

- UART0 Receive Enable

#define UART0_EnReception()                                           REN0=1

UART0이 시리얼 통신으로 데이터를 받아들일 수 있도록 설정한다. S0CON 레지스터의 REN0를 셋(=1) 시킨다.

 

- UART0 Baud Rate S0BRG를 이용한다.

#define UART0_SetBRGFromS0BRG()                                            S0CR1=S0CR1|(S0TCK|S0RCK)                

앞서 S0CR1을 제어 가능하도록 설정해 두었으며, S0TCK, S0RCK를 셋 시킴으로써 S0BRGOverflowUART0의 송신/수신 클럭으로 사용하도록 설정한다.

 

- Baud Rate2배로 설정한다.

#define UART0_SetS0BRGBaudRateX2()                       PCON0=PCON0&(~SMOD1);S0CFG=S0CFG|(SMOD2)

SMOD1을 클리어 시켜 Double Baud RateDisable 시키고, SMOD2를 셋 시켜 향상된 기능의 UART를 사용한다. Baud RateDouble Baud Rate x 2가 된다.

 

- S0BRG의 클럭 설정

#define UART0_SetS0BRGSelSYSCLK()                         S0CR1=S0CR1|(S0TX12)

S0BRG의 클럭을 SYSCLK를 사용하도록 한다.

 

 

- Baud Rate : 9600 설정

#define S0BRG_BRGRL_9600_2X_12000000_1T             0xB2        // 0.16%

#define UART0_SetS0BRGValue(x)                              S0BRT=x;S0BRC=x

위의 수식으로 계산 시 S0BRT 177.875가 나온다. 따라서 9600 Baud Rate를 위해서는 178(0xB2)S0BRT, S0BRC에 초기값으로 저장한다.

 

- S0BRG를 동작시킨다.

#define UART0_EnS0BRG()                                               S0CR1=S0CR1|S0TR

 

è (EN)MG82F6D16_Datasheet_V051.PDF17. Serial Port 0(UART0)를 참조한다.

è (EN)MG82F6D17_Datasheet_V051.PDF18. Serial Port 0(UART0)를 참조한다.

è (EN)MG82F6D64/32_Datasheet_V051.PDF18. Serial Port 0(UART0)를 참조한다.

 

⑹ 인터럽트 초기화

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

*Function:   void InitInterrupt(void)

*Description:           Initialize Interrupt

*Input:  

*Output:    

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

void InitInterrupt(void)

{

           INT_EnTIMER0();                                                                                             //           Enable TIMER0 interrupt

           INT_EnUART0();                                                                                              //           Enable UART0 interrupt

           INT_EnAll();                                                                                          //  Enable global interrupt

}        

- 타이머 0UART0 인터럽트를 초기화한다. 그리고 Global interrupt bit를 셋 시켜 인터럽트 수신이 시작되도록 한다.

#define INT_EnTIMER0()                  ET0=1

#define INT_EnUART0()                   ES0=1

#define INT_EnAll()                         EA=1              // Global enable

 

 

⑺ 타이머 0 인터럽트 루틴

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

*Function:   void INT_T0(void)

*Description:   T0 Interrupt handler

*Input:  

*Output:    

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

void INT_T0(void) interrupt INT_VECTOR_T0

{

           TH0=TIMER_12T_1ms_TH;

           TL0=TIMER_12T_1ms_TL;

 

           if(LedTime!=0) LedTime--;

           if(UartOvTime!=0)

           {

                     UartOvTime--;

                     if(UartOvTime==0) bUartOvFlag=TRUE;

           }

}

- 타이머 01ms 마다 인터럽트가 발생할 수 있도록 TH0, TL0에 값을 저장한다.

- LedTime0이 아니면 1 감소시킨다. LED에 관련된 딜레이 시간을 만들 수 있다.

- UartOvTime0이 아니면 1 감소시킨다.

 

 

 

 

 

UART 0 인터럽트 루틴

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

*Function:   void INT_UART0(void)

*Description:   UART0 Interrupt handler

*Input:  

*Output:    

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

void INT_UART0(void) interrupt INT_VECTOR_UART0

{

           if(TI0)                                            

           {

              TI0 = 0;        

           }

           if(RI0)                                            

           {

                     RI0 = 0;                               

                     if(Uart0RxIn<UART0_RX_BUFF_SIZE)

                     {

                                RcvBuf[Uart0RxIn] = S0BUF;

                                Uart0RxIn++;

 

                                UartOvTime=10;

                     }

           }

}

- 수신 모드 버퍼를 갖고 있도록 설계되었다.

- 한 바이트라도 수신 될 때 마다 UartOvTime10이 저장되고, 이 값이 타이머 0인터럽트 루틴에서 감소되어 0이되면 수신했던 데이터를 다시 전송한다. (10ms 이상의 데이터 수신이 없을경우)

- 데이터 버퍼는 총 32바이트이므로 테스트에서는 32바이트를 송신한 뒤 다시 리턴 되는 것으로 확인한다.

 

 

 

 

 

 

4. 프로그램 실행

*** Keil compiler가 인스톨되어 있어야함 ***

해당 Example 폴더를 찾아가 KeilPrj폴더를 Open 한다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\ MG82F6D16_UART0_RX_TX_INT\KeilPrj

 

해당 폴더의 Keil project 파일을 더블 클릭하여 실행시킨다.(MG82F6D16_DEMO.uvproj)

 

Rebuild 아이콘을 클릭하여 프로젝트를 컴파일 한다.

 

Demo BoardUSB Connector를 연결하여 전원을 인가하고, 전원 스위치를 ON시키고, OCD ICE를 연결한 상태에서 위 이미지의 Start/Stop Debug Session(Ctrl+F5) 버튼을 눌러 컴파일된 프로젝트의 디버그 데이터를 다운로드 시킨다.(컴파일 시 에러가 발생하지 않아야함)

 

 

다운로드 후 Run(F5) 버튼을 클릭하면 프로그램이 동작한다.

5. 동작 영상

 

https://youtu.be/wgPRk5T80EA

 

반응형