📄 softuart.c
字号:
//------------------------------------------------------------------------------------
//
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// FILE NAME : softuart.c
// TARGET DEVICE : C8051F02x
// CREATED ON : 06/07/04
// CREATED BY : JS
//
// Software UART program, using PCA as baud rate source.
// PCA module 0 is used as receive baud rate source and START detector. For START
// detection, module 0 is configured in negative-edge capture mode. For all other
// SW_UART operations, module 0 is configured as a software timer. Module match
// interrupts are used to generate the baud rate. Module 1 generates the transmit
// baud rate in software timer mode.
// Code assumes an external crystal is attached between the XTAL1 and XTAL2 pins.
// The frequency of the external crystal should be defined in the SYSCLK constant.
//
// INITIALIZATION PROCEDURE:
// 1) Define SYSCLK according to external crystal frequency.
// 2) Define desired BAUD_RATE.
// 3) Call SW_UART_INIT().
// 4) Set SREN to enable SW_UART receiver.
// 5) Set SES only if user-level interrupt support is desired.
// 6) Call SW_UART_ENABLE().
//
// TO TRANSMIT:
// 1) Poll STXBSY for zero.
// 2) Write data to TDR.
// 3) Set CCF1 to initiate transmit.
// 4) STI will be set upon transmit completion. An IE7 interrupt is generated if
// user-level interrupts are enabled.
//
// TO RECEIVE:
// 1) If in polled mode, poll SRI. If in interrupt mode, check SRI in IE7 Interrupt
// Service Routine.
// 2) Read data from RDR.
//
// Test code is included, for both polled and interrupt mode. Test code assumes
// the HW_UART pins and SW_UART pins are connected externally:
// P0.0 (HW_UART TX) -> P2.2 (SW_UART RX)
// P0.1 (HW_UART RX) -> P2.7 (SW_UART TX)
//
// To use the test code in polled mode, comment out the call to the INTERRUPT_TEST()
// at the bottom of the main routine, and uncomment the call to POLLED_TEST(). To
// test the interrupt mode, comment out the POLLED_TEST() call and uncomment the
// INTERRUPT_TEST() call.
//
// The test routines configure the HW_UART to operate with Timer 1 as the baud rate
// source. The Timer 1 preload values are auto-calculated from the SYSCLK and BAUD_RATE
// constants.
//
//-----------------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------------
#include <c8051f020.h> // SFR declarations
//-----------------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------------
#define BAUD_RATE 38400 // User-definable SW_UART baud rate
#define SYSCLK 11059200 // System clock derived from 11.0592MHz XTL
#define TIME_COUNT SYSCLK/BAUD_RATE/4 // Number of PCA counts for one bit-time.
// (PCA configured to count SYSCLK/4)
#define TH_TIME_COUNT TIME_COUNT*3/2 // 3/2 bit-time, for use after receiving
// a START bit. RX should be LOW for one
// bit-time after the edge of the START,
// and the first bit sample starts in the
// middle of the next bit-time.
#define HW_TIME_COUNT SYSCLK/BAUD_RATE/16 // Time count for HW_UART baud rate
// generation. Auto-calculated from the
// SYSCLK and BAUD_RATE constants defined
// above.
//-----------------------------------------------------------------------------------
//Global VARIABLES
//-----------------------------------------------------------------------------------
bit SRI; // SW_UART Receive Complete Indicator
bit STI; // SW_UART Transmit Complete Indicator
bit STXBSY; // SW_UART TX Busy flag
bit SREN; // SW_UART RX Enable
bit SES; // SW_UART User-level Interrupt Support Enable
sbit SW_RX = P2^2; // SW_UART Receive pin
sbit SW_TX = P2^7; // SW_UART Transmit pin
char TDR; // SW_UART TX Data Register
char RDR; // SW_UART RX Data Register (latch)
// Test Variables
char k, m; // Test indices.
char idata SW_BUF[20]; // SW_UART test receive buffer.
bit HW_DONE; // HW transfer complete flag (15 characters
// transmitted.)
bit SW_DONE; // SW transfer complete flag (15 characters
// transmitted.)
//------------------------------------------------------------------------------------
// Function PROTOTYPES
//------------------------------------------------------------------------------------
void SW_UART_INIT(); // SW_UART initialization routine
void SW_UART_ENABLE(); // SW_UART enable routine
void PCA_ISR(); // SW_UART interrupt service routine
void INTERRUPT_TEST(void); // SW_UART test routine using interrupt mode
void POLLED_TEST(void); // SW_UART test routine using polled mode
void USER_ISR(void); // SW_UART test interrupt service routine
void HWU_INIT(void); // HW_UART initialization and setup routine
void HW_UART_ISR(void); // HW_UART interrupt service routine
//------------------------------------------------------------------------------------
// MAIN Routine
//------------------------------------------------------------------------------------
// - Disables Watchdog Timer
// - Configures external crystal; switches SYSCLK to external crystal when stable.
// - Configures crossbar and ports.
// - Initializes and enables SW_UART.
// - Calls Test Routines.
//
void MAIN (void){
// int delay; // Delay counter.
unsigned int i;
//OSCXCN = 0x66; // Enable external crystal
WDTCN = 0xDE; // disable watchdog timer
WDTCN = 0xAD;
// Port Setup
XBR0 = 0x0f; // HW_UART routed to pins P0.0 and P0.1;
// CEX0 routed to pin P0.2.
XBR2 = 0x44; // Enable crossbar, pull-ups enabled.
P1MDIN = 0x00; // P0.0 (HW TX), and P0.3 (SW TX)
P2MDOUT |= 0X80; // configured for push-pull output.
P0MDOUT |= 0X01;
OSCXCN = 0x67; // start external oscillator with
// 11.0592MHz crystal
for (i=0; i < 256; i++) ; // XTLVLD blanking interval (>1ms)
while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settle
OSCICN = 0x88; // select external oscillator as SYSCLK
// source and enable missing clock
// detector
// POLLED_TEST(); // Call Polled mode SW_UART test routine.
INTERRUPT_TEST(); // Call Interrupt mode SW_UART test routine.
while(1); // Spin forever
}
//------------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// INTERRUPT_TEST: SW_UART Interrupt Mode Test
// Test code to transmit and receive 15 characters to/from the HW_UART (in interrupt
// mode), with SW_UART in interrupt mode.
// - Initializes and enables the SW_UART & HW_UART
// - Clears all test variables & counters
// - Transfers 15 characters from HW to SW_UART, and 15 characters from SW to HW_UART,
// simultaneously.
//
void INTERRUPT_TEST(void){
SW_UART_INIT(); // Initialize SW_UART
SW_UART_ENABLE(); // Enable SW_UART
SREN = 1; // Enable SW_UART Receiver
SES = 1; // User-level interrupt support enabled.
HWU_INIT(); // Configure HW_UART for testing routine.
k=m=0; // Clear user ISR counters.
HW_DONE=0; // Clear transfer complete indicators
SW_DONE=0; //
IE |= 0x10; // Enable HW_UART interrupts
STI=1; // Indicate transmit complete to initiate
// next transfer.
EIE2 |= 0x20; // Start SW_TX by enabling
P3IF |= 0x80; // and forcing an IE7 interrupt
TI0 = 1; // Initiate a HW_UART transmit
// by forcing TX interrupt.
while(!(HW_DONE&SW_DONE)); // Wait for transfers to finish.
}
//---------------------------------------------------------------------------------------
// POLLED_TEST: SW_UART Polled Mode Test
// Test code to transmit and receive 15 characters to/from the HW_UART, with SW_UART
// in polled mode.
// - Initializes and enables the SW_UART & HW_UART
// - Clears all test variables & counters
// - Sends 15 characters from the HW_UART to be received by SW_UART.
// - Sends 15 characters from the SW_UART to be received by the HW_UART.
//
void POLLED_TEST(void){
SW_UART_INIT(); // Initialize SW_UART
SW_UART_ENABLE(); // Enable SW_UART
SREN = 1; // Enable SW_UART Receiver
SES=0; // Disable user-level interrupt support.
HWU_INIT(); // Configure HW_UART for testing routine.
k=m=0; // Clear test counter variables.
HW_DONE=0; // Clear transfer complete indicators
SW_DONE=0; //
IE |= 0x10; // Enable HW_UART interrupts.
TI0 = 1; // Initiate a HW_UART transmit
// by forcing TX interrupt.
// Receive 15 characters with SW_UART; transmit with HW_UART.
while(SREN){ // Run while SW_UART Receiver is
// enabled.
if (SRI){ // If Receive Complete:
SRI = 0; // Clear receive flag.
SW_BUF[k++] = RDR; // Read receive buffer.
if (k==15){ // If 15 characters have been received:
SREN = 0; // Disable SW_UART Receiver.
} // Indicate 15 characters received.
}
}
// Transmit 15 characters with SW_UART; receive with HW_UART.
while(STXBSY); // Poll Busy flag.
STXBSY = 1; // Claim SW_UART Transmitter
TDR=m++; // Load TX data.
CCF1=1; // Initiate first SW_UART TX
// by forcing a PCA module 1 interrupt.
while(!SW_DONE){ // SW_UART transmitting here; HW_UART receiving.
if (STI){ // If Transmit Complete:
STI = 0; // Clear transmit flag.
if (m<16){ // Transmit 15 characters.
STXBSY = 1; // Claim SW_UART Transmitter.
TDR = m++; // Transmit, increment variable.
CCF1 = 1; // Force module 1 interrupt to initiate TX.
}
else // If this is 15th character,
SW_DONE=1; // Indicate last character transmitted.
}
}
}
//------------------------------------------------------------------------------------------
// HWU_INIT: HW_UART Initialization Routine
// Sets up HW_UART for use in SW_UART testing.
// - HW_UART in mode 1
// - Timer 1 used as baud rate source, clocked by SYSCLK.
//
void HWU_INIT(void) {
PCON |= 0x80; // SMOD=1 (HW_UART uses Timer 1 overflow
// with no divide down).
TMOD = 0x20; // Configure Timer 1 for use by HW_UART
CKCON |= 0x10; // Timer 1 derived from SYSCLK
TH1 = -HW_TIME_COUNT; // Timer 1 initial value
TL1 = -HW_TIME_COUNT; // Timer 1 reload value
TR1 = 1; // Start Timer 1
RI0=0; // Clear HW_UART receive and transmit
TI0=0; // complete indicators.
SCON0 = 0x50; // Configure HW_UART for mode 1, receiver enabled.
}
//------------------------------------------------------------------------------------------
// SW_UART_INIT: SW_UART initialization routine
// Prepares SW_UART for use.
// - Configures PCA: Module 0 in negative capture mode; module 1 in software
// timer mode; PCA time base = SYSCLK/4; PCA interrupt disabled; PCA counter
// disabled.
// - Clears pending PCA module 0 and 1 interrupts
// - Resets TX and RX state variables
//
void SW_UART_INIT(void){
PCA0CPM0 = 0x10; // Module 0 in negative capture mode; module
// 0 interrupt disabled.
PCA0CPM1 = 0x48; // Module 1 in software timer mode; module
// 1 interrupt disabled.
PCA0CN = 0; // Leave PCA disabled
PCA0MD = 0x02; // PCA timebase = SYSCLK/4; PCA counter
// interrupt disabled.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -