Counter incrementation with atmega32u4

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

Hi,

 

I'm currently working on a project using the counter and interrupts. I have moslty completeted the project but i'm stuck on the counter incrementation part.

 

The following is my interrupt body:

ISR(INT0_vect)
{
    
        PORTD |= (1<<6);                         // Turns ON BLUE LED
        _delay_ms(1000);
        
        counter++;                              // counter increments
    
    if (counter = ?)
    {
        i++;
    }
}

 

In the above condition i want to know what is the MAXIMUM(?- in the pgm) value till the counter increments, so that when the counter reaches its MAX value, i can increment i++ and the counter automatically resets to ZERO. So, i want to know the overflow value of the counter in the atmega32u4.

Thankyou. 
 

This topic has a solution.
Last Edited: Sat. Oct 29, 2016 - 04:37 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

No one can answer this until you show your definition of the "counter" variable. Is it char, int, unsigned char, long, uint16_t, int32_t or something else? They all have their own upper limit which is going to be some power of 2 but until you tell us what the type is it's impossible to say what "MAX" is.

 

In passing I'll point out that when you eventually get there you will want to test:

if (counter == ?)

not

if (counter = ?)

(that is two '=' to test equality not one, which would mean assignment).

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

I would test for zero, regardless of the max value (which will vary by the size of counter), when it rolls over it will be 0 (assuming it is an unsigned variable!).

Jim

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

 

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

Actually an interesting approach (assuming unsigned) might be to use:

counter = 0;

...
ISR() {
    counter--;
    if (!counter) {
        i++;
    }
}

Now you don't need to know the width/MAX value for "counter" because the first "counter--" after it starts at 0 will will set it to MAX. So if it is "unsigned char" then counter-- will set it to 255 and it will count down from there to 0. If it is "unsigned int" it will decrement to 65535. If it is "unsigned long" then 4294967295 etc.

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

And since you are using a 1-second delay within your interrupt routine, even an 8-bit variable won't overflow until more than 4 minutes have passed... (assuming constantly firing interrupt sources)

Einstein was right: "Two things are unlimited: the universe and the human stupidity. But i'm not quite sure about the former..."

Last Edited: Tue. Oct 25, 2016 - 03:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In addition, i have a strange feeling that the OP mixed up the hardware counter of the AVR with his own variable, as well as the discussion around a certain MAXIMUM defined for the different modes of an AVR Timer/Counter module vs. his opinion about the "capacity" of his counter variable.

Einstein was right: "Two things are unlimited: the universe and the human stupidity. But i'm not quite sure about the former..."

Last Edited: Tue. Oct 25, 2016 - 03:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Using a 1s sw delay in an interrupt is "not good". Il assume itis pseudo code, and not in your real program.

 

When using a counter for timing things the overflow of your counter always needs some attention.

An often used trick is to calculate the "time lapsed" interval by subtracting 2 values.

The subtraction generates a positive difference and this also eliminates problems with overflow of your "tick" variable.

volatile int8_t tick;

ISR(){
    ++tick;
}

main(){
    int8_t old;

    ...
    old = tick;
    while (( tick - old) < 10)
    ;   // delay of 10 ticks.

}

This is a much better technique than just making all timer variables bigger. (needs more ram, flash, computing cycles, more jitter).

The 32 bit ms tick in the "arduino" world will still overflow every  42 days.

Note that recently a similar bug was found in a Boeing 787.

https://duckduckgo.com/html?q=bo...

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

Last Edited: Tue. Oct 25, 2016 - 11:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks everyone for valuable replies. I'm using unsigned int as counter data type. So i suppose it will count till 65535 and then reset. That would be ideal for me. :)

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

Also, im using UART for communication but i cant sent values such as 12,23,100 etc and also characters as abc,abcd etc. Only thing i'm able to view in Tera Term terminal are SINGLE characters as in if i sent abcd, only d is obtained on the terminal. 

void uart_transmit(unsigned int value)
{
    // wait for empty transmit buffer
    while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) );
    // put data into buffer, sends data
    UDR1 = value;
    
}

j=12;
         
          j = uart_receive();
          uart_transmit(j);  // send value

These are the functions for uart.

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

The uart_transmit() routine only transmits a single byte on each call to the routine.

To transmit a string (e.g. "abcd") you will need to send 4 individual characters.

This is usually done by doing something like:

void uart_put_string (const char *str) {
	while (*str) {		// Output till first 0
		uart_transmit (*str++);
	}
}

 

If you are trying to send an int, then you must first convert it to its ASCII representation (unless the receiver KNOWs it is receiving binary) doing something like:

void uart_put_int( const int val ) {
	char buffer[10];
	uart_put_string( itoa( val, buffer, 10 ) );
}

 

David

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

I have read about this. I'm senting the integers via uart. There is no requirement for writing anything. I just  want to read the data's being sent via uart. I connected the serial port and opened Tera Term terminal with same baud rate and such. Still if i sent '1' then it continuosly reads 1 but '123' etc doesnt read at all. Since Uart sents 8 bit datas at the maximum, i wonder why it doesnt even sent 123,120,255 etc. Also Tera Term reads both ASCII and integers, i guess.

 

Also the numbers I want to get on the tera term terminal will range from 0- ALOT coz the number i'm retrieving is{ j= (i*65535)+counter }where counter will range from 0- 65535 and i will range from 0- any number till it stops incrementing (i++).

So can i can get these huge numbers via uart? If so , can you help me out.

Last Edited: Fri. Oct 28, 2016 - 07:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Why don't you just use the Arduino tools where the stuff that you've decided not to learn is already done for you? The 32u4 is used on the Arduino leonardo. Plenty of examples.

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

A "huge number" is just a sequence of characters. So when you type 1, 2, 3 in TeraTerm what the AVR receives is '1', '2', '3'. If you put those together you have a string: "123". Of course you don't know yet if there are more digits to come (is it "1234" or "123456") so you need to recognize some kind of "that's the end of the number" indicator. The usual one is the [Enter] key which when typed on the PC should appear on your AVR as either just '\n' or '\r','\n'. So if you keep adding the characters you receive into an array of characters until you see '\n' then your buffer will either contain "123\r" or just "123". Once you have built your received buffer in this way you can then call the C function atoi() which stands for Ascii TO Integer and it will convert the ASCII characters "123" into the binary value 123.

 

To achieve all this you first need uart_getcharacter() routine that can receive one character at a time. Then you need a uart_getstring() function which keeps calling uart_getcharacter() until it sees '\n' and it builds an array of char[] until that happens (or the space in the array runs out). And finally you return that string and pass it as input to number=atoi(string_buffer) and finally "number" holds 123.

 

This has been done a thousand million times in computer programs all over the world. Many have been posted on the internet.

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

Thanks for your replies. I''ll look into this sort of implementation. 

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

I have tried to sent via UART in the following way:

//main

j='1234';
         
          x[0]=j/1000; // this is the first digit
          x[1]=(j % 1000)/100; // this is the second digit
          x[2]=(j % 100)/10; // this is the third digit
          x[3]=(j % 10); // this is the fourth digit
          uart_transmit(x[0]);  // send value
           uart_transmit(x[1]);
            uart_transmit(x[2]);
             uart_transmit(x[3]);
          _delay_ms(250);
// ends

void uart_transmit(unsigned char value)
{
    // wait for empty transmit buffer
    while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) );
    // put data into buffer, sends data
    UDR1 = value;
    
}

and still no luck in the pursuit. and also can't find many examples were pgms are being done using this sort of implementation via uart.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*
 * GccApplication1.c
 *
 * Created: 9/21/2016 10:44:50 AM
 * Author : Work
 */ 

#include <stdio.h>
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#define F_CPU 16000000UL


# define UART_BAUDRATE 9600
//# define BAUD_PRESCALE (((F_CPU / (UART_BAUDRATE * 16UL))) - 1)
# define BAUD_PRESCALE (((( F_CPU / 16) + ( UART_BAUDRATE / 2) ) / ( UART_BAUDRATE )) - 1)



unsigned char pulse, x[4];
unsigned int a[10], counter=0, i=0, j=0;	
  

// initialize uart
void uart_init(void)
{
	// set baud rate
	
	UBRR1H = (BAUD_PRESCALE >> 8);
	UBRR1L = BAUD_PRESCALE;
	
	// enable received and transmitter
	UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 );
	
	// set frame format ( 8data, 2stop )
	UCSR1C = ( 1 << USBS1 ) | ( 3 << UCSZ10 );
}

// transmit a char to uart
void uart_transmit(unsigned char value)
{
	// wait for empty transmit buffer
	while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) );
	// put data into buffer, sends data
	UDR1 = value;
	
}

// interrupt for pulse
ISR(INT0_vect)
{
	
	   // codes
	}
}

int main(void)
 {

    DDRD = 0b01000000;                           
    DDRC = 0b10000000;     
	                      
    // setup uart
    uart_init();
	
	EICRA |= ((0 << ISC01) | (1 << ISC00)); // any edge of INT0 will fire the ISR
	EIMSK |= (1 << INT0); // Enable INT0 interrupt, will call INT0_vect ISR when INT0 fires
	
	sei();				//Enable Global Interrupt
          
  while(1)
    {
                           
              //codes
      }   
	  
	//  j = (i * 65535) + counter;               // gives the current total pulses as output
	    
		j='1234';
		 
		  x[0]=j/1000; // this is the first digit
		  x[1]=(j % 1000)/100; // this is the second digit
		  x[2]=(j % 100)/10; // this is the third digit
		  x[3]=(j % 10); // this is the fourth digit
		  uart_transmit(x[0]);  // send value
		   uart_transmit(x[1]);
		    uart_transmit(x[2]);
			 uart_transmit(x[3]);
		  _delay_ms(250);
		                        // delay just to stop teraterm screen cluttering up
	  
    } 

        
    return 0;


}

So above is the body of my pgm. CAn you help me on what i'm doing wrong here?

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

aashi711 wrote:
j='1234';
Well stop right there.

 

In C do you understand the difference between 7, '7' and "7" ? If you don't then time to dig out your C reference manual and start learning. What you will learn is that '1234' is not valid and does not make sense.

Last Edited: Fri. Oct 28, 2016 - 10:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

remove the single quotes around the '1234' and try to get a decent understanding of the differences between an integer value, and an integer number represented in an ASCII string.

Einstein was right: "Two things are unlimited: the universe and the human stupidity. But i'm not quite sure about the former..."

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

Actually, i was trying stuff out and i do know the differences. I did sent the value as 1234 not '1234';

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

How can you write C if you don't know the difference between 1234 and '1234' ??

 

For your info anything in single quotes is a character representation of ASCII so things like 'W' or '7'. You put a SINGLE character within the quotes and C reads this as a character representation (ASCII) so 'W' is ASCII character number 87. So using:

char j = 'W';

is the same as typing:
 

char j = 87;

It's just that if you are really using this as the character W then 'W' is going to be more obvious to the reader of your code than 87. If you used:

char j = '7';

then the character '7' actually has the value 55 aka 0x37 (in fact '0'..'9' are all the digit they represent plus 48).

 

As you can only put ONE character between the single quotes then '1234' does not make any sense. C will give a warning then will actually assign 0x31323334 to the variable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*
 * GccApplication1.c
 *
 * Created: 9/21/2016 10:44:50 AM
 * Author : Work
 */ 

#include <stdio.h>
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#define F_CPU 16000000UL


# define USART_BAUDRATE 9600
//# define BAUD_PRESCALE (((F_CPU / (UART_BAUDRATE * 16UL))) - 1)
# define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2) ) / ( USART_BAUDRATE )) - 1)



unsigned char pulse, x[4], z;
unsigned int a[10], counter=0, i=0, j=0;	
  

// initialize uart
void usart_init(void)
{
	// set baud rate
	
	UBRR1H = (BAUD_PRESCALE >> 8);
	UBRR1L = BAUD_PRESCALE;
	
	// enable received and transmitter
	UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 );
	
	// set frame format ( 8data, 2stop )
     UCSR1C = ( 1 << USBS1 ) | ( 3 << UCSZ10 );

}

// transmit a char to uart
void usart_transmit(unsigned char value)
{
	// wait for empty transmit buffer
	while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) );
	// put data into buffer, sends data
	UDR1 = value;
	
}

// interrupt for pulse
ISR(INT0_vect)
{
	
}

int main(void)
 {

    DDRD = 0b01000000;                           
    DDRC = 0b10000000;     
	                      
    // setup uart
    usart_init();
	
	EICRA |= ((0 << ISC01) | (1 << ISC00)); // any edge of INT0 will fire the ISR
	EIMSK |= (1 << INT0); // Enable INT0 interrupt, will call INT0_vect ISR when INT0 fires
	
	sei();				//Enable Global Interrupt
          
  while(1)
    {
                           
    
	//  j = (i * 65535) + counter;               // gives the current total pulses as output
	    
		j= 1234;
// 		 z = j >> 8;
// 		 usart_transmit(x);
// 		 z = j & 0xFF;
// 		 usart_transmit(x);
		  x[0]=j/1000; // this is the first digit
		  x[1]=(j % 1000)/100; // this is the second digit
		  x[2]=(j % 100)/10; // this is the third digit
		  x[3]=(j % 10); // this is the fourth digit
		  usart_transmit(x[0]);  // send value
		   usart_transmit(x[1]);
		    usart_transmit(x[2]);
			 usart_transmit(x[3]);
             //usart_transmit(j);
 		  _delay_ms(250);
// 		                        // delay just to stop teraterm screen cluttering up
	  
    } 

        
    return 0;


}

Still, im unable to  get any of the digits. Any idea why?

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

Why are you not using itoa() ?

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

you mean like

itoa(j, x, 10); ??

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I mean this. The usual way to send muti-digit binary values to a human receiver (who reads ASCII) is to convert the number to a string of ASCII first. For example:

void uart_sendchar(char c) {
    wait UDRE
    UDR = c;
}

void uart_sendstring(char * str) {
    while(*str) {
        uart_sendchar(*str++);
    }
}

int main(void) {
    uint16_t n = 12345;
    char buffer[8];
    
    itoa(n, buffer, 10);
    uart_sendstring(buffer);
}

I have omitted things like uart_init() in that and have not really implemented the sendchar() correctly but that gives the essence of how you would normally transit a multi-digit number. Once you have uart_sendstring() you can also:

uart_sendstring("hello world");

so uart_sendchar() and uart_sendstring() are useful tools to have in your toolbox anyway.

 

Above your usart_transit() is really the same as my uart_senchar() s you already have the basis of this.

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

		j= 13;
		void uart_put_int( j ) {
			char buffer[10];
			usart_transmit( itoa( j, buffer, 10 ) );
		}

 tried doing this way with no  luck. 

I'll try doing the way you told me now.

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

You do not understand C. You can't program an AVR (or anything) in C until you have first learned the C language.

 

You appear to be trying to define a function called uart_put_int() in the middle of another function?!?

 

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

The j =13; is in the main program.

The function is out side as global function. Thought you would understand that. Sorry.

Last Edited: Fri. Oct 28, 2016 - 11:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I mean this. The usual way to send muti-digit binary values to a human receiver (who reads ASCII) is to convert the number to a string of ASCII first. For example:

void uart_sendchar(char c) {
    wait UDRE
    UDR = c;
}

void uart_sendstring(char * str) {
    while(*str) {
        uart_sendchar(*str++);
    }
}

int main(void) {
    uint16_t n = 12345;
    char buffer[8];

    itoa(n, buffer, 10);
    uart_sendstring(buffer);
}

I have omitted things like uart_init() in that and have not really implemented the sendchar() correctly but that gives the essence of how you would normally transit a multi-digit number. Once you have uart_sendstring() you can also:

uart_sendstring("hello world");

so uart_sendchar() and uart_sendstring() are useful tools to have in your toolbox anyway.

 

Above your usart_transit() is really the same as my uart_senchar() s you already have the basis of this.

itoa is finally working for numbers having 5 digits and not more. What if i need digits of 10 digits to display? I have to sent them by splitting into 2?

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

An "int" on an AVR has a range from -32768 to +32767. You cannot possibly have any more than 5 digits if using int. If you need more use a wider type such as long. You would then replace itoa() with ltoa(). But in my example the buffer[8] may not be long enough so make that bigger too. A long has a range from -2,147,483,648 to +2,147,483,647

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

Thanks. I'll check it out and if i may, whats the difference of Itoa() from itoa()? Is there a function Itoa()?

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

What would Itoa() do? How do you think it would be different to itoa()?

 

What is available is give in the user manual...

 

http://www.nongnu.org/avr-libc/u...

 

As you can see there:

Non-standard (i.e. non-ISO C) functions.

 
char *  ltoa (long val, char *s, int radix)
 
char *  utoa (unsigned int val, char *s, int radix)
 
char *  ultoa (unsigned long val, char *s, int radix)
 
   
 
   
 
   
 
char *  itoa (int val, char *s, int radix)

So there are four variants. Pick the "u/ul" ones for unsigned. The "i/l" ones for signed. Use the ones with "l" for long,the others for int.

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

Clawson was referring to ltoa, that's a lower case L. ltoa is Long TO ASCII

 

Edit: Clawson beat me to it... and with a lot more detail too

Last Edited: Fri. Oct 28, 2016 - 12:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys, esp Clawson. That was a great help. :D

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

All done. Thanks again :D

Last Edited: Sat. Oct 29, 2016 - 09:05 AM