Jump to content

ra68gi

EstablishedMember
  • Content Count

    229
  • Joined

  • Last visited

Posts posted by ra68gi


  1. Hi guys,

     

    Can any one tell me the advantages of using hardware uart over software uart?

     

    Raghunathan.

     

    Less software required, you are not tieing up the processor to some bit bashing routine.

     

    Make cyclic buffers for your RX and TX data and service in interrupt time.

     

    Hi Picxie,

     

    I have not used the hardware uart so far. I suppose Huart will take less code space compared to Suart. Picxie, can you explain the second advantage regarding servicing in interrut time with any example.

     

    Thanks,

     

    Raghunathan.


  2. Raghunathan,

     

    I haven't posted the ISR for this routine, where I'm resetting TMR1

    The maximum frequency I need to measure would be 1.5kHz, that is enough time for reading the  registers CCPR2L and CCPR2H. I would be using the TMR1 interrupt since I don't inted it to overflow.

     

     

    Emte, thanks,

     

    I'm noticing that may questions are always coming back to reading a writing into two registers simultaneuosly.

     

    If I declare and integer and map it to CCPR2L, wouldn't it take the space of two bits and also include CCPR2H ?

    Yes, for measuring frequency in the range you have mentioned its fine, but if your frequency is less then 15 hz then i think my technique will be better. Infact you can get very good accuracy upto 300hz with my method. Trying to use the highest possible clock frequency will result in best accuracy. Make sure that the time period of your signal is larger then the time taken to attend to the ISR.If a second capture pulse occurs before you read the value from ccpr, the old captured value is over written with the new captured value, resulting in wrong frequency value.

     

    Regards

    Raghunathan.


  3. I wish to calculate frequency using the CCP2 module. I need to pass the two registers CCPR2L and CCPR2H into one variable.

    If I define that variable as integer will that work:

     

    Frequency = getFreq(ccpr2);

     

    where

    int getFreq(int reg)
    {
          //       calculate frequency according to value captured in CCPR2 register
          //    period between captures = 4/Fosc  x CCPR2 (=FreqCapture_Reg)
      
      if reg < 0xFF;
         return Fosc/4/reg; // frequency = 1/period
      else 
         return 0;
    }

     

    OrmatEli,

    Why don't you start a new thread on this topic? Don't you think this thread has got a bit too old & long?

    In the capture mode the 16 bit value of the timer1 gets latched to the ccpr2h & ccpr2l registers every time a ccp pin senses a pulse. When do you intend to start the timer1? in the first capture interrupt or do you just wish to keep it running right from the beginning? How will you know if the timer1 has over flowed or not ? are you setting the timer1 interrupt also?

    I had written code for a similar project. It lacks explaination. but if you follow it closely you will understand it. I am yet to test it on a bread board.

    See how i use the tmr1 register values directly instead of the ccp register values. I have done this because it takes some time " T " to save the important registers before it enters to execute the ISR code. Since this time interval "T" is more or less equal every time it enters the ISR, so I decided to take the timer1 value to avoid any error. See how in the first ccp interrupt the tmr1 is reset & in the second ccp interrupt, the tmr1 is switched off and its registers read. I have also unmasked the tmr1 interrupt & i count the tmr1 ticks which i multiply with 65536. The total value is then found out by adding the above value with the tmr1 counter(tmr1l,tmr1h), from which the frequency is determined.

    see this thread..engine RPM using PIC16F72

     

    See if this code is useful.

    Regards

    Raghunathan.


  4. First a brief description since i've yet to decide if this is a bug or not.

     

    This crude block of code sets up and starts Timer2:

    void badTimer(void)
    {
       tmr2 = 25;
       t2con = 0xFF;
       pr2 = 0xFF;
       intcon.7 = 1;
       intcon.6 = 1;
       pir1.1 = 0;
       pie1.1 = 1;    
    }

     

    Now the question is "How can this be?"

    If in main or in a library, the code should behave the same but

    for some reason it does not. Any insights would be appreciated,

    or even someone else to test the behaviour. i have reproduced

    it 5 times now just trying to figure out why.

     

    I am sorry. I got a bit confused with the ccp module. Yes as a timer the settings for the tmr2 module looks fine. But try t2con = 0B01111111; & disable the ccp module.

     

    Regards

    Raghunathan.


  5. First a brief description since i've yet to decide if this is a bug or not.

     

    This crude block of code sets up and starts Timer2:

    void badTimer(void)
    {
       tmr2 = 25;
       t2con = 0xFF;
       pr2 = 0xFF;
       intcon.7 = 1;
       intcon.6 = 1;
       pir1.1 = 0;
       pie1.1 = 1;    
    }

     

    That should be simple enough, but here is the issue i've run into:

     

    The function works fine if placed in the main project .c file(or in

    main() for that matter), but if placed directly into a header

    (for development reasons), or in the proper hreader+library.c

    files, Timer2 will not run.

     

    The simulator is of no help in this as it shows correct/expected

    operation of setup variables. The code disassembly is identical

    for both and as follows:

     
    void badTimer(void)
    
    {
    tmr2 = 25;
    0020  0E19          MOVLW 0x19
    0022  6ECC          MOVWF gbl_tmr2
    
    t2con = 0xFF;
    0024  68CA          SETF gbl_t2con
    
    pr2 = 0xFF;
    0026  68CB          SETF gbl_pr2
    
    intcon.7 = 1;
    0028  8EF2          BSF gbl_intcon,7
    
    intcon.6 = 1;
    002A  8CF2          BSF gbl_intcon,6
    
    pir1.1 = 0;
    002C  929E          BCF gbl_pir1,1
    
    pie1.1 = 1;    
    002E  829D          BSF gbl_pie1,1
    
    }
    0030  0012          RETURN

     

    Now the question is "How can this be?"

    If in main or in a library, the code should behave the same but

    for some reason it does not. Any insights would be appreciated,

    or even someone else to test the behaviour. i have reproduced

    it 5 times now just trying to figure out why.

    Hello emte,

     

    We can't test it until you give us your code.

    I can see you have used the period register(pr2) & so i assume you are using the tmr2 in the PWM mode. Have you configured which mode you are using in the ccpcon1 register in your main()? I am talking with respect to 16F pics but that should hold good even for pic18. Also bit 7 of t2con is unimplemented & the data sheet suggests that you write it as 0 instead of 1. make it.. t2con = 0b01111111; I assume you are using 1:16 post scaler & prescaler.

     

    Regards

    Raghunathan.


  6. hello :

     

    my graduation project is called "voice speech synthesizer" i'll read temprature from LM35 sensor then send it to 16F877 pic then it will convert the voltage into ASCII and send it to the EMIC module to say the temprature

    but am lost and i cant focus how to start ,the code the interfacing ...

    can anyone guide me how to write c code ?..

    i tested the pic and send the result through MAX232 and read it from PC..

    then wut should i do????!!!! i dont have much time really

     

    60% of your project is already here...programming pic micro in BoostC for beginners.

    Atleast for the rest of the project you need to make some effort. Use my code as a template & make adjustments by adding serial routines. You can use the same wiring circuit details i have mentioned. I did it on a bread board. You too can do the same. Good luck!

     

    Regards

    Raghunathan.


  7. Hi everyone,

     

    Me and my team are having problems sending data from a pic16F690  to a lprs radio using a serial interface. It looks like it sends data fine but just not the right ones. For example, when we send a 'h', the radio returns the french C. We used the provided sample and here is our code after we changed a couple things:

     

    //********************************************************************************

    ************

    #include <system.h>

     

    #ifdef _PIC16F690

    #pragma CLOCK_FREQ 8000000

    #endif

     

     

    void putc(char c)  // Put char function to transmit one char

    {

    txreg = c;    // Put function parameter txc into the txreg

    while( !txsta.TRMT ){} // Wait until character transmission finished

    }

     

    char getc(void)    // Getc function loop until a character is pressed

    {

    while( !pir1.RCIF ); // Loop until Rxflag = 1

    return rcreg;  // Return rcreg

    }

     

    void puts(char *source)  // put string function, return the refered string

    {

    do

    {

      char c = *source;

      if( c == '>' ) // end of string

      break;

     

      putc( c ); // Send the string refered by pointer 

      source++;

    }

    while( 1 );

    }

     

    void serial_init()

    {

    trisb = 00100000b;  //Set RB7/TX as an output and RB5/RX as an input in decimal

    baudctl = 00000000b;

    spbrg = 51;  //9600 baud @ 8MHz

    txsta=00100100b;  //full duplex asynchronous

        rcsta=10010000b;  //full duplex asynchronous

     

    }

     

    void main()

    serial_init();

     

    while( 1 )

    {

            putc('h');

    delay_s( 1 );

    }

    }

     

    ---------------------------------------------------------------------------------------

     

    If anyone knows how to fix this problem please help us, this project is due soon. Thank you.

     

    Did you first check it up on a hyper-terminal?

     

    Regards

    Raghunathan


  8. extract from the BoostC compiler user manual:

    unsigned char sprintf32( char* buffer, const char *format, unsigned long val )

    Outputs a numerical value to a string in the specified format. The buffer must be

    long enough to hold the result. Only one numerical value can be output at a time.

    Declared in stdio.h. This function operates as sprintf, but it handles a 32bit value. It also supports the “%l” radix specifier, which is handled the same as “%d”.

     

        long x = 123456789;
       char buf[ 10 ]; // must be long enough to hold the max number of digits we will get plus null terminator
       sprintf( buf, "%d", x );
       lprintf( buf );

     

    Regards

    Dave

     

    Dave, i have version 6.6. In the above code example you have not use sprintf32 function, which is used for long. I think thats available only in version 6.7.

     

    Regards

    Raghunathan.


  9. Or use sprintf32 to convert number to a string and then display using lprintf.

     

    Regards

    Dave

     

    Dave i got lprintf("%u",x); to work upto 65535. but i was not successful in converting it into string using sprintf32 & displaying it using lprintf.

     

    I first tried lprintf (sprintf32(x)); & it didn't work.

    Can you please show me how its done.

     

    extract from the BoostC compiler user manual:

    unsigned char sprintf32( char* buffer, const char *format, unsigned long val )

    Outputs a numerical value to a string in the specified format. The buffer must be

    long enough to hold the result. Only one numerical value can be output at a time.

    Declared in stdio.h. This function operates as sprintf, but it handles a 32bit value. It also supports the “%l” radix specifier, which is handled the same as “%d”.

     

        long x = 123456789;
       char buf[ 10 ]; // must be long enough to hold the max number of digits we will get plus null terminator
       sprintf( buf, "%d", x );
       lprintf( buf );

     

    Regards

    Dave

     

    Thanks very much Dave. The mistake is mine because i was searching an earlier version of the user manual. I will immediately take print of the current version.

     

    Regards

    Raghunathan.


  10. Or use sprintf32 to convert number to a string and then display using lprintf.

     

    Regards

    Dave

     

    Dave i got lprintf("%u",x); to work upto 65535. but i was not successful in converting it into string using sprintf32 & displaying it using lprintf.

     

    I first tried lprintf (sprintf32(x)); & it didn't work.

    Can you please show me how its done.

     

    Regards

    Raghunathan.


  11. How do i display values larger than 32767 on LCD . beyond this value the lcd  displays negative numbers & it starts to wrap(+32767 to-32768). I am using the boostC lcd command lprintf("%d",x); I had declared x as unsigned int. I would like it to display upto 65535 or probably a long variable.

     

    Use:

    lprintf("%u",x);

     

    Or use sprintf32 to convert number to a string and then display using lprintf.

     

    Regards

    Dave

     

    Thanks Dave,

    I searched the SB user's manual but didn't find sprintf32.

     

    is it written this way...

     

    lprintf (sprintf32(x)); ?

     

    Raghunathan.


  12. Do you know, how to implement a PID with C2C (or any exemples)?

     

    Here is a example for a flow control regulator.

     

    Regards /Jörgen

     

    void DFlowPID(void) {
    
        float    e;            // The controller error
        float    up;            // Output signals
        float    awc;        // Anti windup compensation
        float    IState;        // I state (integrated error)
        float    DState;        // D state (last error)
        short    Ticks;        // Ticks
        short    ScanRate;    // Scan rate
        
        ScanRate = XXX;
        Ticks = 0;
        
        // Check if time to run
        if ((++Ticks % ScanRate) != 0)
            return;
        
        // Get current control parameters
        DFlowCnt.Kp = Conf.DFlowCntKp;
        DFlowCnt.Ti = Conf.DFlowCntTi;
        DFlowCnt.Td = Conf.DFlowCntTd;
        
        
        // Get Time
        DFlowCnt.Time = CLOCK;
        
        // Read PV
        DFlowCnt.PV = AIn(AIX);
        
        // Calculate the error
        e = DFlowCnt.SP - DFlowCnt.PV;
        
        e *= DFlowCnt.Kp;                                                        // P-part
        up    = e;
        up += (e-DState)*DFlowCnt.Td/Conf.DFlowCnth;        // D-part
        up += IState;                                                                // I-part
        
        // Limit output from controller
        DFlowCnt.Output = up;
        if (DFlowCnt.Output > Conf.DFlowCntUMax)
            DFlowCnt.Output = Conf.DFlowCntUMax;
        else
            if (DFlowCnt.Output < Conf.DFlowCntUMin)
                DFlowCnt.Output = Conf.DFlowCntUMin;
        
        if (!DFlowCnt.Active)
            DFlowCnt.Output = ReadAOut(AOX);
        
        awc = up - DFlowCnt.Output;
        
        // Update states
        DState = e;
        if (DFlowCnt.Ti > 0.01)
            IState = e * Conf.DFlowCnth / DFlowCnt.Ti + IState - awc;
        else
            IState = 0.0;
        
        if (DFlowCnt.Active)
            AOut(AOX, DFlowCnt.Output);
        
        return;
    }

     

    Hi sdujolo,

    I am very interested in you project. Can you explain the whole project in detail, like what flow meter you are using & what are its outputs & other detail about the flow meter, the proportional valve you control etc ? It will also be nice if you can elobrate on how the code functions. I know thats going to take a lot of time. But i would really appreciate if you can explain like you would to a beginner.

     

    Regards

    Raghunathan.


  13. I'm bouncing this old and untreated thread since I also need to implement a PID with a PIC microcontroller.

    Especially: how do I deal with negative values which are bound to appear during the computations.

     

    Are you talking about proportional, integral , derivative used in feed back control systems? Rigt now i am working on a project with feed back control using PIC. If you are interested i will post it & we can discuss.

     

    Regards,

    Raghunathan.


  14. I have seen that BoostC permits one interrupt handler called "interrupt"; I have not yet explored that land but I think that I have to manage each single interrupt event inside that routine, is that correct? I mean, if I would like to manage T0IF, T1IF, RB0/INT interrupt etc, I have to make a if-else-else if- structure to manage all them, correct?

    And what about interrupt for PIC18? They have low and high priority interrupt; how can I distinguish one from the other?

     

    Thank you.

     

    Paolo.

     

    If you are looking for an example of multiple interrupts, i can give you an example i am right now working on. Its an frequency/RPM meter. It measures the time interval between two pulses of a optical or proximity sensor. There are two interrupt generating source, they are timer1 over flow flag & ccp capture flag. An LCD is use to display the RPM. I am using PIC16F72.

    I have tested it on the SB simulator & it works fine.

    code..

    #include <system.h>
    #include "lcd_driver.h"
    
    // Set clock frequency to 4MHz.
    
    #pragma CLOCK_FREQ 4000000
    
    //set configuration fuse.
    #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
    
    
    #define LCD_ARGS 	2,	/* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
    	0, 				/* Use busy signal: 1 = use busy, 0 = use time delays */\
    	PORTC, TRISC, 	/* Data port and data port tris register */ \
    	PORTB, TRISB, 	/* Control port and control port tris register */ \
    	2,				/* Bit number of control port is connected to RS */ \
    	7,				/* Bit number of control port is connected to RW */ \
    	3 				/* Bit number of control port is connected to Enable */
    
    
    unsigned char tick;
    unsigned int value1;
    bit frequency_update_flag;
    
    /*Interrupt service routine (ISR).On timer1 overflow or  
    ccp pulse capture program will jump to this code location.  */	
    void interrupt( void )
    {
    unsigned char capture_count;
    
      if(pir1.0 == 1)   //tmr1 overflow flag(tmr1if).
    {
      tick++;           // count the number of tmr1 interrupts.
      if(tick > 15)    //if frequency is too low
     {
      ccp1con = 0;
      t1con = 0;
      tmr1l = 0;
      tmr1h = 0;
      tick = 0; 
      value1 = 0;
      capture_count = 0;  
      frequency_update_flag = 1;
     }  
      pir1.0 = 0;       //clear tmr1if 
    }
    
      else
      
      if(pir1.2 == 1)   //ccp interrupt flag(ccp1if).
    {
      capture_count ++;
      if(capture_count > 1)
     {
      t1con = 0;
      ccp1con = 0;       //switch off capture mode.
      value1 = tmr1l + (tmr1h * 256); 
      
      capture_count = 0;
      frequency_update_flag = 1;
      }
      
      else
    //The first ccp interrupt resets tmr1 & starts it.   
     {
      t1con = 0;
      tick = 0;
      tmr1l = 0;
      tmr1h = 0;
      t1con = 1;
     }
      
      pir1.2 = 0;     //clear ccp flag.
    }
    }  
    
    /* function to display RPM. */
    
    void display (int x)
    {
       lcd_clear();   
       lprintf("%d",x);
       delay_s(2);
    }
    
    /* The main code configures the intcon, pie1, t1con & ccpcon1 
      registers.*/
    
    void main()
    {
    trisb = 0;		 //configure port B
    portb = 0;		 //clear port B
    trisc = 0b00000100; //RC2/ccp1 pin as input.
    
    
    // enable interrupts: interrupt control register.
    intcon.6=1;     //enable peripheral interrupts    
    intcon.7=1;     //enable global interrupt
    
    //peripheral interrupt enable register 1.
       pie1.2 = 1;    //enable ccp1 interrupt.
       pie1.0 = 1;    //enables tmr1 overflow interrupt.
       
    /*  timer1 control register:
    
       t1ckps1:t1ckps0: input prescaler
       bit5-4.....select 00= 1:1 prescale
       
       tmr1cs: timer1 clock source select bit.
       bit1...select 0 = internal clock (Fosc/4)
       
       tmr1on: timer1 on bit
       bit0......1 = enable timer1
       bit0......0 = stop timer1         
      	 
    we are not concerned about the other bits of t1con. */
    
    //set t1con
       t1con = 0b00000000;  //tmr1 not yet enabled.
       
    /*ccpcon1: capture/compare/pwm control register1. 
       
       bit3-0.....ccpxm3:ccpxm0: ccpx mode select bits.
       we will use...
       0100 = capture mode, every falling edge.
       0101 = capture mode, every rising edge.
     we can choose any one of the above mode.
     but we will use 0100 in our project.  
    */
    
    /* print " RPM = " in the first line of LCD */
    
       lcd_setup();
       lcd_clear();
       lprintf(" RPM = ");
       lcd_gotoxy(0,1);
    
    unsigned long count; 
       while (1)
    {    
       frequency_update_flag = 0;
       ccp1con = 0b00000101;  //set capture mode.   
       t1con = 1;  //start timer1.
         
     while (frequency_update_flag == 0);   
     
     count = (tick*65536) + value1;
     if(count == 0)   //if frequency is too low.
     {
     display(count); 
     }
     else
     {
     count = 100000000/count; //to find frequency.
     count *= 60;      //for cycles per minute.
     count /= 100;     //divide by 100 to get actual RPM.
     display(count);
     }	 
    }
    }

     

    see if its useful.

    Regards

    Raghunathan.


  15. I am using LCD driver provided with BoostC; this is a part of my code:

     

    #define LCD_ARGS     2,    /* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
            1,                 /* Use busy signal: 1 = use busy, 0 = use time delays */\
            PORTB, TRISB,     /* Data port and data port tris register */ \
            PORTB, TRISB,     /* Control port and control port tris register */ \
            1,                /* Bit number of control port is connected to RS */ \
            2,                /* Bit number of control port is connected to RW */ \
            3                 /* Bit number of control port is connected to Enable */
    
    #include <lcd_driver.h> // include the LCD template code
    
    void main()
    {
        lcd_setup();
        trisa=0x0F;
        lprintf( "First line");
        lcd_gotoxy(1,2);
        lprintf( "Second line" );
        while(1);
    }

     

    The code above does not work properly; instead of

        lprintf( "First line");
        lcd_gotoxy(1,2);
        lprintf( "Second line" );

     

    I must write:

        lprintf( "First line\n"); //added "/n" and removed lcd_gotoxy(1,2);
        lprintf( "Second line" );

     

    It seems that lcd_gotoxy(1,2) does not work. How can I access the second line of my LCD display?

     

    try lcd_gotoxy(0,1) ;

     

    regards

    Raghunathan.


  16. How the output of this ADC is represented in your application is completely up to you and the choices you make when you implement the SPI driver to communicate with the part.

     

    Are you asking for someone to make these choices for you?

     

    Perhaps you should look at the web page for this chip:

     

    http://www.cirrus.com/en/products/pro/detail/P1038.html

     

    There appears to be some source code in 8051 C that implements what you have asked for.

     

    Hi cac001,

    I am not having doubt on the communication part. My doubt is about the total bit weight and how i should calculate the total adc value. In the data sheet they say that the bit weight is in two's compliment. You say that i can make the choice. Then can I store the bit value in long var & use the same binary weight to the bits instead of two's compliment ? If i were to use the two's compliment, then i need to multiply the msb with 1/2, the next significant bit with 1/4 and so on, which will be very cumbersome. Will it not alter the precision in calculation if i used the binary bit weight ?

    I want to write the code in boostC, so please suggest.

    Actally 16bit precision is enough for me. Suppose i truncate rest of the bits will there be an error between using the binary weight and that of two's compliment weight?

    At some stage i might have to use fp lib in the calculation i suppose.

    Thanks for the link, i have down loaded the c code example.

     

    Regards

    Raghunathan.


  17. Hi friends,

     

    I want to interface cirrus logic's cs5550 analog to digital converter to the PIC.

    The output adc result register is a 24 bit one. The most significant bit is the sign bit which will indicate whether the bit is + or -. The rest of the bit values are in two's compliment notation. ie. 1/2, 1/4, 1/8, 1/16, 1/32,.........& so on until the least significant bit.

    Is there any way in BoostC that i can load the value onto a variable at one go instead of having to multiply these value and add them up ? Like say for binary we write 0bxxxxxxxx, for hex its 0xXX .

     

    Those of you who have already worked with this chip, please be generous to spare a few minutes writing your experience and knowledge.

     

    I am connecting the adc to loadcell.

     

    Regards

    Raghunathan.


  18. Being instigated by an earlier post on this topic i set out to write a program for this project.

    I have used the capture module of PIC16F72 to capture the pulses from any sensor( optical or proximity ) connected to the engine/motor. Its connected to the ccp pin RC2. I have used the timer1 to measure the time T elapsed between two pulses from which i calculate the frequency(1/T). The RPM is calculated & displayed on a LCD. This will display the instantaneous RPM value only. I have not done any averaging to keep coding simple.

     

    This project will be posted on my thread once i have tested it fully.

    Before i start wiring i have a few doubts.

     

    In the code below i have used data type long for variable count & made calculations. Should i use optimization directive here? if so please show me how & where i should insert the direcitve.

    again in the display function you will see that i have made the argument as integer variable(x). But we will be entering the long variable "count" as the argument . I have done so because the resultant value in count is only an integer value.

    Do i have to change the x in display function as long?

    If you find any other fault please do report.

    code..

    #include <system.h>
    #include "lcd_driver.h"
    
    // Set clock frequency to 4MHz.
    
    #pragma CLOCK_FREQ 4000000
    
    //set configuration fuse.
    #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
    
    
    #define LCD_ARGS 	2,	/* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
    	0, 				/* Use busy signal: 1 = use busy, 0 = use time delays */\
    	PORTC, TRISC, 	/* Data port and data port tris register */ \
    	PORTB, TRISB, 	/* Control port and control port tris register */ \
    	2,				/* Bit number of control port is connected to RS */ \
    	7,				/* Bit number of control port is connected to RW */ \
    	3 				/* Bit number of control port is connected to Enable */
    
    
    unsigned char tick;
    unsigned int value1;
    bit frequency_update_flag;
    
    /*Interrupt service routine (ISR).On timer0 interrupt, program 
     will jump to this code location.  */	
    void interrupt( void )
    {
     bit capture_flag;
    
      if(pir1.0 == 1)   //tmr1 overflow flag(tmr1if).
    {
      tick++;           // count the number of tmr1 interrupts.
      if(tick > 15)    //if frequency is too low
     {
      ccp1con = 0;
      t1con = 0;
      tmr1l = 0;
      tmr1h = 0;
      tick = 0; 
      value1 = 0;  
      frequency_update_flag = 1;
     }  
      pir1.0 = 0;       //clear tmr1if 
    }
    
      else
      
      if(pir1.2 == 1)   //ccp interrupt flag(ccp1if).
    {
      capture_flag++;
      if(capture_flag > 1)
     {
      t1con = 0;
      ccp1con = 0;       //switch off capture mode.
      value1 = tmr1l + (tmr1h * 256); 
      
      capture_flag = 0;
      frequency_update_flag = 1;
      }
      
      else
    //The first ccp interrupt resets tmr1 & starts it.   
     {
      t1con = 0;
      tmr1l = 0;
      tmr1h = 0;
      t1con = 1;
     }
      
      pir1.2 = 0;     //clear ccp flag.
    }
    }  
    
    /* function to display RPM. */
    
    void display (int x)
    {
       lcd_clear();   
       lprintf("%d",x);
       delay_s(2);
    }
    
    /* The main code configures the intcon, pie1, t1con & ccpcon1 
      registers.*/
    
    void main()
    {
    trisb = 0;		 //configure port B
    portb = 0;		 //clear port B
    trisc = 0b00000100; //RC2/ccp1 pin as input.
    
    
    // enable interrupts: interrupt control register.
    intcon.6=1;     //enable peripheral interrupts    
    intcon.7=1;     //enable global interrupt
    
    //peripheral interrupt enable register 1.
       pie1.2 = 1;    //enable ccp1 interrupt.
       pie1.0 = 1;    //enables tmr1 overflow interrupt.
       
    /*  timer1 control register:
    
       t1ckps1:t1ckps0: input prescaler
       bit5-4.....select 00= 1:1 prescale
       
       tmr1cs: timer1 clock source select bit.
       bit1...select 0 = internal clock (Fosc/4)
       
       tmr1on: timer1 on bit
       bit0......1 = enable timer1
       bit0......0 = stop timer1         
      	 
    we are not concerned about the other bits of t1con. */
    
    //set t1con
       t1con = 0b00000000;  //tmr1 not yet enabled.
       
    /*ccpcon1: capture/compare/pwm control register1. 
       
       bit3-0.....ccpxm3:ccpxm0: ccpx mode select bits.
       we will use...
       0100 = capture mode, every falling edge.
       0101 = capture mode, every rising edge.
     we can choose any one of the above mode.
     but we will use 0100 in our project.  
    */
    
    /* print " RPM = " in the first line of LCD */
    
       lcd_setup();
       lcd_clear();
       lprintf(" RPM = ");
       lcd_gotoxy(0,1);
    
    unsigned long count; 
       while (1)
    {    
       frequency_update_flag = 0;
       ccp1con = 0b00000101;  //set capture mode.   
       t1con = 1;  //start timer1.
         
     while (frequency_update_flag == 0);   
     
     count = (tick*65536) + value1;
     if(count == 0)   //if frequency is too low.
     {
     display(count); 
     }
     else
     {
     count = 100000000/count; //to find frequency.
     count *= 60;      //for cycles per minute.
     count /= 100;     //divide by 100 to get actual RPM.
     display(count);
     }	 
    }
    }

     

    Regards

    Raghunathan.


  19. Hi guys,

     

    I am using the ccp module in the capture mode to measure time interval between two pulses or (frequency) of a signal. This is possible if the period is smaller than the 16 bit timer1 value. in the case of low frequency one needs to count the no.of interrupts the timer1 produces and multiply that with 65536 & add that value to the final timer1 value.

    So i decided to use capture module just to generate an interrupt when the ccp pin reads a pulse( either falling edge or rising edge of thepulse) & i would read the tmr1 directly instead of the ccppr1h &ccpr1l.

     

    Now the question..

     

    Will the capture module work with the tmr1 in the off state?

    I wish to start the tmr1 in the ISR of the capture module.

    Will it work?

     

    Regards

    Raghunathan.



  20. /* digital_clock.c
    Now that you know how to configure the timer0 to generate accurate
    time interval, let's construct a digital clock that will display
    hours, minutes and seconds on six led segment display. We will use
    the same common cathode segment used in our earlier projects. We will
    use PIC16F72 for this project because it has 22 i/o pins. The main
    features of this project at a glance.

    a)Uses tmr0 for time keeping.
    b)We use PIC16F72
    c)4MHZ crystal frequency
    d)six no. of 7-segment display, to display hours, minutes & seconds.
    e)two button switch to set hours and minutes.
    f)six BC547(NPN)transistors to demultiplex the data bus(portb).

    In the previous project i had explained about interrupts by comparing
    the similarity in real world like the example of calling bell ringing
    & that of microcontrollers hardware interrupts. Let's apply the calling
    bell example to our digital clock. If you look at the program below,
    you will see that the microcontroller spends most of its time firing
    the transistors to display the hours, minutes & seconds segments, this
    is similar to us doing our household activity. But in the background
    the tmr0 counter keeps ticking without any of our intervention. In fact
    we are not even aware that the tmr0 is ticking until an interrupt occurs
    when it rolls over from 255 to 0.And when the interrupt occurs we quickly
    update the tick, tick1, seconds, minutes, hours in the ISR and then get
    back to doing our usual work of lighting the segments. The interrupt
    generated by tmr0 can be considered similar to the ringing of the calling
    bell.

    This code may initially look more convoluted with the function
    sec(), min(),hrs(),but you will soon see how advantageous it would
    be to call them only when the data gets updated & rest of the time
    we simply display the old value of data. By doing this we get a
    flicker free display.

    I had made this circuit on a bread board. Since the segments are dirctly
    connected to the PIC via 150 ohms without any driver and since multiplexing
    six segments will reduce the mean led current, you will see that the segments
    are not very bright, but i found it excellent when seen with a red filter.

    Circuit connection:
    pin20- VDD pin to +5v.
    pin8- VSS pin to 0v.
    pin1- MCLR pin to +5v via 4.7K resistor
    pin9-10 4mhz crystal(across pin 9 & 10)
    connect 22pf capacitors( between pin9 & gnd, pin10 & gnd)
    pin21-RB0-no connection.

    Seven segment modules.
    The segment pins of the six 7-segment module must be paralled,ie. all
    "a" segments are connected together & all "b" segments are connected &
    so on.

    pin22-RB1-connect to segment "e" of the 7-segment display via 150 ohms.
    pin23-RB2-connect to segment "a" of the 7-segment display via 150 ohms.
    pin24-RB3-connect to segment "f" of the 7-segment display via 150 ohms.
    pin25-RB4-connect to segment "c" of the 7-segment display via 150 ohms.
    pin26-RB5-connect to segment "g" of the 7-segment display via 150 ohms.
    pin27-RB6-connect to segment "b" of the 7-segment display via 150 ohms.
    pin28-RB7-connect to segment "d" of the 7-segment display via 150 ohms.

    pin11-RC0-to base of Q1 driving the units segment of seconds via 10k.
    pin12-RC1-to base of Q2 driving the tens segment of seconds via 10k.
    pin13-RC2-to base of Q3 driving the units segment of minutes via 10k.
    pin14-RC3-to base of Q4 driving the tens segment of seconds via 10k.
    pin15-RC4-to base of Q5 driving the units segment of hours via 10k.
    pin16-RC5-to base of Q6 driving the tens segment of hours via 10k.

    collector of Q1 is connected to cc(common cathode)of units segment of
    seconds digit & its Emitter to ground.
    collector of Q2 is connected to cc of tens segment of seconds digit & its
    Emitter to ground.
    collector of Q3 is connected to cc of units segment of minutes digit & its
    Emitter to ground.
    collector of Q4 is connected to cc of tens segment of minutes digit & its
    Emitter to ground.
    collector of Q5 is connected to cc of units segment of hours digit & its
    Emitter to ground.
    collector of Q6 is connected to cc of tens segment of hours digit & its
    Emitter to ground.

    Q1,Q2,Q3,Q4,Q5,Q6- BC547 NPN transistors.

    button switch connection:
    button switches will generally have two pins which are normally open and
    on pressing the button gets closed.
    Connect a 10k resistor to +5v. on the other end of the resitor is conncted
    both to PIC micros input pin & one of the pins of the button switch. The
    other pin of the button switch is grounded.
    When the button switch is NOT pressed the PIC micro will read a high & when
    pressed it will read a low.

    pin17-RC6 to button switch1 and a pullup resistor of 10k connected to +5v.
    pin18-RC7 to button switch2 and a pullup resistor of 10k connected to +5v.

    pressing button switch1 will increment minutes.
    pressing button switch2 will increment hours.

    How to set the clock?
    You have two button switches connected to portc.6 & postc.7. As soon
    as you power on the circuit you will see the hours and minutes segements
    flash 00 alternately. Now pressing the hours button(portc.7)will increment
    the hours. As soon as it reaches the right hours, stop pressing or release
    the button. next press the minutes button(portc.6) & set it similarly. Once
    both value are set press both these buttons(portc.6 & portc.7) simultaneously.
    It will immediately jump to the clock routine and the clock will start to
    tick( you can see the seconds segment increment).

    */

     

    #include <system.h>
    // Set configuration word
    #pragma CLOCK_FREQ 4000000
    #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
    /*all of the below variables are made global for easy access in
    our functions.*/
    bit updatesec = 0;
    bit updatemin = 0;
    bit updatehrs = 0;
    unsigned char seconds = 0;
    unsigned char minutes = 0;
    unsigned char hours = 0;
    unsigned char unitsec = 0;
    unsigned char tensec = 0;
    unsigned char unitmin = 0;
    unsigned char tenmin = 0;
    unsigned char unithrs = 0;
    unsigned char tenhrs = 0;
    //timer0 interrupt service routine.   
    void interrupt( void )
    {
    unsigned char tick;
    unsigned char tick1;
       tmr0 +=9;  // add 9 to generate interrupt every 250us.
       tick++;
       if(tick>19)
       {
       tick=0;
       tick1++;
       if(tick1>199)
       {
       tick1=0;
       seconds++;
    //a flag to indicate that seconds has been updated   
       updatesec=1; 
       if(seconds>59)
       {
       seconds=0;
       minutes++;
    //a flag to indicate that minutes has been updated
       updatemin=1;
       if(minutes>59)
       {
       minutes=0;
       hours++;
    //a flag to indicate that hours has been updated
       updatehrs=1;
       if(hours>23)
      {
       hours=0;
         }
        }
      }
     }
    }
        intcon.2=0;  //clear TMR0 overflow flag
    }
    //function to get segment values.
    unsigned char get_value(unsigned char y)
    {
    unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC};
    return segments[y];
    }
    
    //a function to get tens & units place for seconds.
    void sec(void)
    {
      tensec = get_value(seconds/10);
      unitsec= get_value(seconds%10);
    }
    //a function to get tens & units place for minutes.
    void min(void)
    {
      tenmin = get_value(minutes/10);
      unitmin = get_value(minutes%10);
    }
    //a function to get tens & units place for hours.
    void hrs(void)
    {
      tenhrs = get_value(hours/10);
      unithrs = get_value(hours%10);
    } 
     
    //main program starts here.   
    void main()
    {
    unsigned char a;
        trisb = 0;        //configure port B
        portb = 0;        //clear port B
    //portc.7 & portc.6 are made as inputs & the rest as outputs.   
       trisc = 0b11000000; 
        portc = 0;
       
       while(1)
       {
    //set time by pressing the appropriate button.   
      
    //if both switches are closed start clock.   
       if((portc.6 == 0) && (portc.7 == 0))
       {
        goto clock;
         }
    //if switch in portc.6 is pressed increment minutes     
       if(portc.6 == 0)
       {
        minutes++;
        if(minutes>59)
        {
         minutes=0;
          }
        }
    //call function min() to get units & tens value for minutes.   
       min();
       for(a=0;a<250;a++)
       {
        portb = unitmin;
        portc.2=1;
        delay_ms(2);
        portc.2=0;
        portb = tenmin;
        portc.3=1;
        delay_ms(2);
        portc.3=0;
         }
    //again check for both switches to be closed.
        if((portc.6 == 0) && (portc.7 == 0))
        {
         goto clock;
          }
    //if switch in portc.7 is pressed increment hours.     
        if(portc.7 == 0)
        {
         hours++;
         if(hours>23)
         {
          hours=0;
           }
         }
    //call function min() to get units & tens value for hours.     
        hrs();
        for(a=0;a<250;a++)
        {
         portb = unithrs;
         portc.4=1;
         delay_ms(2);
         portc.4=0;
         portb = tenhrs;
         portc.5=1;
         delay_ms(2);
         portc.5=0;
         }
        if((portc.6 == 0) && (portc.7 == 0))
        {
         goto clock;
           }
    }
    //start clock
    clock:
        updatesec=1;
        updatemin=1;
        updatehrs=1;
      
    //assign prescaler to wdt & start tmr0.
        option_reg = 8;   
       
       // enable interrupts
        intcon.5=1; //enable tmr0 overflow interrupt   
        intcon.7=1; //enable global interrupt
    //set tmr0 to genterate interrupt at every 250us.   
        tmr0=6;   
    
        while( 1 )   //endless loop
        {
       if(updatesec==1)  //check for update flag,if set
        {
        updatesec=0;  //clear the flag & call function sec
        sec();        // to get units & tens value
        }             //for seconds.
        for(a=0;a<60;a++)
        {
        portb = unitsec;
        portc.0=1;
        }
        portc.0=0;
        for(a=0;a<60;a++)
        {
        portb = tensec;
        portc.1=1;
        }
        portc.1=0;
        if(updatemin==1)
        {
        updatemin=0;
        min();
        }
        for(a=0;a<60;a++)
        {
        portb = unitmin;
        portc.2=1;
        }
        portc.2=0;
        for(a=0;a<60;a++)
        {
        portb = tenmin;
        portc.3=1;
        }
        portc.3=0;
        if(updatehrs==1)
        {
        updatehrs=0;
        hrs();
        }
        for(a=0;a<60;a++)
        {
        portb = unithrs;
        portc.4=1;
        }
        portc.4=0;
        for(a=0;a<60;a++)
        {
        portb = tenhrs;
        portc.5=1;
        }
        portc.5=0;
     }
    }

     

    /*
    In the ISR see how the tick, tick1 gets incremented. Also see how
    the seconds minutes and hours gets incremented. See how these update
    flag bits are set and cleared.
    This code compiles to 397 words
    */

×
×
  • Create New...