Any objection to using:
noInterrupts ();
?
Any objection to using:
noInterrupts ();
?
ddemunshi:
Hi,I am currently building a device which requires manipulating several TTL pulses, which in turn controls other devices.
I test the ideas, I initially tried to generate a TTL sequence with Aurdino Uno. I wrote a very simple code which I am copying below.
However, when I see the signal on an oscilloscope, I see that the TTL is jittering, which means the rising and/or falling edges of two respective TTL pulses are moving with respect to each other, by about,t 8 -10 microseconds. This will effect the response of my device.
You are seeing the results of interrupts running in the background. Try this:
cli (); // disable interrupts
void loop (void)
{
digitalWrite(ledPin, HIGH);
delayMicroseconds(500);
digitalWrite(ledPin, LOW);
delayMicroseconds(500);
}
I know you are in an endless loop, but if you were not (say you were generating only 10 pulses, then doing something else, then do this:
cli (); // turn off interrupts
// generate your pulses
// now we're done
sei (); // turn interrupts back on
Hope this helps.
ddemunshi:
2% is actually not very god enough for photonics research. Also the final goal is to move down to hundreds of KHz region of frequency and hence I am wondering if Uno is good enough for that.CPU clock on Uno as far as I understand is 16 MHz so at 1KHz, I am quite far away from the CPU clock frequency. But I think the timer is required for stabilizing the waveform, atleast that is what has to be done on labview based systems.
I do not care about the value of software solution since this will be a driving part of a device. However, if you can provide some example of what you mean by "careful coding" it will be immensely helpful.
thanks
The code below is an IR remote control generator, but it uses techniques that you also need (if I understand you correctly).
One important part of the code is the timer driven interrupt which is used to make accurate pulses to turn the IR LED on and off at exactly the right rate, duty cycle and pulse width. You will see how the timer is setup to accomplish this.
The timer control registers will vary from part to part (for example, TIMSK vs TIMSK0 or TCCR0A vs TCCR1A), but the idea is the same.
And, despite the fact that this code uses "int main (void)" rather than "setup" and "loop" means nothing. It's still "Arduino" code.
Hope this helps...
///////////////////////////////////////////////////////////////////////////////
//
// Infrared Remote Control for SONY DSLR A-700 Digital Camera
// Copyright (c) 2015 Roger A. Krupski <rakrupski@verizon.net>
//
// Last update: 06 October 2015
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#define F_CPU 8000000UL // 8.00 mhz external crystal
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/pgmspace.h>
#include <util/delay.h> // for _delay_xs
// ATtiny25/45 fuse settings (in Makefile):
// L-fuse: 0xFF (external crystal)
// H-fuse: 0xDF (SPI enabled, BOD disabled)
// E-fuse: 0xFF (self program enabled)
#define IO_PORT PORTB // (port write)
#define IO_PIN PINB // (port read)
#define IO_DDR DDRB // (port ddr)
#define IR_BIT PB0 // 2N4401 base drive for IR LED (thru 330 ohm resistor)
#define MODE PB1 // mode select: select shutter0 or shutter1 (has external 10K pullup)
#define BUTTON PB2 // send IR code (red button - active low - external 10K pullup)
#define KHZ 40 // IR carrier freq
volatile uint8_t state = 0; // led on/off state
volatile uint8_t onoff = 0; // bit polarity
volatile uint8_t count = 0; // led pulse counter
// Sony camera shutter release code 0x00B4B8F (focus and shoot)
// (header + 20 bits)
static const uint8_t shutter1[] PROGMEM = {
// header
0x60, 0x18,
// command
0x30, 0x18, 0x18, 0x18, 0x30, 0x18, 0x30, 0x18, // B
0x18, 0x18, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, // 4
0x30, 0x18, 0x18, 0x18, 0x30, 0x18, 0x30, 0x18, // B
0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 8
0x30, 0x18, 0x30, 0x18, 0x30, 0x18, 0x30, 0x18, // F
// end of command
0x00,
};
// Sony camera shutter release code 0x00ECB8F (focus, wait 2 sec, then shoot)
// (header + 20 bits)
static const uint8_t shutter2[] PROGMEM = {
// header
0x60, 0x18,
// command
0x30, 0x18, 0x30, 0x18, 0x30, 0x18, 0x18, 0x18, // E
0x30, 0x18, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, // C
0x30, 0x18, 0x18, 0x18, 0x30, 0x18, 0x30, 0x18, // B
0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 8
0x30, 0x18, 0x30, 0x18, 0x30, 0x18, 0x30, 0x18, // F
// end of command
0x00,
};
void send_cmd (const uint8_t *cmd, uint8_t rpt, uint8_t dly)
{
uint8_t idx;
IO_DDR |= _BV (IR_BIT); // set IR drive pin as an output
while (rpt--) {
idx = 0; // reset index
state = 0; // insure state starts correctly
do { // each one is a pulse count at carrier freq
while (count); // wait until ISR is done sending pulses
count = pgm_read_byte (cmd + idx++); // set next pulse count
onoff = (idx % 2); // set which side is high
} while (count); // until we hit 0 (end of command)
_delay_ms (dly); // delay between commands
}
IO_DDR &= ~_BV (IR_BIT); // set IR drive pin back to an input
}
ISR (TIMER0_COMPA_vect)
{
if (count) { // if a count was pushed in...
state ? IO_PORT &= ~_BV (IR_BIT) : onoff ? IO_PORT |= _BV (IR_BIT) : IO_PORT &= ~_BV (IR_BIT);
count -= state; // decrement count (on times only)
state ? state = 0 : state = 1; // if led was on set it off, else set it on
}
}
ISR (INT0_vect) // INT0 handler - we arrive here when the button is pressed
{
GIMSK = (0x00 & ~_BV (INT0)); // disable hardware INT0
cli (); // disable any further interrupts
}
int main (void)
{
uint8_t deb;
cli (); // disable interrupts while setting stuff
IO_PORT = 0x00;
IO_PORT |= _BV (BUTTON); // button pin high = pullup
IO_DDR = 0x00; // all pins inputs (for now)
ADCSRA = 0x00; // turn off ADC
// set timer 0 (8 bit) to CTC mode, carrier freq. this times the IR pulses.
TCCR0A = (0x00 | _BV (WGM01)); // mode 2 (CTC) OCR0A = top
TCCR0B = (0x00 | _BV (CS00)); // F_CPU/1 = 8000000
OCR0A = ((F_CPU / 2000 / KHZ) - 1); // divider for IR carrier freq
TIMSK = (0x00 | _BV (OCIE0A)); // enable interrupt on OCR0A match
MCUCR = (0x00 & ~(_BV (ISC01) | _BV (ISC00))); // set hardware INT0 active on low LEVEL
sei (); // setup done, enable interrupts
while (1) {
set_sleep_mode (SLEEP_MODE_PWR_DOWN); // set CPU to go into power down mode
sleep_enable (); // enable CPU to be powered down
sleep_bod_disable (); // turn off brown-out detector
GIMSK = (0x00 | _BV (INT0)); // enable INT0 active low
sei (); // enable interrupts so cpu can recognize pushbutton INT0
sleep_cpu (); // power down cpu (all clocks stopped)
/////////////// asleep - awaiting pushbutton INT0 ///////////////
sleep_disable (); // turn off sleep mode
sei (); // enable interrupts because they were disabled upon waking up
// send "shutter1" or "shutter2" depending in the state of pin 6 (PB2)
(IO_PIN & _BV (MODE)) ? send_cmd (shutter1, 3, 24) : send_cmd (shutter2, 3, 24); // send code
// wait for button to be released (prevent repeats if button held down).
deb = 100; // init debounce
while (deb--) {
_delay_us (100); // tiny delay
if (! (IO_PIN & _BV (BUTTON))) { // if button is pressed...
deb = 100; // ...keep checking
}
} // now button confirmed released for 10000 usec (10 msec)
}
}
// end of sony_ir.cpp