这次介绍如何在 uC/OS-II 上实现串口驱动。
/*sci_ucos.h*/
#ifndef _SCI_RTOS_H_
#define _SCI_RTOS_H_
#define SCI_RX_BUF_SIZE 64 /* Number of characters in Rx ring buffer */ #define SCI_TX_BUF_SIZE 64 /* Number of characters in Tx ring buffer */
/* ********************************************************************************************************* * CONSTANTS ********************************************************************************************************* */
#ifndef NUL #define NUL 0x00 #endif
/* ERROR CODES */ #define SCI_NO_ERR 0 /* Function call was successful */ #define SCI_BAD_CH 1 /* Invalid communications port channel */ #define SCI_RX_EMPTY 2 /* Rx buffer is empty, no character available */ #define SCI_TX_FULL 3 /* Tx buffer is full, could not deposit character */ #define SCI_TX_EMPTY 4 /* If the Tx buffer is empty. */ #define SCI_RX_TIMEOUT 5 /* If a timeout occurred while waiting for a character*/ #define SCI_TX_TIMEOUT 6 /* If a timeout occurred while waiting to send a char.*/
#define SCI_PARITY_NONE 0 /* Defines for setting parity */ #define SCI_PARITY_ODD 1 #define SCI_PARITY_EVEN 2
/* ********************************************************************************************************* * DATA TYPES ********************************************************************************************************* */ typedef struct { short RingBufRxCtr; /* Number of characters in the Rx ring buffer */ OS_EVENT *RingBufRxSem; /* Pointer to Rx semaphore */ unsigned char *RingBufRxInPtr; /* Pointer to where next character will be inserted */ unsigned char *RingBufRxOutPtr; /* Pointer from where next character will be extracted */ unsigned char RingBufRx[SCI_RX_BUF_SIZE]; /* Ring buffer character storage (Rx) */ short RingBufTxCtr; /* Number of characters in the Tx ring buffer */ OS_EVENT *RingBufTxSem; /* Pointer to Tx semaphore */ unsigned char *RingBufTxInPtr; /* Pointer to where next character will be inserted */ unsigned char *RingBufTxOutPtr; /* Pointer from where next character will be extracted */ unsigned char RingBufTx[SCI_TX_BUF_SIZE]; /* Ring buffer character storage (Tx) */ } SCI_RING_BUF;
/** * To obtain a character from the communications channel. * @param port, port can be SCI0 / SCI1 * @param to, is the amount of time (in clock ticks) that the calling function is willing to * wait for a character to arrive. If you specify a timeout of 0, the function will * wait forever for a character to arrive. * @param err, is a pointer to where an error code will be placed: * *err is set to SCI_NO_ERR if a character has been received * *err is set to SCI_RX_TIMEOUT if a timeout occurred * *err is set to SCI_BAD_CH if you specify an invalid channel number * @return The character in the buffer (or NUL if a timeout occurred) */ unsigned char SCIGetCharB (unsigned char ch, unsigned short to, unsigned char *err);
/** * This function is called by your application to send a character on the communications * channel. The function will wait for the buffer to empty out if the buffer is full. * The function returns to your application if the buffer doesn't empty within the specified * timeout. A timeout value of 0 means that the calling function will wait forever for the * buffer to empty out. The character to send is first inserted into the Tx buffer and will * be sent by the Tx ISR. If this is the first character placed into the buffer, the Tx ISR * will be enabled. * * @param port, port can be SCI0 / SCI1 * @param c is the character to send. * @param to is the timeout (in clock ticks) to wait in case the buffer is full. If you * specify a timeout of 0, the function will wait forever for the buffer to empty. * @return SCI_NO_ERR if the character was placed in the Tx buffer * SCI_TX_TIMEOUT if the buffer didn't empty within the specified timeout period * SCI_BAD_CH if you specify an invalid channel number */ unsigned char SCIPutCharB (unsigned char port, unsigned char c, unsigned short to);
/** * To initialize the communications module. * You must call this function before calling any other functions. */ void SCIBufferInit (void);
/** * To see if any character is available from the communications channel. * * @param port, port can be SCI0 / SCI1 * @return If at least one character is available, the function returns * FALSE(0) otherwise, the function returns TRUE(1). */ unsigned char SCIBufferIsEmpty (unsigned char port);
/** * To see if any more characters can be placed in the Tx buffer. * In other words, this function check to see if the Tx buffer is full. * * @param port, port can be SCI0 / SCI1 * @return If the buffer is full, the function returns TRUE * otherwise, the function returns FALSE. */ unsigned char SCIBufferIsFull (unsigned char port);
#endif
/** * SCI(Serial Communication Interface) Buffered Serial I/O * @file sci_ucos.c * @author Li Yuan * @platform mc9s12XX * @date 2012-7-22 * @version 1.0.1 */
#include "derivative.h" /* derivative-specific definitions */ #include
/** * GLOBAL VARIABLES */ SCI_RING_BUF SCI0Buf; SCI_RING_BUF SCI1Buf;
/** * To obtain a character from the communications channel. * @param port, port can be SCI0 / SCI1 * @param to, is the amount of time (in clock ticks) that the calling function is willing to * wait for a character to arrive. If you specify a timeout of 0, the function will * wait forever for a character to arrive. * @param err, is a pointer to where an error code will be placed: * *err is set to SCI_NO_ERR if a character has been received * *err is set to SCI_RX_TIMEOUT if a timeout occurred * *err is set to SCI_BAD_CH if you specify an invalid channel number * @return The character in the buffer (or NUL if a timeout occurred) */ unsigned char SCIGetCharB (unsigned char port, unsigned short to, INT8U *err) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif unsigned char c; unsigned char oserr; SCI_RING_BUF *pbuf;
switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: *err = SCI_BAD_CH; return (0); } OSSemPend(pbuf->RingBufRxSem, to, &oserr); /* Wait for character to arrive */ if (oserr == OS_TIMEOUT) { /* See if characters received within timeout*/ *err = SCI_RX_TIMEOUT; /* No, return error code */ return (NUL); } else { OS_ENTER_CRITICAL(); pbuf->RingBufRxCtr--; /* Yes, decrement character count */ c = *pbuf->RingBufRxOutPtr++; /* Get character from buffer */ if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[SCI_RX_BUF_SIZE]) { /* Wrap OUT pointer */ pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; } OS_EXIT_CRITICAL(); *err = SCI_NO_ERR; return (c); } }
/** * This function is called by your application to send a character on the communications * channel. The function will wait for the buffer to empty out if the buffer is full. * The function returns to your application if the buffer doesn't empty within the specified * timeout. A timeout value of 0 means that the calling function will wait forever for the * buffer to empty out. The character to send is first inserted into the Tx buffer and will * be sent by the Tx ISR. If this is the first character placed into the buffer, the Tx ISR * will be enabled. * * @param port, port can be SCI0 / SCI1 * @param c is the character to send. * @param to is the timeout (in clock ticks) to wait in case the buffer is full. If you * specify a timeout of 0, the function will wait forever for the buffer to empty. * @return SCI_NO_ERR if the character was placed in the Tx buffer * SCI_TX_TIMEOUT if the buffer didn't empty within the specified timeout period * SCI_BAD_CH if you specify an invalid channel number */ unsigned char SCIPutCharB (unsigned char port, unsigned char c, unsigned short to) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif
SCI_RING_BUF *pbuf; unsigned char oserr; switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return (SCI_BAD_CH); }
OSSemPend(pbuf->RingBufTxSem, to, &oserr); /* Wait for space in Tx buffer */ if (oserr == OS_TIMEOUT) { return (SCI_TX_TIMEOUT); /* Timed out, return error code */ } OS_ENTER_CRITICAL(); pbuf->RingBufTxCtr++; /* No, increment character count */ *pbuf->RingBufTxInPtr++ = c; /* Put character into buffer */ if (pbuf->RingBufTxInPtr == &pbuf->RingBufTx[SCI_TX_BUF_SIZE]) { pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; /* Wrap IN pointer */ } if (pbuf->RingBufTxCtr == 1) /* See if this is the first character */ { SCIEnableTxInt(port); /* Yes, Enable Tx interrupts */ } OS_EXIT_CRITICAL(); return (SCI_NO_ERR); }
/** * To initialize the communications module. * You must call this function before calling any other functions. */ void SCIBufferInit (void) { SCI_RING_BUF *pbuf;
pbuf = &SCI0Buf; /* Initialize the ring buffer for SCI0 */ pbuf->RingBufRxCtr = 0; pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxSem = OSSemCreate(0); pbuf->RingBufTxCtr = 0; pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxSem = OSSemCreate(SCI_TX_BUF_SIZE);
pbuf = &SCI1Buf; /* Initialize the ring buffer for SCI1 */ pbuf->RingBufRxCtr = 0; pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxSem = OSSemCreate(0); pbuf->RingBufTxCtr = 0; pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxSem = OSSemCreate(SCI_TX_BUF_SIZE); }
/** * To see if any character is available from the communications channel. * * @param port, port can be SCI0 / SCI1 * @return If at least one character is available, the function returns * FALSE(0) otherwise, the function returns TRUE(1). */ unsigned char SCIBufferIsEmpty (unsigned char port) {
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif unsigned char empty; SCI_RING_BUF *pbuf; switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break; default: return (0xff); break; } OS_ENTER_CRITICAL(); if (pbuf->RingBufRxCtr > 0) { /* See if buffer is empty */ empty = 0; /* Buffer is NOT empty */ } else { empty = 1; /* Buffer is empty */ } OS_EXIT_CRITICAL(); return (empty);
}
/** * To see if any more characters can be placed in the Tx buffer. * In other words, this function check to see if the Tx buffer is full. * * @param port, port can be SCI0 / SCI1 * @return If the buffer is full, the function returns TRUE * otherwise, the function returns FALSE. */ unsigned char SCIBufferIsFull (unsigned char port) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif char full; SCI_RING_BUF *pbuf; switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return (255); } OS_ENTER_CRITICAL(); if (pbuf->RingBufTxCtr < SCI_TX_BUF_SIZE) { /* See if buffer is full */ full = 0; /* Buffer is NOT full */ } else { full = 1; /* Buffer is full */ } OS_EXIT_CRITICAL(); return (full); }
// This function is called by the Rx ISR to insert a character into the receive ring buffer. static void SCIPutRxChar (unsigned char port, unsigned char c) {
SCI_RING_BUF *pbuf;
switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return; } if (pbuf->RingBufRxCtr < SCI_RX_BUF_SIZE) { /* See if buffer is full */ pbuf->RingBufRxCtr++; /* No, increment character count */ *pbuf->RingBufRxInPtr++ = c; /* Put character into buffer */ if (pbuf->RingBufRxInPtr == &pbuf->RingBufRx[SCI_RX_BUF_SIZE]) { /* Wrap IN pointer */ pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; } (void)OSSemPost(pbuf->RingBufRxSem); /* Indicate that character was received */ } }
// This function is called by the Tx ISR to extract the next character from the Tx buffer. // The function returns FALSE if the buffer is empty after the character is extracted from // the buffer. This is done to signal the Tx ISR to disable interrupts because this is the // last character to send. static unsigned char SCIGetTxChar (unsigned char port, unsigned char *err) { unsigned char c; SCI_RING_BUF *pbuf;
switch (port) { /* Obtain pointer to communications channel */ case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: *err = SCI_BAD_CH; return (0); } if (pbuf->RingBufTxCtr > 0) { /* See if buffer is empty */ pbuf->RingBufTxCtr--; /* No, decrement character count */ c = *pbuf->RingBufTxOutPtr++; /* Get character from buffer */ if (pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[SCI_TX_BUF_SIZE]) { /* Wrap OUT pointer */ pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; } (void)OSSemPost(pbuf->RingBufTxSem); /* Indicate that character will be sent */ *err = SCI_NO_ERR; return (c); /* Characters are still available */ } else { *err = SCI_TX_EMPTY; return (NUL); /* Buffer is empty */ } }
void SCI0_ISR_Handler(void) { char status; char data; unsigned char err; status = SCI0SR1;
if(status & 0x0F) // 0x1F = 0001 1111, if status is not Receive Data Reg Full Flag { // See if we have some kind of error // Clear interrupt (do nothing about it!) data = SCI0DRL; } else if(status & 0x20) //Receive Data Reg Full Flag { data = SCI0DRL; SCIPutRxChar(SCI0, data); // Insert received character into buffer } else if(status & 0x80) { data = SCIGetTxChar(SCI0, &err); // Get next character to send. if (err == SCI_TX_EMPTY) { // Do we have anymore characters to send ? // No, Disable Tx interrupts SCIDisTxInt(SCI0); } else { SCI0DRL = data; // Yes, Send character } } }
void SCI1_ISR_Handler (void) { char status; char data; unsigned char err; status = SCI1SR1;
if(status & 0x0F) // 0x1F = 0001 1111, if status is not Receive Data Reg Full Flag { // See if we have some kind of error // Clear interrupt (do nothing about it!) data = SCI1DRL; } else if(status & 0x20) //Receive Data Reg Full Flag { data = SCI1DRL; SCIPutRxChar(SCI1, data); // Insert received character into buffer } else if(status & 0x80) { data = SCIGetTxChar(SCI1, &err); // Get next character to send. if (err == SCI_TX_EMPTY) { // Do we have anymore characters to send ? // No, Disable Tx interrupts SCIDisTxInt(SCI1); } else { SCI1DRL = data; // Yes, Send character } } }
#pragma CODE_SEG NON_BANKED interrupt VectorNumber_Vsci0 void SCI0_ISR(void) {
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm ldaa PPAGE; // 3~, Get current value of PPAGE register __asm psha; // 2~, Push PPAGE register onto current task's stack #endif __asm inc OSIntNesting; //OSIntNesting++;
//if (OSIntNesting == 1) //{ // OSTCBCur->OSTCBStkPtr = Stack Pointer ; //} __asm { ldab OSIntNesting cmpb #$01 bne SCI0ISR1
ldx OSTCBCur sts 0, x SCI0ISR1: }
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm call SCI0_ISR_Handler; __asm call OSIntExit; #else __asm jsr SCI0_ISR_Handler; __asm jsr OSIntExit; #endif
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm pula; // 3~, Get value of PPAGE register __asm staa PPAGE; // 3~, Store into CPU's PPAGE register #endif
}
interrupt VectorNumber_Vsci1 void SCI1_ISR(void) {
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm ldaa PPAGE; // 3~, Get current value of PPAGE register __asm psha; // 2~, Push PPAGE register onto current task's stack #endif __asm inc OSIntNesting; //OSIntNesting++;
//if (OSIntNesting == 1) //{ // OSTCBCur->OSTCBStkPtr = Stack Pointer ; //} __asm { ldab OSIntNesting cmpb #$01 bne SCI1ISR1
ldx OSTCBCur sts 0, x SCI1ISR1: }
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm call SCI1_ISR_Handler; __asm call OSIntExit; #else __asm jsr SCI1_ISR_Handler; __asm jsr OSIntExit; #endif
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) __asm pula; // 3~, Get value of PPAGE register __asm staa PPAGE; // 3~, Store into CPU's PPAGE register #endif
}
下面给个简单的例子:
#include
#include "INCLUDES.H" #include "crg.h" #include "sci.h" #include "sci_rtos.h"
OS_STK AppStartTaskStk[64];
static void AppStartTask (void *pdata);
void main(void) { /* put your own code here */ OS_CPU_SR cpu_sr;
CRGInit(); CRGSetRTIFreqency(0x54); // 200Hz
EnableInterrupts; OS_ENTER_CRITICAL() ; SCIInit(SCI0) ; SCIInit(SCI1) ; OS_EXIT_CRITICAL() ; OSInit(); SCISetIEBit(SCI0, SCI_RIE) ; SCISetIEBit(SCI1, SCI_RIE) ; SCIBufferInit(); (void) OSTaskCreate(AppStartTask, (void *)0x4321, (void *)&AppStartTaskStk[63], 0); (void)OSStart(); for(;;) { _FEED_COP(); /* feeds the dog */ } /* loop forever */ /* please make sure that you never leave main */ }
static void AppStartTask (void *pdata) { INT8U err; char C; (void) pdata; for(;;) { C = SCIGetCharB(SCI1, 0, &err); if(err == SCI_NO_ERR) (void) SCIPutCharB (SCI1, C, 0); } }