CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

4" 7-segment LED display in 3-digit with 2x7W amplifier

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
JohnLeung



Joined: 18 May 2004
Posts: 15

View user's profile Send private message

4" 7-segment LED display in 3-digit with 2x7W amplifier
PostPosted: Thu Jan 12, 2006 4:42 am     Reply with quote

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;
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group