⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 mcs51,2051,x86系列MCU
💻 C
字号:
/*
 *  ApBUILDER CODE FILE - Intel Corporation
 *
 *
 *  Purpose:            Serial port file distributed for Full-code-generation on 251SX, and 8X930AX families.
 *
 *                      Contains Serial port init code, and some useful sub-routines for
 *                      interrupt driven serial transmission/reception using circular buffers.
 *
 *
 *                      The Software is provided "AS IS."
 *
 *                      LIMITATION OF LIABILITY:    NEITHER INTEL NOR ITS VENDORS OR AGENTS
 *                      SHALL BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA,
 *                      INTERRUPTION OF BUSINESS, NOR FOR INDIRECT, SPECIAL, INCIDENTAL OR
 *                      CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER THIS AGREEMENT OR
 *                      OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 *                      While we have made every attempt to completely test this code, we highly recommend that
 *                      you personally test it completely prior to actual inclusion in your project.
 *
 *  Compiler:           Developed using Compass251 from Production Languages corporation.
 *
 *  Ext Packages:       None
 *
 *  Author:             Brad B.
 *
 *  Revisions:
 *
 *
 *
 *
 */

#include "global.h"
#include "serial.h"

#define SERIAL_ISR_ROUTINES_ENABLED


#ifdef SERIAL_ISR_ROUTINES_ENABLED
/* take care to declare variables that may be changed in Interrupt service routines as volatile.  In some compilers,
 * this prevents undesirable optimizations that assume the values remain unchanged throughout a function */
static volatile char *rcv_head, *rcv_tail;
static volatile char *tx_head, *tx_tail;
static volatile char rx_overflow_flag = FALSE;  /* set when we overrun our tx_buf */
static volatile char transmission_in_progress = FALSE;
static char rcv_buf[MAX_RECEIVE_BUF];           /* circulating receive buffer */
static char tx_buf[MAX_TRANSMIT_BUF];           /* circulating transmit buffer */
#endif


/*
   Function: init_serial()

   General purpose initialization routine for serial port.
   Also includes initialization for circular buffer pointers.
*/

void init_serial(char sconval);
{
   PCON &= ~(0x40);                 /* Clear SMOD0 prior to writing serial mode bits in SCON */
   SCON = sconval;                  /* set serial control / mode bits */
   PCON |= 0x40;                    /* Set SMOD0 to enable future access to Framing Error bit FE in SCON*/

#ifdef SERIAL_ISR_ROUTINES_ENABLED
   if (sconval & 0x10)              /* is receive enabled ? */
   {
      rcv_head = rcv_tail = rcv_buf;
   }
   else                             /* no, transmit is enabled */
   {
      tx_head = tx_tail = tx_buf;
   }
#endif
}



#ifdef SERIAL_ISR_ROUTINES_ENABLED

/*
   Function: serial_int()

   Interrupt service routine for serial port.
   If received byte, stuffs it into receive circular buffer.
   If transmitted byte, gets next byte from circular buffer and sends it.

   The effective receive circular buffer size is MAX_RECEIVE_BUF -1.  If a character
   causes an overflow in the receive buffer, the tail-character is lost.

   The effective transmit circular buffer size is MAX_TRANSMIT_BUF -1.
*/

void interrupt serial_int(void)
{
   SET_VECTOR(SERIO, serial_int);   /* set up int vector */

   if (RI == 1)                     /* SCON.0, receive interrupt flag bit.  Character was received. */
   {
      *rcv_head = SBUF;             /* get the character from the serial port */
      rcv_head++;
      if ((rcv_head - rcv_buf) >= MAX_RECEIVE_BUF)
      {
         rcv_head = rcv_buf;        /* wrap head pointer back to beginning of buffer */
      }

      if (rcv_head == rcv_tail)     /* we wrapped around, overflowing the buffer. */
      {
         rx_overflowflag = TRUE;
         inc_rcv_tail();            /* loose a character from tail of rcv buffer and move on */
      }

      RI = 0;                       /* reset receive interrupt flag */
   }

   if (TI == 1)                     /* SCON.1, transmitted byte has completed */
   {
      /* check to see if there are more bytes in tx_buf to send out */
      if (tx_head == tx_tail)
      {
         /* we are done with transmission, set up this global to indicate so. */
         transmission_in_progress = FALSE;
      }
      else
      {
         SBUF = *tx_tail;           /* send out next character from circular buffer */
         inc_tx_tail();             /* point to next char in circular buffer */
      }
      TI = 0;                       /* reset the transmit interrupt flag */
   }
}


/* Send out a message of len characters out the serial port using interrupt driven transmission, return FALSE if this
 * message overflows the tx circular buffer */
bool transmit_message(unsigned char *message, unsigned char len)
{
   unsigned char x;

   for (x=0; x < len; x++)
   {
      *tx_head = *message;
      message++;
      tx_head++;
      if ((tx_head - tx_buf) >= MAX_TRANSMIT_BUF)
      {
         tx_head = tx_buf;          /* wrap head pointer back to beginning of buffer */
      }

      if (tx_head == tx_tail)       /* we wrapped around to the tail, overflowing the buffer. */
      {
         return(FALSE);
      }
   }

   /* Message has been placed in tx_buf, now start-up the transmission process */
   start_tx();
   return(TRUE);
}


static void start_tx(void)
{
   /* Start transmission if one is not already in-progress */
   if !(transmission_in_progress)
   {
      transmission_in_progress = TRUE;

      /* stuff first byte of transmission in the transmit SFR.. The ISR will stuff the
         remainder automaticly. */
      SBUF = *tx_tail;
      inc_tx_tail();
   }
}

static void inc_tx_tail(void)
{
   tx_tail++;
   if ((tx_tail - tx_buf) >= MAX_TRANSMIT_BUF)
   {
      tx_tail = tx_buf;           /* wrap tail pointer back to beginning of buffer. */
   }
}


/*
   Function get_message()

   Retrieves a message from the receive queue of len characters in length.
   If a message of this length is not yet available in the receive buffer, the
   function returns false, and no characters are removed from the receive buffer.
   This function does not place a terminating value on the message.
*/

bool get_message(char *message, char len)
{
   char *temp_tail;
   char count = 0;
   bool done = FALSE;
   char rcvd_char;

   if (len < 2) return FALSE;    /* receiving a single char, use get_rcv_char() */

   /* look at buffer pointers to see if enough characters have been received.. */
   temp_tail = rcv_tail;
   while(!done)
   {
      temp_tail++
      if ((temp_tail - rcv_buf) >= MAX_RECEIVE_BUF)
      {
         temp_tail = rcv_buf;
      }
      count++;
      if (temp_tail == rcv_head)
      {
         done = TRUE;
      }
   }
   if (count < len) return(FALSE);

   /* now, since we have enough received characters, get them and put into the message */
   while(len--)
   {
      get_rcv_char(&rcvd_char);
      *message = rcvd_char;
      message++;
   }
}

/* pull a character off the tail of the circulating receive buffer.  If no characters waiting, return FALSE
 * characters received using interrupt driven reception in circular buffer
*/
bool get_rcv_char(char *value)
{
   if (rcv_tail == rcv_head)           /* no characters in receive buffer */
   {
      return(FALSE);
   }
   else
   {
      *value = *rcv_tail;
      inc_rcv_tail();               /* increment tail pointer */
   }
   return(TRUE);
}

static void inc_rcv_tail(void)
{
   rcv_tail++;
   if ((rcv_tail - rcv_buf) >= MAX_RECEIVE_BUF)
   {
      rcv_tail = rcv_buf;           /* wrap tail pointer back to beginning of buffer. */
   }
}

#endif      /* #ifdef SERIAL_ISR_ROUTINES_ENABLED */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -