Simple question regarding concatenating TMR1H and TMR1L

Discussion in 'Programmer's Corner' started by dannybeckett, Mar 7, 2011.

  1. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Code ( (Unknown Language)):
    1.  
    2. #include <stdio.h>
    3. #include <string.h>
    4.  
    5. main() {
    6.        int TMR1H = 12345678;
    7.        int TMR1L = 12345678;
    8.        char str1[8];
    9.        char str0[8];
    10.        str1[0] = TMR1H;
    11.        str0[0] = TMR1L;
    12.        char str[16];
    13.        strcpy (str, str1);
    14.        strcat (str, str0);
    15.        printf("%s", str);
    16.        getchar();
    17. }
    18.  
    This is my code so far. All I want is to create a variable which consists of TMR1H immediately followed by TMR1L, so I can perform math operations on the time captured from TMR1. Obviously, these two variables contain the first half(L) and second half(H) of a 16 bit binary number. I dont want any arithmetic operations performed on them, simply str = 1234567812345678. Ideally, the output type is an int. At the moment I'm getting some odd characters from the printf function. Im probably doing very silly things here so if anyone can enlighten me I would be very grateful!

    Dan
     
  2. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Just thought - would

    t1 = TMR1L + (TMR1H*256);

    work?
     
  3. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,908
    2,169
    You can use the timer union from C18.

    /* ... */
    #include <timers.h>
    union Timers timer;
    /* ... */

    timer.lt = timer0; // Copy timer value into union

    TMR0H = timer.bt[1]; // Write low byte to Timer0

    TMR0L = timer.bt[0]; // Write high byte to Timer0

    /* ... */

    http://www.microchip.com/forums/m103913-print.aspx
     
  4. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    That looks useful, but I dont seem to have timers.h. Using the hi-tech c compiler. I have time.h, but im guessing thats different...
     
  5. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    You can use a union here I think. But your code is dodgy. Have you read the quickstart.pdf document in the compiler install folder see under the folder docs
     
  6. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Yeah apologies, the code is rediculous. Ive not read that document, I will give it a go. Thanks
     
  7. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,908
    2,169
    I'll have to download Hi-Tech C and take a look at the headers but they should have something similar.
     
  8. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Dan which PIC do you use? This should be defined properly in the header file. As an example from a header file. Note the type definition do not mix int and char
    Code ( (Unknown Language)):
    1. // Register: TMR1L
    2. volatile unsigned char           TMR1L               @ 0x00E;
    3. // bit and bitfield definitions
    4. // Register: TMR1H
    5. volatile unsigned char           TMR1H               @ 0x00F;
    6. // bit and bitfield definitions
    7. // Register: TMR1
    8. volatile unsigned int            TMR1                @ 0x00E;
    Edit this is from the 9.81 compiler version of PICC (for 16F series pic) Older versions may not have this in the header file.
     
    Last edited: Mar 8, 2011
  9. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    I'm using a PIC16F887 - I have just checked my header file and found this:

    // Register: TMR1L
    volatile unsigned char TMR1L @ 0x00E;
    // bit and bitfield definitions

    // Register: TMR1H
    volatile unsigned char TMR1H @ 0x00F;
    // bit and bitfield definitions

    // Register: TMR1
    volatile unsigned int TMR1 @ 0x00E;

    Is TMR1 the full 16 bit timer contents? That would save a bit of hastle lol....
     
  10. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Yes that is correct. One more thing in your code you do not include the htc.h file (ref quickstart.pdf). And how about your configuration words setting. Is this done in MPLAB?
     
  11. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Oh thats a little bit of testing code I wrote in devc++ (very badly), not taken from mplab. My full code is as follows:

    Code ( (Unknown Language)):
    1.  
    2. // A program to measure the period of a square wave
    3.  
    4. #include <htc.h>
    5. //#include <stdio.h>
    6.  
    7. #define _XTAL_FREQ 1000000
    8. __CONFIG (FOSC_INTRC_NOCLKOUT & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF);
    9.  
    10. void initDigitalOut() {
    11.     PORTA = PORTB = PORTC = PORTD = 0;
    12.     TRISA = TRISB = TRISC = TRISD = 0;
    13.     ANSEL = ANSELH = 0;
    14. }
    15.  
    16. void initIntOscillator() {
    17.     OSCCONbits.IRFC     = 4;        // Internal oscillator frequency set. 3 bits wide, 100 = 1MHz, 11 = 500KHz
    18.     OSCCONbits.OSTS        = 0;        // Use internal oscillator. 1 = ext osc.
    19.     OSCCONbits.HTS        = 1;        // High frequency stability bit (8 MHz to 125 kHz). What do?
    20.     OSCCONbits.LTS        = 0;        // Low frequency stability bit (31KHz). What do?
    21.     OSCCONbits.SCS        = 1;        // System clock select. 1 = int, 0 = ext.
    22. }
    23.  
    24. void initCaptureRisingCCP1() {
    25.     CCP1CONbits.CCP1M    = 0b101;
    26.     /* write to the CCP1CON register, specifically the CCP1M (Enhanced Capture/Compare/PWM mode
    27.      * select bits) selection, and set '0101 = Capture mode, every rising edge'. All other pins
    28.      * in register are not used.
    29.      */
    30. }
    31.  
    32. void initOptionRegister() {            // This is used to configure Timer0 amongst other things.
    33.     OPTION_REGbits.nRBPU    = 1;     // Disable PORTB pullups.
    34.     OPTION_REGbits.INTEDG    = 1;     // Interrupt edge select. 1 = rising edge on INT pin.
    35.     OPTION_REGbits.T0CS        = 0;     // Timer0 Clock source. 0 = Fosc/4, 1 = T0CKI pin.
    36.     OPTION_REGbits.T0SE        = 0;     // Timer0 source edge select. 0 = Increment on low-to-high transition on T0CKI pin (not arsed).
    37.     OPTION_REGbits.PSA        = 0;     // Prescaler allignment. 1 = WDT, 0 = Timer0.
    38.     OPTION_REGbits.PS        = 7;    // 3 bits wide, set prescaler rate. 111 = 1:256.
    39. }
    40.  
    41.  
    42. void initTimer1() {
    43.     T1CONbits.T1GINV    = 0;     // Set T1 Gate active high or active low. 1 = high, 0 = low.
    44.     T1CONbits.TMR1GE    = 0;     // 1 = Timer1 is on if Timer1 gate is not active. 0 = Timer1 is on.
    45.     T1CONbits.T1CKPS    = 3;    // Timer1 clock prescale, 2 bits wide. 00 = /1. 11 = /8
    46.     T1CONbits.T1OSCEN    = 0;     // LP oscillator enable for Timer1. Runs at 32.768KHz.
    47.     T1CONbits.T1SYNC    = 0;     // Sync external clock (dont think this applies but sync JIC). Inverted, 0 = sync.
    48.     T1CONbits.TMR1CS    = 0;     // 1 = External clock from T1CLI pin (RC0). 0 = Internal clock. Not sure what this should be when using LP osc!
    49.     T1CONbits.TMR1ON    = 0;     // 1 Enables timer, 0 stops it.
    50.     TMR1H = TMR1L        = 0;     // Clear whatever is in Timer1. Values are unknown on startup.
    51. }
    52.  
    53. void initInterruptCCP1() {
    54.     INTCONbits.GIE    = 1;    // Global interrupt enable. Enables all unmasked interrupts, must be set. Clears all interrupts also.
    55.     INTCONbits.PEIE    = 1;    // Peripheral interrupt enable. Enables all unmasked peripheral interrupts. Clears all associated interrupts also.
    56.     TRISC2            = 1;    // Pin CCP1 set to input.
    57.     PIE1bits.CCP1IE    = 1;    // CCP1 interrupt enable bit, RC2.
    58. }
    59.  
    60.  
    61. volatile float horizontalPixelDelayMS = 0;    // Volatile keyword prevents any optimization from compiler. Tells it that timeCaptured could be altered outside the scope of this program. Don't think its needed tbh.
    62. interrupt void rpmTrigger() {    
    63.     /* Note the keyword ‘interrupt’.  Hi-Tech C handles the code to save and restore the
    64.      * state of the micro, and the calculating the address to hook into the interrupt.
    65.      */
    66.     horizontalPixelDelayMS = (((CCPR1H & 0xFF) * 0x100) + (CCPR1L & 0xFF))*0.032; // Actually might be able to just refer to CCPR1 insead of doing all that BS.
    67.  
    68.     TMR1H = 0;
    69.     TMR1L = 0;
    70.  
    71.     PIR1bits.CCP1IF    = 0;    // Clear CCP1 interrupt request flag.
    72. }
    73.  
    74. void main() {
    75.     initDigitalOut();
    76.     initIntOscillator();
    77.     initTimer1();
    78.     initCaptureRisingCCP1();
    79.     initInterruptCCP1();
    80.     T1CONbits.TMR1ON    = 1;    // Turn timer on.
    81.     while(1) {}
    82. }
    83.  

    The noob friendly comments are there for my refference.
     
  12. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    (its also no way near finished yet)
     
  13. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Take a look here
    Code ( (Unknown Language)):
    1. ]#define _XTAL_FREQ 1000000
    2. __CONFIG (FOSC_INTRC_NOCLKOUT......);
    3.  
    You can have max 8MHz with internal OSC. Se figure FIGURE 4-1 in the data sheet. So the #define _XTAL_FREQ 1000000 must be changed to correct value or the delay functions __DELAY_MS, __DELAY_US will be wrong. But so far you have not used them yet.
     
  14. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Yeah I know, the PIC is running at 1MHz. This was done to slow down the counting of Timer1 somewhat.
     
  15. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    You need to be careful with any kind of math done on timer registers, or even copying them to another variable. If the timer is running when you do this, you can't be sure that you're grabbing the contents at a favorable time, and at least the low-order byte and possibly the high-order byte will change quickly. The foolproof way to do it is stop the timer, do what you have to do and restart the timer.

    Or grab the high byte, grab the low byte, grab the high byte again and if it changed since the first time, grab the low byte again. But don't let an interrupt occur anywhere in this process.
     
  16. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    Thanks John, noted. My code has changed quite a lot since this, I have realised that TMR1 addresses the whole 16 bits, and I dont perform any maths operations on this register at all. CCPR1 is a 16 bit capture register that captures the contents of TMR1 whenever an event on RC2 is detected, I only use that number in the maths now. Ill paste the code as it stands once its polished up a little bit. Ill put an explanation of what I am doing with it, along side the post =D
     
  17. dannybeckett

    Thread Starter Active Member

    Dec 9, 2009
    163
    0
    As promised, if anyone's interested - this is the program I am planning to implement to control the persistance of vision led display:

    Code ( (Unknown Language)):
    1.  
    2. #include <htc.h>
    3. #include <stdint.h>
    4. #include <delay.c>
    5. #include <math.h>
    6.  
    7. #define _XTAL_FREQ 1000000 // For __delay_us()
    8. #define PIC_CLK 1000000 // For DelayBigUs()
    9. #define RADIUS_ROTOR_MM 220
    10. #define LED_WIDTH_MM 5
    11. #define LED_DUTY_CYCLE 20
    12.  
    13. __CONFIG (FOSC_INTRC_NOCLKOUT & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF);
    14.  
    15.  
    16. /***********
    17.  * Globals *
    18.  ***********/
    19.  
    20. uint32_t TMR1_FREQ = 0;
    21. float DELAY_H_PIXELS_US = 0;    
    22. uint16_t NUMBER_H_PIXELS = 0;
    23. float DELAY_H_PIXELS_US_ON = 0;
    24. float DELAY_H_PIXELS_US_OFF = 0;
    25.    
    26. /***************
    27.  * Initiatiors *
    28.  ***************
    29.  * Functions to set up the PIC the way we want it.
    30.  */
    31.  
    32. void initDigitalOut() {
    33.     PORTA = PORTB = PORTC = PORTD = 0;
    34.     TRISA = TRISB = TRISC = TRISD = 0;
    35.     ANSEL = ANSELH = 0;
    36. }
    37.  
    38. void initIntOscillator() {
    39.     OSCCONbits.IRFC     = 4;        // Internal oscillator frequency set. 3 bits wide, 100 = 1MHz, 11 = 500KHz
    40.     OSCCONbits.OSTS        = 0;        // Use internal oscillator. 1 = ext osc.
    41.     OSCCONbits.HTS        = 1;        // High frequency stability bit (8 MHz to 125 kHz). What do?
    42.     OSCCONbits.LTS        = 0;        // Low frequency stability bit (31KHz). What do?
    43.     OSCCONbits.SCS        = 1;        // System clock select. 1 = int, 0 = ext.
    44. }    
    45.  
    46.  
    47. void initTimer1() {
    48.     T1CONbits.T1GINV    = 0;     // Set T1 Gate active high or active low. 1 = high, 0 = low.
    49.     T1CONbits.TMR1GE    = 0;     // 1 = Timer1 is on if Timer1 gate is not active. 0 = Timer1 is on.
    50.     T1CONbits.T1CKPS    = 3;    // Timer1 clock prescale, 2 bits wide. 00 = /1. 11 = /8
    51.     T1CONbits.T1OSCEN    = 0;     // LP oscillator enable for Timer1. Runs at 32.768KHz.
    52.     T1CONbits.T1SYNC    = 0;     // Sync external clock (dont think this applies but sync JIC). Inverted, 0 = sync.
    53.     T1CONbits.TMR1CS    = 0;     // 1 = External clock from T1CLI pin (RC0). 0 = Internal clock. Not sure what this should be when using LP osc!
    54.     T1CONbits.TMR1ON    = 0;     // 1 Enables timer, 0 stops it.
    55.     TMR1H = TMR1L        = 0;     // Clear whatever is in Timer1. Values are unknown on startup.
    56.    
    57.     /******************************
    58.       * Calculate Timer1 Frequency *
    59.      ******************************
    60.       * Unsigned 32bit integer required to deal with large _XTAL_FREQ number.
    61.      */
    62.      
    63.     uint32_t freqTMR1 = PIC_CLK/4;        
    64.     switch(T1CONbits.T1CKPS) {                                    
    65.         case 0 : break;
    66.         case 1 : freqTMR1 = freqTMR1/2; break;
    67.         case 2 : freqTMR1 = freqTMR1/4; break;
    68.         case 3 : freqTMR1 = freqTMR1/8; break;
    69.     }
    70.     TMR1_FREQ = freqTMR1;
    71.    
    72.     T1CONbits.TMR1ON = 1; // Turn Timer1 On
    73. }
    74.  
    75. void initCCP1CaptureRising() {
    76.     CCP1CONbits.CCP1M    = 0x05;
    77.     /* write to the CCP1CON register, specifically the CCP1M (Enhanced Capture/Compare/PWM mode
    78.      * select bits) selection, and set '0101 = Capture mode, every rising edge'. All other bits
    79.      * in register are not used.
    80.      */
    81.     CCPR1 = 0;
    82. }
    83.  
    84. void initCCP1Interrupt() {
    85.     INTCONbits.GIE    = 1;    // Global interrupt enable. Enables all unmasked interrupts, must be set. Clears all interrupts also.
    86.     INTCONbits.PEIE    = 1;    // Peripheral interrupt enable. Enables all unmasked peripheral interrupts. Clears all associated interrupts also.
    87.     TRISC2            = 1;    // Pin CCP1 set to input.
    88.     PIE1bits.CCP1IE    = 1;    // CCP1 interrupt enable bit, RC2.
    89. }
    90.  
    91. void initDimensions() {
    92.     /**********************************************
    93.      * Calculate the number of H-pixels available *
    94.      **********************************************
    95.      * Circumference/LED width will give us the number of independent
    96.      * horizontal pixel positions we have available to use for given
    97.      * dimentions. Any fraction this sum produces can be truncated without
    98.      * causing much of an issue. This gets sent to a global variable.
    99.      */
    100.      
    101.     float numberPixelDivisions = (2*M_PI*RADIUS_ROTOR_MM)/LED_WIDTH_MM;
    102.     NUMBER_H_PIXELS = (uint16_t)numberPixelDivisions;
    103. }
    104.  
    105. /******************************************************************************************************/
    106.  
    107. void showMeTheLights() {
    108.     int i = 0;
    109.     int Array1[48]; // 48 is the max size an array can be on the PIC16F887. Use multiple arrays for more characters.
    110.  
    111.     Array1[0] = 0xFF; // Better way would to set up an array with 0x00, 0x01, 0x02... 0xFF and use the numbers to dictate which element to use.
    112.     Array1[1] = 0x81;
    113.     Array1[2] = 0x81;
    114.     Array1[3] = 0x81;
    115.     Array1[4] = 0x81;
    116.     Array1[5] = 0x82;
    117.     Array1[6] = 0x84;
    118.     Array1[7] = 0x78;
    119.    
    120.     while (i != 8) {
    121.         PORTB = Array1[i];
    122.         DelayBigUs((uint16_t)DELAY_H_PIXELS_US_ON);
    123.         PORTB = 0;
    124.         DelayBigUs((uint16_t)DELAY_H_PIXELS_US_OFF);
    125.         i++;
    126.     }
    127.     PORTB = 0;
    128.    
    129. }
    130.  
    131. interrupt void math() {
    132.    
    133.     /**********************************************************
    134.      * Calculate the the time of one revolution (H scan rate) *
    135.      **********************************************************
    136.      * Float wont evaluate a full 32 bit number, have to be careful here when
    137.      * using high clock frequencies. 1/freqTMR1 gives time in seconds it takes
    138.      * for 1 count of TMR1. Multiplying this by CCPR1 gives time in seconds    
    139.      * it takes for 1 revolution to occur. (float) cast on either CCPR1 or      
    140.      * TMR1_FREQ is absolutely neccessary - if performing maths with integers  
    141.      * even using a float type, the calculation is treated as an integers
    142.      * only, and truncates the fractional part of the answer (gay).
    143.      */
    144.  
    145.     float revolutionTime_S = (float)CCPR1/TMR1_FREQ; // Checked TMR1_FREQ = 31250.
    146.    
    147.     /************************************
    148.      * Calculate horizontal pixel delay *
    149.      ************************************
    150.      * Dividing the time it takes for 1 complete revolution by how many pixels
    151.      * we have available will give us the time it takes for the rotor to move
    152.      * from one pixel potition to the next.
    153.      */
    154.  
    155.     float horizontalDelay_US = revolutionTime_S/NUMBER_H_PIXELS;
    156.    
    157.     /**********************************************************
    158.      * Convert delay time to microseconds, reset timer & flag *
    159.      **********************************************************
    160.      * Convert the delay time in seconds to microseconds, and send that value
    161.      * to the specified global variable, then reset Timer1 and clear CCP1
    162.      * interrupt flag.
    163.      */
    164.    
    165.     float horizontalDelay_US = horizontalDelay_US*1000000;
    166.     DELAY_H_PIXELS_US = (uint16_t)horizontalDelay_US;
    167.     TMR1 = 0;
    168.     PIR1bits.CCP1IF    = 0;
    169. /*    PORTB = CCPR1;
    170.     PORTD = CCPR1 >> 8;
    171.     DelayBigMs(500);
    172.     PORTB = PORTD = 0;
    173.     PORTB = DELAY_H_PIXELS_US;
    174.     PORTD = DELAY_H_PIXELS_US >> 8;    
    175. */    
    176. /*    The above code was to check whether numbers were being calculated correctly. They were accurate.
    177.     Need to find good accurate delay function
    178. */                                    
    179.  
    180.     /********************************
    181.      * Combine delay and duty cycle *
    182.      ********************************/
    183.      
    184.     DELAY_H_PIXELS_US_ON = (DELAY_H_PIXELS_US/100.0)*LED_DUTY_CYCLE;
    185.     DELAY_H_PIXELS_US_OFF = (DELAY_H_PIXELS_US/100.0)*(100 - LED_DUTY_CYCLE);
    186.    
    187.     showMeTheLights();
    188. }
    189.  
    190.  
    191. void main() {
    192.     initDigitalOut();
    193.     initIntOscillator();
    194.     initCCP1CaptureRising();
    195.     initCCP1Interrupt();
    196.     initDimensions();
    197.     initTimer1();
    198.     while(1) {}
    199. }
    200. [/i]
     
Loading...