atmega328 input capture

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif

#define BAUD 9600                                 // define baud
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
#define __DELAY_BACKWARD_COMPATIBLE__
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>

uint16_t capture1 = 0;
uint16_t capture2 = 0;
uint16_t capture3 = 0;
uint16_t capture4 = 0;
int count = 0;
uint16_t base_period = 0;
uint16_t capture3_OF = 0;
double capture2_OF = 0;
double base_overflow = 0;
uint16_t overflow_count = 0;
uint16_t overflow_count_1 = 0;
uint16_t overflow_count_2 = 0;
const uint16_t overflow_constant = 64;
uint16_t modified_base_period = 0;
int start_up = 0;
int i = 0;
char store_array[8];

ISR(TIMER1_CAPT_vect){

 
    
    capture1 = ICR1L;
    capture2 = ICR1H;
    capture2 = capture2 << 8;
    capture3 = capture1 + capture2;
    

     itoa(capture3, store_array, 10);
    for (i = 0; i < strlen(store_array); i++){
        UDR0 = store_array[i];
        while (( UCSR0A & (1<<UDRE0))  == 0){}
    }

       UDR0 = '\n';                            // new line
       while (!(UCSR0A & 0b00100000));
       
       UDR0 = '\r';                            // carriage return
       while (!(UCSR0A & 0b00100000));
       

}

int main(void)
{
    cli();
    UBRR0H = (BAUDRATE>>8);                      // shift the register right by 8 bits
    UBRR0L = BAUDRATE;                           // set baud rate
    UCSR0B |= 0b00011000;                        // enable receiver and transmitter
    UCSR0C |= 0b00000110;
    TCCR1B|=(1<<ICES1)|(1<<ICNC1)|(1<<CS10)|(1<<CS12);
    TIMSK1|=(1<<ICIE1); //|(1<<TOIE1);
    
    DDRD |= 0b00100000; 
    PORTD =  (PORTD & !(1 << PORTD5));
    TCNT1 = 0;
    
    sei();
    _delay_ms(2000);
    
    while (1) 
    {
     
     
    
    
 
   
   
    }
}

Last Edited: Thu. Aug 4, 2022 - 07:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using timer1 and send a toggle signal on pin 8.  I do get a serial on every positive edge of the input. The only problem is I get a negative number with every other number.  I have no ideal what I am doing wrong here. I mean I go to the input capture interrupt and get the timer value and store it. I add the two 8 bit numbers after shifting the high byte. Now even if I use IRC1 and not the lower and upper byte I still get the same thing. The numbers should be between 0 and 65535 only.  Grateful for any advice and help, I'm sure its something simple. 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Engineer5000 wrote:

The numbers should be between 0 and 65535 only.

Use the utoa function.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

did you look up itoa

If base is 10 and value is negative, the resulting string is preceded with a minus sign (-). With any other basevalue is always considered unsigned

 

In other words the value given must be treated as a signed value (there are no other parameters included to supply a sign).  Hence value must likely be treated as 2's complement, which you ignore.....you need a wider range use a unit32_t.

 

also why all the vars to calc the value?  Can't you just say  myval= ICR1; & it will take care of thee H &L on its own?

 

In your setup, all setting should use = not  |= or &=.  Use only =  to establish your settings.

 

Don't convert & print in the irq!!! , do that in main...use volatile for shared variables (your value)  .set a flag in IRQ to show a new value is ready to print.

in main the flag tells to convert & print & reset the flag

 

Now you are ready to write round 2

 

edit:  Actually, your setup itoa  might not work with a uint32_t (itoa is not standard everywhere), so you will have to try it yourself.  There's other alternatives like variations of sprintf.

But move the code out of the IRQ first!!

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Aug 4, 2022 - 08:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW this code looks like a terrible design. You really don't want to be doing "long operations" like itoa/utoa conversions and UART string transmission from inside and ISR()! How many interrupts will occur and be missed in the time it takes to convert and transmit just one value?

 

What you should do is just collect the capture value in the ISR, maybe store to an array or perhaps a running average then, at leisure, in the while(1) in main() you convert and transmit the value without missing capture events.

 

EDIT: oh and something like:

    for (i = 0; i < strlen(store_array); i++){
        UDR0 = store_array[i];
        while (( UCSR0A & (1<<UDRE0))  == 0){}
    }

       UDR0 = '\n';                            // new line
       while (!(UCSR0A & 0b00100000));
       
       UDR0 = '\r';                            // carriage return
       while (!(UCSR0A & 0b00100000));

if you find yourself doing the same thing three times in a row consider putting that in a function. In fact you probably want a single UART_sendChar() and then build on top of that a UART_sendString()

Last Edited: Thu. Aug 4, 2022 - 10:52 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Engineer5000 wrote:
 

    capture1 = ICR1L;
    capture2 = ICR1H;
    capture2 = capture2 << 8;
    capture3 = capture1 + capture2;

 

Better read the datasheet:

 

/* Read ICR1 into i */
i = ICR1;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Thanks so much for the reply. I've used a 32 bit variable and it would not print anything out. I also used the ICR1 and got the pretty much the same result. I am sending a 2 second digital high/low signal so not worried about 

missing anything, I do the =| so I dont change any of the other bits. Good point on printing out of the ISR. I will try that. However, I should not be getting a negative number, it should only be between 0 and 65535 since its out of the timer1 register. I wont be using the print in the end result, I just want to make sure I am getting the right result at the moment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For the moment just shift your value over 1 spot (divide by 2, so less than 32768), then all this negative stuff will evaporate...you have so many other issues to work on, it is best to put this one quickly aside, even with a temp workaround.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Engineer5000 wrote:

However, I should not be getting a negative number, it should only be between 0 and 65535 since its out of the timer1 register.

itoa vs utoa simulated on Falstad: