Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
nightchild12
Jan 8, 2005
hi i'm sexy

huhu posted:

So I made this code so that you could enter a value into serial monitor and have it turn that number of steps on a stepper motor. I added the line of

Because I couldn't control the steps and say that 0 would turn it 48, 1 would turn it 49, etc. I tried calibrating it so 0 would give 0 and then ran it again. It's fine now except 10=0, 11=1, 12=2, etc. What is affecting these values?

A couple of problems: Serial.read() only reads one byte at a time before returning. It also doesn't parse it as characters or an int, but reads it as a raw byte. So in your loop it's reading the first byte received, trying to use it as a value, then reading the next byte, trying to use it as a value, etc, rather than interpreting the bytes as a single integer.

You probably want to be using Serial.parseInt(), which will pull characters off the serial stream until it gets a non-integer character, and then turn them into an int value to return. If you do this, be sure to turn on newline in your serial program on your PC, and/or use Serial.setTimeout() to reduce the serial read timeout, or else you will get long pauses if you enter an int value with no trailing non-int characters. This is because it reads until it gets a non-integer character, and doesn't know that you have finished sending the number you want until it either gets a non-int value or times out (I think by default it's a full second).

huhu posted:

It's fine now except 10=0, 11=1, 12=2, etc. What is affecting these values?

As Delta-Wye said, it's because Serial.read() is interpreting the byte value instead of the ASCII value. For something like "10 11 12" it should be spitting out "49 48 49 49 49 50".

nightchild12 fucked around with this message at 19:31 on Jan 24, 2013

Adbot
ADBOT LOVES YOU

nightchild12
Jan 8, 2005
hi i'm sexy

Capntastic posted:

I can't really see what sort of project would require a Mega.

Something with a lot of inputs/outputs with a design goal of "as few parts as possible"? Or if you're unable to get shift registers, muxes, etc? I can buy a Mega locally in a store, but not the ICs I'd need to get more I/O out of an Uno. Like, I want to drive >2 strings of RGB LEDs independently of each other - the Uno only lets me do 2 (6 PWM channels, 3 per LED string), but the Mega lets me do up to 5 without needing to find and figure out new hardware. Or something along those lines, maybe?

edit: Or just something with lots of I/O needed. I have a garden sensor / automatic gardener project I've been kicking around in my head that gets way simpler if I use a Mega vs an Uno.

double edit: I refuse to let any one pin have more than one purpose since I think it is an affront to God.

nightchild12 fucked around with this message at 01:47 on Jan 31, 2013

nightchild12
Jan 8, 2005
hi i'm sexy

huhu posted:

I'm making a basic control system using the following elements:
- Arduino Uno
- 3x Temp Sensors https://www.sparkfun.com/products/11050
- 2x Float Sensors http://www.aquahub.com/store/ifloatfloatswitch.html
- 1x LCD display https://www.sparkfun.com/products/255
- 2x LEDs

Is it correct to assume that these are the pin usages:

- Temp Sensors 3 pins, 3 Vin, 3 ground
- Float sensors 2 pins, 2 ground
- LCD display 9 pins, 1 Vin, 1 ground
- LEDs 2 pins, 2 ground

Which would mean I'm using 16 pins and will have to get a bigger board than the Arduino Uno? The operation of the system is that thee float sensors will trigger the LEDs and the temperature sensors will display temperature on the LCD. Maybe I could print all the info on the LCD and get rid of the two LED pins. Thoughts?

The temp sensors use a 1-wire interface and have unique serials, they can all go on one IO pin.
The LCD display needs 11 IO pins, plus GND and +5V (unless I'm misreading the datasheet when I skim it). This is your big pin hog.

LEDs need a pin each, Float switches need a pin each. If you are just turning the LEDs on based on the float switches, you probably don't need to run them through a microcontroller, though; just hook the LED up directly to the float switch. That brings you down to 12 pins needed: 11 for the LCD and 1 for the temp sensors, with the float switches and LEDs not connected to any IO pins.

edit: You should learn about multiplexing anyways, though. Here's a bit from the Arduino playground on an analog multiplexer/demultiplexer: http://playground.arduino.cc/learning/4051

nightchild12 fucked around with this message at 02:29 on Mar 1, 2013

nightchild12
Jan 8, 2005
hi i'm sexy

Yakattak posted:

I have a programming question for the Arduino. We have a keypad that is used to "dial a phone". We got the numbers working perfectly fine, when you hit 1, it means 1. The problem we're having is we can't get it to act like a phone, in the sense that, when you dial 1, and wait like a second or two, it will go and dial that number, but when you hit 1,2 and 3 within that period, it dials 123. Is this possible at all?

So, I'd change "key" to an array, and have that array of numbers print instead.

That is totally possible. Easiest way is probably to use the Metro library as a timer to see if ~200 ms has passed between keypresses. I haven't used it myself so this may not be right, but here's something along the lines of what you want:

code:
Metro keypressTimer = Metro(2000); // set up timer with 2000ms period
char keyArray[10] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
int keyArrayIndex = 0;

void loop(){

  if( keypressTimer.check() == 1 && keyArray[0] != '\0' ) { // if timer expired and keyArray has contents
    Serial.println(keyArray); // print keyArray
    keyArray = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'}; // clear keyArray
    keyArrayIndex = 0; // reset keyArrayIndex
  }

  char key = keypad.getKey(); // read in key press

  if (key != NO_KEY){ // if we got a value for the key press
    keyArray[keyArrayIndex] = key; // put key press into keyArray
    if(keyArrayIndex < 9) {keyArrayIndex++}; // increment index if it won't overflow
    keypressTimer.reset(); // reset timer
  }
}
The above makes several assumptions. I haven't included most of your keypad code. The length of keyArray should be set to the longest string of characters you expect. The tenth input value will be modified if more keys are pressed before the timer expires but after you've filled the array. I am assuming that \0 is an acceptable way to write a null character. You might be better off using a string object rather than an array for this. I haven't tested this to see if it will run or even checked it very thoroughly for correctness. You can also roll your own timer using millis() instead of using Metro.

But that's a basic way you can do it. Run a timer which resets each time a key is pressed, and only output when the timer expires or reaches a certain value.

nightchild12 fucked around with this message at 19:57 on Mar 10, 2013

nightchild12
Jan 8, 2005
hi i'm sexy

HATE TROLL TIM posted:

I've got some older code here that's calling prog_uchar to store an array of data in PROGMEM, however it seems that prog_uchar is deprecated and the Arduino IDE won't allow me to compile it.

I'm calling that like this:

prog_uchar startscreenMV[1024] PROGMEM={ <snip> };


void setup() {
mydisp.begin();
mydisp.clearScreen();
mydisp.print("Uploading new start screen... (1024 bytes)");
mydisp.uploadStartScreen(1024,startscreenMV);
delay(1000);
mydisp.clearScreen();
mydisp.print("Done!");


Obviously that's giving me an error since uchar is deprecated. So I tried const unsigned char instead. That compiles and uploads, but it just spits garbage out to the display, so obviously it's not right.

What would be the correct replacement for prog_uchar?

Edit: Here's the library and sample code if anyone wants to have a look... http://www.digole.com/images/file/Tech_Data/DigoleSerial.zip

The correct data type to use is const unsigned char. The uploadStartScreen() function wants an unsigned char pointer.

The relevant function from that library:

code:
void DigoleSerialDisp::uploadStartScreen(int lon, const unsigned char *data) {
     int j;
     uint8_t c;
    Print::print("SSS");
    write((uint8_t) (lon % 256));
    write((uint8_t) (lon / 256));
    for (j = 0; j < lon;j++) {
        if((j%32)==0)
         delay(50);
         delay(_Comdelay);
        c=pgm_read_byte_near(data+j);
        write(c);
    }
}
Are you just running the example with no other modifications? Do you have the Wire library installed and in the right place for the Digole stuff to reach it ("../Wire/Wire.h")? Are you using UART, I2C, or SPI? Is it hooked up right for using whatever method (visible in comments at the top of uploadStartScreenandFonts.ino)?

I think there is a problem other than the data type you are using. Can you get it to display anything meaningful at all? Like, clear the screen and put a few characters without messing around with the start screen or fonts or anything? Strip it down to something like the below and make sure that works, then add pieces back one by one:

code:
#define _Digole_Serial_I2C_  //To tell compiler compile the special communication only, 
//other available is: _Digole_Serial_I2C_ and _Digole_Serial_SPI_
#include <DigoleSerial.h>
#include <Wire.h>
DigoleSerialDisp mydisp(&Wire,'\x27');  //I2C:Arduino UNO: SDA (data line) is on analog input pin 4, and SCL (clock line) is on analog input pin 5 on UNO and Duemilanove
#define LCDCol 16
#define LCDRow 2
#define LCDW 240
#include <sampledata.h>
void setup() {
  mydisp.begin();
  mydisp.clearScreen();
  mydisp.print("TEST OUTPUT");
  delay(500);
}
edit: Also FYI, your code block with the big long data block for the start screen data is breaking the poo poo out of my tables.

edit2: I did a little more looking around. prog_uchar is deprecated? I can't find an official source for that. Have you tried including the <avr/pgmspace.h> library? I noticed that the PROGMEM reference page says you need to "#include <avr/pgmspace.h>" in order to use PROGMEM, and that it isn't included anywhere in the DigoleSerial library or example.

edit3: OK, prog_uchar is deprecated according to the avr-libc website. Looks like the correct way to do this is: const unsigned char startscreenMV[1024] PROGMEM. Here's the old typedef: typedef unsigned char PROGMEM prog_uchar.

nightchild12 fucked around with this message at 00:32 on Mar 27, 2013

nightchild12
Jan 8, 2005
hi i'm sexy

Not directly Arduino, but closely related: I'm doing a thing on an ATtiny2313 with avr-gcc and having problems with progmem.

I'm trying to set up a character (and graphics) set for a 5x7 LED matrix. I don't have enough RAM on the ATtiny2313 to hold the whole array of character maps, so I'm trying to store them on flash using progmem. However, when I try to access the data, the progmem array is giving me pointers to someplace before where the data is actually stored. It's storing the data OK, I can see it in the compiled .hex file, but when I try to access it with pgm_read_byte(&(alphanum[ch][c])) it returns the byte at &alphanum[ch-17][c+1].

code:
// character mapping definitions
uint8_t alphanum[27][5] PROGMEM =
{
 {0x3F, 0x48, 0x48, 0x48, 0x3F}, // A
 {0x7F, 0x49, 0x49, 0x49, 0x36}, // B
 //... removed some arrays here for readability ...
 {0x43, 0x45, 0x49, 0x51, 0x61}, // Z
 {0x78, 0x08, 0x08, 0x7F, 0x08} // 4
// {0x, 0x, 0x, 0x, 0x}
};

void parse_char(int ch)
{
 int r;
 int c;
 int byte;
 // poo poo that is broke
 for(c=0; c<5; c++)
 {
  // for some reason, this is getting me the bytes
  //  starting from alphanum[ch-17][c+1]?
  byte = pgm_read_byte(&(alphanum[ch][c]));
  blank();
  set_col(c+1);
  for(r=1; r<8; r++)
  {
   if(byte & _BV(6)) { set_row(r); }
   byte = byte << 1;
  }
 }
}
I have my main loop set up to call parse_char constantly, and increment the value I pass to it when I push a button. I can make it work by doing pgm_read_byte(&(alphanum[ch+17][c-1])), but that offends my sensibilities. Anyone have any idea why &alphanum[ch][c] is not giving me the correct pointer?

Compiled like so: avr-gcc tinypendant.c -Os -mmcu=attiny2313 -o tinypendant.hex
Uploaded to ATtiny2313 like so: avrdude -p attiny2313 -c usbtiny -U flash:w:tinypendant.hex

Could it be the -Os? If I turn that off, it pitches a fit and stops working since I'm using delay functions from avr-libc in other parts of the code.

fake edit: for you people that read the Embedded Programming thread, should I cross-post this there?

real edit: here's the main loop
code:
 uint16_t k = 17;
 for(;;)
 {
  blank();
  parse_char(k);
  if( (PIND & (1<<PD6)) == 0 )
  {
   k++;
   if( k > 50 )
   k = 0;
   // lazy "debouncing"
   _delay_ms(200);
  }
 }

nightchild12 fucked around with this message at 05:41 on May 15, 2013

nightchild12
Jan 8, 2005
hi i'm sexy

nightchild12 posted:

Not directly Arduino, but closely related: I'm doing a thing on an ATtiny2313 with avr-gcc and having problems with progmem.

I'm trying to set up a character (and graphics) set for a 5x7 LED matrix. I don't have enough RAM on the ATtiny2313 to hold the whole array of character maps, so I'm trying to store them on flash using progmem. However, when I try to access the data, the progmem array is giving me pointers to someplace before where the data is actually stored. It's storing the data OK, I can see it in the compiled .hex file, but when I try to access it with pgm_read_byte(&(alphanum[ch][c])) it returns the byte at &alphanum[ch-17][c+1].

Turns out it was a problem with WinAVR and/or that version of avr-gcc. I downloaded Atmel Studio and recompiled the exact same code with it and it magically started working, at like a quarter the size of the WinAVR compiled program. The Atmel Studio IDE is quite nice, as well.

nightchild12
Jan 8, 2005
hi i'm sexy

Sagebrush posted:

I think there's also a way to fire a timer interrupt if you need microsecond-precision timing. If you're already using a method like this, ignore and carry on.

There is a way to do this, but the standard Arduino library doesn't support it. To use interrupts properly, you have to find another library or poke bits into the AVR registers directly. I prefer to access the AVR registers directly. Keep in mind, if you do stuff with interrupts (especially timer interrupts), you can easily break other Arduino-provided functions (like PWM, since it relies on timer interrupt functions to work).

Here's how you set up a timer interrupt on an ATTiny2313, taken from an LED matrix project I'm working on. A quick check of the datasheet shows that this looks like it should work with the ATMega328 as well. Example assumes 1MHz CPU frequency:

quote:

//
// necessary includes
//
#include <avr/interrupt.h>

//
// Timer0 Comparison A Interrupt Vector Interrupt Service Routine //
// runs code in the function when timer0 reaches the compA value
// then returns and runs at least one instruction from where it left
//
ISR(TIMER0_COMPA_vect)
{
// do stuff here
}

//
// Timer0 Comparison A Setup
//
// Timer0 set "Clear on Timer Compare" mode, register TCCR0A |= 0b00000010 (WGM01 = 1, WGM00 = 0)
// in CTC mode, Timer0 counts up from 0 until it hits the value of OCR0A, then sets Timer0 to 0 and fires the interrupt
TCCR0A |= (1<<WGM01);
// Timer0 output compare match A interrupt enable, register TIMSK |= 0b00000001 (OCIE0A = 1)
// enables the interrupt so the timer actually fires it off instead of just counting up to OCR0A and resetting to 0
TIMSK |= (1<<OCIE0A);
// Timer0 clock select /8 prescaler (125KHz), register TCCR0B |= 0b00000010 (CS02 = 0, CS01 = 1, CS00 = 0)
// sets the timer0 prescaler, so that timer0 only counts once every 8 clock cycles
TCCR0B |= (1<<CS01);
// Timer0 Output Compare A (3125Hz refresh), register OCR0A = 40
// value of OCR0A, since I use a 1MHz clock and set the prescaler to /8, this fires off at a 3125Hz rate (1,000,000 / 8 = 125,000 / 40 = 3,125)
OCR0A = 40;
// enable global interrupts so that interrupts can actually fire
sei(); // global interrupt enable

The above makes it so that the interrupt fires at 3125Hz and does whatever you have in the ISR. You can change the prescaler and Output Compare A values to change the rate at which the interrupt fires. I believe that the ATMega328 has 3 timers, each with a Compare A and Compare B plus overflow interrupts, which you can be clever with and stretch out to get a whole lot of different interval timer interrupts out of.

With the above, assuming a 1MHz clock, if you want a 50ms delay between interrupts firing, you'd want to set the prescaler to /256 [ TCCR0B = 0; TCCR0B |= (1<<CS02); ] and the compare value to 195 (1,000,000Hz / 256 = 3906.25 / 195 = reciprocal of 49.92ms) or 196 (1,000,000Hz / 256 = 3906.25 / 196 = reciprocal of 50.176ms). Or use Timer1 since it's 16 bit and can actually get the exact 50ms timing.

To do it with an Arduino running at 16MHz, I think you'd need to use the 16 bit Timer1, since Timer0 and Timer2 are 8 bit and can only get up to 16,000,000Hz / 1024 = 15625Hz / 255 = ~61.275Hz = ~16.32ms max delay between triggering interrupts. Assuming my math isn't off, of course.

Possible prescaler values are /1, /8, /64, /256, and /1024. Timer compare values are 8-bit for Timer0 and Timer2 and 16-bit for Timer1 (same size as the timer counters).

edit: If you do use interrupts, I believe that it's generally considered best practice to keep the ISR as short as possible so you aren't blocking in the interrupt for longer than necessary. Especially never let an ISR get big enough that another interrupt might trigger during it, unless you really really have to and account for the possibility.

nightchild12 fucked around with this message at 05:51 on Apr 5, 2014

Adbot
ADBOT LOVES YOU

nightchild12
Jan 8, 2005
hi i'm sexy

Amberskin posted:

Wasn't it posible to brick the arduino reprogramming the timer interrupts? I remember to have read something about breaking the bootloader so rendering the Arduino bricked until you can reinstall it.

I can't find it in google though, so perhaps I'm wrong.

All I can find is this https://forum.sparkfun.com/viewtopic.php?f=32&t=30417 and I'm not sure how that managed to brick an Arduino. Maybe it's possible for an ISR to overwrite part of the bootloader or the bootloader needs those interrupts for something? I've seen a ton of tutorials on using interrupts via an Arduino (like http://www.instructables.com/id/Arduino-Timer-Interrupts/ which looks pretty good) and never seen problems with it breaking the bootloader mentioned.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply