| JohnLeung 
 
 
 Joined: 18 May 2004
 Posts: 15
 
 
 
			    
 
 | 
			
				| 4" 7-segment LED display in 3-digit with 2x7W amplifier |  
				|  Posted: Thu Jan 12, 2006 4:42 am |   |  
				| 
 |  
				| Dear Sirs 
 A highly recommended book for embedded C programmers :
 Embedded System Building Blocks, Complete and Ready-to-use Modules in C, by Jean J. Labrosse.
 
 I have modified one of the chapters on 7-segment LED display for CCS PICC. Very good performance result with my module being able to communicate with a PC, with DING DONG alert tone (have built-in 7W amplifier), and multiplex feature for 1-digit to max. 15 digits from a single mcu 16F877 @ 20MHz!
 
 Interested parties can download the whole project under www.TechToys.com.hk
 
 John
 
 
  	  | Code: |  	  | /***************************************************************************************************
 *   This is a demonstration for PIC16-LEDSTK1 by TechToys (www.TechToys.com.hk)
 *
 *   Original :
 *   Used in an automatic queuing system for a spam
 *   Intended for showing queue number in 6 groups (3-digit per group)
 *
 *   Now       :
 *   Modified for PIC16-LEDSTK1 in 3-digit format
 
 *   Interrupt tasks:
 a) #INT_TIMER0, for multiplexing the LED display
 b) #INT_RDA, for command / data receive
 c) #INT_TBE, for command / data ack
 *
 *   DisplayManager() is the only function to decode a string/command from a remote PC and
 *   ouptut the string to LED display board. DisplayManager() should be inside TMR1 interrupt
 *   routine because BeepManager() is using a simple delay_us() function,
 *   which can "jam" the main loop. If DisplayManager() was running in main() loop, a frequent
 *   data sequence from PC could overflow the UART receive buffer easily.
 *
 *   Packet Protocol:
 *   +-------+-------+-------+------------+------------+------+
 *   |  '0'  |  '1'  |  '2'  |reserve byte|reserve byte| 0x0d |
 *   +-------+-------+-------+------------+------------+------+
 *   The length of a complete message is dependent on variables DataBuf[6] array
 *   declared under DisplayManager(void).
 *   For example, we want to display 3-digit '0' '1' '2' on the LEDs, we need to write
 *   ASCII characters '0' '1' '2' 'reserve byte' 'reserve byte' 0x0d to PIC16-LEDSTK1
 *   Reserve byte can be used for future expansion, or checksum, etc.
 *
 *   It is easy to modify DisplayManager(void) for display > 3 digits
 *   Adjust the TMR0 rate for different brightness or change the R2 resistor value onboard
 *
 *   Hardware :       PCB 11OCT2004.001
 *   Software :       main1.c, demonstration program for PIC16-LEDSTK1
 *   Created by :    John Leung (www.TechToys.com.hk)
 *   Date:          22th Dec 2004 (Version 1.0)
 *   History      :   modified for PIC16-LEDSTK1 dated 12 Jan 2006
 ***************************************************************************************************/
 
 #include <16F877a.h>               // register definition file for PIC16F877a
 #fuses HS,NOWDT,NOLVP,PUT            // a Microchip PIC16F877
 #priority rda, timer1, timer0         // define a priority over the interrupt source
 #use delay(clock=20000000)
 
 #include "OS_CPU.h"   //typedef compatible with uCOS-II, specified to CCS PICC
 #include "USART.h"   //USART with serial 232 I/O buffer
 #include "USART.c"
 #include "LED.h"   //LED driver header
 #include "LED.c"   //LED driver
 #include "BEEP.c"   //For DINGDONG generation via PORTC.2, modified from CCS driver
 
 
 INT8U    BeepCtr=0;
 
 /***********************************************************************************************
 *****************************     Function Prototypes               ****************************
 ************************************************************************************************/
 void DisplayManager(void);
 void BeepManager(void);
 
 /***********************************************************************************************
 ********************              Interrupt handlers *******************************************
 ************************************************************************************************/
 
 #int_rda
 void rda_isr(void)         //Receive command from remote console
 {
 serial_rx_isr();
 }
 
 #int_tbe
 void tbe_isr(void)         //Send Command (optional) to remote console for ack
 {
 serial_tx_isr();
 }
 
 #int_TIMER0
 void TIMER0_isr(void)
 {
 set_timer0(178);       //reset for ~2ms overflow with prescaler 128, 20MHz clock
 DispMuxHandler();
 }
 
 #int_TIMER1
 void TIMER1_isr(void)
 {
 DisplayManager();
 }
 
 /***********************************************************************************************
 ****************************************     MAIN     *******************************************
 ************************************************************************************************/
 
 void main(void)
 {
 output_low(PIN_B7);                     //disable power amplifier
 
 set_adc_channel(NO_ANALOGS);            //Since PortA & PortE has been used for digit select
 enable_interrupts(int_rda);               //enable USART RX
 DispInit();                           //Initialize 7-seg LED
 setup_counters(RTCC_INTERNAL, RTCC_DIV_128);//Adjust timer0 for multiplexing the display
 enable_interrupts(INT_TIMER0);            //Enable tmr0 interrupt
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);      //setup timer1 for character receive and display
 enable_interrupts(INT_TIMER1);
 enable_interrupts(global);
 
 for(;;) {
 BeepManager();                     //output DING DONG via TDA8944 ampifier onboard
 }
 }
 
 /*********************************************************************************************
 **************************************** Sub-routine *****************************************
 *********************************************************************************************/
 void DisplayManager(void)
 {
 INT8U  c;
 INT8U s[DISP_N_SS];      //Data received for display, DISP_N_SS=3 for PIC16-LEDSTK1 demo
 INT8U crx;
 INT8U DataBuf[6];      //data buffer for serial_rx_isr()
 
 if (EndOfMsg_Flg==TRUE)         //Some character in RX_Buffer
 {
 crx = 0;
 c = bgetc();
 while (c!= EndOfMsg){
 DataBuf[crx++] = c;
 c = bgetc();
 }
 EndOfMsg_Flg = FALSE;
 
 s[0]=DataBuf[0];s[1]=DataBuf[1];s[2]=DataBuf[2];
 DispStr(0,s);      //output to LED display board
 BeepCtr++;         //output an alert tone "DING DONG"
 bputc('*');         //Acknowledge the PC for a successful message
 }
 }//DisplayManager()
 
 
 void BeepManager(void)
 {
 if (BeepCtr>0){                     //BeepCtr increment on every valid call
 BeepCtr--;                     //BeepCtr++ in DisplayManager()
 output_high(PIN_B7);            //ON amplifier
 delay_us(500);                  //For stablize the amplifier
 generate_tone(585, 600);         //DING
 generate_tone(465, 900);         //DONG
 output_low(PIN_B7);               //OFF amplifier
 }
 }//BeepManager()
 
 | 
 
 
  	  | Code: |  	  | /*
 *********************************************************************************************************
 *
 *                                     Multiplexed LED Display Driver
 *                   Reference: Jean J. Labrosse, Embedded Systems Building Blocks
 *
 * Filename   : LED.h
 * Programmer : John Leung (www.TechToys.com.hk)
 * Remarks    : Modified for PIC16-LEDSTK1
 * Date       : First version 1.0 on 19th Nov 2004
 * Language    : CCS C complier for PIC mid-range MCU, PCM version 3.170, under MPLAB IDE 7.01
 * Hardware   : PCB 11OCT2004.001, MCU is Microchip's PIC16F877a
 * History    : Modified for PIC16-LEDSTK1 dated 12 Jan 2006
 *********************************************************************************************************
 *                                              DESCRIPTION
 *
 * This module provides an interface to a multiplexed "7-segments x N digits" LED matrix.
 *
 * To use this driver:
 *
 *     1) To use this module, the following parameters under define (LED.H):
 *
 *        DISP_N_DIG          The total number of segments to display, inc. dp status
 *        DISP_N_SS           The total number of seven-segment digits, e.g "0" "1" "2" is 3-digit
 *        DISP_PORT1_DIG      The address of the DIGITS   output port
 *        DISP_PORT_SEG       The address of the SEGMENTS output port
 *       first_dig_msk       The first digit mask for selecting the most significant digit
 *
 *     2) Allocate a hardware timer which will interrupt the CPU at a rate of at least:
 *
 *        DISP_N_DIG * 60  (Hz)
 *
 *********************************************************************************************************
 */
 
 /*
 *********************************************************************************************************
 *                                               CONSTANTS
 *********************************************************************************************************
 */
 //Assume a PIC 16F877a MCU
 //Using PORTA & PORTE for dig select, make sure it is set as digital
 #byte  DISP_PORT1_DIG =  0x05  /* Port address of DIGITS output for the 1st and 2nd group (PORTA)   */
 #byte  DISP_PORT2_DIG =  0x09  /* Port address of DIGITS output for the 3rd group (PORTE)           */
 #byte  DISP_PORT_SEG  =  0x08  /* Port address of SEGMENTS output (PORTD)                      */
 
 #define set_tris_seg(x)    set_tris_d(x)      /*Set segment port                              */
 #define set_tris1_dig(x) set_tris_a(x)      /*Set digit select port                           */
 #define set_tris2_dig(x) set_tris_e(x)      /*Set digit select port                           */
 
 #define  DISP_N_DIG          8         /* Total number of segments (including dp indicators)       */
 #define  DISP_N_SS           3         /* Total number of seven-segment digits (PORTA) of F877      */
 
 #define    first_dig_msk      0b000000100   /* First seven-segment digit mask                     */
 //remarks: There is no typo error on first_dig_msk. It is a 9-bits constant because the hardware
 //allows extension to 9-digits multiplexing. Actually, if we are using PORT RB as well,
 //we can extend to a maximum of 15 digits!
 
 /*
 *********************************************************************************************************
 *                   User define if hardware is Common Anode or Cathode
 *    The application should define if the hardware is a COMMON ANODE or CATHODE
 *********************************************************************************************************
 */
 
 #define ALL_OFF 0x00
 #define ALL_ON ~ALL_OFF
 
 
 /*
 *********************************************************************************************************
 *                                          FUNCTION PROTOTYPES
 *********************************************************************************************************
 */
 
 void  DispClrScr(void);               //API to clear the display
 void  DispInit(void);               //API to initialize the display, call before using other functions
 void  DispMuxHandler(void);            //called by the hardware timer at a rate of at least DISP_N_DIG*60 (Hz)
 void  DispStr(INT8U dig, char *s);      //API to display an ASCII string
 void  DispStatClr(INT8U dig, INT8U seg);//API to turn off a single LED
 /***************************
 *   dig specifies the digit
 *   seg specfiies segment to set as follows
 *   0 sets segment dp (bit0)
 *   1 sets segment g (bit1)
 *   2 sets segment f (bit2)
 *   3 sets segment e (bit3)
 *   4 sets segment d (bit4)
 *   5 sets segment c (bit5)
 *   6 sets segment b (bit6)
 *   7 sets segment a (bit7)
 **************************/
 void  DispStatSet(INT8U dig, INT8U seg);   //API to turn on a single LED
 
 /*
 *********************************************************************************************************
 *                                          FUNCTION PROTOTYPES
 *                                           HARDWARE SPECIFIC
 *********************************************************************************************************
 */
 void  DispInitPort(void);         //called by DispInit() to initialize the output ports
 void  DispOutDig(INT16U msk);      //digit selector
 void  DispOutSeg(INT8U seg);      //output seven-segment patterns
 
 | 
 
 
  	  | Code: |  	  | /*
 *********************************************************************************************************
 *
 *                                     Multiplexed LED Display Driver
 *                   Reference: Jean J. Labrosse, Embedded Systems Building Blocks
 *
 * Filename   : LED.C
 * Programmer : John Leung (www.TechToys.com.hk)
 * Remarks    : Modified for PIC16-LEDSTK1
 * Date       : First version 1.0 on 19th Nov 2004
 * Language    : CCS C complier for PIC mid-range MCU, PCM version 3.170, under MPLAB IDE 7.01
 * Hardware   : PCB 11OCT2004.001, MCU is Microchip's PIC16F877a
 * History    : Modified for PIC16-LEDSTK1 dated 12 Jan 2006
 *********************************************************************************************************
 *                                              DESCRIPTION
 *
 * This module provides an interface to a multiplexed "7-segments x N digits" LED matrix.
 *
 * To use this driver:
 *
 *     1) To use this module, the following parameters under define (LED.H):
 *
 *        DISP_N_DIG          The total number of segments to display, inc. dp status
 *        DISP_N_SS           The total number of seven-segment digits (modules)
 *        DISP_PORT1_DIG      The address of the DIGITS   output port
 *        DISP_PORT_SEG       The address of the SEGMENTS output port
 *       first_dig_msk       The first digit mask for selecting the most significant digit
 *
 *     2) Allocate a hardware timer which will interrupt the CPU at a rate of at least:
 *
 *        DISP_N_DIG * 60  (Hz)
 *
 *********************************************************************************************************
 */
 
 /*
 *********************************************************************************************************
 *                                            LOCAL VARIABLES
 *********************************************************************************************************
 */
 
 //Remarks: The original Jean's code uses static for local variables; however, this is not valid
 //for CCS PICC complier as "static" has no effect under CCS C.
 
 static   INT16U DispDigMsk;            /* Bit mask used to point to next digit to display  */
 static   INT8U  DispSegTbl[DISP_N_SS]; /* Segment pattern table(buffer) for each digit to display, first entry the left most*/
 static   INT8U  DispSegTblIx;         /* Index into DispSegTbl[] for next digit to display */
 
 /*$PAGE*/
 /*
 *********************************************************************************************************
 *                             ASCII to SEVEN-SEGMENT conversion table
 *                                                             a
 *                                                           ------
 *                                                        f |      | b
 *                                                          |  g   |
 * Note: The segments are mapped as follows:                 ------
 *                                                        e |      | c
 *        a    b    c    d    e    f    g                   |  d   |
 *        --   --   --   --   --   --   --   --              ------
 *        D7   D6   D5   D4   D3   D2   D1   D0 (Using PORTD of 16F877a as the segments output port)
 *********************************************************************************************************
 */
 
 const INT8U DispASCIItoSegTbl[] = {// ASCII to SEVEN-SEGMENT conversion table
 0x00,       // ' '
 0x00,       // '!', No seven-segment conversion for exclamation point
 0x44,       // '"', Double quote
 0x00,       // '#', Pound sign
 0x00,       // '$', No seven-segment conversion for dollar sign
 0x00,       // '%', No seven-segment conversion for percent sign
 0x00,       // '&', No seven-segment conversion for ampersand
 0x40,       // ''', Single quote
 0x9C,       // '(', Same as '['
 0xF0,       // ')', Same as ']'
 0x00,       // '*', No seven-segment conversion for asterix
 0x00,       // '+', No seven-segment conversion for plus sign
 0x00,       // ',', No seven-segment conversion for comma
 0x02,       // '-', Minus sign
 0x00,       // '.', No seven-segment conversion for period
 0x00,       // '/', No seven-segment conversion for slash
 0xFC,       // '0'
 0x60,       // '1'
 0xDA,       // '2'
 0xF2,       // '3'
 0x66,       // '4'
 0xB6,       // '5'
 0xBE,       // '6'
 0xE0,       // '7'
 0xFE,       // '8'
 0xF6,       // '9'
 0x00,       // ':', No seven-segment conversion for colon
 0x00,       // ';', No seven-segment conversion for semi-colon
 0x00,       // '<', No seven-segment conversion for less-than sign
 0x12,       // '=', Equal sign
 0x00,       // '>', No seven-segment conversion for greater-than sign
 0xCA,       //'?', Question mark
 0x00,       // '@', No seven-segment conversion for commercial at-sign
 0xEE,       // 'A'
 0x3E,       // 'B', Actually displayed as 'b'
 0x9C,       // 'C'
 0x7A,       // 'D', Actually displayed as 'd'
 0x9E,       // 'E'
 0x8E,       // 'F'
 0xBC,       // 'G', Actually displayed as 'g'
 0x6E,       // 'H'
 0x60,       // 'I', Same as '1'
 0x78,       // 'J'
 0x00,       // 'K', No seven-segment conversion
 0x1C,       // 'L'
 0x00,       // 'M', No seven-segment conversion
 0x2A,       // 'N', Actually displayed as 'n'
 0xFC,       // 'O', Same as '0'
 0xCE,       // 'P'
 0x00,       // 'Q', No seven-segment conversion
 0x0A,       // 'R', Actually displayed as 'r'
 0xB6,       // 'S', Same as '5'
 0x1E,       // 'T', Actually displayed as 't'
 0x7C,       // 'U'
 0x00,       // 'V', No seven-segment conversion
 0x00,       // 'W', No seven-segment conversion
 0x00,       // 'X', No seven-segment conversion
 0x76,       // 'Y'
 0x00,       // 'Z', No seven-segment conversion
 0x00,       // '['
 0x00,       // '\', No seven-segment conversion
 0x00,       // ']'
 0x00,       // '^', No seven-segment conversion
 0x00,       // '_', Underscore
 0x00,       // '`', No seven-segment conversion for reverse quote
 0xFA,       // 'a'
 0x3E,       // 'b'
 0x1A,       // 'c'
 0x7A,       // 'd'
 0xDE,       // 'e'
 0x8E,       // 'f', Actually displayed as 'F'
 0xBC,       // 'g'
 0x2E,       // 'h'
 0x20,       // 'i'
 0x78,       // 'j', Actually displayed as 'J'
 0x00,       // 'k', No seven-segment conversion
 0x1C,       // 'l', Actually displayed as 'L'
 0x00,       // 'm', No seven-segment conversion
 0x2A,       // 'n'
 0x3A,       // 'o'
 0xCE,       // 'p', Actually displayed as 'P'
 0x00,       // 'q', No seven-segment conversion
 0x0A,       // 'r'
 0xB6,       // 's', Actually displayed as 'S'
 0x1E,       // 't'
 0x38,    // 'u'
 0x00,    // 'v', No seven-segment conversion
 0x00,    // 'w', No seven-segment conversion
 0x00,    // 'x', No seven-segment conversion
 0x76,    // 'y', Actually displayed as 'Y'
 0x00     // 'z', No seven-segment conversion
 };
 
 
 /*
 *********************************************************************************************************
 *                                          CLEAR THE DISPLAY
 *
 * Description: This function is called to clear the display.
 * Arguments  : none
 * Returns    : none
 *********************************************************************************************************
 */
 
 void  DispClrScr (void)
 {
 INT8U i;
 for (i = 0; i < DISP_N_SS; i++) {    /* Zero the buffer */
 DispSegTbl[i] = ALL_OFF;
 }
 }
 
 /*
 *********************************************************************************************************
 *                                      DISPLAY DRIVER INITIALIZATION
 *
 * Description : This function initializes the display driver.
 * Arguments   : None.
 * Returns     : None.
 *********************************************************************************************************
 */
 
 void  DispInit (void)
 {
 DispInitPort();                 // Initialize I/O ports used in display driver
 DispDigMsk   = first_dig_msk;   // digit mask starts from RAx
 DispSegTblIx = 0;
 DispClrScr();                   // Clear the Display
 }
 
 /*
 *********************************************************************************************************
 *                                        DISPLAY NEXT SEVEN-SEGMENT DIGIT
 * Description: Called by an interrupt handler to output the segments and select the next digit
 *              to be multiplexed.
 * Arguments  : none
 * Returns    : none
 * Notes      :
 *********************************************************************************************************
 */
 
 void  DispMuxHandler (void)
 {
 /* Insert code to CLEAR INTERRUPT SOURCE here         */
 DispOutSeg(ALL_OFF);                         /* Turn OFF segments while changing digits            */
 DispOutDig(DispDigMsk);                      /* Select next digit to display                       */
 DispOutSeg(DispSegTbl[DispSegTblIx]);        /* Output digit's seven-segment pattern               */
 if (DispSegTblIx == (DISP_N_SS - 1)) {       /* Adjust index to next seven-segment pattern         */
 DispSegTblIx =    0;                     /* Index into first segments pattern                  */
 DispDigMsk   = first_dig_msk;            /* Select the most significant digit  */
 } else {
 DispSegTblIx++;
 DispDigMsk >>= 1;                        /* Select next digit                                  */
 }
 }
 
 /*
 *********************************************************************************************************
 *                                         CLEAR STATUS SEGMENT
 *
 * Description: This function is called to turn OFF a single segment on the display.
 * Arguments  : dig   is the position of the digit where the segment appears (0..DISP_N_DIG-1)
 *              seg   is the segment bit to turn OFF (0..7)
 * Returns    : none
 *********************************************************************************************************
 */
 
 void  DispStatClr (INT8U dig, INT8U seg)
 {
 DispSegTbl[dig] &= ~(1 << seg);
 }
 
 
 /*
 *********************************************************************************************************
 *                                           SET STATUS SEGMENT
 *
 * Description: This function is called to turn ON a single segment on the display.
 * Arguments  : dig   is the position of the digit where the segment appears (0..DISP_N_DIG-1)
 *              seg   is the segment bit to turn ON (0..7)
 * Returns    : none
 *********************************************************************************************************
 */
 
 void  DispStatSet (INT8U dig, INT8U seg)
 {
 DispSegTbl[dig] |= 1 <<seg;
 }
 
 /*$PAGE*/
 /*
 *********************************************************************************************************
 *                            DISPLAY ASCII STRING ON SEVEN-SEGMENT DISPLAY
 *
 * Description: This function is called to display an ASCII string on the seven-segment display.
 * Arguments  : dig   is the position of the first digit where the string will appear:
 *                        0 for the first  seven-segment digit.
 *                        1 for the second seven-segment digit.
 *                        .  .   .     .     .      .      .
 *                        .  .   .     .     .      .      .
 *                        DISP_N_SS - 1 is the last seven-segment digit.
 *              s     is the ASCII string to display
 * Returns    : none
 * Notes      : - Not all ASCII characters can be displayed on a seven-segment display.  Consult the
 *                ASCII to seven-segment conversion table DispASCIItoSegTbl[].
 *********************************************************************************************************
 */
 
 void  DispStr (INT8U dig, unsigned char *s)
 {
 while (*s && dig < DISP_N_SS) {
 DispSegTbl[dig++] = DispASCIItoSegTbl[*s++ - 0x20];
 }
 }
 
 /*
 *********************************************************************************************************
 *                                        I/O PORTS INITIALIZATION
 *
 * Description: Called by DispInit() to initialize the output ports used in the LED multiplexing.
 * Arguments  : none
 * Returns    : none
 * Notes      :
 *********************************************************************************************************
 */
 
 void  DispInitPort (void)
 {
 DISP_PORT_SEG=ALL_OFF;         //Turn off segments
 DISP_PORT1_DIG=0x00;         //Turn off the 1st and 2nd groups (first group uses RA0,A1,A2, 2nd group
 //      uses RA3,A4,A5)
 DISP_PORT2_DIG=0x00;         //Turn off the 3rd group (3rd group uses RE0,E1,E2)
 set_tris_seg(0x00);            //Set segment port an output
 set_tris1_dig(0x00);         //Set digit port an output
 set_tris2_dig(0x00);
 }
 
 
 /*
 *********************************************************************************************************
 *                                        DIGIT output
 *
 * Description: This function outputs the digit selector.
 * Arguments  : msk    is the mask used to select the current digit.
 * Returns    : none
 *********************************************************************************************************
 */
 
 void  DispOutDig (INT16U msk)
 {
 DISP_PORT1_DIG=msk;   //digit selector here
 DISP_PORT2_DIG=msk>>6;
 }
 
 
 /*
 *********************************************************************************************************
 *                                        SEGMENTS output
 *
 * Description: This function outputs seven-segment patterns.
 * Arguments  : seg    is the seven-segment pattern to output
 * Returns    : none
 *********************************************************************************************************
 */
 
 void  DispOutSeg (INT8U seg)
 {
 DISP_PORT_SEG=seg;   //output seven-segment pattern
 }
 
 
 | 
 
 
  	  | Code: |  	  | /*
 *********************************************************************************************************
 *
 *                    Interrupt Driven Transmit (Tx) and Receive (Rx) modules
 *
 *      Reference: Embedded C Programming and the Microchip PIC by Barnett, Cox, & O'Cull
 *
 * Filename   : USART.h
 * Programmer : John Leung (www.TechToys.com.hk)
 * Date       : 19th Nov 2004
 * Hardware   : PCB 11OCT2004.001
 *********************************************************************************************************
 */
 
 /* Use dialect of CCS PIC complier, assume a PIC with USART Port (16F877a etc)*/
 #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,stream=RS232,bits=8)
 
 #define  RX_BUFFER_SIZE        32      // UART Receive buffer
 #define  TX_BUFFER_SIZE        5      // UART Transmit buffer
 #define    EndOfMsg            0x0d      // <cr> as the end of command marker
 
 
 /*
 *********************************************************************************************************
 *                                          FUNCTION PROTOTYPES
 *********************************************************************************************************
 */
 
 void    serial_rx_isr(void);    //ISR handler for Rx
 INT8U    bgetc(void);         //Get a character from the UART Receiver buffer
 void    serial_tx_isr(void);    //USART Transmitter interrupt service routine
 void    bputc(INT8U c);       //Write a character to the serial transmit buffer
 void    CommRxFlush(void);       //flush any input characters still in the UART Receiver buffer
 
 | 
 
 
  	  | Code: |  	  | /*
 *********************************************************************************************************
 *
 *                    Interrupt Driven Transmit (Tx) and Receive (Rx) modules
 *
 *      Reference: Embedded C Programming and the Microchip PIC by Barnett, Cox, & O'Cull
 *
 * Filename   : USART.c
 * Programmer : John Leung (www.TechToys.com.hk)
 * Date       : 15th June 2004
 *********************************************************************************************************
 */
 
 
 // UART Receive buffer
 INT8U Rx_Buffer[RX_BUFFER_SIZE+1];       // character array (buffer)
 INT8U RX_Wr_Index = 0;                // index of next char to be put into the buffer
 INT8U RX_Rd_Index = 0;                // index of next char to be fetched from the buffer
 INT8U RX_Counter = 0;                 // total count of characters in the buffer
 BOOLEAN  RX_Buffer_Overflow = FALSE;      // this flag is set on UART Receiver buffer overflow
 
 BOOLEAN EndOfMsg_Flg = FALSE;         // End-of-Message flag to indicate EndOfMsg has been received
 
 
 // UART Transmit buffer
 INT8U TX_Buffer [TX_BUFFER_SIZE+1];    // character array (buffer)
 INT8U TX_Rd_Index = 0;                // index of next char to be put into the buffer
 INT8U TX_Wr_Index = 0;                // index of next char to be fetched from the buffer
 INT8U TX_Counter = 0;                // total count of characters in the buffer
 
 // USART Receiver interrupt service routine, slightly modified according to Jean J. Labrosse's routine
 void serial_rx_isr()
 {
 if(++RX_Counter <= RX_BUFFER_SIZE)       //if Rx Ring buffer not full, and keep character count
 {
 Rx_Buffer[RX_Wr_Index] = getc();     // put received char in buffer
 
 if(Rx_Buffer[RX_Wr_Index] == EndOfMsg) //set EndOfMsg_Flg for command process
 EndOfMsg_Flg=TRUE;
 
 if(++RX_Wr_Index > RX_BUFFER_SIZE)    // wrap the pointer
 RX_Wr_Index = 0;
 } else {
 RX_Counter = RX_BUFFER_SIZE;       // if too many chars came
 RX_Buffer_Overflow = TRUE;         // in before they could be used, that could cause an error
 }
 }
 
 // Get a single character from the UART Receiver buffer
 INT8U bgetc(void)
 {
 INT8U c;
 
 while(RX_Counter == 0)      // wait for a character...
 ;
 
 c = Rx_Buffer[RX_Rd_Index];    // get one (first) from the buffer..
 if(++RX_Rd_Index > RX_BUFFER_SIZE) // wrap the pointer
 RX_Rd_Index = 0;
 
 if(RX_Counter)
 RX_Counter--;        // keep a count (buffer size)
 
 return c;
 }
 
 // USART Transmitter interrupt service routine
 void serial_tx_isr()
 {
 //if there are characters to be transmitted....
 if(TX_Counter != 0)
 {
 putc(TX_Buffer[TX_Rd_Index]);
 // send char out port
 
 // test and wrap the pointer
 if(++TX_Rd_Index > TX_BUFFER_SIZE)
 TX_Rd_Index = 0;
 
 TX_Counter--;   // keep track of the counter
 if (TX_Counter == 0)
 disable_interrupts(int_tbe);
 }
 }
 
 // write a character to the serial transmit buffer
 void bputc(INT8U c)
 {
 INT8U restart = 0;
 
 while(TX_Counter > (TX_BUFFER_SIZE-1))
 ;       // WAIT!! Buffer is getting full!!
 
 if(TX_Counter == 0) // if buffer empty, setup for interrupt
 restart = 1;
 
 TX_Buffer[TX_Wr_Index++]=c; // jam the char in the buffer..
 
 if(TX_Wr_Index > TX_BUFFER_SIZE)     // wrap the pointer
 TX_Wr_Index = 0;
 // keep track of buffered chars
 TX_Counter++;
 
 // do we have to "Prime the pump"?
 if(restart == 1)
 enable_interrupts(int_tbe);
 }
 
 //This function flushes any input characters still in the RX UART buffer
 //This must be called whenever RX_Buffer_Overflow = TRUE
 void CommRxFlush(void)
 {
 disable_interrupts(int_rda);   //disable USART Rx interrupt
 //reset all Rx indexes and counters
 RX_Wr_Index = 0;
 RX_Rd_Index = 0;
 RX_Counter = 0;
 RX_Buffer_Overflow = FALSE;
 #ifdef EoM
 EndOfMsg_Flg = FALSE;
 #endif
 enable_interrupts(int_rda);
 }
 
 | 
 
 
  	  | Code: |  	  | /*
 *********************************************************************************************************
 
 *
 *                                    CCS PICC Complier Specific Code
 *
 *
 * File : OS_CPU.H
 * By   : John Leung for CCS PICC complier for low & mid - range CPUs
 *********************************************************************************************************
 */
 
 
 /*
 *********************************************************************************************************
 *                                              DATA TYPES
 *                               (Compiler Specific, CCS PICC in this case)
 *********************************************************************************************************
 */
 
 typedef unsigned char        INT8U;                    /* Unsigned  8 bit quantity */
 typedef signed   char        INT8S;                    /* Signed    8 bit quantity */
 typedef unsigned long int   INT16U;                   /* Unsigned 16 bit quantity */
 typedef long int         INT16S;                   /* Signed   16 bit quantity */
 typedef unsigned int32     INT32U;                   /* Unsigned 32 bit quantity */
 typedef signed int32        INT32S;                   /* Signed   32 bit quantity */
 typedef float                FP32;                     /* Single precision floating point */
 
 
 | 
 
 
  	  | Code: |  	  | ////////////////// Driver to generate musical tones /////////////////////
 ////                                                                 ////
 ////  generate_tone(frequency, duration)     Generates wave at set   ////
 ////                                         frequency (Hz) for set  ////
 ////                                         duration (ms)           ////
 ////                                                                 ////
 /////////////////////////////////////////////////////////////////////////
 ////        (C) Copyright 1996,2003 Custom Computer Services         ////
 //// This source code may only be used by licensed users of the CCS  ////
 //// C compiler.  This source code may only be distributed to other  ////
 //// licensed users of the CCS C compiler.  No other use,            ////
 //// reproduction or distribution is permitted without written       ////
 //// permission.  Derivative programs created using this software    ////
 //// in object code form are not restricted in any way.              ////
 /////////////////////////////////////////////////////////////////////////
 
 
 #ifndef  MUSIC_NOTES
 #define  MUSIC_NOTES
 /*
 //            NOTE                 FREQUENCY
 //                     Octave0  Octave1  Octave2  Octave3
 const long C_NOTE[4]  ={ 262,     523,    1047,    2093};
 const long Db_NOTE[4] ={ 277,     554,    1109,    2217};
 const long D_NOTE[4]  ={ 294,     587,    1175,    2349};
 const long Eb_NOTE[4] ={ 311,     622,    1245,    2489};
 const long E_NOTE[4]  ={ 330,     659,    1329,    2637};
 const long F_NOTE[4]  ={ 349,     698,    1397,    2794};
 const long Gb_NOTE[4] ={ 370,     740,    1480,    2960};
 const long G_NOTE[4]  ={ 392,     784,    1568,    3136};
 const long Ab_NOTE[4] ={ 415,     831,    1661,    3322};
 const long A_NOTE[4]  ={ 440,     880,    1760,    3520};
 const long Bb_NOTE[4] ={ 466,     923,    1865,    3729};
 const long B_NOTE[4]  ={ 494,     988,    1976,    3951};
 #endif
 */
 #define TONE_PIN  PIN_C2
 
 
 void do_delay(int ms_delay, int num_ms, int us_delay, int num_us)  {
 int i;
 
 for(i=0;i<num_ms;i++)
 delay_ms(250);
 delay_ms(ms_delay);
 for(i=0;i<num_us;i++)
 delay_us(250);
 delay_us(us_delay);
 }
 
 
 void generate_tone(long frequency, long duration)
 {
 int32 total_delay_time;                      // in microseconds
 long total_ms_delay_time, total_us_delay_time;
 int num_us_delays, num_ms_delays, ms_delay_time, us_delay_time;
 long num_periods;
 
 total_delay_time = (1000000/frequency)/2-10; // calculate total delay time (10 for error)
 
 total_ms_delay_time = total_delay_time/1000; // total delay time of ms
 num_ms_delays = total_ms_delay_time/250;     // number of 250ms delays needed
 ms_delay_time = total_ms_delay_time%250;     // left over ms delay time needed
 
 total_us_delay_time = total_delay_time%1000; // total delay time of us (ms already acounted for)
 num_us_delays = total_us_delay_time/250;     // number of 250us delays needed
 us_delay_time = total_us_delay_time%250;     // left over us delay time needed
 
 num_periods = ((int32)duration*1000)/(1000000/frequency);
 
 while((num_periods--) != 0)
 {
 do_delay(ms_delay_time, num_ms_delays, us_delay_time, num_us_delays);
 output_high(TONE_PIN);
 do_delay(ms_delay_time, num_ms_delays, us_delay_time, num_us_delays);
 output_low(TONE_PIN);
 }
 
 return;
 }
 
 | 
 |  |