Electronic Projects, forums and more.

Go Back   Electronic Circuits Projects Diagrams Free > Electronics Categories > Micro Controllers


Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc.

Reply
 
LinkBack Thread Tools Display Modes
Old 6th January 2008, 06:22 AM   (permalink)
Default Output two different sine waves with 16F88 in C?

Hello,

Here's what's been bothering me now for a week and perhaps someone could please help me out...

I saw this Brain Machine circuit (Make magazine #10, article here: http://cachefly.oreilly.com/make/wp_brainmachine.pdf ) so I figured to build it. Since I'm a PIC and not an AVR guy I wanted to use what I have handy, a 16F88, thinking it's a fairly modern micro-controller.

In their circuit they use two AVR's built in timers that link to two oscillators (PWM) to generate different frequencies. Great, sounds pretty easy if only most PICs had more than one PWM (yes, I know there are some with two but they are in large packaging, and besides not handy).

My idea was, since there's only one PWM on most PICs to instead use two four bit sine wave ladders on port A or B or both, regardless (four bit sine wave example as seen here, towards bottom part of the page: http://homepage.ntlworld.com/moonsha...lectronics.htm )

Well, the problem is that I can generate one just fine and the output is pretty decent going through and RC filter, but how do I generate two sine-waves at the same time, having two different frequencies, let's say 205Hz and 215Hz?

I have been trying all kinds of things with timers and interrupts, and to be honest I am no expert in writing for micro-controllers (presently using CCS C) so I'm stuck and hoping someone here could enlighten me?

Thank you in advance.

Last edited by 3dluvr; 6th January 2008 at 03:29 PM.
3dluvr is offline  
Old 6th January 2008, 07:16 AM   (permalink)
Default

Did you watch the video demonstrating this thing?
Do you still want to build it?
__________________
--- The days of the digital watch are numbered. ---
kchriste is offline  
Old 6th January 2008, 03:29 PM   (permalink)
Default

Actually I watched author's presentation from the Chaos Communications Camp 2007 where he discussed brain entrainment and his device, which is nothing new really. But that's all beside the point, any ideas on how to achieve the above?
3dluvr is offline  
Old 6th January 2008, 04:05 PM   (permalink)
Default

Can't you just add the two sine waves in software and output them to the one PWM channel?

Mike.
Pommie is online now  
Old 6th January 2008, 04:11 PM   (permalink)
Default

How would I do that?

The sounds need to be so called binaural tones, where one is slightly higher in frequency than the other, ie. 200Hz and 211.4Hz and their difference causes the entrainment of the brain to 11.4Hz.

My understanding is that they need to be outputted at the same time not one following the other, or the effect won't work...

Plus, the tones need to go to different ears, one channel is one tone and the other channel is the other tone, left and right earphone.
3dluvr is offline  
Old 6th January 2008, 06:58 PM   (permalink)
Default

You could use two timers. One running at a (16 x 200Hz) rate and another at (16 x 211.4Hz) to trigger when to output a value from of your 4bit sine lookup table.
__________________
--- The days of the digital watch are numbered. ---
kchriste is offline  
Old 6th January 2008, 08:30 PM   (permalink)
Default

But could the output be simultaneous and independent from each other? If I use the higher nibble of port B for left channel and lower nibble for the right channel? Could you please mock-up an example for me?

In reality one channel/tone is always static and does not change, it's a fixed frequency of let's say 200Hz. The other channel would change depending on which brainwave range user wishes to entrain to (Delta, Theta, Alpha, Beta).

Then there are the LEDs that would need to be pulsed at that entrain frequency (11.1Hz for example for Alpha as used in the Brain Machine) along with the tones being produced.

Thanks.
3dluvr is offline  
Old 6th January 2008, 11:01 PM   (permalink)
Default

Quote:
But could the output be simultaneous and independent from each other?
Yes, if you used interrupts for both timers.
Quote:
If I use the higher nibble of port B for left channel and lower nibble for the right channel?
You can do that, though it would be easier if you used separate ports. To use the same port, you would have to read/modify/write to the port in your ISR without disturbing the "other" bits.
Quote:
Could you please mock-up an example for me?
Sorry I don't have CCS C as a compiler or any C compiler for the 16F series.
Quote:
In reality one channel/tone is always static and does not change, it's a fixed frequency of let's say 200Hz.
I would assign that channel to the timer with the least number of bits (TMR0 or 2) and use Timer 1 and the CCP for the variable tone channel.
Quote:
Then there are the LEDs that would need to be pulsed at that entrain frequency
They could be slaved off the TMR0 or 2 interrupt using a software counter to set the flash rate.
__________________
--- The days of the digital watch are numbered. ---

Last edited by kchriste; 6th January 2008 at 11:04 PM.
kchriste is offline  
Old 7th January 2008, 01:27 AM   (permalink)
Default

Thank you again for the direction pointers, I think I understand now (sort of).

I still have to figure out the interrupts and timers (noob) but using two different ports is not an issue since the chip will do nothing else but produce tones and flash LEDs.
3dluvr is offline  
Old 7th January 2008, 08:56 AM   (permalink)
Default

I didn't realise you needed the 2 signals to be separate. A possible solution would be to use a fixed interrupt of say 500uS and a 32 byte sine lookup table and simply step through the table each interrupt, then you will get a frequency of 1/(500*10-6*32) Hz = 62.5Hz. If we add 2 to our lookup table position then we will get a frequency of 2/(500*10-6*32) = 125Hz. If we want 211.4 Hz then we need to add 211.4*500*10-6*32 = 3.3824 which is not a very nice number. However, if we multiply 3.3824 by 256 we get 868 which is much nicer. If we add this number to a 16 bit variable and then shift the variable right 8 places, we can use the resultant value as our lookup value to get 211.4Hz.

If we also want 200Hz then 200*500*10-6*32 = 3.2. 3.2*256=819

The actual frequencies due to rounding errors would be,
868/(500*10-6*32*256) = 211.9
819/(500*10-6*32*256) = 199.9

Our interrupt would look something like,
(generic C)
Code:
void interrupt(){
    position+=868;
    PORTB=SineTab[(position>>8)&31];
    position2+=819;
    PORTA=SineTab[(position2>>8)&31];
}

or, if you want to use just port B,

void interrupt(){
    position+=868;
    Temp=SineTab[(position>>8)&31]<<4;
    position2+=819;
    PORTB=Temp|SineTab[(position2>>8)&31];
}
You could of course calculate the values in the background and put them in a variable.

Hope that makes sense.

Mike.
edit typo and changes nS to uS as pointed out by kcriste.

Last edited by Pommie; 8th January 2008 at 05:25 AM.
Pommie is online now  
Old 8th January 2008, 01:00 AM   (permalink)
Default

Thank you for the calculation, it seems better than mine...

Here is what I've done so far (yesterday night). I used timer0 and timer2, did not want to mess with the 16bit values in timer1 yet so my freq2 adjustment is rather crude, steps of 4 or so Hz.

Code:
#include <16F88.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP,PUT,CCPB3
#use delay(clock=8000000)

int i, j;

CONST unsigned int SINE_WAVE[30] = {
0b00010000, 0b10010000, 0b01010000, 0b11010000, 0b00110000, 0b10110000, 
0b01110000, 0b11110000, 0b01110000, 0b10110000, 0b00110000, 0b11010000, 
0b01010000, 0b10010000, 0b00010000, 0b11100000, 0b01100000, 0b10100000, 
0b00100000, 0b11000000, 0b01000000, 0b10000000, 0b00000000, 0b10000000, 
0b01000000, 0b11000000, 0b00100000, 0b10100000, 0b01100000, 0b11100000};

#INT_RTCC
void main_wave() {	
	if (i++ == 29)
		i = 0;
	output_b(SINE_WAVE[i]);
}

#INT_TIMER2
void TIMER2_isr() {	
	if (j++ == 29)
		j = 0;
	output_a(SINE_WAVE[j]>>4);
}

void main(void) {
	i = 0;
	j = 0;
	setup_adc_ports(NO_ANALOGS);    // Turn off analogue inputs
	setup_oscillator(OSC_8MHZ | OSC_INTRC);   // Use internal 8MHz osc 
	set_timer0(0);

	setup_counters( RTCC_INTERNAL, RTCC_DIV_1 | RTCC_8_BIT);
        // about 258.7Hz
	
        setup_timer_2( T2_DIV_BY_4, 65, 1 );
        // 65 gives 250.8Hz

        enable_interrupts(INT_TIMER0);
        enable_interrupts(INT_TIMER2);
	enable_interrupts(GLOBAL);
	
	while(TRUE)
	{
		delay_ms(1);
	}
   
        disable_interrupts(INT_RTCC);
}
Any comments on improving the above are welcome.

Also, where do I stick the LED pulsing now in, so they pulse at the binaural beat (the frequency difference)?

Last edited by 3dluvr; 8th January 2008 at 01:04 AM.
3dluvr is offline  
Old 8th January 2008, 01:36 AM   (permalink)
Default

I don't understand your sine table. It seems to go 1, 9, 5, 13, 3, 11 .... which doesn't look very sinusoidal.

A quick play with excel gives a 20 byte sign table as,
7,9,11,13,14,14,14,13,11,9,7,5,3,1,0,0,0,1,3,5,7,9 ,11,13,14,14,14,13,11,9
Where,
7 represents 0
0 represents -1
14 represents +1

As for the binaural beat, I would guess that the LED should be on if one wave form is the opposite sign to the other waveform, but I suspect this would be twice the frequency. Maybe when A>0 and B<0 then LEN is on will work.

Mike.
Pommie is online now  
Old 8th January 2008, 03:03 AM   (permalink)
Default

The sine table is for a 4-bit based resistor network: 1k, 2k, 3k9, 8k2 which seems to work pretty good here (at least according to my scope)

Should I just tie the LEDs to the PWM instead of the one or the other timer, but then I'm afraid that pulsing would be off because the PWM and the timers would not be in the right sync?

If base freq is ~258.7 and second freq ~250.8 the difference is 7.9Hz and that would be the proper pulsing for the LEDs, but does that mean that they need to be on the whole time of those 7.9Hz (126.58227ms) or half the time 3.95Hz (63.29113ms) ?!

Thanks
3dluvr is offline  
Old 8th January 2008, 04:26 AM   (permalink)
Default

Quote:
Originally Posted by Pommie
Code:
void interrupt(){
    position+=868;
    PORTB=SineTab[(position>>8)&31];
    position2+=819;
    PORTA=SineTab[(position2>>8)&31];
}

or, if you want to use just port B,

void interrupt(){
    position+=868;
    Temp=SineTab[(position>>8)&31]<<4;
    position2+=819;
    PORTB=Temp|SineTab[(position2>>8)&31];
}
I'm trying to understand and implement the code above, where should we increase the position/position2 and how do we check we are at the end of the sine table to reset the position/position2?

Am I to presume you are using timer1 which is 16-bit, but you said 500ns which is 0.5us, so at 8MHz that's 1/4 of the instruction cycle or T1_DIV_BY_4 ?
3dluvr is offline  
Old 8th January 2008, 05:15 AM   (permalink)
Default

You won't be able to implement an interrupt at a 500ns rate on a PIC running at 8Mhz which gives you a 500ns instruction cycle. So Pommie's DDS method, while very elegant, won't work for you.
EDIT: OOpps. I see he really meant 500uS not 500ns!!!! So it will work at that rate:
Quote:
868/(500*10-6*32*256) = 211.9
__________________
--- The days of the digital watch are numbered. ---

Last edited by kchriste; 8th January 2008 at 05:21 AM.
kchriste is offline  
Reply

Bookmarks

Thread Tools
Display Modes



Similar Threads
Title Starter Forum Replies Latest
circuit help: square and sin wave input = square wave output spyghost Electronic Projects Design/Ideas/Reviews 2 28th April 2004 02:09 AM
Effects stephenpic Micro Controllers 6 19th January 2004 12:57 PM
VERY low voltage on output pins, please help! New2PIC Micro Controllers 1 18th January 2004 04:22 AM
How do I generate a potentiometer output? klick General Electronics Chat 3 23rd November 2003 03:26 PM
square waves into sine waves... any ideas???? bully_victim Electronic Projects Design/Ideas/Reviews 9 10th November 2003 05:46 PM



All times are GMT. The time now is 02:41 AM.


Electronic Circuits  |  Learning Electronics
Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.

eXTReMe Tracker