Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Using PicBasic with Output compare for sounds

Status
Not open for further replies.

mduong77

New Member
Hi, i guess i'll start off with what i'm trying to do:
I'm using a PIC18f4320 to take in analog values through AN0-AN3 and using those values to trigger sounds for a certain frequency and beep it 3 times for around 75ms each before stopping. These sounds will output from the PIC to two different speakers. Depending on values received from AN0-AN3, there are times when i want the PIC to output a tone through one speaker or the other speaker, and other times i would like it to output through both speakers.

now the problem:
i can't use freqout because it won't cause two different outputs at the same time, so there goes the simple answer. But i remember through a different processor (motorola 68HC12) that you could use output compare to create a tone of a for a certain amount of time. But i'm pretty new to PIC microprocessors and how to go about with BASIC programming.
 
If your PicBASIC will handle interrupts.

Make an interrupt routine that runs every X milliseconds. Have that interrupt routine start by looking at a byte (a singal byte) you set from the main program.

If the signal byte is 0 just exit. If it is a 1, toggle the first speaker on and off via a counter byte and state byte, flipping a bit to the speaker will get your tone. If the signal byte is a 2 then use a second counter byte and state byte and toggle the other speaker on and off. If a 3 toggle both and use their counter bytes and state bytes.
 
Thought about using interrupts and doing many things at the same time?

Using the TMR2 on the PIC you can create a very accurate small timed interrupt, say 1mS

Now every 1mS, the program will be interrupted and passed to the ISR (interrupt service routine)

With a couple of flags (Boolean expressions) you can control your outputs easily.

Heres a few snippets that might help (note that this is for use with a 20Mhz crystal, allowing a 20uS interrupt)

Just on that - You could make it faster, but at 20uS, it gives my program 100 lines of code to execute in between interrupts. eg, 10uS interrupt would limit me to 50 lines of code between interrupts - this leads to problems as not all of the program can be "executed/checked for values" between interrupts

Code:
Result = ADIN 0

Select Result
    Case 0 To 100
        Spkr_uS Delay = 100       ' Create a 5KHz tone later for both speakers
    Case 100 To 200
        Spkr_uS Delay = 200       ' Create a 2.5Khz tone later for both speakers
    .        
    .        
    .        
EndSelect

Loops = 0

Repeat 
    mS = 0

    Repeat
        If uS = Spkr_uS Then
            Speaker_1 = 1
            Speaker_2 = 1
        ElseIf uS = Spkr_uS * 2 Then
            uS = 0
            Speaker_1 = 0
            Speaker_2 = 0
        Endif
    Until mS = 75

    DelaymS 500

    Inc Loops
Until Loops = 3

Your ISR would look something like;

Code:
ISR:
GIE = 0

If TMR2_Overflow = 1 And TMR2_Enable = 1 Then
   TMR2_Overflow = 0
   uS = uS + TMR2_uS
   If uS >= 1000 Then
     uS = uS - 1000
     mS = mS + 1

  EndIf
EndIf

GIE = 1

Context Restore

And To setup TMR2, something like this would be needed;

Code:
Initialization: 

TMR2_Enable = 0

INTCON.6 = 1     ' Peripheral Interrupts   

T2CON.0 = 0     ' 00 = Prescaler is 1
T2CON.1 = 0     ' 01 = Prescaler is 4
                      '1x = Prescaler is 16 
PR2 = 19         ' TMR2 Period     ( * Creates a 20uS interrupt with 20Mhz crystal * )
T2CON.3 = 0   ' 0000 = 1:1 postscale
T2CON.4 = 0   ' 0001 = 1:2 postscale
T2CON.5 = 0   ' 0010 = 1:3 postscale
T2CON.6 = 0   ' 1111 = 1:16 postscale

TMR2 = 0       ' Reset TMR2 Value

TMR2_Enable = 1
TMR2_On = 1 

GIE = 1
 
gramo said:
Just on that - You could make it faster, but at 20uS, it gives my program 100 lines of code to execute in between interrupts. eg, 10uS interrupt would limit me to 50 lines of code between interrupts - this leads to problems as not all of the program can be "executed/checked for values" between interrupts

You think that a line of basic will execute in 200nS?

Mike.
 
The ISR routine (like most) would have to be coded in ASM.
 
Pommie said:
You think that a line of basic will execute in 200nS?

Mike.


My word some will, but other commands will take longer, hence the 20uS ISR to allow 100 instructions to be executed between each interrupt, an decent enough buffer in this simple program


Sceadwian said:
The ISR routine (like most) would have to be coded in ASM.
Mike.

Those days are over with new/updated compilers out there. But if you feel the need to go to asm;

Code:
ASM
    ' ASM Code
ENDASM
 
Just on ISR's, I have found that the best way to calculate the time required for different PIC Basic programs is to use one pin as a simple I/O, and Set it high at the start of the "Looping Routine", and the low at the end, allowing you to time how long the Program is taking.

Allow the above example to run for a while, and you will get a very good idea how much time you require between interrupts

This is very straight forward in a VSM like Proteus
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top