understanding touchLib.h

Hi,
since there is an easy-to-use library for my touch-display I looked forward to design my own menu.

nice video here, too
http://www.mafu-foto.de/elektronik/arduino/98-touch-library-fuer-arduino-und-watterott-mi0283qt-2-display

Now I tried to customize a bit further than just modifying the buttons. It seems like the touch.buttonAdd()-function has to be called from the setup. Could it be, that there is no way to call it from a function?

Could someone help me reading this short-code? It has just a lot of arrows in there...
http://www.mafu-foto.de/download/elektronik/arduino/libraries/TouchLib_v0.1.zip

Thanks,
Kevin

It seems like the touch.buttonAdd()-function has to be called from the setup.

Why do you think this? Have you tried calling it from another function?

yes.

this works:

void setup()
{
  touch.buttonAdd(...);
}

this wont:

void funct()
{
  touch.buttonAdd(...);
}

void setup()
{
  funct();
}

"This doesn't work" doesn't mean anything. You need to do a better job of describing the problem. Does the code fail to compile? Does the code compile, but the function doesn't get called? Does the code compile and the function gets called, but doesn't appear to add a button to the screen? Does the button get added but not look right?

If the code compiles, and the function gets called, but the button does not appear, you need to post all of your real code.

sorry for the bad description.

I started with the given example. It works fine and does what it should do displaying buttons which can be pressed correctly.

Then I tried to "outsource" a single buttonAdd-Line in a separate function.
Compiling gives no error, but the display keeps black. As I do not understand the touchLib.h-code it is really hard for me to do some systematic troubleshooting.

As I do not understand the touchLib.h-code it is really hard for me to do some systematic troubleshooting.

As you haven't posted your code, it is really hard for us to help you.

As I used the given example-code I thought it would be easier to download it directly.

Here it comes.

My modified version of TouchLib_Demo.pde. (commented with "<---- this is the change"

/* Arduino touch library v0.1 example
 * Copyright (C) 2011 Manfred Fuchs
 * www.mafu-foto.de
 * manfred@fuchsrudel.de
 *
 * 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 2 of the License, or
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <MI0283QT2.h>
#include <ADS7846.h>
#include <TouchLib.h>

#define TP_EEPROMADDR (0x00) //eeprom address for calibration data

MI0283QT2 lcd;
ADS7846 tp;
Touch touch(&lcd, &tp, 5);

void tp_calibration(uint8_t check_eeprom)
{
  int i;
  CAL_POINT lcd_points[3] = {{CAL_POINT_X1,CAL_POINT_Y1},
                             {CAL_POINT_X2,CAL_POINT_Y2},
                             {CAL_POINT_X3,CAL_POINT_Y3}}; //calibration point postions
  CAL_POINT tp_points[3], *p;

  //calibration data in EEPROM?
  if(tp.readCalibration(TP_EEPROMADDR) && check_eeprom)
  {
    return;
  }

  //wait for touch release
  lcd.clear(COLOR_WHITE);
  lcd.drawText((lcd.getWidth()/2)-50, (lcd.getHeight()/2)-10, "Calibration", 1, COLOR_BLACK, COLOR_WHITE);
  while(tp.getPressure() > 5){ tp.service(); };

  //show calibration points
  i = 0;
  do
  {
    //draw points
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 1, RGB(0,0,0));
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 4, RGB(0,0,0));
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 8, RGB(255,0,0));

    //run service routine
    tp.service();

    //press dectected?
    if(tp.getPressure() > 5)
    {
      tp_points[i].x = tp.getXraw();
      tp_points[i].y = tp.getYraw();
      i++;
      lcd.clear(COLOR_WHITE);
      delay(100);
    }
  }while(i<3);

  //calulate calibration matrix
  tp.setCalibration(lcd_points, tp_points);

  //save calibration matrix
  tp.writeCalibration(TP_EEPROMADDR);
}

void button2()
{
  touch.buttonAdd( 10,  70, 160, 40, COLOR_BLUE, COLOR_RED, COLOR_WHITE, true,  false, 0, 2, "Button 2");
}


void setup()
{
  //init Display
  lcd.init(4); //spi-clk = Fcpu/4

  //init Touch-Controller
  tp.init();

  //clear Screen
  lcd.clear(COLOR_WHITE);

  //Touch-Panel Calibration
  tp.service();
  if(tp.getPressure() > 5)
  {
    tp_calibration(0); //dont check EEPROM for calibration data
  }
  else
  {
    tp_calibration(1); //check EEPROM for calibration data
  }

  //Backlight LED
  lcd.led(60); //backlight 0...100%
  lcd.drawText( 2, 2, "BL", 1, COLOR_RED, COLOR_WHITE);
  lcd.drawText(20, 2, 60,   1, COLOR_RED, COLOR_WHITE);

  //Cal text
  lcd.drawText(lcd.getWidth()-30, 2, "CAL", 1, COLOR_RED, COLOR_WHITE);

  touch.buttonAdd( 10,  20, 160, 40, COLOR_BLUE, COLOR_RED, COLOR_WHITE, true,  false, 0, 2, "Button 1");
  button2; // <---- this is the change
  
  /*touch.buttonAdd( 10,  70, 160, 40, COLOR_BLUE, COLOR_RED, COLOR_WHITE, true,  false, 0, 2, "Button 2");
  touch.buttonAdd( 10, 120, 160, 40, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false, true,  0, 2, "Button 3");
  touch.buttonAdd( 10, 170, 160, 40, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false, true,  0, 2, "Button 4");
  touch.buttonAdd(200,  26,  90, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, true,  false, 0, 1, "Button 5");
  touch.buttonAdd(200,  76,  90, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false, true,  1, 1, "Button 6");
  touch.buttonSetDown(touch.buttonAdd(200, 126,  90, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false, true,  1, 1, "Button 7"), true);
  touch.buttonAdd(200, 176,  90, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false, true,  1, 1, "Button 8");*/
  touch.buttonsDraw();
}


void loop()
{
  char tmp[128];
  static uint16_t last_x=0, last_y=0;
  static uint8_t led=60;
  unsigned long m;
  static unsigned long prevMillis=0;
  TouchButtonPtr btn;
  uint16_t txtPos;

  //service routine
  tp.service();

  //show tp data
  sprintf(tmp, "X:%03i|%04i Y:%03i|%04i P:%03i", tp.getX(), tp.getXraw(), tp.getY(), tp.getYraw(), tp.getPressure());
  lcd.drawText(45, 2, tmp, 1, COLOR_BLACK, COLOR_WHITE);

  btn = touch.check();
  if (btn != NULL)
  {
    txtPos = lcd.drawText(10, 220, "\"", 1, COLOR_BLACK, COLOR_WHITE);
    txtPos = lcd.drawText(txtPos, 220, btn->caption, 1, COLOR_BLACK, COLOR_WHITE);
    lcd.drawText(txtPos, 220, "\" pressed", 1, COLOR_BLACK, COLOR_WHITE);
  }

  if(tp.getPressure() > 3) //touch press?
  {
    //change backlight power
    if((tp.getX() < 45) && (tp.getY() < 15))
    {
      m = millis();
      if((m - prevMillis) > 800) //change only every 800ms
      {
        prevMillis = m;

        led += 10;
        if(led > 100)
        {
          led = 10;
        }
        lcd.led(led);
      }
    }

    //calibrate touch panel
    else if((tp.getX() > (lcd.getWidth()-30)) && (tp.getY() < 15))
    {
      tp_calibration(0);
    }

    //show backlight power and cal text
    lcd.drawText( 2,                2, "BL    ", 1, COLOR_RED, COLOR_WHITE);
    lcd.drawText(20,                2, led,      1, COLOR_RED, COLOR_WHITE);
    lcd.drawText(lcd.getWidth()-30, 2, "CAL",    1, COLOR_RED, COLOR_WHITE);
  }
  else
  {
    last_x = 0;
  }
}

TouchLib.h

/* Arduino touch library v0.1
 * Copyright (C) 2011 Manfred Fuchs
 * www.mafu-foto.de
 * manfred@fuchsrudel.de
 *
 * 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 2 of the License, or
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef TouchLib_h
#define TouchLib_h

/**
 * max length of button caption
 */
#define TOUCH_MAX_BUTTON_CAPTION_LEN  32

/**
 * size of button shadow
 */
#define BUTTON_SHADOW  2

/**
 * color macros
 */
#define RGB_R(rgb)   ((rgb>>8)&0x00F8)
#define RGB_G(rgb)   ((rgb>>3)&0x00FC)
#define RGB_B(rgb)   ((rgb<<3)&0x00F8)

/**
 * define pointer type for LCD and panel
 */
typedef MI0283QT2 *lcdPtr;
typedef ADS7846   *tpPtr;

/**
 * button format struct
 */
typedef struct
{
  void      *next;
  uint16_t  left;
  uint16_t  top;
  uint16_t  width;
  uint16_t  height;
  uint16_t  col_normal;
  uint16_t  col_down;
  uint16_t  col_text;
  uint8_t   size;
  uint8_t   group;
  bool      round;
  bool      toggle;
  bool      down;
  char      caption[TOUCH_MAX_BUTTON_CAPTION_LEN+1];
} TouchButton;
typedef TouchButton *TouchButtonPtr;

class Touch
{
  private:
    lcdPtr         lcd;
    tpPtr          tp;
    uint8_t        pressure;
    TouchButtonPtr buttons;
    TouchButtonPtr startBtn;
    TouchButtonPtr lastBtn;
    bool           pressed;
    uint16_t       startX;
    uint16_t       startY;
    uint16_t       posX;
    uint16_t       posY;
    void           buttonDraw(TouchButtonPtr _button, bool _down);
    void           buttonDrawRect(uint16_t _l, uint16_t _t, uint16_t _w, uint16_t _h, uint16_t _c);
    void           buttonDrawRound(uint16_t _l, uint16_t _t, uint16_t _w, uint16_t _h, uint16_t _c);
    TouchButtonPtr buttonFromPos(uint16_t _x, uint16_t _y);
    void           buttonState(TouchButtonPtr _current);
    bool           checkPressure(bool _pressed);
  public:
    Touch(lcdPtr _lcd, tpPtr _tp, uint8_t _pressure);
    TouchButtonPtr buttonAdd(uint16_t _left, uint16_t _top, uint16_t _width, uint16_t _height, uint16_t _col_normal, uint16_t _col_down, uint16_t _col_text, bool _round, bool _toggle, uint8_t _group, uint8_t _size, char *_caption);
    bool           buttonDown(TouchButtonPtr _button);
    void           buttonSetDown(TouchButtonPtr _button, bool _down);
    void           buttonsClear();
    void           buttonsDraw();
    TouchButtonPtr check();
};

#endif

...

...
TouchLib.cpp

#undef abs
#include <MI0283QT2.h>
#include <ADS7846.h>
#include <fonts.h>
// include this library's description file
#include "TouchLib.h"


// *** private functions *****************************************************

void Touch::buttonDraw(TouchButtonPtr _button, bool _down)
{
  uint16_t col;

  if (_button != NULL)
  {
    col = (_down) ? _button->col_down : _button->col_normal;
    if (_button->round)
      this->buttonDrawRound(_button->left, _button->top, _button->width, _button->height, col);
    else
      this->buttonDrawRect(_button->left, _button->top, _button->width, _button->height, col);
    this->lcd->drawText(_button->left + _button->width / 2 - strlen(_button->caption) * FONT_WIDTH * _button->size / 2,
                        _button->top + _button->height / 2 - FONT_HEIGHT * _button->size / 2,
                        _button->caption, _button->size, _button->col_text, col);

/*
    // buttons with shadow
    if (_down)
    {
      if (_button->round)
      {
        this->buttonDrawRound(_button->left, _button->top, _button->width, _button->height, COLOR_BLACK);
        this->buttonDrawRound(_button->left + BUTTON_SHADOW, _button->top + BUTTON_SHADOW, _button->width, _button->height, _button->col_down);
      }
      else
      {
        this->buttonDrawRect(_button->left, _button->top, _button->width, _button->height, COLOR_BLACK);
        this->buttonDrawRect(_button->left + BUTTON_SHADOW, _button->top + BUTTON_SHADOW, _button->width, _button->height, _button->col_down);
      }
      this->lcd->drawText(_button->left + _button->width / 2 - strlen(_button->caption) * FONT_WIDTH * _button->size / 2 + BUTTON_SHADOW,
                          _button->top + _button->height / 2 - FONT_HEIGHT * _button->size / 2 + BUTTON_SHADOW,
                          _button->caption, _button->size, _button->col_text, _button->col_down);
    }
    else
    {
      if (_button->round)
      {
        this->buttonDrawRound(_button->left + BUTTON_SHADOW, _button->top + BUTTON_SHADOW, _button->width, _button->height, COLOR_BLACK);
        this->buttonDrawRound(_button->left, _button->top, _button->width, _button->height, _button->col_normal);
      }
      else
      {
        this->buttonDrawRect(_button->left + BUTTON_SHADOW, _button->top + BUTTON_SHADOW, _button->width, _button->height, COLOR_BLACK);
        this->buttonDrawRect(_button->left, _button->top, _button->width, _button->height, _button->col_normal);
      }
      this->lcd->drawText(_button->left + _button->width / 2 - strlen(_button->caption) * FONT_WIDTH * _button->size / 2,
                          _button->top + _button->height / 2 - FONT_HEIGHT * _button->size / 2,
                          _button->caption, _button->size, _button->col_text, _button->col_normal);
    }
*/
  }
}

void Touch::buttonDrawRect(uint16_t _l, uint16_t _t, uint16_t _w, uint16_t _h, uint16_t _c)
{
  this->lcd->fillRect(_l, _t, _l + _w - 1, _t + _h - 1, _c);
}

void Touch::buttonDrawRound(uint16_t _l, uint16_t _t, uint16_t _w, uint16_t _h, uint16_t _c)
{
  int16_t x0, y0, x, y, xw, err;

  x0  = _l + _w / 2;
  y0  = _t + _h / 2;
  x   = _h / 2;
  y   = 0;
  xw  = _w / 2 - x;
  err = -x;

  this->lcd->setArea(0, 0, this->lcd->lcd_width - 1, this->lcd->lcd_height - 1);

  while(x >= y)
  {
    this->lcd->drawLine(x0 - x - xw, y0 + y, x0 + x + xw - 1, y0 + y, _c);
    this->lcd->drawLine(x0 - x - xw, y0 - y, x0 + x + xw - 1, y0 - y, _c);
    this->lcd->drawLine(x0 - y - xw, y0 + x, x0 + y + xw - 1, y0 + x, _c);
    this->lcd->drawLine(x0 - y - xw, y0 - x, x0 + y + xw - 1, y0 - x, _c);

    err += y;
    y++;
    err += y;
    if(err >= 0)
    {
      x--;
      err -= x;
      err -= x;
    }
  }
}

TouchButtonPtr Touch::buttonFromPos(uint16_t _x, uint16_t _y)
{
  TouchButtonPtr btn = (TouchButtonPtr)this->buttons;
  while (btn != NULL)
  {
    if ((_x >= btn->left) && (_x < btn->left + btn->width) &&
        (_y >= btn->top)  && (_y < btn->top  + btn->height))
    {
      return btn;
    }
    btn = (TouchButtonPtr)btn->next;
  }
  return NULL;
}

void Touch::buttonState(TouchButtonPtr _current)
{
  if (_current != NULL)
  {
    if (_current->toggle)
    {
      if (_current->group == 0)
      {
        _current->down = !_current->down;
        this->buttonDraw(_current, _current->down);
      }
      else
      {
        if (!_current->down)
          this->buttonDraw(_current, true);
        _current->down = true;
      }
    }
  }
  TouchButtonPtr btn = (TouchButtonPtr)this->buttons;
  while (btn != NULL)
  {
    if ((btn != _current) && btn->toggle && (btn->group > 0) && (btn->group == _current->group))
    {
      if (btn->down)
        this->buttonDraw(btn, false);
      btn->down = false;
    }
    btn = (TouchButtonPtr)btn->next;
  }
}

bool Touch::checkPressure(bool _pressed)
{
  if (this->tp->getPressure() >= this->pressure)
  {
    if (!_pressed)
    {
      for (uint8_t i = 0; i < 10; i++)
      {
        delay(10);
        if (this->tp->getPressure() < this->pressure)
          return false;
      }
      return true;
    }
    else
      return true;
  }
  else
  {
    if (_pressed)
    {
      for (uint8_t i = 0; i < 10; i++)
      {
        delay(10);
        if (this->tp->getPressure() >= this->pressure)
          return true;
      }
      return false;
    }
    else
      return false;
  }
}


// *** public functions ******************************************************

Touch::Touch(lcdPtr _lcd, tpPtr _tp, uint8_t _pressure)
{
  this->lcd      = _lcd;
  this->tp       = _tp;
  this->pressure = _pressure;
  this->buttons  = NULL;
  this->startBtn = NULL;
  this->lastBtn  = NULL;
  this->pressed  = false;
  this->startX   = 0;
  this->startY   = 0;
  this->posX     = 0;
  this->posY     = 0;
}

TouchButtonPtr Touch::buttonAdd(uint16_t _left, uint16_t _top, uint16_t _width, uint16_t _height, uint16_t _col_normal, uint16_t _col_down, uint16_t _col_text, bool _round, bool _toggle, uint8_t _group, uint8_t _size, char *_caption)
{
  TouchButtonPtr btn = (TouchButtonPtr)malloc(sizeof(TouchButton));
  btn->next          = NULL;
  btn->left          = _left;
  btn->top           = _top;
  btn->width         = _width;
  btn->height        = _height;
  btn->col_normal    = _col_normal;
  btn->col_down      = _col_down;
  btn->col_text      = _col_text;
  btn->size          = _size;
  btn->group         = _group;
  btn->round         = _round;
  btn->toggle        = _toggle;
  btn->down          = false;
  strcpy(btn->caption, _caption);
  if (this->buttons == NULL)
    this->buttons = btn;
  else
  {
    TouchButtonPtr nxt = (TouchButtonPtr)this->buttons;
    while (nxt->next != NULL)
      nxt = (TouchButtonPtr)nxt->next;
    nxt->next = btn;
  }
  return btn;
}

bool Touch::buttonDown(TouchButtonPtr _button)
{
  if (_button != NULL)
    return _button->down;
  else
    return false;
}

void Touch::buttonSetDown(TouchButtonPtr _button, bool _down)
{
  if ((_button != NULL) && (_button->down != _down))
  {
    if (_down && _button->toggle && (_button->group != 0))
      this->buttonState(_button);
    else
    {
      _button->down = _down;
      this->buttonDraw(_button, _down);
    }
  }
}

void Touch::buttonsClear()
{
  TouchButtonPtr btn;
  while (this->buttons != NULL)
  {
    btn           = (TouchButtonPtr)this->buttons;
    this->buttons = (TouchButtonPtr)this->buttons->next;
    free(btn);
  }
}

void Touch::buttonsDraw()
{
  TouchButtonPtr btn = (TouchButtonPtr)this->buttons;
  while (btn != NULL)
  {
    this->buttonDraw(btn, btn->down);
    btn = (TouchButtonPtr)btn->next;
  }
}

TouchButtonPtr Touch::check()
{
  TouchButtonPtr selBtn = NULL;
  if (checkPressure(this->pressed))
  {
    this->posX = this->tp->getX();
    this->posY = this->tp->getY();
    if (!this->pressed)
    {
      this->pressed  = true;
      this->startX   = this->posX;
      this->startY   = this->posY;
      this->startBtn = this->buttonFromPos(this->startX, this->startY);
      this->lastBtn  = this->startBtn;
      this->buttonDraw(this->startBtn, true);
    }
    else
    {
      if ((this->posY != this->startX) || (this->posY != this->startY))
      {
        TouchButtonPtr currBtn = this->buttonFromPos(this->posX, this->posY);
        if (currBtn != this->startBtn)
          currBtn = NULL;
        if (currBtn != this->lastBtn)
        {
          this->buttonDraw(this->lastBtn, false);
          this->buttonDraw(currBtn, true);
          this->lastBtn = currBtn;
        }
      }
    }
  }
  else
  {
    if (this->pressed)
    {
      if (this->buttonFromPos(this->posX, this->posY) == this->startBtn)
      {
        selBtn = this->startBtn;
        this->buttonState(selBtn);
        if (!selBtn->down)
          this->buttonDraw(selBtn, false);
      }
      else
        this->buttonState(NULL);
      this->pressed = false;
    }
  }
  return selBtn;
}
  button2; // <---- this is the change

This is not how to call a function. You need () after the function name to call the function, just like every other function call you are making.

thanks a lot - I already found out, that it was some general mistake I was doing.

I am using the same library but encountered some difficulties trying to directly set several button functions. I would like to combine the Touchshield interaction with a rotary encoder. Hence, I need to toggle the Button state from within the arduino code (ideally triggered by an external interrupt!). As far as I understood, I would need to assign a pointer to the buttonAdd() function. Something like this:

[code]
TouchButton *button1 = touch.buttonAdd( 10,  10,  80, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false,  true,  1, 1, "Button1",  1);

// interrupt function
ISR(INT1_vect) {
// toggle current submenu
 if (touch.buttonDown(button1) == true) { 
    touch.buttonSetDown(button1, false);
  }
  else {
    touch.buttonSetDown(button1, true);
  }
}

The problem is that as soon as I put the pointer variable declaration inside of a function the code breaks.

for example like this:

void draw_main_screen() {
  TouchButton *button1 = touch.buttonAdd( 10,  10,  80, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false,  true,  1, 1, "Button1",  1);
  TouchButton *button2 = touch.buttonAdd( 10,  50,  80, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false,  true,  1, 1, "Button2",  2);
  TouchButton *button3 = touch.buttonAdd( 10,  90,  80, 28, COLOR_BLUE, COLOR_RED, COLOR_WHITE, false,  true,  1, 1, "Button3",  3);
}

draw_main_screen();

// interrupt function
ISR(INT1_vect) {
// toggle current submenu
 if (touch.buttonDown(button1) == true) { 
    touch.buttonSetDown(button1, false);
  }
  else {
    touch.buttonSetDown(button1, true);
  }
}

I also noticed some glitches for the toggle (using the buttonSetDown function). Sometimes part of the button remain in blue whereas the background below the font changes to red.

I am not sure whether using the Touchlib library is a constraint to what I am planning to do. So, perhaps someone can't point out about the problematic with using pointers outside of void_functions and what are the flaws of such an approach!?

thx![/code]

The problem is that as soon as I put the pointer variable declaration inside of a function the code breaks.

Those variables are local to the function. As soon as the function ends, the variable goes out of scope (ceases to exist).

In the ISR, the pointers do not exist, so you can't reference them.

In the ISR, the pointers do not exist, so you can't reference them.

Sure, that's what I was expecting, but what would be an efficient approach to use them outside of the function?; i.e. the only way is to define them outside in the global scope of the program?

what would be an efficient approach to use them outside of the function?

For a variable of any type to be used outside of a function, it's scope must extend such that it covers where it is defined and where it is to be used.

Scope is local, class, file or global. Since you are not dealing with a class, and file is not really relevant when you only have one file, that leaves local and global. You already know that local is too narrow, so that only leaves you with one choice.