1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

C18 Questions

Discussion in 'Microcontrollers' started by 3v0, Jun 25, 2009.

  1. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    I added some text to the previous post.
     
  2. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    It will indeed still take a while, I just meant it will help me get past the current snag. The final goal of making a device plug into two ports of a servo receiver and control two motors in two directions is a way off. But one by one I'm knocking parts of it off the list.
     
  3. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    Sending an array of data(not string)

    Hi i want to send a array of data through the serial port but when i try to use a pointer to address the array and then write

    at start of program tempptr=tempdata;


    then

    putcUSART(*tempptr);
    tempptr++;

    it gives a syntax error.

    On the other hand tempdata[counter] works fine.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,162
    Likes:
    340
    Location:
    Brisbane Australia

    If you're using BoostC then it doesn't support ROM based pointers. You have to use the Var[offset] type of indexing.

    Mike.
     
  6. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    I am using C18 and wanted to use a pointer to index an array(a very very simple application).But i got errors so i used the conventional method.My question is

    Can you index a numeric array using the built in functions of the USART.I tried and i got errors..am i doing it incorrectly?

    PS: I have already done it the other way but wanted to clear my self about the abilities of C18.
     
  7. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,162
    Likes:
    340
    Location:
    Brisbane Australia
    I would guess that the function expects a ram based variable and wont work with a rom pointer, try,
    Code (text):

    static rom char HW[]="Hello World!";
    rom char *P;
    char i;

    P=HW;           // or P=&HW[0];
    while(*P){
        i=*P++;
        putcUSART(i);
    }
    Mike.
     
    Last edited: Sep 7, 2009
  8. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    I am using a RAM Array already, but since it does not accept a ram array pointer so guess it was not working.I would rather use the conventional array indexing approach since my application allows it.The code you provide works.Thanks for you reply.
     
  9. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    Alright, I coded a C18 version of what 3v0 posted above in post #139. The code is below, I have just included the part for the CCP setup, the interrupt and the timer setup:

    configuration
    Code (text):

        //configure timer1
        OpenTimer1(0b10010101);
       
        PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
        PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag

        //configure CCP1 for capture, rising edge
        CCP1CON = 0b0000101;
     
    code withen interrupt function
    Code (text):

        //ccp interrupt
        if(PIR1bits.CCP1IF == 1)
        {  
            if(PWM1Edge == 1)//if detecting rising
            {  
                interrupttest3++;
               
                PWM1RiseTime = CCPR1;//save the low timer value for the rise time
                CCP1CON = 0b0000100;//switch to detect falling edge
                PWM1Edge = 0;//switch to indicate falling edge is next
            }
            else //detecting falling
            {
                interrupttest2++;

                PWM1Width = CCPR1 - PWM1RiseTime;
                CCP1CON = 0b0000101;//switch to detect rising edge
                PWM1Edge = 1;//switch to indicate rising edge is next
            }
           
            interrupttest1++;
            PIR1bits.CCP1IF = 0; //clear the flag
        }
    }
     
    So far it is working ok. The value I get ranges from 178 with the knob all the way in one direction to 143 all the way in the other, at a given position the value varies by as much as 9, but that variance increases towards the extremes, varying only by 3 in the neutral center position.

    I'm looking for suggestions on how this could be improved. As I am not very good with timers, and CCP1 depends on timer1, I suspect that I could improve the settings there to get higher resolution. Would the resolution go up as the prescaler goes down or vice versa? Part of my concern is that I haven't really followed this step "Configure Timer1 prescaler so that Timer1 will run WMAX without overflowing." since I don't really understand prescalers. So, I'll need to read up on them and get that part fine tuned.

    Any other suggestions on how this could be improved would be appreciated.

    details: Im using a traxas 2215 receiver at 27mhz, it is connected to the 3 pin port of my junebug (RB3,UV5,GND)
     
    Last edited: Sep 16, 2009
  10. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,162
    Likes:
    340
    Location:
    Brisbane Australia
    You don't mention the speed of your chip but as it's a Junebug I assume you set it to 8MHz. If this is the case then I would set the prescaler to 2 so each timer 1 count = 1uS. This will mean that typical servo pulses should give you readings from 1000(1mS) to 2000(2mS). The prescaler is how much to divide the clock by before feeding it to timer 1 - it is already divided by 4 and so is effectively 2MHz.

    Mike.
     
  11. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    Yes, I'm using the 18F1320 on the junebug. I don't remember setting the speed of the chip, but I'll check on that.

    I also have a question about debug mode. So far it seems as if it runs at full speed, if I have a LED set to blink every 1000mS, it seems to keep blinking every second weather I'm in debug mode or not, and the capture timing seems correct too. Does debug run at full speed?
     
  12. blueroomelectronics

    blueroomelectronics Well-Known Member

    Joined:
    Jan 21, 2007
    Messages:
    12,536
    Likes:
    170
    Location:
    Toronto, Canada
    Debug runs the chip at it's real speed when in RUN mode. But when you want to single step it's very slow at 31kHz (the default 18F1320 speed).
    OSCCON = $72 will speed things up to 8MHz.

    Note: The more variables you're watching the slower single step / animate will run.
     
  13. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    I usually have been using run mode, even though I wasnt sure that would capture pwm properly I was sure that step animate wouldent get it.

    Thanks for the speed control pointer.
     
  14. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    I had the PWM measuring code working pretty well inside 3V0's program, but now that I moved it on its own I cant get the interrupt to go. I must be missing something. The standalone program I have so far is fairly short.

    I wouldent be surprised if the problem is in the way I configured the interrupt as thats something I dont understand very well yet. Does each type of interrupt use its own function, or do they all call the interrupt function, then you sort out what to do by checking the flags? I've seen various interrupt code, and I cant really tell what each part means, so its hard to know what I copied over wrong. I've tried this line "#pragma code low_vector = 0x18" with 0x08 and 0x18 since I've seen both in examples, I cant see to get that interrupt to trigger.

    Code (text):

     #pragma    config OSC = INTIO2, WDT = OFF, LVP = OFF
     #include <p18f1320.h>


    //set up interrupt
    void low_ISR(void);//prototype
    #pragma code low_vector = 0x18
    void low_interrupt (void){
    _asm goto low_ISR _endasm
    }
    #pragma code
    #pragma interrupt low_ISR


    //setup pins for PWM input
    #define ReceiverPin PORTBbits.RB3
    #define ReceiverTris TRISBbits.TRISB3


    //PWM capture variables
    unsigned int PWM1RiseTime = 0;
    unsigned int PWM1Width = 0;
    char PWM1Edge = 1;

    char test1 = 0;

    // Interrupts
    void low_ISR(void)
    {      

        test1 = 1;
        //ccp interrupt
        if(PIR1bits.CCP1IF == 1)
        {  
            PIR1bits.CCP1IF = 0; //clear the flag
            if(PWM1Edge == 1)//if detecting rising
            {  
               
                PWM1RiseTime = CCPR1;//save the low timer value for the rise time
                CCP1CON = 0b0000100;//switch to detect falling edge
                PWM1Edge = 0;//switch to indicate falling edge is next
            }
            else //detecting falling
            {

                PWM1Width = CCPR1 - PWM1RiseTime;
                CCP1CON = 0b0000101;//switch to detect rising edge
                PWM1Edge = 1;//switch to indicate rising edge is next
            }
           
        }
    }

    void main(void)
    {  
        //set clock to 8 Mhz
        OSCCONbits.IRCF0=1;  
        OSCCONbits.IRCF1=1;  
        OSCCONbits.IRCF2=1;  

        //configure timer1
        OpenTimer1(0b10010101);
        PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
        PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag

        //configure CCP1
        CCP1CON = 0b0000101; //configure CCP1 for capture, rising edge
        ReceiverTris = 1; //set RB3 for input so the capture can work.
       
        //configure ports
        ADCON1 = 0xff; //all digital
        INTCON2bits.RBPU = 0; //port b weak pullups on
       
        while(1)
        {
        }
    }
     
     
    Last edited: Sep 20, 2009
  15. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,162
    Likes:
    340
    Location:
    Brisbane Australia
    You aren't enabling the interrupts, you need to add these lines,
    Code (text):

        INTCONbits.PEIE=1;      //enable peripheral ints
        PIE1bits.CCP1IE=1;      //namely the CCP1 int
        INTCONbits.GIE=1;       //finally turn them on
     
    And remove these lines,
    Code (text):

        PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
        PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag
     
    This is because you are using the ccp interrupt - not the timer1 interrupt.

    Mike.
     
  16. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    936
    Likes:
    22
    Location:
    Bay Area
    Thanks, what was missing from all my variations so far in trying to get it to work was turning on GIE.

    For anyone interested, heres the working code I have so far for Capturing the width of a PWM signal. In this case from a servo receiver plugged into RB3 of the junebug:

    Code (text):

    //Basic configureation of chip periferials
     #pragma config OSC = INTIO2, WDT = OFF, LVP = OFF
     #include <p18f1320.h>

    //setup pins for PWM input
    #define ReceiverPin PORTBbits.RB3
    #define ReceiverTris TRISBbits.TRISB3


    //PWM capture variables
    unsigned int PWM1RiseTime = 0;
    unsigned int PWM1Width = 0;
    char PWM1Edge = 1;

    //set up interrupt
    void low_ISR(void);//prototype
    #pragma code low_vector = 0x08
    void low_interrupt (void){
    _asm goto low_ISR _endasm
    }
    #pragma code
    #pragma interrupt low_ISR

    //debug stuff
    char test1 = 0;
    char test2 = 0;

    void main(void)
    {  
        OSCCON = 0x72; //8MHz clock
        while(!OSCCONbits.IOFS); //Wait for OSC to become stable

        //configure timer1
        OpenTimer1(0b10010101);
        PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
        PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag

        //configure CCP1
        CCP1CON = 0b0000101; //configure CCP1 for capture, rising edge
        INTCONbits.PEIE=1;      //enable peripheral interrupts
        PIE1bits.CCP1IE=1;      //enabled CCP1 interrupt
        INTCONbits.GIE=1;       //enable branching to interrupt
       
        ReceiverTris = 1; //set RB3 for input so the capture can work.
       
        //configure ports
        ADCON1 = 0xff; //all digital
        INTCON2bits.RBPU = 0; //port b weak pullups on
       
        while(1)
        {
        }
    }


    void low_ISR(void)
    {      

        test1 = 1;
        //ccp interrupt
        if(PIR1bits.CCP1IF == 1)
        {  
            PIR1bits.CCP1IF = 0; //clear the flag
            if(PWM1Edge == 1)//if detecting rising
            {  
               
                PWM1RiseTime = CCPR1;//save the low timer value for the rise time
                CCP1CON = 0b0000100;//switch to detect falling edge
                PWM1Edge = 0;//switch to indicate falling edge is next
            }
            else //detecting falling
            {

                PWM1Width = CCPR1 - PWM1RiseTime;
                CCP1CON = 0b0000101;//switch to detect rising edge
                PWM1Edge = 1;//switch to indicate rising edge is next
            }
           
        }
    }
     
     
  17. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    Hi! me again...i was doing a program on the 18LF4620 that requires me to calculate the percent difference between two integers.I was surprised to find out that although C18 allows multiplication and division of 'int' but when i was subtracting one from the other, it was only subtracting the Lower 8 bits.Weird huh?Is there any way with out using the 32 bit libraries(huge code size)?Except the manual way(8 bit operations)
     
  18. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,162
    Likes:
    340
    Location:
    Brisbane Australia
    Post the code. You have done something wrong. Sixteen bit maths works fine in C18.

    Mike.
     
  19. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    Just worked it out.The problem was with the result that i was expecting.I cant calculate percentages with out using floating point math since the answer is going to be in decimals(after divisions) which cant be used with out teh math library so even after multiplying it with 100 i got zero.So what i have done is just calculated the difference and then did the other stuff in my labview vi(constituting the other part of the 'project').Thanks for you reply Mike.
     
  20. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    I would still like to see the code that did not work.

    I think we could have fixed it for you.

    3v0
     
  21. Wond3rboy

    Wond3rboy Member

    Joined:
    Jun 25, 2008
    Messages:
    762
    Likes:
    7
    Location:
    Sindh,Pakistan
    Hi 3V0,here is the code.This is just a math test.

    Code (text):
    #include<p18f4620.h>
    void main(void)
    {   unsigned int result;
        unsigned int a=0x1018;
        unsigned int b=0x0018;
        unsigned int ceilingrd=0x1018;
        unsigned int ceilingr=0x0018;
        unsigned int diff,perc,castingl,castingh;
        castingl=(ceilingrd);
        castingh=(ceilingrd/256);
        diff=ceilingrd-ceilingr;
        result=b-a;
        perc=(diff/ceilingrd)*100;
       
        while(1);
    If you see in MPLab Sim the variable perc is zero.


    PS:3V0 can i PM you about a board that i made.Its basically a question(not technical) and may be useful to you.I would be really thankful.If you say yes the i will get back to you i 2 or 3 days..just wanted to ask since i have your attention.
     

    Attached Files:

Share This Page