1. 프로그램 개요
P22는 Green 0 LED, P24는 Red LED, P26은 Green 1 LED가 연결되어 있다.
UART0을 송신은 폴링 방식으로 사용하고, 수신은 인터럽트를 사용하도록 한다.
P17을 RS485의 DE/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 초기화
- USR0의 S0BRG 초기화
- 인터럽트 동작 설정
⑶ 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, P26은 LED 구동을 위하여 Push-Pull type로 설정한다.
PORT_SetP1OpenDrainPu(BIT7); // set P17 open-drain with pull-high, for 485 control
è P17을 Pull-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로하여 모드 1의 16비트 타이머로 설정한다.
- 타이머 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이다. 따라서 타이머 0은 1us마다 1씩 증가한다.
- 게이트 사용하지 않음
#define TM_SetT0Gate_Disable() TMOD=TMOD&(~T0GATE)
타이머 0의 Gate를 사용하지 않는 것으로 설정한다.
- 1ms 타이머로 설정
#define TM_SetT0HighByte(x) TH0=x
#define TM_SetT0LowByte(x) TL0=x
타이머 0이 1ms 타이머가 되도록 TH0, TL0에 초기값을 저장한다.
- 타이머 0 시작
#define TM_EnableT0() TR0=1
TR0를 셋 시켜 타이머 0을 동작 시킨다.
⑸ UART0초기화 èS0를 이용해서 UART0의 Baud 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을 제어한다.
- UART0를 MODE 1으로 설정한다.
#define UART0_SetMode8bitUARTVar() S0CFG=S0CFG&(~SM30);SM00_FE=0;SM10=1
SM30 비트 클리어, SM00비트 클리어, SM10 비트 셋 시킴으로서 MODE 1으로 설정한다. Mode 1은 8-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를 셋 시킴으로써 S0BRG의 Overflow를 UART0의 송신/수신 클럭으로 사용하도록 설정한다.
- Baud Rate를 2배로 설정한다.
#define UART0_SetS0BRGBaudRateX2() PCON0=PCON0&(~SMOD1);S0CFG=S0CFG|(SMOD2)
SMOD1을 클리어 시켜 Double Baud Rate를 Disable 시키고, SMOD2를 셋 시켜 향상된 기능의 UART를 사용한다. Baud Rate는 Double 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.PDF의 17. Serial Port 0(UART0)를 참조한다.
è (EN)MG82F6D17_Datasheet_V051.PDF의 18. Serial Port 0(UART0)를 참조한다.
è (EN)MG82F6D64/32_Datasheet_V051.PDF의 18. 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
}
- 타이머 0과 UART0 인터럽트를 초기화한다. 그리고 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;
}
}
- 타이머 0이 1ms 마다 인터럽트가 발생할 수 있도록 TH0, TL0에 값을 저장한다.
- LedTime이 0이 아니면 1 감소시킨다. LED에 관련된 딜레이 시간을 만들 수 있다.
- UartOvTime이 0이 아니면 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;
}
}
}
- 수신 모드 버퍼를 갖고 있도록 설계되었다.
- 한 바이트라도 수신 될 때 마다 UartOvTime에 10이 저장되고, 이 값이 타이머 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 Board에 USB Connector를 연결하여 전원을 인가하고, 전원 스위치를 ON시키고, OCD ICE를 연결한 상태에서 위 이미지의 Start/Stop Debug Session(Ctrl+F5) 버튼을 눌러 컴파일된 프로젝트의 디버그 데이터를 다운로드 시킨다.(컴파일 시 에러가 발생하지 않아야함)
다운로드 후 Run(F5) 버튼을 클릭하면 프로그램이 동작한다.
5. 동작 영상
'MEGAWIN' 카테고리의 다른 글
MG82F6D Series ADC ROLL (0) | 2022.12.07 |
---|---|
MG82F6D Series I2C Master (0) | 2022.12.06 |
MG82F6D Series UART0 TX RX INT (0) | 2022.12.02 |
MG82F6D Series RTC Timer (0) | 2022.12.01 |
MG82F6D PCA PWM 16bit (0) | 2022.11.30 |