8051 UART C Version

這版本的是當初退伍後,工作幾個月後寫的,靈感來自於 Paul’s 8051 Free Tools 的ASM版本,前一兩年在一個案子中還經過一次修訂,改進了使用 RS-485時不需使用 Loop Delay 來產生最後一個位元。這個版本有針對C語言(這裡指的是 Franklin/Keil 5.x or later, 並未在其他Compiler 使用過)的最佳化編寫,因此相較於使用 Assemble 來說增加的程式碼與RAM的使用並不會增加太多成本。程式碼如下

現在提供一個類似, 但是更完整而且實際運行的source code 請參考這 Note: A Remote Programable Digital Input/Ouput module


in uart.h

#if !defined ( _UART_H_ )
#define _UART_H_
#define MaxLength 16
#define UART0_R_Length   RLength0
#define UART0_T_Length   TLength0
#define UART0_R_IsEmpty  ((RLength0 == 0 ) ? TRUE : FLASE)
#define UART0_R_IsFull   ((RLength0 == MaxLength) ? TRUE : FLASE )
#define UART0_T_IsEmpty  ((TLength0 == 0 ) ? TRUE : FLASE)
#define UART0_T_IsFull   ((TLength0 == MaxLength) ? TRUE : FLASE )
#define UART1_R_Length   RLength1
#define UART1_T_Length   TLength1
#define UART1_R_IsEmpty  ((RLength1 == 0 ) ? TRUE : FLASE)
#define UART1_R_IsFull   ((RLength1 == MaxLength) ? TRUE : FLASE )
#define UART1_T_IsEmpty  ((TLength1 == 0 ) ? TRUE : FLASE)
#define UART1_T_IsFull   ((TLength1 == MaxLength) ? TRUE : FLASE )

#if ! defined ( _PYHSICAL_UART_ )
extern BYTE RLength0;
extern BYTE TLength0;
extern BYTE RLength1;
extern BYTE TLength1;
#endif 

void UART0_Interrupt(void);
void UART1_Interrupt(void);
void InitUART0(void);
void InitUART1(void);
BOOLEAN UART0_Put(BYTE);
BOOLEAN UART0_Get(BYTE *);
void UART0Drive(void);
void UART1Drive(void);
BOOLEAN UART1_Put(BYTE);
BOOLEAN UART1_Get(BYTE *);

#endif /* UART.H FILE END */ 

in UART.C implement function
#define OSC 22118400L
#define UART0_BaudRate 9600L
#define UART1_BaudRate 1200L
#define UART0_RS485_Adapter
#define UART0_RS485_DelayTime 5
#define UART1_RS485_Adapter
#define UART1_RS485_DelayTime 40

#if defined ( UART0_RS485_Adapter )
sbit DIR0 = P1 ^ 0;
   #if !defined( TRANSMIT )
      #define TRANSMIT 1
      #define RECEIVE  0
   #endif
#endif 
#if defined ( UART1_RS485_Adapter )
sbit DIR1 = P1 ^ 1;
    #if !defined( TRANSMIT )
        #define TRANSMIT 1
        #define RECEIVE  0
    #endif
#endif 

BYTE TLength0 = 0;
BYTE RLength0 = 0;

BYTE TLength1 = 0;
BYTE RLength1 = 0;

static EXTERN_DATA BYTE UART0_RFIFO[MaxLength];
static EXTERN_DATA BYTE UART0_TFIFO[MaxLength];
static EXTERN_DATA BYTE UART1_RFIFO[MaxLength];
static EXTERN_DATA BYTE UART1_TFIFO[MaxLength];

static P_INTERNAL_DATA BYTE R_Tail0;
static P_INTERNAL_DATA BYTE R_Head0;
static P_INTERNAL_DATA BYTE T_Tail0;
static P_INTERNAL_DATA BYTE T_Head0;

static P_INTERNAL_DATA BYTE R_Tail1;
static P_INTERNAL_DATA BYTE R_Head1;
static P_INTERNAL_DATA BYTE T_Tail1;
static P_INTERNAL_DATA BYTE T_Head1;

static bit uart0;
static bit uart1;

void UART0_Interrupt(void) interrupt 4 using 2
{
   int i;
   register BYTE temp;

   if (TI)                                        /* Is TI flag set                          */
     {  RESET_REGISTER(TI);                       /* Clear TI Flage                          */
        if (TLength0 != 0 )                       /* UART0 Tx FIFO is empty                  */
          { SBUF = UART0_TFIFO[T_Tail0];          /* Put a byte to SBUF                      */
            if (++T_Tail0 == MaxLength)           /* Is T_Tail0 point to UART0 Tx FIFO tail  */
              { T_Tail0 = 0; }                    /* Set T_Tail0 point to UART0 Tx FIFO head */
            TLength0--;
          }
        else
          {
            uart0 = OFF;
       #if defined( UART0_RS485_Adapter )              /* Is UART0 use RS485 Adapter        */
                                                       /* UART0 Tx FIFO is empty            */
            for ( i = 0; i < UART0_RS485_DelayTime;)   /* then delay one bit time           */
               { i++; }
            DIR0 = RECEIVE;                            /* change R/T Direction              */
       #endif
          }
     }
   else
     {
      RESET_REGISTER(RI);
      temp = SBUF;                                     /* Get a byte from SBUF                    */
      if (!(RLength0 == MaxLength))                    /* Is UART0 Rx FIFO not full               */
        { UART0_RFIFO[R_Head0] = temp;                 /* Put a byte to UART0 Rx FIFO             */
          if (++R_Head0 == MaxLength)                  /* Is R_Head0 point to UART0 Rx FIFO tail  */
            { R_Head0 = 0; }                           /* Set R_Head0 point to UART0 Rx FIFO head */
          RLength0++;
        }
     }
}

void UART1_Interrupt(void) interrupt 7  using 2
{
   int i;
   register BYTE temp;
   if (TI1)                                             /* Is TI flag set                          */
     {  RESET_REGISTER(TI1);                            /* Clear TI Flage                          */
        if (TLength1 != 0 )                             /* UART1 Tx FIFO is empty                  */
          {
          /* generation last bit*/
            for ( i = 0; i < UART1_RS485_DelayTime;)    /* then delay one bit time           */
               { i++; }

            SBUF1 = UART1_TFIFO[T_Tail1];               /* Put a byte to SBUF1                     */
            if (++T_Tail1 == MaxLength)                 /* Is T_Tail1 point to UART1 Tx FIFO tail  */
              { T_Tail1 = 0; }                          /* Set T_Tail1 point to UART1 Tx FIFO head */
            TLength1--;
          }
        else                                            /* UART1 Tx FIFO is empty            */
          {
            uart1 = OFF;
       #if defined( UART1_RS485_Adapter )               /* Is UART1 use RS485 Adapter        */
            for ( i = 0; i < UART1_RS485_DelayTime;)    /* then delay one bit time           */
               { i++; }
            DIR1 = RECEIVE;                             /* change R/T Direction              */
       #endif
          }
     }
   else
     {
      RESET_REGISTER(RI1);
      temp = SBUF1;                                    /* Get a byte from SBUF                    */
      if (!(RLength1 == MaxLength))                    /* Is UART1 Rx FIFO not full               */
        { UART1_RFIFO[R_Head1] = temp;                 /* Put a byte to UART1 Rx FIFO             */
          if (++R_Head1 == MaxLength)                  /* Is R_Head1 point to UART1 Rx FIFO tail  */
            { R_Head1 = 0; }                           /* Set R_Head1 point to UART1 Rx FIFO head */
          RLength1++;
        }
     }
}

BOOLEAN UART0_Put(const BYTE Value)
{
  RESET_REGISTER(EA);                         /* Disable Interrupt                         */
  if (TLength0 == MaxLength)                  /* Is UART0 Tx FIFO full                     */
    { SET_REGISTER(EA);                       /* Enable Interrupt                          */
      return FALSE; }                         /* Return FALSE                              */

  UART0_TFIFO[T_Head0] = Value;               /* Put a byte to UART0 Tx FIFO               */
  TLength0++;
  if (++T_Head0 == MaxLength)                 /* Is T_Head0 point to UART0 Tx FIFO tail    */
    { T_Head0 = 0; }                          /* Set T_Head0 point to UART0 Tx FIFO head   */
  SET_REGISTER(EA);                           /* Enable Interrupt                          */
  return TRUE;
}

BOOLEAN UART0_Get(BYTE *Value)
{
  RESET_REGISTER(EA);                           /* Disable Interrupt                       */
    if (RLength0 == 0 )                         /* Is UART0 Rx FIFO empty                  */
      { SET_REGISTER(EA);                       /* Enable Interrupt                        */
        return FALSE; }                         /* Return FALSE                            */
    *Value = UART0_RFIFO[R_Tail0];              /* Get a Byte from UART0 Rx FIFO           */
    if (++R_Tail0 == MaxLength)                 /* Is R_Tail0 point to UART0 Rx FIFO tail  */
      { R_Tail0 = 0; }                          /* Set R_Tail0 point to UART0 Rx FIFO head */
    RLength0--;                                 /*                                         */
    SET_REGISTER(EA);                           /* Enable Interrupt                        */
    return TRUE;
}

BOOLEAN UART1_Put(BYTE Value)
{
  RESET_REGISTER(EA);                           /* Disable Interrupt                       */
  if (TLength1 == MaxLength)                    /* Is UART1 Tx FIFO full                   */
  { SET_REGISTER(EA);                           /* Enable Interrupt                        */
    return FALSE; }                             /* Return FALSE                            */

  UART1_TFIFO[T_Head1] = Value;                 /* Put a byte to UART1 Tx FIFO             */
  if (++T_Head1 == MaxLength)                   /* Is T_Head0 point to UART0 Tx FIFO tail  */
    { T_Head1 = 0; }                            /* Set T_Head0 point to UART0 Tx FIFO head */
  TLength1++;
  SET_REGISTER(EA);                             /* Enable Interrupt                        */
  return TRUE;
}

BOOLEAN UART1_Get(BYTE *Value)
{
  RESET_REGISTER(EA);                           /* Disable Interrupt                       */
    if (RLength1 == 0 )                         /* Is UART0 Rx FIFO empty                  */
      { SET_REGISTER(EA);                       /* Enable Interrupt                        */
        return FALSE; }                         /* Return FALSE                            */
    *Value = UART1_RFIFO[R_Tail1];              /* Get a Byte from UART0 Rx FIFO           */
    if (++R_Tail1 == MaxLength)                 /* Is R_Tail0 point to UART0 Rx FIFO tail  */
      { R_Tail1 = 0; }                          /* Set R_Tail0 point to UART0 Rx FIFO head */
    RLength1--;                                 /*                                         */
    SET_REGISTER(EA);                           /* Enable Interrupt                        */
    return TRUE;
}

void InitUART0(void)
{
/* =================================================== UART 0 Use Time 2 Baud General 9600bps @ 22.118MHZ RCAP2H,RCAP2L = 65535 - (Osc) / (32 * Baud Rate) =================================================== CKCON Register (clock control) MSB Bit Function . 7 WD1 . 6 WD0 . 5 T2M . 4 T1M . 3 T0M . 2 MD2 . 1 MD1 LSB 0 MD0 Set Time Clk ;Osc/4 or Osc/12 SCON Register (serial port control) MSB Bit Function . 7 SM0 MODE SM0 SM1 . 6 SM1 0 0 0 . 5 SM2 1 0 1 . 4 REN 2 1 0 . 3 TB8 3 1 1 . 2 RB8 . 1 TI LSB 0 RI */
   R_Head0 = 0;
   R_Tail0 = 0;
   T_Head0 = 0;
   T_Tail0 = 0;
   RLength0 = 0;
   TLength0 = 0;

   CKCON  = 0x82;
   SCON   = 0x50;
   RCAP2H = (65535 - (OSC / (32 * UART0_BaudRate))/256);
   RCAP2L = (65535 - (OSC / (32 * UART0_BaudRate))%256)+1;
   TH2 = RCAP2H;
   TL2 = RCAP2L;
   T2CON  = 0x34;
   uart0 = 0;
   #if defined( UART0_RS485_Adapter )              /* Is UART0 use RS485 Adapter */       DIR0 = RECEIVE;                              /* change R/T Direction */
   #endif    SET_REGISTER(PS);
   ES0    = ENABLE; /* Enable UART 0 Interrupt */
}
void InitUART1(void)
{
// UART 1 Use Time 1 Baud General 1200bps @ 22.118MHz // SoftTime Use Time 0, Mode 1 // SMOD = 0, then K = 1 else K = 2 // W77E5X or DS80C3X // T1M = 1, then C = 3, else C = 1 // TH1 = 256 - (osc * K(1 or 2) * C(1 or 3) /32*12*Baud Rate)
   R_Head1 = 0;
   R_Tail1 = 0;
   T_Head1 = 0;
   T_Tail1 = 0;
   RLength1 = 0;
   TLength1 = 0;

   SCON1 = 0x50;
   TMOD  = 0x21;
   TH1 = (256 - ((OSC)/(32*12*UART1_BaudRate)));
   TR1 = ENABLE;
   uart1 = 0;
   SET_REGISTER(PS1);
   ES1 = ENABLE; /* Enable UART1 Interrupt */
/*   TMOD |= 0x21;
   TH0 = 0xFD;       */
      DIR1 = RECEIVE;                              /* change R/T Direction              */
}

void UART0Drive(void)
{
  if (!IsReceiveExtendUnit())
    {
      if ((TLength0 > 0) && (uart0 == OFF))
        {
          uart0 = ON;
          DIR0 = TRANSMIT;
          SET_REGISTER(TI);
        }
    }
}

void UART1Drive(void)
{
  if (!IsReceiveCallStation())
    {
      if ((TLength1 > 0) && (uart1 == OFF))
        {
          uart1 = ON;
          DIR1 = TRANSMIT;
          SET_REGISTER(TI1);
        }
    }
}

8051 UART C Version 有 “ 1 則迴響 ”

回覆給Note: A Remote Programable Digital Input/Ouput module « 願~~ 取消回覆