Need help with passive piezo buzzer

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

Hello all,

I am having some trouble with an elegoo passive piezo buzzer that I am trying to use. I am trying to create a "pseudo-piano" program where (using a terminal) keys can be pressed (on a computer keyboard) and a buzzer plays a tone corresponding to the pressed key.

 

The problem I'm experiencing is that when I press a key, the buzzer makes a clicking sound (pitched lower than any of the intended tones) and the tone of the click does not change when different keys are pressed. I also tried writing simple code to play a single tone and I get the same result.

 

Here is my code for manipulating timer 0 (which controls the buzzer). I am using an ATMega 2560. I don't have the datasheet for the buzzer and the buzzer has no markings. The timer is set to CTC mode with 256 prescaler and toggles OC0A on timer compare match.

void initBuzzer(){
	DDRB |= 0b10000000;		//OC0A (PORTB 7, Pin 13) set as output

	TCCR0B |= (1 << WGM02);		//8-bit CTC mode
	TCCR0A |= (1 << COM0A0);	//toggle OC0A on compare match
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));	//stop timer 0

   	sei();          //Enable global interrupts by setting global interrupt enable
                        //bit in SREG
   	TCNT0 = 0;	//initialize timer counter at 0

   	TIMSK0 |= (1 << OCIE0A);	//enable timer0 compare A
   	return;
}

void startBuzzer(double freq){
	TCNT0 = 0;	        //start timer counter at 0

	//Set output compare value using frequency equation for CTC mode from
	//ATMEGA2560 datasheet:  Fclk = Foc / (2 * N * (1 + OCR))
	OCR1A = (int)(F_CPU / (freq * 2.0 * 256.0)) - 1;

	TCCR0B |= (1 << CS02);	//start timer 0 with 256 prescaler
	return;
}

I have included my files as attachments. This is my first post so I apologize if anything looks weird or if I am missing something important. I appreciate any help you can provide.

Thank you

 

 

Attachment(s): 

Last Edited: Tue. Jul 28, 2020 - 01:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want a passive buzzer ringing, you should give it a square wave signal.

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

The CTC mode for the timer/counter does generate a square wave signal as it toggles a pin on and off (5V and GND) every time the counter reaches the output compare value.

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

Welcome to the Forum.

 

A Moderator might move your Thread to another Sub-Forum, this one is for completed projects.

 

Please connect your piezo between +5V and Ground, and see if it makes a single click, or if it makes a nice tone.

Report back the result.

 

Please write a simple "Flash the LED" at once per second program, and run it with an LED.

See what the LED flashes at, (once / Second, or once every 8 Seconds, etc.).

This is a simple test to confirm that the microcontroller itself is running at the clock speed you think it is running at.

The I/O pin should be connected to a 330 or 470 or 510 or something similar resistor, which then connects to the LED, whose other lead connects to Ground.

 

If your piezo plays a nice tone when you supply +5V/Ground to it, it will be challenging to make it play a range of different tones.

 

If it simply clicks once, then it is truly a raw piezo without an internal driver, and you can drive it with a square wave.

If you change the frequency of the square wave it will change the tone. 

Note, however, that the piezo is designed to resonate at a given frequency, +/- a rather small amount.

If you drive it at a significantly higher or lower frequency, the output volume will be very low.

 

A "better" approach to making a simple electronic organ might well be to have the micro's I/O pin drive a small amplifier chip, and have that drive a small speaker, (or an external speaker for a PC, for example).  You can then play a wide range of frequencies.

 

JC 

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

this looks suspicious:

OCR1A = (int)(F_CPU / (freq * 2.0 * 256.0)) - 1;

Make sure it is giving the correct results. Or as a quick test, calculate by hand the required value and try that. eg: OCR1A = 100;

That will quickly determine if the problem is with the calculation or elsewhere.

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

DocJC wrote:

A Moderator might move your Thread to another Sub-Forum, this one is for completed projects.

I don't think I saw an option to select a subforum when I made this post, but I'll keep an eye out for it in the future.

 

DocJC wrote:

Please write a simple "Flash the LED" at once per second program, and run it with an LED.

See what the LED flashes at, (once / Second, or once every 8 Seconds, etc.).

This is a simple test to confirm that the microcontroller itself is running at the clock speed you think it is running at.

The I/O pin should be connected to a 330 or 470 or 510 or something similar resistor, which then connects to the LED, whose other lead connects to Ground.

I did this, and the LED did flash at the intended frequency as far as I could tell (looking at the led and at a stopwatch). I do not have an oscilloscope on hand to get more precise results unfortunately.

 

DocJC wrote:

If it simply clicks once, then it is truly a raw piezo without an internal driver, and you can drive it with a square wave.

If you change the frequency of the square wave it will change the tone. 

Note, however, that the piezo is designed to resonate at a given frequency, +/- a rather small amount.

If you drive it at a significantly higher or lower frequency, the output volume will be very low.

It only clicks once. I checked when I initially started this project (as I have an active piezo beeper that looks similar) and double checked just now. I am aware of the small volume at frequencies that are not aliases of its natural frequency, and I have created a simple circuit to amplify the sound. The result was louder clicking. I understand that it needs a square wave and that a change in frequency will change the tone. The code that I have provided should illustrate this.

 

DocJC wrote:

A "better" approach to making a simple electronic organ might well be to have the micro's I/O pin drive a small amplifier chip, and have that drive a small speaker, (or an external speaker for a PC, for example).  You can then play a wide range of frequencies.

I am looking to use parts I already have, and the issues with this project make me want to find out what's happening even more. :)

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

Kartman wrote:

this looks suspicious:

OCR1A = (int)(F_CPU / (freq * 2.0 * 256.0)) - 1;

From page 121 of the ATMega2560 datasheet:

After some quick math, I arrived at the equation used in the code.

 

Kartman wrote:

Make sure it is giving the correct results. Or as a quick test, calculate by hand the required value and try that. eg: OCR1A = 100;

That will quickly determine if the problem is with the calculation or elsewhere.

I calculated one of the OCR0A values by hand and hard coded it in, and I was able to get a good tone! Thank you for your help! Also I noticed that it should be OCR0A not OCR1A (which didn't prevent the clicking sound earlier, so that's interesting if nothing else). I will try to fix the output compare calculation statement. Suggestions are always welcome.

Last Edited: Tue. Jul 28, 2020 - 01:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After some experimentation, I've determined that the output compare calculation statement is fine after changing OCR1A to OCR0A. It looks like my issues lie in either the USART code or some combination of the USART and Buzzer code. I'm not sure what exactly is causing this (I've heard USART and timer/counters don't always play nicely together), so any help is appreciated.

 

The clicking that I have been experiencing is actually caused by the program crashing/restarting. The initialization code for the buzzer causes a single click to happen (when the pin connected to the buzzer changes state), and holding a key to play a tone was just causing repeated and quick crashes.

 

Here are my functions that interact with USART0.

void initUSART0Buzzer(){

        //Enable RX with 8 bit character frames in async mode
        UCSR0B = (1 << RXEN0);
        UCSR0C = (1 << UCSZ01)|(1 << UCSZ00);	

	//set baud rate (upper 4 bits should be zero)
	UBRR0L = BAUD_PRESCALE;
	UBRR0H = (BAUD_PRESCALE >> 8);
	return;
}


char getChar(){
	char temp = 'l';
	
	while((UCSR0A & (1 << RXC0)) == 0){}	//wait for receive complete flag set
	temp = UDR0;						//store received byte
	return temp;						//return received byte
}

 

Here is my main function. The value for the delay function will be changed in the future.

int main(){
        
        char key = '0';    //initialize key char
        initBuzzer();      //initialize timer0 for the buzzer
        initUSART0Buzzer();

	while(1){
		key = getChar();	//get next key
		playKey(key);		//play tone
		_delay_ms(1000);	//delay
		stopBuzzer();		//stop playing tone
	}
        return 1;    //loop exits unexpectedly
} 

 

I have verified that the playKey and getChar functions work properly on their own, but they cause a crash/restart when they are both used. In my main function, the crash occurs during the _delay_ms function.

 

I created the following code for troubleshooting purposes. As is, the program crashes after the first iteration of the while loop. Commenting the key = getChar statement causes the program to run fine. 


	key = getChar();	//get next key
	playKey('k');
	while(1){}

Please let me know what you think my issue is caused by. As always, I appreciate any help that can be offerred.

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

The equation was ok, but the question is how the compiler decodes it. You have mixed floats and integer variables and how the compiler determines how the operations are done. I would try to avoid such code or be-very explicit with casts to ensure the compiler does what i want.
Also, you don’t put code in header files unless you understand the implications.
As for the crash - how do you know the code crashes?

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

I switched the equation to only use integers, but haven't seen any difference. I considered this a possibility of a problem, but I don't think I fully understand how the compiler interprets using floating point and integer values in one equation. To my understanding, this should not be an issue due to the (int) declaration in the equation. Regardless, I changed it to (hopefully) have fewer questionable lines of code.

 

What do you mean exactly by the implications of header files? I've never had any issues working with them in the past.

 

I have a header file that I wrote some time ago that helps me interface with USART. I often use it to help with troubleshooting. It's a fairly standard bit of code to allow fprintf and fscanf to be used to read/write to the serial port. I've included it below.

 

In my code, I used fprintf to print out different strings at different points in the code. This way, I was able to discover the points at which the program would reset. I also used this to determine the values that were resulting from the aforementioned equation. In terms of a "crash" vs a reset, I can't say I'm perfectly versed on the exact difference. I know that crashes are unintentional and that a non-crash reset is usually intentional, but not the exact definition point of separation.

Attachment(s): 

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

I forgot to mention: I added a counter for troubleshooting. I would print it to the serial port and increment it every iteration of the while loop. One interesting thing is that the program does not reset when a key that is not mapped to a tone is pressed.

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

You mention floating point.....

get rid of it, I do not see the need for that in your simple program.

I think you can do it all with integer math...... A lot has been posted on that here.

 

//set baud rate (upper 4 bits should be zero)
	UBRR0L = BAUD_PRESCALE;
	UBRR0H = (BAUD_PRESCALE >> 8);

why not do UBR0 = BAUD_PRESCALE ?

will save you thinking about writing the 2 bytes in the right order.

 

It might be that the clicking is coming from re-starting the timer. if the OCR registers are actually opposite of what you initialize them to at the start of the next tone you wil get a klik as the piezo is activated by the switch in lines. You might need to add a bit were before you start putting out a tone you first check what the current status of the pins is and configure the timer accordingly.

 

 

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

Don't put code in header files! It's bad juju. Why? The compiler doesn't like you redeclaring stuff.  Whilst your current code doesn't suffer this.....at the moment. You've created a trap for yourself.

 

have a read of this:

https://www.avrfreaks.net/forum/...

 

 

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

Kartman wrote:
The compiler doesn't like you redeclaring stuff.  
Just to be a pedant but what the linker doesn't like is you redefining stuff devil

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

hey - that's my line!

 

laugh

 

More reading on the subject:  http://c-faq.com/decl/decldef.html

 

EDIT

 

https://www.avrfreaks.net/commen...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Jul 29, 2020 - 02:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for sending this. I think I understand use of header files a bit better after reading it. I attempted to implement this, and ran into some issues and questions. I'm sure there is something I am not quite grasping fully, so I appreciate any input on things that look funky.

Kartman wrote:

have a read of this:

https://www.avrfreaks.net/forum/...

 

I could not find a line in the makefile with something called SRC (like mentioned in the tutorial). However, I was able to find similarly named things (C_SRC, O_SRC, OBJ_SRC, etc). The top of the file had a commented block that said the file should not be edited, so I am skeptical about making changes to it directly. I was able to find this set of lines, and I think this means things are being linked correctly.

 

I do still have header files to declare things. My Buzzer.c and Buzzer.h are shown below as examples. Suggestions are appreciated.

 

Buzzer.h

#ifndef BUZZER_H_
#define BUZZER_H_

#include <avr/io.h>
#include <avr/interrupt.h>
#include "main.h"

#ifndef F_CPU
#define F_CPU 16000000
#endif

void initBuzzer();
void startBuzzer(int freq);
void stopBuzzer();

#endif

 

Buzzer.c

#include "Buzzer.h"


void initBuzzer(){
	DDRB |= 0b10000000;			//OC0A (PORTB 7, Pin 13) set as output
	
	TCCR0B |= (1 << WGM02);		//8-bit CTC mode
	TCCR0A |= (1 << COM0A0);	//toggle OC0A on compare match
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));		//stop timer 0
	
   	sei();    	//Enable global interrupts by setting global interrupt enable
                //bit in SREG
   	TCNT0 = 0;	//initialize timer counter at 0
	   
   	TIMSK0 |= (1 << OCIE0A);	//enable timer0 compare A
   	return;
}


void startBuzzer(int freq){
	int temp = 0;
	TCNT0 = 0;				//start timer counter at 0
	
	//Set output compare value using frequency equation for CTC mode from
	//ATMEGA2560 datasheet page 121:  Fclk = Foc / (2 * N * (1 + OCR))
	OCR0A = ((F_CPU / (freq * 2 * 256) / 2) - 1);
	
	//fprintf(&USART0_OUT, "%d", OCR0A);
	TCCR0B |= (1 << CS02);	//start timer 0 with 256 prescaler
	return;
}


void stopBuzzer(){
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));		//stop timer 0
	return;
}

 

With this, I've run into many errors that I need help interpreting. "count" is a variable only declared/defined in a single header file. I assume the multiple definition errors are caused by an issue with how I setup my header files. I have never seen a "Disabling relaxation" error before, and I am lost with this one.

 

For reference, here is my header file for main. The only header code (probably a better name for it) in main.c is the line: #include "main.h"

 

main.h

#ifndef MAIN_H_
#define MAIN_H_

#define F_CPU 16000000

#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include "USART0.h"
#include "Buzzer.h"	//custom header files
#include "USART0Buzzer.h"

void playKey(char key);	//play input key

#endif /* MAIN_H_ */

 

Regardless of my issues involving header files, I tried consolidating all of my code into main.c and removing all other files. Running the program yields the same results as before: program restarts after the first iteration of the while(1) loop.

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

Well the multiple def error is about "count" so in one of your nested header files you have a definition 

type count;

(Where type is int, char or whatever) rather than a declaration:

extern type count;

You can only put definitions in ONE of the .c filesbut you can have declarations for the same thing multiple times all over the place (as long as 'type' agrees).

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

J_Squared_ wrote:

Don't use this 'Error List' view!

 

Instead, look at the 'Output' window: https://www.avrfreaks.net/commen...

 

The 'Output' window shows you the full compiler output - which will not only say "multiple definitions" but will also tell you where all those definitions are !

 

The 'Error List', stupidly, strips that additional - very helpful -  information away (or, at least, disconnects it from the error message)

 

I really can't imaging how anyone thought that was a good idea?!

 

frown

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

J_Squared_ wrote:
"count" is a variable only declared/defined in a single header file.

Suggests you haven't understood the difference between a declaration and a definition.

 

Again, take a look at this: http://c-faq.com/decl/decldef.html

 

and this: https://www.avrfreaks.net/commen...

 

As described in that FAQ, and also by clawson, you must have exactly one definition; and you may have multiple declarations.

 

This is standard 'C' stuff - nothing specifically to do with AVR or Atmel Studio.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see what happened. I accidentally put a global variable (int count) in a header file while I was reorganizing things. I've moved it to the .c file where it should be. Thank you for pointing that out. The errors have been resolved, and the program compiles and runs.

 

I am currently still having the same issues as before: the program resets after one iteration of a while(1) loop. Here are the functions from my .c files

 

main.c

int main(void)
{
	
	char str[40] = "";
	char key = '0';	//initialize key char
	
	initBuzzer();	//initialize timer0 for the buzzer
	initUSART0();
	initUSART0Buzzer();
	
	/*
	//used for troubleshooting
	DDRB |= 0b00100000;			//OC0A (PORTB 7, Pin 13) set as output
	key = getChar();	//get next key
	playKey('k');
	while(1){
		PORTB ^= 0b00100000;
		fprintf(&USART0_OUT, "loop\n");
	}
	*/
    
	while(1){
		key = getChar();	//get next key
		playKey(key);		//play tone
		_delay_ms(1000);	//short delay
		stopBuzzer();		//stop playing tone
		//fprintf(&USART0_OUT, "loop\n");	//used for troubleshooting
	}
	
    return 1;	//loop exits unexpectedly
}


void playKey(char key){
	switch(key){				//switch statement for key tone to play
		case 'a':
			startBuzzer(2616);	//C key
			break;
		case 's':
			startBuzzer(2937);	//D key
			break;
		case 'd':
			startBuzzer(3296);	//E key
			break;
		case 'f':
			startBuzzer(3492);	//F key
			break;
		case 'j':
			startBuzzer(3920);	//G key
			break;
		case 'k':
			startBuzzer(4400);	//A key
			break;
		case 'l':
			startBuzzer(4662);	//Bb key
			break;
		case ';':
			startBuzzer(4939);	//B key
			break;
		default:				//default case (exit immediately)
			break;
	}
	return;
}

 

Buzzer.c

void initBuzzer(){
	DDRB |= 0b10000000;			//OC0A (PORTB 7, Pin 13) set as output
	
	TCCR0B |= (1 << WGM02);		//8-bit CTC mode
	TCCR0A |= (1 << COM0A0);	//toggle OC0A on compare match
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));		//stop timer 0
	
   	sei();    	//Enable global interrupts by setting global interrupt enable
                //bit in SREG
   	TCNT0 = 0;	//initialize timer counter at 0
	   
   	TIMSK0 |= (1 << OCIE0A);	//enable timer0 compare A
   	return;
}


void startBuzzer(int freq){
	int temp = 0;
	TCNT0 = 0;				//start timer counter at 0
	
	//Set output compare value using frequency equation for CTC mode from
	//ATMEGA2560 datasheet page 121:  Fclk = Foc / (2 * N * (1 + OCR))
	OCR0A = ((F_CPU / (freq * 2 * 256) / 10) - 1);
	
	TCCR0B |= (1 << CS02);	//start timer 0 with 256 prescaler
	return;
}


void stopBuzzer(){
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));		//stop timer 0
	return;
}

 

USART0Buzzer.c

int count = 0;


void initUSART0Buzzer(){
	//Enable RX with 8 bit character frames in async mode
	UCSR0B |= (1 << RXEN0);
	UCSR0C |= (1 << UCSZ01)|(1 << UCSZ00);	
	
	//set baud rate (upper 4 bits should be zero)
	UBRR0 = BAUD_PRESCALE;
	return;
}


char getChar(){
	//fprintf(&USART0_OUT, "count: %d\n", count);		//used for troubleshooting
	count++;
	char temp = 'l';
	
	while((UCSR0A & (1 << RXC0)) == 0){}	//wait for receive complete flag set
	temp = UDR0;						//store received byte
	//fprintf(&USART0_OUT, " received: %c ", temp);	//used for troubleshooting
	return temp;						//return received byte
}

 

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

awneil wrote:

J_Squared_ wrote:
"count" is a variable only declared/defined in a single header file.

Suggests you haven't understood the difference between a declaration and a definition.

Having a variable in a header file was a result of a brain fart surprise ..oof.. The wording I used was referring to the constants (e. g. #define SOMECONSTANT 23) that are in the header file. To my understanding, it is common to have these constants in header files, and the statements that create them are considered definitions. Please let me know if I am wrong somewhere so I can fix my code (or perhaps my language).

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

Sorry, I deflected the discussion towards code quality and away from your core problem. Nevertheless, you've got to put the quality in up front otherwise it bites you at the end.

 

Back to the core problem - your code doesn't work as you'd like. Seems you've done some debugging that has yielded some results. I've not fully grasped what the problem description is, but there's a long delay in your code and that's going to affect how often you poll the usart. This can give the appearance of the code crashing, but in reality the code is working fine but not quite how you'd like.

Rather than one large delay, think about using a smaller delay, but count a number of them for a longer one. Arrange your code so that it does a number of things per loop. ie:

loop()

{

little delay

test for char from usart

if key pressed, load timer with freq and load count with the duration/ little delay

decrement count

if count == 0, stop tone.

}

that way your system is more responsive.

 

As for timers and usarts not playing well together, that's a load of bollox. In your instance, the timers are not using interrupts, so there should be zero impact on the usart code.

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

No worries Kartman. if nothing else, this project has turned into an interesting learning experience about header files and proper creation of modular code.

 

Back on topic. I implemented the following changes to my main.c loop:

	fprintf(&USART0_OUT, "Entering loop\n");	//should only be encounterred once
	while(1){
		for(int i = 0; i < 5; i++){}	//short delay
		
		key = getChar();	//get next key
		//fprintf(&USART0_OUT, "Key is: %c   ", key);
		playKey(key);		//play tone
		
		_delay_ms(1000);	//short delay
		stopBuzzer();		//stop playing tone
		
		fprintf(&USART0_OUT, "loop count: %d\n", counter);	//print number of loop iterations
		counter++;
	}
	
    return 1;	//loop exits unexpectedly
}

Where counter is an int and key is a char; both are local to int main().

 

Using this, the output at my terminal is:

Entering loop

loop count: 0

Entering loop

loop count: 0

Entering loop

...

where each new key I press causes "loop count: 0" to be printed, following by a reset (shown by the entering loop message).

 

I changed the delay to _delay_ms(1); This resulted in a second iteration of the loop before the reset (output shows "Entering loop\n loop count: 0\n loop count: 1" that repeats).

I then changed the delay to _delay_us(1); This resulted in no resets (output shows "Entering loop\n loop count: 0\n loop count 1\n loop count 2\n loop count 3\n loop count 4\n ..."). No resets is good, but I'm still not getting any sound from my buzzer. I then changed the delay to for(int i = 0; i < 5; i++){} for a shorter delay that does not use any libraries. This gave the same result as using _delay_us(1);

 

I tried the following code for more information on possible issues:

	DDRB |= 0b00100000;			//OC0A (PORTB 5, Pin 11) set as output
	//key = getChar();	//get next key
	playKey('k');
	_delay_us(1);
	fprintf(&USART0_OUT, "Entering loop\n");
	while(1){
		_delay_us(1);
		PORTB ^= 0b00100000;
		fprintf(&USART0_OUT, "loop count: %d\n", counter);
		counter++;
	}

The buzzer produced a good sound and a correct tone. Unfortunately, this was my terminal. I tried the same code without the delays and had the same result. Looks to me like the issue lies in the buzzer code somewhere.

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

Might be time to have a look at the hardware.

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

that looks like power failure at first glance. add a big capacitor ( 10uF or so) the piezo does not take much DC current, but does need current to make sound.

 

first btw what happens when you disconnect the buzzer? does it then do the same or is all OK then?

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

Adding a cap and disconnecting the buzzer both yield the same results. The buzzer is able to produce a fairly loud sound when the getChar function is commented out. I can't imagine getting input from the buffer for USART would use enough additional power to cause the microcontroller to lose power. Especially since the program uses this buffer anyway when it sends and transmits data.

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

You do use an external crystal?

You have set the fuses correct for the crystal you use?

You have adjusted the F_CPU parameter in your project to match that specific crystal frequecy?

You have confirmed that the crystal is running correct and stable ( right decoupling caps used) ?

You have enough decoupling capacitors near the processor, and a larger buffer capacitor ( 10uF to 100uf )

You have removed floating point stuff for plain text writing ( which already seems to go wrong) ?

You have no compiler warnings after you have recompiled your entire project?

 

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

I am not using an external crystal and the floating point stuff was all changed to use ints. There are no warnings, errors, or messages in the error list when compiled.

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

Firstly:

TCCR0B |= (1 << WGM02);		//8-bit CTC mode
	TCCR0A |= (1 << COM0A0);	//toggle OC0A on compare match
	TCCR0B &= !((1 << CS02)|(1 << CS01)|(1 << CS00));		//stop timer 0

When initialising the peripherals, don't use |= or &=. Just do a direct assignment so you know exactly what value is stored. If there is a bootloader involved, it may have played with the hardware so it may not be in the state you expect.

 

That's not to say there are hardware issues as well. If there is more than one defect at play, that can confuse things. Do not underestimate the complexity of what you might think is simple -there's a lot that has to be right for it to work.

 

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

Who told you to use  |=   or  &=  instead of  =  ....??  I'm not sure where you got this idea, or exactly where it emanates from.  To be safe you should configure all of the bits---don't leave things to chance.

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

J_Squared_ wrote:

I am not using an external crystal and ..........

 

For a sustainable good uart you need an external crystal to start with. The internal RC oscillators of almost all ATmega chips are not stable enough.