Go Down

Topic: Change variable from Interrupt while loop is running (Read 1 time) previous topic - next topic

bilbo

Hi all,
Maybe this is a dumb question, but I have this code for a WiFi spectrum analyzer I made, and it works well, but I have two problems. First, while the scan is running, it is a loop drawing the array of values onto the lcd. However, if I press the button (the interrupt routine) during the update, it doesnt change until the loop is finished. Is there a way to change the loop counter (variable n) from the interrupt, so it will advance to the new mode right away? Also, it takes a very long time to draw the array of values on the LCD, is there any way to reduce this? More information and a video are here: http://arduino.cc/forum/index.php/topic,52655.msg375811.html#msg375811
Code: [Select]
#include <rssi.h>
#include <SPI.h>

///Spectrum analyzer code for Arduino, CYWM6935, and PCD8544 Display.
///LCD Functions adapted from http://www.arduino.cc/playground/Code/PCD8544 thanks to the great community there!
///CYWM6935 Functions adapted from http://ea4eoz.ure.es/hsa.html thank you as well.
/////////////////////////////////////////////////////////////////
// Connections:
//Arduino pin 8 => Logic Level Translator => CYWM6935 Reset Pin
//Arduino pin 9 => Logic Level Translator => CYWM6935 SS Pin
//Arduino pin 11 => Logic Level Translator => CYWM6935 MOSI Pin
//Arduino pin 12 => CYWM6935 MISO Pin
//Arduino pin 13 => Logic Level Translator => CYWM6935 SCK Pin
//Radio PD pin -> 5v
//Arduino pin 6 => Logic Level Translator => LCD Reset pin
//Arduino pin 5 => Logic Level Translator => LCD DC pin
//Arduino pin 4 => Logic Level Translator => LCD SDIN pin
//Arduino pin 3 => Logic Level Translator => LCD SCLK pin
/////////////////////////////////////////////////////////////////

// LCD Pin Definitions and Variables
#define PIN_SCE   7 
#define PIN_RESET 6 
#define PIN_DC    5 
#define PIN_SDIN  4
#define PIN_SCLK  3
#define LCD_VISIBLE_X_RES 84
#define LCD_C     LOW
#define LCD_D     HIGH
#define LCD_X     84
#define LCD_Y     48
#define LCD_CMD   0
#define OUT_OF_BORDER 1
#define PIXEL_ON  1
#define PIXEL_OFF   0
#define MAXCHANNEL 84
int bottom = 0;

#define MODECOUNT 5
int buttonPin = 2;  // Mode-Changing Button
volatile int mode; //1 is normal, 2 is digital (stepping) mode, 3 is exposure mode
char signal[MAXCHANNEL];
unsigned char n=0;
int Lcd_TOP = 40;
int Lcd_visible = Lcd_TOP - bottom;
volatile bool toggled = 0;
rssi radio;

void setup() {
  pinMode(buttonPin, INPUT);    // button as input
  digitalWrite(buttonPin, HIGH); // turns on pull-up resistor after input
  // Hardware initialization


  LcdInitialise();
  LcdClear();
  radio.RADIO_Init();
  attachInterrupt(0, toggle, FALLING);
  mode = 1;

}
void loop() {
  if(toggled)
  {
    switchmode();
  }
  if (mode == 1)
  {


    gotoXY(75,5);
    LcdCharacter('F');
    gotoXY(69,5);
    LcdCharacter('a');
    gotoXY(63,5);
    LcdCharacter('s');

    gotoXY(57,5);
    LcdCharacter('t');

    gotoXY(51,5);
    LcdCharacter(' ');
    gotoXY(45,5);
    LcdCharacter('S');
    gotoXY(39,5);
    LcdCharacter('c');

    gotoXY(33,5);
    LcdCharacter('a');

    gotoXY(27,5);
    LcdCharacter('n');


    // Read signals
    for (unsigned char n=0; n<MAXCHANNEL; n++){
      // Read the signal on current channel
      unsigned char s = radio.RADIO_RSSI(n);
      s = map(s, 0, 31, 0,Lcd_visible);
      signal[n]=s;
    }
    for (unsigned char n = LCD_VISIBLE_X_RES; n > 0; n--){
      drawLine(n,Lcd_TOP,PIXEL_OFF);
      drawLine(n,signal[abs(LCD_VISIBLE_X_RES-n)], PIXEL_ON);

    }
  }

  else if (mode == 2)
  {

    gotoXY(75,5);
    LcdCharacter('S');
    gotoXY(69,5);
    LcdCharacter('l');
    gotoXY(63,5);
    LcdCharacter('o');

    gotoXY(57,5);
    LcdCharacter('w');

    gotoXY(51,5);
    LcdCharacter(' ');
    gotoXY(45,5);
    LcdCharacter('S');
    gotoXY(39,5);
    LcdCharacter('c');

    gotoXY(33,5);
    LcdCharacter('a');

    gotoXY(27,5);
    LcdCharacter('n');

    // Read signals
    for (unsigned char n=0; n<MAXCHANNEL; n++){
      // Read the signal on current channel
      unsigned char s = radio.RADIO_RSSI(n);
      s = map(s, 0, 31, 0,Lcd_visible);
      if(s < signal[n])
      {
        signal[n] = signal[n]-1;
      }
      else {
        signal[n]=s;
      }
    }
    for (unsigned char n = LCD_VISIBLE_X_RES; n > 0; n--){
      drawLine(n,Lcd_TOP,PIXEL_OFF);
      drawLine(n,signal[abs(LCD_VISIBLE_X_RES-n)], PIXEL_ON);

    }
  }
  else if (mode == 3)
  {

    gotoXY(75,5);
    LcdCharacter('G');
    gotoXY(69,5);
    LcdCharacter('h');
    gotoXY(63,5);
    LcdCharacter('o');

    gotoXY(57,5);
    LcdCharacter('s');

    gotoXY(51,5);
    LcdCharacter('t');
    gotoXY(45,5);
    LcdCharacter(' ');
    gotoXY(39,5);
    LcdCharacter('S');

    gotoXY(33,5);
    LcdCharacter('c');

    gotoXY(27,5);
    LcdCharacter('a');

    gotoXY(21,5);
    LcdCharacter('n');
    // Read signals
    for (unsigned char n=0; n<MAXCHANNEL; n++){
      // Read the signal on current channel
      unsigned char s = radio.RADIO_RSSI(n);
      s = map(s, 0, 31, 0,Lcd_visible);
      if(s < signal[n])
      {
        signal[n] = signal[n];
      }
      else {
        signal[n]=s;
      }
    } 
    for (unsigned char n = LCD_VISIBLE_X_RES; n > 0; n--){
      drawLine(n,Lcd_TOP,PIXEL_OFF);
      drawLine(n,signal[abs(LCD_VISIBLE_X_RES-n)], PIXEL_ON);

    }

  }
  else if (mode == 4)
  {

    gotoXY(75,5);
    LcdCharacter('V');
    gotoXY(69,5);
    LcdCharacter('o');
    gotoXY(63,5);
    LcdCharacter('l');

    gotoXY(57,5);
    LcdCharacter('t');

    gotoXY(51,5);
    LcdCharacter('m');
    gotoXY(45,5);
    LcdCharacter('e');
    gotoXY(39,5);
    LcdCharacter('t');

    gotoXY(33,5);
    LcdCharacter('e');

    gotoXY(27,5);
    LcdCharacter('r');

    gotoXY(21,5);
    LcdCharacter('(');

    gotoXY(15,5);
    LcdCharacter('A');

    gotoXY(9,5);
    LcdCharacter('5');

    gotoXY(3,5);
    LcdCharacter(')');


    int aread = analogRead(5);
    float readval = (float)aread / 1023.0;
    readval = readval * 5.0;
    readval = readval * 100.0;
    int finalval = int(readval);
    char buffer [3] = {
      0, 0, 0            };
    itoa (finalval,buffer,10);

    gotoXY(50,3);
    LcdCharacter(buffer[0]);

    gotoXY(44,3);
    LcdCharacter('.');

    gotoXY(38,3);
    LcdCharacter(buffer[1]);

    gotoXY(32,3);
    LcdCharacter(buffer[2]);
    delay(500);

  }

  else if (mode == 5)
  {
    toggled = 0;
    gotoXY(75,5);
    LcdCharacter('M');
    gotoXY(69,5);
    LcdCharacter('i');
    gotoXY(63,5);
    LcdCharacter('n');

    gotoXY(57,5);
    LcdCharacter('i');

    gotoXY(51,5);
    LcdCharacter('-');
    gotoXY(45,5);
    LcdCharacter('S');
    gotoXY(39,5);
    LcdCharacter('c');

    gotoXY(33,5);
    LcdCharacter('o');

    gotoXY(27,5);
    LcdCharacter('p');

    gotoXY(21,5);
    LcdCharacter('e');

    gotoXY(15,5);
    LcdCharacter(' ');

    gotoXY(9,5);
    LcdCharacter('A');

    gotoXY(3,5);
    LcdCharacter('5');

    for (unsigned char n = LCD_VISIBLE_X_RES; n > 0; n--){

      drawLine(n,Lcd_TOP,PIXEL_OFF);
      int mappedval = map(analogRead(5), 0, 1023, 0,Lcd_visible);
      drawLine(n,mappedval,PIXEL_ON);


    }


    delay(10);
  }
}
void switchmode()
{
  toggled = 0;
  LcdClear();
  if(mode == MODECOUNT)
  {
    mode = 1;
  }
  else
  {
    mode++;
  }

}
void toggle()
{
  toggled = 1;

}

nickgammon

Well that's a cool project! I want one!

The simple way of speeding up the detection of button presses would be to exit from your inner loops when you detect a toggle.

Something like (using this loop as an example):

Code: [Select]
for (unsigned char n = LCD_VISIBLE_X_RES; n > 0; n--){
      drawLine(n,Lcd_TOP,PIXEL_OFF);
      drawLine(n,signal[abs(LCD_VISIBLE_X_RES-n)], PIXEL_ON);

      if (toggled) return;   // give up, they pressed the switch

    }


That will take you out of "loop", you get thrown back in, you notice the toggle, you change modes, etc.

Or this:

Code: [Select]
for (unsigned char n = LCD_VISIBLE_X_RES; n > 0 && !toggled; n--){
      drawLine(n,Lcd_TOP,PIXEL_OFF);
      drawLine(n,signal[abs(LCD_VISIBLE_X_RES-n)], PIXEL_ON);
    }

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon


Also, it takes a very long time to draw the array of values on the LCD, is there any way to reduce this?


I don't see how the drawing is implemented, but you should be able to do something with that. Is that I2C or SPI? Looks like SPI judging by the pins. That should be pretty fast.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

bilbo

The LCD is SPI, but Im using shiftOut because the hardware SPI is being used by the radio. Here are the functions to communicate with the LCD. (from a seperate h file).
My theory is that it is because I am running the LCD out of spec. (The LCD is 3.3v as an operating standard, but 5v as maximum). Would this cause it to slow down? Or is pulseout really that slow. If you look at the video in my last post, you see that the lcd write time is responsible for the slowness of the scanner. The flash at the end of each cycle is the radio turning on and consuming power on the 3,3 bus. The rest of the time per scan is being wasted on the lcd.
Here are the lcd functions:
Code: [Select]
void LcdWrite(byte dc, byte data)
{

 bitWrite(PORTD, PIN_DC, dc) ;
 bitWrite(PORTD, PIN_SCE, 0) ;
 shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
 bitWrite(PORTD, PIN_SCE, 1) ;

}

void LcdClear(void)
{
 for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
 {
   LcdWrite(LCD_D, 0x00);
 }
}
void LcdInitialise(void)
{

 pinMode(PIN_RESET, OUTPUT);
 pinMode(PIN_DC,    OUTPUT);
 pinMode(PIN_SDIN,  OUTPUT);
 pinMode(PIN_SCLK,  OUTPUT);
 pinMode(PIN_SCE, OUTPUT);
 digitalWrite(PIN_RESET, LOW);
 // delay(1);
 digitalWrite(PIN_RESET, HIGH);

 LcdWrite( LCD_CMD, 0x21 );  // LCD Extended Commands.
 LcdWrite( LCD_CMD, 0xB0 );  // Set LCD Vop (Contrast). //B1
 LcdWrite( LCD_CMD, 0x04 );  // Set Temp coefficent. //0x04
 LcdWrite( LCD_CMD, 0x14 );  // LCD bias mode 1:48. //0x13
 LcdWrite( LCD_CMD, 0x0C );  // LCD in normal mode. 0x0d for inverse
 LcdWrite(LCD_C, 0x20);
 LcdWrite(LCD_C, 0x0C);
}
void drawLine(unsigned int x, unsigned int y, int mode){
 y = y + bottom;
 for(int j= bottom; j<y; j++)
 {
   setPixel(x, j, mode);
 }
}
void setPixel(int x, int y, int d) {
 if (x > 84 || y > 48) {
   return;
 }
 // The LCD has 6 rows, with 8 pixels per  row.
 // 'y_mod' is the row that the pixel is in.
 // 'y_pix' is the pixel in that row we want to enable/disable
 int y_mod = (int)(y >> 3); // >>3 divides by 8
 int y_pix = (y-(y_mod << 3));// <<3 multiplies by 8
 int val = 1 << y_pix;

 /// We have to keep track of which pixels are on/off in order to
 // write the correct character out to the LCD.
 if (d){
   pixels[x][y_mod] |= val;
 }
 else {
   pixels[x][y_mod] &= ~val;
 }

 // Write the updated pixel out to the LCD
 // TODO Check if the pixel is already in the state requested,
 //      if so, don't write to LCD.
 gotoXY(x,y_mod);
 LcdWrite (1,pixels[x][y_mod]);
}

// gotoXY routine to position cursor
// x - range: 0 to 84
// y - range: 0 to 5
void gotoXY(int x, int y) {
 LcdWrite( 0, 0x80 | x);  // Column.
 LcdWrite( 0, 0x40 | y);  // Row.  
}

byte rev_bits ( byte val )
{
 byte ret = 0;
 byte n_bits = 8;

 for ( unsigned i = 0; i < n_bits; ++i ) {
   ret = ( ret << 1 ) | ( val & 1 );
   val >>= 1;
 }

 return ret;
}


void LcdCharacter(char character)
{
 LcdWrite(LCD_D, 0x00);
 for (int index = 5; index > -1; index=index-1)
 {
   LcdWrite(LCD_D, rev_bits(ASCII[character - 0x20][index]));
 }
 LcdWrite(LCD_D, 0x00);
}









nickgammon

You should be able to share the hardware SPI with the LCD. Just have a different SS (slave select) pin for each (that saves pins compared to what you are doing). Share the MOSI, MISO, and SCLK between both devices. Then bring SS low for the radio (to grab the info) and high again. Then bring the other SS low (for the LCD), write to it, and bring it high again. Using hardware SPI for the LCD should speed up things considerably.

So in setup, make sure both SS pins are high, and just bring the relevant ones low at the correct time.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

bilbo

I had tried this before and it hadn't worked. Is there any reason why it shouldn't or did I just make a mistake with the wiring? I think I will try it again when I get a chance. My breadboard prototype isn't too well organized so I probably just wired it wrong. I can't think of any reason why they shouldn't work on the same bus, because they are both running within spec for speed, and they have the same clock polarity and phase (at least I'm pretty sure of it from looking at the datasheets)...

Thanks!

nickgammon

You should be able to make it work. I think you can even change the clock polarity before activating the SS line if you absolutely had to.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up