1

I've seen a lot of videos of people playing different kinds of music with piezo ... I got a constant squeak. I don't know how I can start doing at least a few different squeaks ? ( Using AT90USB647 )

int Start_Beep() {
    
    DDRB = 0b01000000; // DDRB |= (1<<PB6)
    
    for(int i = 0; i < 2000; i++) {
        PORTB ^= 0b01000000;
        char delay_cnt = 0xAA;
        while(delay_cnt){
            --delay_cnt;    
        }
    }
    return 5;
        
}

I'm doing just a little memory game where you are shown some kind of sequence using two diodes, and the player must repeat it using joystick.

My entire code, just in case...

#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

// Global
uint8_t Game[8];
int i;

uint16_t n = 500;



void ADC_Init() {
     // It is not necessary that the ADC uses 10 Bit so should configure
    // left adjustment (ADLAR = 1)
    ADMUX = (1<<MUX1 | 1<<REFS0 | 1<<ADLAR);
    // ADEN --> ADC Enable | ADSC --> ADC Start Conversion | ADPS --> ADC Prescaler Select Bits (16)
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS2);    
}
void PWM_Init() {
    OCR1A = 200;
    TCCR1A |= (1<<COM1A1);
    TCCR1B |= (1<<WGM13);   
}


unsigned int NewDelayValue() {

    while (ADCSRA & (1<<ADSC));

    unsigned char data = ADCH;

    return 100 * ((data>>5) + 1);


}



void delay(uint16_t time_ms) {
    for(uint16_t i = 0; i < time_ms ; i++) {
        for(uint16_t j = 0; j < 200 ; j++) {
            asm volatile ("NOP");
        }
    }
}

int Start_Beep() {
    
    DDRB = 0b01000000; // DDRB |= (1<<PB6)
    
    for(int i = 0; i < 2000; i++) {
        PORTB ^= 0b01000000;
        char delay_cnt = 0xAA;
        while(delay_cnt){
            --delay_cnt;    
        }
    }
    return 5;
        
}

void RandomNumber() {
    
    srand((unsigned int)time(NULL));
    for(unsigned int i = 0; i < sizeof(Game)/sizeof(Game[0]); i++) {
        int v = rand() % 2;
        Game[i] = v;
    }
}

void PlayDemo() {
    Start_Beep();
    for(i = 0; i < 8; i++) {
        if(Game[i] == 1) {
            PORTA = 0x80;
            delay(NewDelayValue());
            PORTA = 0x00;
            delay(NewDelayValue());
            //return;
        }
        else if (Game[i] == 0) {
            PORTA = 0x01;
            delay(NewDelayValue());
            PORTA = 0x00;
            delay(NewDelayValue());
            //return;
        }
        else {
            PORTA = 0x00;
        }
    }
}


uint8_t isRightButtonPressed(uint8_t PortValue) {
    if(PortValue & 0x08) {
        return 0;
    } else {
        return 1;
    }
}

uint8_t isLeftButtonPressed(uint8_t PortValue) {
    if(PortValue & 0x20) {
        return 0;
    } else {
        return 1;
    }
}

uint8_t isButtonPressed(uint8_t PortValue) {
    return isLeftButtonPressed(PortValue) || isRightButtonPressed(PortValue);
}

enum Button{
    LEFT = 1,
    RIGHT= 0    
};


enum Button waitForPress() {

    uint8_t x = PINF;

    while(!isButtonPressed(x)) {
        x = PINF;
    }
    // Debouncing
    delay(50); 
    while(isButtonPressed(PINF)) {
    }

    if(isRightButtonPressed(x)) {
        return RIGHT;   
    } else {
        return LEFT;
    }
}

int main(void) {
    MCUCR |= 0x80;
    MCUCR |= 0x80;
    DDRA = 0xFF;
    DDRB = 0xFF;
    // 0x20 / 0x08 --> Joystick
    PORTF = 0x28;
    
    ADC_Init();
    
    
    PWM_Init();
    
    
    
    RandomNumber();
    PlayDemo();
    
    while(1)
    {
        /*
        if(isRightButtonPressed(PINF)) {
            PORTA = 0x01;
        } else {
            PORTA = 0x00;   
        }
        
        if(isLeftButtonPressed(PINF)) {
            PORTA = 0x80;
        } else {
            PORTA = 0x00;   
        }
        */
        for(uint8_t index = 0; index < 8; index++) {
            enum Button btn = waitForPress();
            if(btn == LEFT && Game[index] == LEFT) {
                // Good
                PORTA = 0xFF;
                delay(n);
                PORTA = 0x00;
                //PlayDemo();
            } else if (btn == RIGHT && Game[index] == RIGHT) {
                // Good
                PORTA = 0xFF;
                delay(n);
                PORTA = 0x00;
                //PlayDemo();
            } else if (btn == RIGHT && Game[index] != RIGHT) {
                PORTA = 0xFF;
                break;
            } else if (btn == LEFT && Game[index] != LEFT) {
                PORTA = 0xFF;
                break;
            }
        }
    }
}

Ximaks
  • 105
  • 6
  • 4
    Use the PWM hardware in your timer peripheral, not some home-made dirty hack loop. – Lundin Aug 25 '20 at 12:34
  • 1
    is it an active buzzer or passive buzzer? – Juraj Aug 25 '20 at 13:16
  • 2
    Let a beginner use a dirty hack loop before they have to start worrying about memory-mapped i/o! An important part of learning is trying inadequate solutions, understanding them, seeing why they're inadequate, and then moving to more sophisticated solutions. – John M Aug 25 '20 at 15:58

2 Answers2

1

Change delay_cnt accordingly: more delay between flipping PORTB ^= 0b01000000; state means a lower frequency, less delay means a higher frequency.

Generally though, depending on your chip, there may be a less intensive way of playing sounds, such as some PWM hardware.

AKX
  • 152,115
  • 15
  • 115
  • 172
  • 2
    The compiler is free to replace that whole skunky while loop with a no-op. Also `char` might not be able to hold 0xAA so it may start at a negative number and then downcount until underflow. When the compiler, again, is free to do whatever it pleases. What's worse is that if it even works as intended, it will busy-wait lock the whole MCU when the sound is playing. – Lundin Aug 25 '20 at 12:48
  • @Lundin - _ `char` might not be able to hold `0xAA`_. `0xAA` is 170 decimal, positive range of `char` is `127`. Curious why you said _might not_? – ryyker Aug 25 '20 at 12:57
  • 2
    @ryyker `char` can be either signed or unsigned, it's up to the compiler. https://stackoverflow.com/questions/2054939/is-char-signed-or-unsigned-by-default. One of many reasons why we never use `char` for any other purpose than holding strings. – Lundin Aug 25 '20 at 12:58
0

It seems that there is a problem with initialization of delay_cnt becaus it´s of type char. The range of type char is -128 to +127 so the value 0xAA (decimal 170) will become negative. So try to change the delay_cnt to type unsigned char:

int Start_Beep() {
    
    DDRB |= (1<<PB6)
    
    for(unsigned int i = 0; i < 2000; i++) {
        PORTB ^= (1<<PB6);

        unsigned char delay_cnt = 0xAA;

        while(delay_cnt){
            --delay_cnt;
        }
    }
    return 5;       
}

Let me know if it works...

sunriax
  • 592
  • 4
  • 16