Show Posts
Pages: 1 2 [3] 4 5 6
31  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 11, 2009, 08:21:45 pm
Quote
Does this means that when i need serial in version 0013 i need to manually to modify wiring_serial.c back again to the original?

It depends on whether you need Serial.flush(), which as near as I can tell is the only thing this change to wiring_serial.c would disable.  I started this thread in hopes that someone would chime in with a better work-around, but at the moment this is the only one I've got.

Quote
yes it works

Interestingly, this code doesn't work with my controller (an Enttec USB-DMX Pro with Lightfactory software), even when I compile it in the 0012 version of the software, with an unmodified wiring_serial.c

What controller(s) have you used it with?

I'm currently trying to write some software that will work with my (or any) controller, so I'm interested to know.  Thanks,

Max
32  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 10, 2009, 10:49:51 pm
Well, it compiles fine on my computer, with my altered wiring_serial.c

Once I load it onto the Arduino, it doesn't do anything, though -- from poking at it it looks like it's not setting the values in DMX[] to anything, they just stay at their default value of 0.  I haven't gone through it in detail, though.

Have you managed to receive DMX correctly with this code, under any version of the Arduino library?  

If you want to compile it, here's what I did to wiring_serial.c  (towards the end, there's a part that's commented out):
Code:
/*
  wiring_serial.c - serial functions.
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2005-2006 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $

  Modified on March 1, 2009 by Norbert Pozar
*/

#include "wiring_private.h"

// Define constants and variables for buffering incoming serial data.  We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.

// use only powers of 2 for the buffer size to produce optimal code
// 8, 16, 32, 64, 128 or 256

// input buffer
#define RX_BUFFER_SIZE 128
// output buffer
// set to 0 to disable the output buffer altogether (saves space)
#define TX_BUFFER_SIZE 32

unsigned char rx_buffer[RX_BUFFER_SIZE];

unsigned char rx_buffer_head = 0;
unsigned char rx_buffer_tail = 0;


void beginSerial(long baud)
{

#if defined(__AVR_ATmega8__)
      UBRRH = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRRL = ((F_CPU / 16 + baud / 2) / baud - 1);
      
      // enable rx and tx
      sbi(UCSRB, RXEN);
      sbi(UCSRB, TXEN);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSRB, RXCIE);
#else
      UBRR0H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRR0L = ((F_CPU / 16 + baud / 2) / baud - 1);
      
      // enable rx and tx
      sbi(UCSR0B, RXEN0);
      sbi(UCSR0B, TXEN0);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSR0B, RXCIE0);
#endif

      // defaults to 8-bit, no parity, 1 stop bit
}

// advanced function, saves ~200 bytes because it doesn't use the long division
// prescaler for the baud rate can be found using the formula
// prescaler = fClock / (16 * baud rate) - 1
// see beginSerial
void beginSerialWithPrescaler(unsigned int prescaler)
{

#if defined(__AVR_ATmega8__)
      UBRRH = prescaler >> 8;
      UBRRL = prescaler;
      
      // enable rx and tx
      sbi(UCSRB, RXEN);
      sbi(UCSRB, TXEN);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSRB, RXCIE);
#else
      UBRR0H = prescaler >> 8;
      UBRR0L = prescaler;
      
      // enable rx and tx
      sbi(UCSR0B, RXEN0);
      sbi(UCSR0B, TXEN0);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSR0B, RXCIE0);
#endif

      // defaults to 8-bit, no parity, 1 stop bit
}

int serialAvailable()
{
      unsigned char i = RX_BUFFER_SIZE + rx_buffer_head - rx_buffer_tail;
      i %= RX_BUFFER_SIZE;

      return i;
}

int serialRead()
{
      // if the head isn't ahead of the tail, we don't have any characters
      if (rx_buffer_head == rx_buffer_tail) {
            return -1;
      } else {
            unsigned char c = rx_buffer[rx_buffer_tail];
            rx_buffer_tail = rx_buffer_tail + 1;
            rx_buffer_tail %= RX_BUFFER_SIZE;
            return c;
      }
}

void serialFlush()
{
      // don't reverse this or there may be problems if the RX interrupt
      // occurs after reading the value of rx_buffer_head but before writing
      // the value to rx_buffer_tail; the previous value of rx_buffer_head
      // may be written to rx_buffer_tail, making it appear as if the buffer
      // were full, not empty.
      rx_buffer_head = rx_buffer_tail;
}

/* #if defined(__AVR_ATmega8__)  *********THIS PART COMMENTED OUT*********
SIGNAL(SIG_UART_RECV)
#else
SIGNAL(USART_RX_vect)
#endif
{
#if defined(__AVR_ATmega8__)
      unsigned char c = UDR;
#else
      unsigned char c = UDR0;
#endif

      unsigned char i = rx_buffer_head + 1;
      i %= RX_BUFFER_SIZE;

      // if we should be storing the received character into the location
      // just before the tail (meaning that the head would advance to the
      // current location of the tail), we're about to overflow the buffer
      // and so we don't write the character or advance the head.
      if (i != rx_buffer_tail) {
            rx_buffer[rx_buffer_head] = c;
            rx_buffer_head = i;
      }
} */

// buffered output
#if (TX_BUFFER_SIZE > 0 )

// TX is buffered
// ************************
// tested only for ATmega168
// ************************

unsigned char tx_buffer[TX_BUFFER_SIZE];

unsigned char tx_buffer_head = 0;
volatile unsigned char tx_buffer_tail = 0;


// interrupt called on Data Register Empty
#if defined(__AVR_ATmega8__)
SIGNAL(SIG_UART_DATA)
#else
SIGNAL(USART_UDRE_vect)
#endif
{
  // temporary tx_buffer_tail
  // (to optimize for volatile, there are no interrupts inside an interrupt routine)
  unsigned char tail = tx_buffer_tail;

  // get a byte from the buffer      
  unsigned char c = tx_buffer[tail];
  // send the byte
#if defined(__AVR_ATmega8__)
      UDR = c;
#else
      UDR0 = c;
#endif

  // update tail position
  tail ++;
  tail %= TX_BUFFER_SIZE;

  // if the buffer is empty,  disable the interrupt
  if (tail == tx_buffer_head) {
#if defined(__AVR_ATmega8__)
    UCSRB &=  ~(1 << UDRIE);
#else
    UCSR0B &=  ~(1 << UDRIE0);
#endif

  }

  tx_buffer_tail = tail;

}


void serialWrite(unsigned char c) {

#if defined(__AVR_ATmega8__)
       if ((!(UCSRA & (1 << UDRE)))
#else
      if ((!(UCSR0A & (1 << UDRE0)))
#endif
  || (tx_buffer_head != tx_buffer_tail)) {
    // maybe checking if buffer is empty is not necessary,
    // not sure if there can be a state when the data register empty flag is set
    // and read here without the interrupt being executed
    // well, it shouldn't happen, right?

    // data register is not empty, use the buffer
    unsigned char newhead = tx_buffer_head + 1;
    newhead %= TX_BUFFER_SIZE;

    // wait until there's a space in the buffer
    while (newhead == tx_buffer_tail) ;

    tx_buffer[tx_buffer_head] = c;
    tx_buffer_head = newhead;

    // enable the Data Register Empty Interrupt
#if defined(__AVR_ATmega8__)
    UCSRB |=  (1 << UDRIE);
#else
    UCSR0B |=  (1 << UDRIE0);
#endif

  }
  else {
    // no need to wait
#if defined(__AVR_ATmega8__)
      UDR = c;
#else
      UDR0 = c;
#endif
  }
}

#else

// unbuffered write
void serialWrite(unsigned char c)
{
#if defined(__AVR_ATmega8__)
      while (!(UCSRA & (1 << UDRE)))
            ;

      UDR = c;
#else
      while (!(UCSR0A & (1 << UDRE0)))
            ;

      UDR0 = c;
#endif
}

#endif


33  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 09, 2009, 05:02:11 pm
Thanks for the info, I love the hexadecimal reward system.  
34  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 08, 2009, 04:06:33 pm
I take your point that there are some trade-offs between ease of use and configurability.  But in this case I don't see the upside of automatically including the serial receive ISR in the uploaded code when there's no serial definitions in the code.

I'll look into that circular buffer algorithm if I can track down that book, it sounds interesting.

Cutting and pasting the ISR definition into the code is definitely an easier work-around than mine, thanks for the tip.
35  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 07, 2009, 04:49:31 pm
The following code configures the USART manually without use of the Arduino serial functions.  The reason for this is that to get it to compile you have to comment out some of the wiring_serial.c file, and thus we can't use the Arduino serial commands.

Functionally, every time the receive interrupt is called it increments an index and then prints it to the serial buffer (again, manually).  

If you run the code, and you have Putty or hyperterminal or whatever properly configured, you'll just get the ASCII chart over and over as the index overflows.

Here it is:
Code:
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
/* Definitions for setting and clearing register bits
*  See http://www.sigterm.de/projects/sens-o-nuts/Dokumentation/atmel/libc/group__avr__sfr.html */

int receiveroutputenable = 3;  
/* receiver output enable (pin2) on the max485.  
*  will be left low to set the max485 to receive data. */

int driveroutputenable = 4;    
/* driver output enable (pin3) on the max485.  
*  will left low to disable driver output. */

int rxpin = 0;                  // serial receive pin, which takes the incoming data from the MAX485.

unsigned long baud = 250000;    // The baud rate for DMX is 250000bps, since each bit = 4 microseconds.
unsigned long clockspeed = F_CPU;
/* F_CPU is a predefined constant equal to the clock speed of the microcontroller.
*  for the Arduino duomilanove it is 16000000.
*  I'm going to dump it into clockspeed because I'm worried about it being a signed long,
*  which could screw up the bitwise math I'm going to do on baudprescale, maybe. */

unsigned long baudprescale;    
/* The baud prescale that will be loaded into the
*  UBRR0H and UBRR0L registers to set the USART baud rate */


volatile int i = 0;           //dummy variable for for() loops, etc.
volatile byte ReceivedByte = 0; //holds the incoming byte from the receive buffer.

void setup() {
  pinMode(receiveroutputenable, OUTPUT);
  pinMode(driveroutputenable, OUTPUT);
  digitalWrite(receiveroutputenable, LOW);
  digitalWrite(driveroutputenable, LOW);    //sets pins 3 and 4 to low to enable reciever mode on the MAX485.

  pinMode(rxpin, INPUT);  //sets serial pin to receive data

  baudprescale = (((clockspeed / (baud * 16UL))) - 1); //

  cli();  //disable interrupts while initializing the USART

  sbi(UCSR0A, TXC0);
  cbi(UCSR0A, FE0);
  cbi(UCSR0A, DOR0);
  cbi(UCSR0A, UPE0);
  cbi(UCSR0A, U2X0); //
  cbi(UCSR0A, MPCM0);
  /* set transfer complete flag (TXC0 = 1).
  *  clear Frame Error flag (FE0 = 0).  
  *  clear Data overrun flag (DOR0 = 0).
  *  clear Parity overrun flag (UPE0 = 0).
  *  disable doubling of USART transmission speed (U2X0 = 0).  
  *  Disable Multi-Processor Communication Mode-- whatever that is. (MCPM0 = 0)  */
  
  sbi(UCSR0B, RXCIE0);
  cbi(UCSR0B, TXCIE0);
  cbi(UCSR0B, UDRIE0);
  sbi(UCSR0B, RXEN0);
  sbi(UCSR0B, TXEN0);
  cbi(UCSR0B, UCSZ02);
  /* Enable Receive Interrupt (RXCIE0 = 1).
  *  Disable Tranmission Interrupt (TXCIE = 0).
  *  Disable Data Register Empty interrupt (UDRIE0 = 0).
  *  Enable reception (RXEN0 = 1).
  *  Enable transmission (TXEN0 = 1).
  *  Set 8-bit character mode (UCSZ00, UCSZ01, and UCSZ02 together control this,
  *  But UCSZ00, UCSZ01 are in Register UCSR0C). */
  
  cbi(UCSR0C, UMSEL00);
  cbi(UCSR0C, UMSEL01);
  cbi(UCSR0C, UPM00);
  cbi(UCSR0C, UPM01);
  sbi(UCSR0C, USBS0);
  sbi(UCSR0C, UCSZ00);
  sbi(UCSR0C, UCSZ01);
  cbi(UCSR0C, UCPOL0);
  /* USART Mode select -- UMSEL00 = 0 and UMSEL01 = 0 for asynchronous mode.
  *  disable parity mode -- UPM00 = 0 and UPM01 = 0.
  *  Set USBS = 1 to configure to 2 stop bits per DMX standard.  The USART receiver ignores this
  *  setting anyway, and will only set a frame error flag if the first stop bit is 0.  
  *  But, we have to set it to something.
  *  Finish configuring for 8 data bits by setting UCSZ00 and UCSZ01 to 1.  
  *  Set clock parity to 0 for asynchronous mode (UCPOL0 = 0). */
  
  UBRR0L = baudprescale; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
  UBRR0H = (baudprescale >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
  // ***note to self: at some point add a command to write UBRR0H high bits to 0 per datasheet for "future compatibility"

  sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
}  //end setup()

ISR(USART_RX_vect){
  ReceivedByte = UDR0;  
  /* The receive buffer (UDR0) must be read during the reception ISR, or the ISR will just
  *  execute immediately upon exiting. */
  i++;
  UDR0 = i;
} // end ISR

void loop()  {
 
} // end loop()

36  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 07, 2009, 04:39:30 pm
Okay, I have some answers:

First of all, the serial receive interrupt is USART_RX_vect, not USART_RXC_vect as I had in my first post.  Defining USART_RXC_vect is like defining NOTHINGWILLHAPPEN_vect, it's a valid name for an interrupt vector, but it will never execute, because the CPU will never call it.

When you define USART_RX_vect, however, the compiler throws you an error, because the arduino software defines that interrupt vector and includes it in your code, whether you reference Arduino serial functions or not.  So you have to comment out some parts of wiring_serial.c

IMHO, and I'm new at this so please correct me if I'm wrong about this, including the serial functions even if they're not referenced is a bug, not a feature.  It increases the uploaded sketch size, and reduces the flexibility of the programmer, with no upside.  Anyway, in the next post is my workaround:
37  Forum 2005-2010 (read only) / Interfacing / Re: interrupt-driven USART reception: I'm stumped. on: March 05, 2009, 06:33:57 pm
Thank you for your post, it was illuminating to me on a number of levels.

So it sounds like if I want to access the UART_RXC ISR, I'll need to configure/access the USART manually by setting the bits in the control register and reading the buffer register, rather than using the Arduino serial library.  I can probably figure out how to do that.

I think that the problems receiving data I was having are due to buffer overrun, not noise.  I'm using good twisted pair shielded cable that I've properly terminated, etc. per EI485 best practices.  I'll check for slew rate on my o-scope, but I've used this controller with no problems before, so I'm sure it's fine.

I was assuming that ALL the interrupts were enabled by default.  

As a first step, I was attempting to read and post to the serial port all 512 levels as they came in.  But I'm actually only interested in a small subset of those values, so perhaps if I write that code first, the resulting routine will be fast enough that it won't overflow the buffer.

I'll post my results, thanks for your help so far.
38  Forum 2005-2010 (read only) / Interfacing / interrupt-driven USART reception: I'm stumped. on: March 04, 2009, 10:22:43 pm
Hi all,
    I'm trying to program the arduino to receive DMX-512, which runs at a 250Kbit baud rate.  I can receive the channel information, but I get intermittent bad values, which I think is because of other interrupts running and disrupting the serial reception.

However, there is an interrupt on the Atmega168 that indicates a new byte has been received by the USART, USART_RXC_vect.  So I thought, if I did the time-critical work of reading the incoming values inside the serial receive ISR, it would prevent that work from being screwed up by other interrupts, and also allow me to do other things besides poll the serial receive all the time.

I'm having trouble getting the ISR to work.  Here's my test code:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

int receiveroutputenable = 3;  // receiver output enable (pin2) on the max485.  will be left low to set the max485 to receive data.
int driveroutputenable = 4;    // driver output enable (pin3) on the max485.  will left low to disable driver output.
int rxpin = 0;                // serial receive pin on the Arduino, which takes the incoming data from the MAX485.

volatile int index = 0;  //a variable incremented in the ISR and printed in the main routine.


void setup() {
  pinMode(receiveroutputenable, OUTPUT);
  pinMode(driveroutputenable, OUTPUT);
  digitalWrite(receiveroutputenable, LOW);
  digitalWrite(driveroutputenable, LOW);    //sets pins 3 and 4 to low to enable reciever mode on the MAX485.

  pinMode(rxpin, INPUT);  //sets serial pin to receive data

  Serial.begin(250000);  //the baud rate for DMX is 250000bps (since each bit is 4 microseconds).

  UCSR0B |= (1 << RXCIE0);  //sets RXCIE0 in register UCSR0B to 1, to enable USART reception interrupt.

  sei();  //Enable global interrupts
  
}  //end setup()

ISR(USART_RXC_vect){  //the USART receive Interrupt Service Routine
  index++;  //increment index
}

void loop()  {
  Serial.println(index);  //print index.  If the ISR is running, this should increment (although not in lockstep with the ISR).
}

If the ISR(USART_RXC_vect) is firing, it should increment "index" every time.  Then at some point the main code should print out the new value.  However, the serial code just prints out 0's, so I conclude the ISR isn't firing (I'm using Putty to read the incoming values at 250000bps).

Can anyone help me get the ISR up and running?  I'm new to assembly/reading the Atmega168 data sheet, so it's probably something pretty simple.

Thanks for the help!
39  Forum 2005-2010 (read only) / Interfacing / Re: Volume control for HTPC on: June 06, 2009, 05:39:14 pm
btw, welcome to the forums!
40  Forum 2005-2010 (read only) / Interfacing / Re: Volume control for HTPC on: June 06, 2009, 05:38:13 pm
HTPC is home theater pc?

Well, interfacing a potentiometer to the arduino and converting it to a numeric range is easy:

http://www.arduino.cc/en/Tutorial/Potentiometer

You can capture the analog value and either output it on the serial port or using the Ethernet shield, I guess.  The tricky thing will be getting your PC to take that value and control the volume, for that you'll have to write code that runs on your computer, not the arduino.

There has to be an inexpensive commercial solution that will do this for you, if you just want it to work why not do that?
41  Forum 2005-2010 (read only) / Interfacing / Re: Arduino and HM91710A - Generate DTMF! on: June 09, 2009, 02:54:06 am
Ah, I took another look at the datasheet and you're right.  I revise my answer to ^^^  smiley
42  Forum 2005-2010 (read only) / Interfacing / Re: Arduino and HM91710A - Generate DTMF! on: June 08, 2009, 04:50:36 am
I don't think this is the ideal IC for your purpose, because it's set up to receive inputs from a 12-key numeric pad.  To get it to work, you'll have to get the arduino to mimic the electrical behavior caused by the capacitance change that happens when you press one of those buttons.  

I think what you want is an IC that takes something the arduino can talk to easily, like serial, i2c, etc. and converts that to DTMF.

OR... cut out the middleman, and get the arduino to output DTMF directly... I know I've seen threads from other people trying to interface Arduino to DTMF, maybe there's a solution out there that you could adapt.
43  Forum 2005-2010 (read only) / Interfacing / Re: What should I do with all this stuff? Ideas wanted on: May 26, 2009, 11:13:00 pm
I also have old cell phones, and it seems like there ought to be a good way to interface them to the Arduino.  I think you should develop a digital picture frame/greeting card thingy where you could load a picture on the arduino, display it on the screen, and give them to your friends.
44  Forum 2005-2010 (read only) / Interfacing / Re: Non-contact proximity sensor on: June 08, 2009, 04:09:36 am
Just out of idle curiosity, what's this for?
45  Forum 2005-2010 (read only) / Interfacing / Re: Non-contact proximity sensor on: June 06, 2009, 05:40:59 pm
Or capacitive sensing?
http://www.arduino.cc/playground/Main/CapSense
Pages: 1 2 [3] 4 5 6