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

📄 8051单片机uart驱动程序.txt

📁 8051串口驱动程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Embedded Firmware Design, Inc.                               Copyright ?2002
// _____________________________________________________________________________
//
// File:                uart.c
//
// Author:              Mark A. Odell
//
// Description:
// ------------
// An example of a ring buffered, interrupt driven, UART driver for the 8051.
//
// Design Notes:
// -------------
// Define DBG for test only.
//
// Sets up the 8051 standard UART using Timer 1 for a baud rate generator. You
// pick the XTAL frequency by setting XTAL_FREQ to one of the listed speeds
// in the form of defines XTAL_XX_XXXMHZ.
//
// Call initUart(baudRate) with baudRate set to one of the enum's listed in
// uart.h as a type called UartBaudRates. The initUart() function will do
// everything for you except touch the global interrupt enable bit. You must
// enable this when you are ready to start your system.
//
// The UART interrupt preserve/disable/restore operation really needs high
// priority interrupt to provide completely safe interrupt posture control.
//
// All functions that return status return zero for "no failure" and non-zero
// for "some failure". The exception to this rule is for standard C functions
// that I override here (e.g. _getkey() and putchar()).
//
// Note that __RC51__ is unique to Amrai tools but __C51__ is defined by both
// Keil and Amrai. Thus, don't try to distinguish the two toolsets by __C51__.
//
// Thanks to Jon Young for pointing out the benefits of _testbit_().
//
// License:
// --------
// This software is copyrighted by Embedded Firmware Design, Inc. and comes
// with absolutely no warranty whatsoever. Use at your own risk. There are no
// use limitations on this software, commercial or otherwise, as long as
// Embedded Firmware Design, Inc. is fully indemnified from any and all harm
// incurred as a result of using this software.
//
// Revision Control:
// -----------------
// Last committed on  --> $Date: 2002/05/03 21:01:19 $
// This file based on --> $Revision: 1.15 $
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Header files
//
#include "uart.h"
#include <stdio.h>

// Required for _testbit_();
#include <intrins.h>
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Private Constants
//
// Common XTAL frequencies (Hz).
#define XTAL_11_059MHZ  11059200
#define XTAL_12_000MHZ  12000000
#define XTAL_12_288MHZ  12288000
#define XTAL_16_000MHZ  16000000
#define XTAL_20_000MHZ  20000000
#define XTAL_22_118MHZ  22118400
#define XTAL_24_000MHZ  24000000

// Choose your frequency.
#define XTAL_FREQ       XTAL_12_000MHZ

// Choice of memory space will affect ring buffer sizes. Usually, RX >= TX size.
//      0 - data
//      1 - idata
//      2 - pdata
//      3 - xdata
#define RING_MEM_SPACE  3
#define RX_RING_SIZE    256
#define TX_RING_SIZE    128

#if RING_MEM_SPACE == 0
#   undef  RING_MEM_SPACE
#   define RING_MEM_SPACE data
#   if RX_RING_SIZE + TX_RING_SIZE > 0x7F - 0x20
#       error Suggest you drop the size of UART ring buffers or switch to another memory space.
#   endif
#elif RING_MEM_SPACE == 1
#   undef  RING_MEM_SPACE
#   define RING_MEM_SPACE idata
#   if RX_RING_SIZE + TX_RING_SIZE > 0xFF - 0x20
#       error Suggest you drop the size of UART ring buffers or switch to another memory space.
#   endif
#elif RING_MEM_SPACE == 2
#   undef  RING_MEM_SPACE
#   define RING_MEM_SPACE pdata
#   if RX_RING_SIZE + TX_RING_SIZE > 0xFF
#       error Suggest you drop the size of UART ring buffers or switch to another memory space.
#   endif
#elif RING_MEM_SPACE == 3
#   undef  RING_MEM_SPACE
#   define RING_MEM_SPACE xdata
#   if RX_RING_SIZE + TX_RING_SIZE > 0xFFFF - 0x20
#       error Suggest you drop the size of UART ring buffers or switch to another memory space.
#   endif
#else
#   error You must pick a UART ring buffer memory space of xdata, idata, or data.
#endif

// Handy debug control macro.
#ifdef DBG
#   define debug
#else
#   define debug while (0)
#endif

// Documentational.
#define UART_INTR_NUM       4
#define REGISTER_BANK_1     1

#define SCON_8N1            0x40 // SCON.SM1 = 1, SM0,2 = 0
#define SCON_REN            0x10

// Timer 1 only (Timer 0 not used here)
#define TMOD_GATE_T1        0x80
#define TMOD_C_T_T1         0x40
#define TMOD_M1_T1          0x20
#define TMOD_M0_T1          0x10
#define T1_MODE_MASK        (TMOD_GATE_T1 | TMOD_C_T_T1 | TMOD_M1_T1 | TMOD_M0_T1)
#define T1_8BIT_AUTO_RELOAD (TMOD_M1_T1)

#define PCON_SMOD           0x80 // Doubles baud rate timing of Timer 1
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Private Objects
//
typedef bit           Bool;
typedef signed char   S8;
typedef unsigned char U8;
typedef signed int    S16;
typedef unsigned int  U16;
typedef signed long   S32;
typedef unsigned long U32;

// Clip indexes at 2^16 since the 8051 only supports a 16-bit XDATA space.
#if RX_RING_SIZE > 256
    typedef unsigned int  RxRingIndex;
#else
    typedef unsigned char RxRingIndex;
#endif

#if TX_RING_SIZE > 256
    typedef unsigned int  TxRingIndex;
#else
    typedef unsigned char TxRingIndex;
#endif
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Private module functions (prototyped as 'static')
//
static void uartIsr(void);
static Bool setUartBaudRate(UartBaudRates baudRate);
static Bool putUartChar(U8 outChar);
static Bool getUartChar(U8 *pInChar);
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Private module variables (static module global 's_' prefixed for 's'tatic)
//
static const char code s_moduleInfo[] = __FILE__ " modified " __DATE__ " at " __TIME__;

// Ring variables.
static          U8            RING_MEM_SPACE s_rxRing[RX_RING_SIZE];
static          U8            RING_MEM_SPACE s_txRing[TX_RING_SIZE];
static          Bool          data           s_translateEol;
static volatile Bool          data           s_rxRingEmpty;
static volatile Bool          data           s_txRingEmpty;
static volatile RxRingIndex   data           s_rxWrIdx;
static volatile RxRingIndex   data           s_rxRdIdx;
static volatile TxRingIndex   data           s_txWrIdx;
static volatile TxRingIndex   data           s_txRdIdx;
static          UartBaudRates data           s_currentBaudRate;
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// CPU resouces (for this module, 'r_' prefixed for 'r'egister)
//
sbit   r_ieEs    = 0xAC; // IE.ES
sbit   r_ieEt1   = 0xAB; // IE.ET1

sfr    r_scon    = 0x98; // SCON
sbit   r_sconSm1 = 0x9E; // SCON.SM1
sbit   r_sconRen = 0x9C; // SCON.REN
sbit   r_sconTi  = 0x99; // SCON.TI
sbit   r_sconRi  = 0x98; // SCON.RI

sfr    r_sbufRx  = 0x99; // SBUF (rx on read)
sfr    r_sbufTx  = 0x99; // SBUF (tx on write)

sfr    r_tmod    = 0x89; // TMOD

sfr    r_tcon    = 0x88; // TCON
sbit   r_tconTf1 = 0x8F; // TCON.TF1
sbit   r_tconTr1 = 0x8E; // TCON.TR1
sbit   r_tconIe1 = 0x8B; // TCON.IE1
sbit   r_tconIt1 = 0x8A; // TCON.IT1

sfr    r_tl1     = 0x8B; // TL1
sfr    r_th1     = 0x8D; // TH1

sfr    r_pcon    = 0x87; // PCON
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Function:  putchar
//
// Description:
// ------------
// Simply overrides the library supplied verion.
//
// Design Notes:
// -------------
// Do not prototype, prototyped in stdio.h.
//
// Called by library verion of printf(), allows printf() to use our driver.
// Also called by the library version of getchar() to provide character echo.
//
// Simply blocks until there is room in the Tx Ring since printf() may not
// know what to do if putchar() fails.
// _____________________________________________________________________________
//
#ifdef __RC51__
int  putchar(const int outChar)
#else // __C51__
char putchar(char outChar)
#endif
{
    while (putUartChar((U8) outChar));

    if (s_translateEol && '\n' == outChar)
    {
        while (putUartChar('\r'));
    }

    return outChar;
}
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Function:  _getkey
//
// Description:
// ------------
// Simply overrides the library supplied verion. Blocks until a character is
// available and then returns it to the caller. It does not echo, use getchar()
// you need loopback echo.
//
// Design Notes:
// -------------
// Do not prototype, prototyped in stdio.h.
//
// Used by toolset getchar() function.
// _____________________________________________________________________________
//
#ifdef __RC51__
int  _getkey(void)
#else // __C51__
char _getkey(void)
#endif
{
    U8 data inChar;

    while (getUartChar(&inChar));

    return inChar;
}
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Function:  initUart
//
// Description:
// ------------
// Sets up the 8051 Serial Port for UART (SCON.SM1 = 1, Mode 1) operation and
// initializes the ring buffers.
//
// Design Notes:
// -------------
// Byte framing is 8-N-1.
// _____________________________________________________________________________
//
bit initUart(UartBaudRates baudRate)
{
    // For restartability.
    r_ieEs = 0;

    // Setup the baud rate generator.
    if (setUartBaudRate(baudRate)) return 1;

    // Setup the serial port.
    r_scon = SCON_8N1 | SCON_REN;

    // Setup ring buffers.
    s_rxRingEmpty = 1;
    s_txRingEmpty = 1;
    s_rxWrIdx     = 0;
    s_rxRdIdx     = 0;
    s_txWrIdx     = 0;
    s_txRdIdx     = 0;

    // Printf() translates for us so no need for it here.
    s_translateEol = 0;

    // Start driver.
    r_ieEs = 1;

    return 0;
}
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// Function:  setUartBaudRate
//
// Description:
// ------------
// Attempts to setup Timer 1 to generate baud for the disired <baudRate>. Will
// try TH1 values for both PCON.SMON = 1 and 0. Returns zero for no failure
// in setting the desired baud rate.
//
// Design Notes:
// -------------
// The absolute value of the negative entries are the actual number of Timer
// 1 ticks required for a given baud rate. The 2x table assumes PCON.SMOD is set
// to double the baud rate generated by TH1. Zeros indicate a baud rate could
// not be generated with 4% or less difference. The 1x table assumes PCON.SMOD
// is clear.
// _____________________________________________________________________________
//
static Bool setUartBaudRate(UartBaudRates baudRate)
{
    static const S8 code baudRateTable2x[NUM_BAUD_RATES] =
    {
    //  1200  2400  9600  19200  38400  57600  115200
#if   XTAL_FREQ == XTAL_11_059MHZ
         -48,  -24,   -6,    -3,     0,    -1,      0
#elif XTAL_FREQ == XTAL_12_000MHZ
         -52,  -26,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_12_288MHZ
         -53,  -27,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_16_000MHZ
         -69,  -35,   -9,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_20_000MHZ
         -87,  -43,  -11,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_22_118MHZ
         -96,  -48,  -12,    -5,    -3,    -2,     -1
#elif XTAL_FREQ == XTAL_24_000MHZ
        -104,  -52,  -13,     0,     0,     0,      0
#else // Add more if needed.
#   error Pick a known XTAL frequency from list provided in this file.
#endif
    };
    static const S8 code baudRateTable1x[NUM_BAUD_RATES] =
    {
    //  1200  2400  9600  19200  38400  57600  115200
#if   XTAL_FREQ == XTAL_11_059MHZ
         -24,  -12,   -3,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_12_000MHZ
         -26,  -13,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_12_288MHZ
         -27,  -13,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_16_000MHZ
         -35,  -17,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_20_000MHZ
         -43,  -22,    0,     0,     0,     0,      0
#elif XTAL_FREQ == XTAL_22_118MHZ
         -48,  -24,   -6,    -3,     0,    -1,      0
#elif XTAL_FREQ == XTAL_24_000MHZ
         -52,  -26,    0,     0,     0,     0,      0
#else
#   error Pick a known XTAL frequency from list provided in this file.
#endif
    };
    S8   data th1Value;
    Bool data ieEs;

    // Look for cases where we don't want to or can't change the baud rate.
    if (BAUD_RATE_NO_CHANGE == baudRate || s_currentBaudRate == baudRate)
    {
        return 0;
    }

⌨️ 快捷键说明

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