Show Posts
Pages: 1 [2] 3 4 ... 6
16  Forum 2005-2010 (read only) / Syntax & Programs / Question about variable scope and processor load on: May 28, 2009, 09:29:48 pm
Hi all,
      I have a question about how variable scope works.  As I understand it, if you define a variable in the setup() loop, it's only accessible within setup().  Ditto for the loop() functions, or interrupt routines.

Say that I put a variable declaration within loop(), like so:

Code:
void loop() {
int myvariable;

//some other code here...
.
.
.

} //end loop()

does that mean that the processor will spend time finding a spot in memory for that variable every time it rolls through loop(), or is it smart enough to skip that instruction after the first time?

What if I define and initialize the variable, e.g.


Code:
void loop() {
int myvariable = 24; //now I have set an initial value

//some other code here...
.
.
.

} //end loop()
17  Forum 2005-2010 (read only) / Syntax & Programs / Re: Need help for fast (10bits) analogRead & serial TX on: May 28, 2009, 09:20:13 pm
Software serial is if anything going to be slower, because the hardware USART does a lot of things (like automatically generating start and stop bits) that the software serial library has to emulate in software.

For the timeframe of <1mS, you should be able to do everything with the default arduino functions with plenty of time left over.

Note also that you can set the serial baud rate faster than even the 115200baud listed as the max baud rate in the Arduino IDE.  I've set the baud rate to 250000 and still been able to send and receive with no errors, although I had to optimize the code pretty carefully in some places.  Not sure how well Processing will support those speeds, though.

18  Forum 2005-2010 (read only) / Syntax & Programs / Re: Interrupts... on: May 27, 2009, 03:56:42 am
Quote
Ideally, I will need to disable all external interrupts and all timers except the one I'll be using...

If I'm understanding your goals right, you won't need to disable the other timers.  While in an interrupt, no other interrupts can run, so nothing can interfere with your 1000Hz timer.

As far as generating a 1000Hz square wave, though, you could probably get that just by manually configuring the PWM frequency.  That way, it would be set and forget, and you would have 100% of your processor speed left over to do other things.

Also, beware of trying to do an analogRead() inside an interrupt-- it takes a long time to run, and so you risk locking up your program.

19  Forum 2005-2010 (read only) / Syntax & Programs / Re: using the Timer1 library for PCM audio output on: May 26, 2009, 03:22:39 pm
Okay, I did get it working by manually configuring timer1.  Changes in capacitance are reflected as a change in frequency in the speaker output.

It's definitely quick and dirty, but fwiw here's the code (I'm using Paul Badger's capacitance sensing code here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1171076259):
Code:

int  i;
unsigned int x, y;
float accum, fval = .20;    // these are variables for a simple low-pass (smoothing) filter - fval of 1 = no filter - .001 = max filter
long fout;

int period = 160;


char sineovertones[] = {0,84,106,99,113,127,107,79,71,51,1,-26,7,43,23,-17,-26,-23,-43,-60,-49,-44,-66,-63,0,63,66,44,49,60,43,23,26,17,-23,-43,-8,26,-1,-51,-71,-79,-107,-127,-113,-99,-106,-84};


char sine[] = {0, 22, 44, 64, 82, 98, 111, 120, 126, 128, 126, 120, 111, 98, 82, 64, 44, 22, 0, -22, -44, -64, -82, -98, -111, -120, -126, -128, -126, -120, -111, -98, -82, -64, -44, -22};
//a simple sine wave with 36 samples

int analog0 = 160; //variable used to store analog input pin 0

byte speakerpin = 3;  //audio playback on pin 3.  This can also be set to pin 11.
 
volatile byte waveindex = 0; //index variable for position in waveform array Sine[]
volatile byte currentvalue = 0;

void setup() {
  
Serial.begin(57600);
  
/************************** PWM audio configuration ****************************/
// Configures PWM on pins 3 and 11 to run at maximum speed, rather than the default
// 500Hz, which is useless for audio output

pinMode(3,OUTPUT); //Speaker on pin 3

cli(); //disable interrupts while registers are configured

bitSet(TCCR2A, WGM20);
bitSet(TCCR2A, WGM21); //set Timer2 to fast PWM mode (doubles PWM frequency)

bitSet(TCCR2B, CS20);
bitClear(TCCR2B, CS21);
bitClear(TCCR2B, CS22);
/* set prescaler to /1 (no prescaling).  The timer will overflow every
*  62.5nS * 256ticks = 16uS, giving a PWM frequency of 62,500Hz, I think.   */

sei(); //enable interrupts now that registers have been set
  
  
/************************* Timer 1 interrupt configuration *************************/

cli(); //disable interrupts while registers are configured

bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);
/* Normal port operation, pins disconnected from timer operation (breaking pwm).  
*  Should be set this way by default, anyway. */

bitClear(TCCR1A, WGM10);
bitClear(TCCR1A, WGM11);
bitSet(TCCR1B, WGM12);
bitClear(TCCR1B, WGM13);
/* Mode 4, CTC with TOP set by register OCR1A.  Allows us to set variable timing for
*  the interrupt by writing new values to OCR1A. */

bitClear(TCCR1B, CS10);
bitSet(TCCR1B, CS11);
bitClear(TCCR1B, CS12);
/* set the clock prescaler to /8.  Since the processor ticks every 62.5ns, the timer
*  will increment every .5uS.  Timer 1 is a 16-bit timer, so the maximum value is 65536,
*  Giving us a theoretical range of .5us-32.7mS.  There are 48 samples, so the
*  theoretical frequency range is 41.7KHz - .635Hz, which neatly covers the audio
*  spectrum of 20KHz-20Hz.  Theoretical, because I wouldn't recommend actually calling
*  the Timer1 interrupt every .5uS :)  */

bitClear(TCCR1C, FOC1A);
bitClear(TCCR1C, FOC1B);
/* Disable Force Output Compare for Channels A and B, whatever that is.
*  Should be set this way by default anyway. */

OCR1A = 160;
/* Initializes Output Compare Register A at 160, so a match will be generated every
*  62.5nS * 8 * 160 = 80uS, for a 1/(80uS*48) = 260Hz tone. */

bitClear(TIMSK1, ICIE1); //disable input capture interrupt
bitClear(TIMSK1, OCIE1B); //disable Output Compare B Match Interrupt
bitSet(TIMSK1, OCIE1A); //enable Output Compare A Match Interrupt
bitClear(TIMSK1, TOIE1); //disable Overflow Interrupt Enable

sei(); //enable interrupts now that registers have been set

delay(1000);

}//end setup()
 
 
 
ISR(TIMER1_COMPA_vect) {
/* timer1 ISR.  Every time it is called it sets
*  speakerpin to the next value in Sine[].  frequency modulation is done by changing
*  the timing between successive calls of this function, e.g. for a 1KHz tone,
*  set the timing so that it runs through Sine[] 1000 times a second. */

if (waveindex > 47) { //reset waveindex if it has reached the end of the array
  waveindex = 0;
  }

analogWrite(speakerpin, sineovertones[waveindex] + 128);
waveindex++;

OCR1A = period;

} //end Timer1 ISR
 
void loop()
{
  
  
//analog0 = analogRead(0) + 4;
//Serial.println(analog0);
  
 y = 0;        // clear out variables
 x = 0;

 for (i=0; i < 4 ; i++ ){       // do it four times to build up an average - not really neccessary but takes out some jitter

   // LOW-to-HIGH transition
   digitalWrite(8, HIGH);    
   // output pin is PortB0 (Arduino 8), sensor pin is PortB1 (Arduinio 9)                                  

   while ((PINB & B100) != B100 ) {        // while the sense pin is not high
     //  while (digitalRead(9) != 1)     // same as above port manipulation above - only 20 times slower!                
     x++;
   }
   delay(1);

   //  HIGH-to-LOW transition
   digitalWrite(8, LOW);              
   while((PINB & B100) != 0 ){            // while pin is not low  -- same as below only 20 times faster
     // while(digitalRead(9) != 0 )      // same as above port manipulation - only 20 times slower!
     y++;  
   }

   delay(1);
 }

 fout =  (fval * (float)x) + ((1-fval) * accum);  // Easy smoothing filter "fval" determines amount of new data in fout
 accum = fout;  
period = constrain(fout / 3, 50, 500);
Serial.println(period);


}//end loop()



Perhaps whoever maintains the timer1 library should take a gander at why you can't change timer frequency dynamically?
20  Forum 2005-2010 (read only) / Syntax & Programs / Re: using the Timer1 library for PCM audio output on: May 25, 2009, 03:09:10 am
Sorry, example code here:
Code:
#include "TimerOne.h"

char sineovertones[] = {0,84,106,99,113,127,107,79,71,51,1,-26,7,43,23,-17,-26,-23,-43,-60,-49,-44,-66,-63,0,63,66,44,49,60,43,23,26,17,-23,-43,-8,26,-1,-51,-71,-79,-107,-127,-113,-99,-106,-84};


char sine[] = {0, 22, 44, 64, 82, 98, 111, 120, 126, 128, 126, 120, 111, 98, 82, 64, 44, 22, 0, -22, -44, -64, -82, -98, -111, -120, -126, -128, -126, -120, -111, -98, -82, -64, -44, -22};
//a simple sine wave with 36 samples

long analog0 = 160; //variable to store input from analog input pin 0

byte speakerpin = 3;  //audio playback on pin 3.  This can also be set to pin 11.
 
volatile byte waveindex = 0; //index variable for position in waveform array Sine[]
volatile byte currentvalue = 0;

void setup() {
  
Serial.begin(57600);
  
  
/************************** PWM audio configuration ****************************/
// Configures PWM on pins 3 and 11 to run at maximum speed, rather than the default
// 500Hz, which is useless for audio output

pinMode(speakerpin,OUTPUT); //Speaker on pin 3

cli(); //disable interrupts while registers are configured

bitSet(TCCR2A, WGM20);
bitSet(TCCR2A, WGM21); //set Timer2 to fast PWM mode (doubles PWM frequency)

bitSet(TCCR2B, CS20);
bitClear(TCCR2B, CS21);
bitClear(TCCR2B, CS22);
/* set prescaler to /1 (no prescaling).  The timer will overflow every
*  62.5nS * 256ticks = 16uS, giving a frequency of 62,500Hz, I think.   */

sei(); //enable interrupts now that registers have been set
  
  
/************************* Timer 1 interrupt configuration *************************/

Timer1.initialize(160);         // initialize timer1, and set a 1/2 second period
Timer1.attachInterrupt(playtone);  // attaches playtone() as a timer overflow interrupt
}
 
 
 
void playtone() {
/* This function is called by the timer1 interrupt.  Every time it is called it sets
*  speakerpin to the next value in Sine[].  frequency modulation is done by changing
*  the timing between successive calls of this function, e.g. for a 1KHz tone,
*  set the timing so that it runs through Sine[] 1000 times a second. */
if (waveindex > 47) {
  waveindex = 0;
  }

analogWrite(speakerpin, sineovertones[waveindex] + 128);
waveindex++;
}
 
void loop()
{

analog0 = analogRead(0) / 2;
Serial.println(analog0);
delay(100);
Timer1.setPeriod(analog0);
 
}

21  Forum 2005-2010 (read only) / Syntax & Programs / using the Timer1 library for PCM audio output on: May 25, 2009, 03:02:59 am
Hi All,
    I'm trying to generate audio from the Arduino, using Pulse Code Modulation.  

If you're not familiar with this technique, I take a waveform (let's say a sine wave), divide it up into 48 samples, and encode it's level at that point into a char array.  Then I set up an interrupt on timer1 so that every time it fires, it sets one of the timer2 pwm pins the current sample point, then increments the array index.  I've changed the prescaler on timer2 so that the pwm frequency is 62,500 Hz, so once I put the output through a low-pass filter it sounds...surprisingly decent, actually.

So this all works as expected with a static frequency.  On my oscilloscope, I can see the waveform that I've encoded, and I can hear it on my speaker.

Now, I should be able to vary the frequency by changing how quickly the timer1 interrupt is called, i.e. how quickly it steps through the array of samples.  I'm currently using the Timer1 library in the Arduino playground, but when I try to vary the interrupt period, I get squat-- no output at all.

Has anyone used this library with varying interrupt frequencies?  Or had success generating sound with this method?  I'd like to use the library because manually configuring timers makes me  :'(
22  Forum 2005-2010 (read only) / Syntax & Programs / Re: newbie, need critique/suggestions for clock code on: May 25, 2009, 03:05:38 pm
If you're interested in doing more advanced projects with the Arduino, I think it will repay you many times over to learn how to configure a timer and its associated interrupt(s) manually.  It's a real pain to figure out the first time, but get ye to the datasheet, I say.  

You could use Timer1 in CTC mode with a /256 prescaler.  Then the timer will tick 62,500 times per second, so you set your output compare register to 62500, and write the interrupt to increment your seconds variable every time it fires.  Voila, you have a subroutine that will run exactly every 1 second, independent of how much you're loading down your processor with your main program routine.
23  Forum 2005-2010 (read only) / Development / Re: Using own interrupt handlers: Collision of ISRs on: March 07, 2009, 04:54:03 pm
I found a sort of work-around, which I've posted here:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236223363/0

sorry about the double post.
24  Forum 2005-2010 (read only) / Development / Re: Using own interrupt handlers: Collision of ISRs on: March 06, 2009, 03:14:28 am
Thanks for the info, but I'm trying to receive DMX, not send it.

How do I override the default USART_RX_vect ISR?
25  Forum 2005-2010 (read only) / Development / Re: Using own interrupt handlers: Collision of ISRs on: March 03, 2009, 10:10:41 pm
Hello,
       I am working on the same project, in a similar plan of attack as you, Zeb.

My serial receive operations are giving me junk at times, and I think it is because of other interrupts disrupting the serial read at critical moments.  So I thought I could put my time sensitive code inside the USART_RX_vect ISR, which would not be interrupted by other interrupts while running.

When compiling, I get a similar error message:

C:\Users\Max\AppData\Local\Temp\build3450.tmp\wiring_serial.c.o: In function `__vector_18':


C:\Program Files (x86)\arduino-0013-win\arduino-0013\hardware\cores\arduino/wiring_serial.c:112: multiple definition of `__vector_18'


o:C:\Users\Max\AppData\Local\Temp\build3450.tmp/Temporary_6403_5722.cpp:42: first defined here
Couldn't determine program size: C:\Program Files (x86)\arduino-0013-win\arduino-0013\hardware/tools/avr/bin/avr-size: 'C:\Users\Max\AppData\Local\Temp\build3450.tmp\receiver_rev3.hex': No such file

I tried moving the ISR code over to blink.pde as suggested by mem, but got the same error message.  Has anyone had any luck setting up a custom serial receive ISR?

Thanks,
Max


26  Forum 2005-2010 (read only) / Troubleshooting / Re: Duemilanove Vista Driver Problems on: May 10, 2009, 01:34:02 am
I'm having problems like this in my Vista Home Premium x64 install.  The ports work fine in Ubuntu, so it's not a physical hardware issue.

Does anyone know where I could get a copy of the 2.04.06 drivers?  I'd like to try installing them instead of the latest 2.04.16 version, even though it says it's digitally signed.
27  Forum 2005-2010 (read only) / Troubleshooting / Re: arduino pro : usb + external power supply on: June 10, 2009, 08:22:18 pm
I'm putting together finishing touches on a project with the Arduino pro and an external 9V power supply.  I'd like to be able to connect the USB cable after I've soldered the power supply connection in and do software uploads.  Will that damage the board (5V + 9V > 12V) or is the power select module smart enough to power off one source, but not both?

It's the 16Mhz/5V version, btw.
28  Forum 2005-2010 (read only) / Interfacing / Re: Receive DMX-512 with an Arduino! on: June 06, 2009, 06:02:26 pm
Update:

Code is confirmed working on the Atmega 328.  Turns out the register names are the same, so it works without any adjustment.

I have designed a shield for it, which can also be used for DMX output:
http://blog.wingedvictorydesign.com/2009/04/29/arduino-dmx-512-io-shield/

The shield allows in-the-field addressing, without permanently disabling any of the pins.

Address is stored in non-volatile EEPROM, so it is retained when power is lost to the Arduino.

Drop me a line in this thread or the comments section on my blog if it worked for you  smiley, or didn't work for you  smiley-sad
29  Forum 2005-2010 (read only) / Interfacing / Receive DMX-512 with an Arduino! on: March 20, 2009, 02:50:17 pm
Hi All,
     I've written a sketch that allows you to receive DMX-512 with an Arduino.  If you're not familiar with it, DMX is the control protocol for theatrical/live event lighting.  It's been possible to send DMX with an arduino for quite awhile, but this will allow you to receive DMX values and execute your custom code accordingly.

The code is quite long, and there's some hardware setup and malarkey with the wiring_serial.c file involved, so I'm just going to give you the link:

http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/

It's my first project with the Arduino, and I worked really hard on it, so please let me know if it works for you and how you like it.

It has the following features:
  • Capable of receiving 8 contiguous addresses from 1 to 505.
  • Works with controllers that send less than the full 512 address DMX frame.
  • Break detection is done correctly by detecting a Low value of >88[ch956]S per ANSI E1.11-2008, rather than the frame error hack used by many devices.
  • Uses interrupt-based algorithms to eliminate processor-load related timing problems.  It may be of general interest to those in this forum who are trying to get interrup-based sketches off the ground
  • If the DMX data signal is lost, the Arduino will maintain the current state until new values are received.
  • The reception and user code run sequentially rather than at the same time, so they won't interfere with each others timing.
And the following limitations, as of now:
  • Atmega168 based processors only (you will have to rename the registers and interrupt vectors if you want to use it for another processor).
  • Currently only tested with a USB-DMX Pro controlled via Lightfactory and MagicQ software, since that's what I could get my hands on.  But it handles a variety of frame rates, break lengths, etc. just fine.  If you're in the Portland area, and you'd like to let me test it with other controllers, drop me a line.  Also, if you use it with other controllers, let me know how it turned out.
  • Because I needed access to exact timing, I had to use the Timer2 functionality, so pins 3 and 11 cannot be used for PWM.
  • Will not detect bad addressing, such as “dmxaddress=510;” or ”dmxaddress=50;” when only 55 slots are sent by the controller.
I'm still developing and improving the software, so check the link above for the latest version.

Max
30  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: January 13, 2010, 10:00:49 am
Hi Dolby,
      If you want to send DMX, you can check out the playground on this site.  If you want to receive it, try my project:
http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/

both sites are the top results of a Google search, so you may want to start there.
Pages: 1 [2] 3 4 ... 6