📄 8051单片机uart驱动程序.txt
字号:
// _____________________________________________________________________________
// _____________________________________________________________________________
//
// 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 + -