Что такое void setup ардуино

Структура программы на языке C++ для Arduino

Рассмотрим пример минимально возможной программы на C++ для Arduino, которая ничего не делает:

Разберёмся что здесь написано и почему это обязательно: почему нельзя обойтись просто пустым файлом.

Из чего состоит программа

Для начала стоит понять, что программу нельзя читать и писать как книгу: от корки до корки, сверху вниз, строку за строкой. Любая программа состоит из отдельных блоков. Начало блока кода в C/C++ обозначается левой фигурной скобкой < , его конец — правой фигурной скобкой >.

Блоки бывают разных видов и какой из них когда будет исполняться зависит от внешних условий. В примере минимальной программы вы можете видеть 2 блока. В этом примере блоки называются определением функции. Функция — это просто блок кода с заданным именем, которым кто-то затем может пользоваться из-вне.

В данном случае у нас 2 функции с именами setup и loop . Их присутствие обязательно в любой программе на C++ для Arduino. Они могут ничего и не делать, как в нашем случае, но должны быть написаны. Иначе на стадии компиляции вы получите ошибку.

Классика жанра: мигающий светодиод

Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.

Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.

В наши ранее пустые функции мы добавили несколько выражений. Они были размещены между фигурными скобками функций setup и loop . В setup появилось одно выражение, а в loop сразу 4.

Каждое выражение — это приказ процессору сделать нечто. Выражения в рамках одного блока исполняются одно за другим, строго по порядку без всяких пауз и переключений. То есть, если мы говорим об одном конкретном блоке кода, его можно читать сверху вниз, чтобы понять что делается.

Теперь давайте поймём в каком порядке исполняются сами блоки, т.е. функции setup и loop . Не задумывайтесь пока что значат конкретные выражения, просто понаблюдайте за порядком.

Если пронумеровать выражения по порядку, как они исполняются, получится:

Ещё раз напомним, что не стоит пытаться воспринимать всю программу, читая сверху вниз. Сверху вниз читается только содержимое блоков. Мы вообще можем поменять порядок объявлений setup и loop .

Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.

Что делают выражения

Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.

Как известно, пины Arduino могут работать и как выходы и как входы. Когда мы хотим чем-то управлять, то есть выдавать сигнал, нам нужно перевести управляющий пин в состояние работы на выход. В нашем примере мы управляем светодиодом на 13-м пине, поэтому 13-й пин перед использованием нужно сделать выходом.

Это делается выражением в функции setup :

Выражения бывают разными: арифметическими, декларациями, определениями, условными и т.д. В данном случае мы в выражении осуществляем вызов функции. Помните? У нас есть свои функции setup и loop , которые вызываются чем-то, что мы назвали «нечто». Так вот теперь мы вызываем функции, которые уже написаны где-то.

Конкретно в нашем setup мы вызываем функцию с именем pinMode . Она устанавливает заданный по номеру пин в заданный режим: вход или выход. О каком пине и о каком режиме идёт речь указывается нами в круглых скобках, через запятую, сразу после имени функции. В нашем случае мы хотим, чтобы 13-й пин работал как выход. OUTPUT означает выход, INPUT — вход.

Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции. Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:

На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.

Вернёмся к нашему коду. Итак, поскольку мы планируем вечно мигать светодиодом, управляющий пин должен один раз быть сделан выходом и затем мы не хотим вспоминать об этом. Для этого идеологически и предназначена функция setup : настроить плату как нужно, чтобы затем с ней работать.

Перейдём к функции loop :

Она, как говорилось, вызывается сразу после setup . И вызывается снова и снова как только сама заканчивается. Функция loop называется основным циклом программы и идеологически предназначена для выполнения полезной работы. В нашем случае полезная работа — мигание светодиодом.

Пройдёмся по выражениям по порядку. Итак, первое выражение — это вызов встроенной функции digitalWrite . Она предназначена для подачи на заданный пин логического нуля ( LOW , 0 вольт) или логической единицы ( HIGH , 5 вольт) В функцию digitalWrite передаётся 2 аргумента: номер пина и логическое значение. В итоге, первым делом мы зажигаем светодиод на 13-м пине, подавая на него 5 вольт.

Как только это сделано процессор моментально приступает к следующему выражению. У нас это вызов функции delay . Функция delay — это, опять же, встроенная функция, которая заставляет процессор уснуть на определённое время. Она принимает всего один аргумент: время в миллисекундах, которое следует спать. В нашем случае это 100 мс.

Пока мы спим всё остаётся как есть, т.е. светодиод продолжает гореть. Как только 100 мс истекают, процессор просыпается и тут же переходит к следующему выражению. В нашем примере это снова вызов знакомой нам встроенной функции digitalWrite . Правда на этот раз вторым аргументом мы передаём значение LOW . То есть устанавливаем на 13-м пине логический ноль, то есть подаём 0 вольт, то есть гасим светодиод.

После того, как светодиод погашен мы приступаем к следующему выражению. И снова это вызов функции delay . На этот раз мы засыпаем на 900 мс.

Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.

Если перевести написанное на русский, получится следующий алгоритм:

Источник

Arduino Void Setup and Void Loop Functions [Explained]

When you open a new program in the Arduino IDE, you immediately get empty void setup and void loop functions written for you.

What are those void setup and void loop functions in Arduino?

In this tutorial I’ll explain to you the role of those functions and how to use them. At the end I’ll also give you some best practices to improve your Arduino programs.

Here is a quick video you can watch as an additional resource to this article:

If you like this video, subscribe to the Robotics Back-End Youtube channel so you don’t miss the next tutorials!

You are learning how to use Arduino to build your own projects?

Check out Arduino For Beginners and learn step by step.

Table of Contents

Void setup and void loop: mandatory functions in Arduino

The Arduino void setup and void loop functions are mandatory. Try to compile a code with one of those functions missing, and you’ll get an error.

When you run a “standard” C/C++ program, you have to write a “main” function. This main function will be called first, and from there, you will call other functions and execute the functionalities of your program.

In Arduino, there is no main function. This is replaced by setup and loop. Instead of one mandatory function, you have 2.

All your Arduino program must include those functions. On top of them, you can add any number of functions, variables, and create as many files as you want. You just need to make sure that the void setup and void loop are present.

How void setup and void loop work

Principle

As the “main” function is called when you run a C/C++ program, the setup and loop functions will be automatically called.

As soon as the program starts:

  1. Variables that you create on top of the program will be declared/initialized.
  2. The setup function will be called once.
  3. All the code you’ve written inside this function will be executed. After that, the setup function exits.
  4. Now the loop function will be called, so all the code inside the loop will be executed.
  5. When the loop function exists, go back to step 4.

The code inside the void setup will be executed once, and only once, at the beginning of the program.

Then, the code inside the void loop will be executed again and again (hence the name “loop”), until you:

  • Power off the Arduino board.
  • or Restart the Arduino program – by pressing the reset button / uploading a new sketch / re-opening the Serial Monitor on some Arduino boards.

After you start or restart the program, all the data – variable states and execution step – from the previous run will be lost. If you want to keep some data between different program runs, one easy way is to use the EEPROM memory if available.

Code Example

Let’s write a code example to see how the Arduino void setup and void loop work in detail.

And here’s the result when you compile the code, upload it to your Arduino board, and open the Serial Monitor.

Great, now let’s analyze this by breaking down the code line by line.

Init and void setup

First we create a global variable, so we can modify it inside a function and still be able to get its value in another function.

Note: even if you declare a variable without initializing it in Arduino, it will automatically get the value “0” (more info about the Arduino language). So, at this point of the program, the counter variable contains the value “0”.

This is the beginning of the void setup function. The execution will start with Serial.begin(9600); .

Still in the setup function, we set a new value (10) for the counter variable. And just after that we print the value in the Serial Monitor. In the output you get, this is where the line “Counter: 10” comes from.

And as you can notice, in line 9 we close the curly brackets for the void setup function. So, what’s happening now?

void loop

The void loop function is now called and every instruction you’ve provided here will be executed.

In this case, we increase the counter by 1 (so the first time we enter the loop, the counter goes from 10 to 11). Just after that, we print the value for the counter – this will be “Counter: 11”.

And finally, we add a 1 second pause to the program, so the output on the Serial Monitor will not be displayed to fast for our human eyes.

What happens when the void loop function exits?

Well, just after, it is called again. So, it means the line that comes after line 15 is line 12. The instruction just after delay(1000); is counter++; .

As the counter variable is a global variable, its value is not lost when we go out and enter the loop function again. So, now we increment it, it goes from 11 to 12.

And the cycle continues. Every time we enter the loop, we add 1 to the counter, print the value, and wait for 1 second.

Now, if you power off the Arduino, the program will stop. If you restart the program, any progress for the variables will be lost, and the entire program will start from the beginning.

Writing Arduino programs – best practices for void loop and void setup

Great, now that you understand how things work, I’m going to give you a few best practices you can implement right now in your Arduino programs, regarding those void setup and void loop functions.

Arduino void setup

As the void setup function is called only once at the very beginning of the program, this will be the place to:

  • Initialize variables’ values.
  • Setup communications (ex: Serial).
  • Setup modes for digital pins (input/output).
  • Initialize any hardware component (sensor/actuator) plugged to the Arduino.
  • Etc.

The void setup, as its name suggest, is made for you to do any setup required at the beginning of the program. Don’t write the core functionalities here, just the initialization code.

Depending on the complexity of your program, you may have a lot of instructions to write in that void function. You can create new functions that you call from the void setup, no problem with that.

Also, in general it’s better to avoid using delay(), but there’s no problem in the void setup: if a component needs 2 seconds to be initialized after being powered on, then wait 2 seconds!

Arduino void loop

Now, in the void loop you’ll write your main program, knowing that the initialization is already done. In this function, always keep in mind that the last line is followed by the first line!

Also, any variable you’ve declared inside the void loop will be lost when the program exits and enters the function again. So, if you want to be able to keep data between 2 void loop, make sure to declare variables in a more global scope.

As for void setup, there’s no need to write all the code directly in the function. You can create as many other functions as you want (and classes too), and call those functions in the void loop. Ideally, the void loop should contain just a few lines calling other functions. Don’t bloat your void loop, just as you don’t bloat your “main” in a standard C/C++ program.

Finally, pay attention to delay(). In the void loop (and any function called from the void loop) you don’t want to block the execution of the code too long, especially if you plan to do some kind of multi-threading with your Arduino.

Conclusion

Now you should have a better idea of the concept behind Arduino void setup and loop functions.

For now, focus on creating programs that work, and try to follow the best practices from this guide. As you progress with Arduino, you’ll get more understanding from your own experience. This experience will help you decide what you can/can’t do in your void setup and void loop functions – because in the end, every program is different.

Did you find this tutorial useful?

Do you want to learn Arduino from scratch?

If yes, this course is for you:

Did you find this tutorial useful?

Do you want to become better at programming robots, with Arduino, Raspberry Pi, or ROS2?

If yes, subscribe to receive exclusive content and special offers!

Источник

Что такое void setup arduino

Урок 2. Программируем Arduino: структура кода

В прошлой статье мы разобрали устройство платы Arduino, научились подключать ее к компьютеру и загрузили свой первый скетч! Называется он Blink и отвечает за мигание встроенного светодиода в плату с определенной частотой. Если вы начинающий, и только начали изучать мир Arduino, то вам некоторые функции в коде могут быть непонятны. Поэтому давайте разберем все по порядку. Структура кода в Arduino IDE – начинаем!

Программный код состоит из двух обязательных частей – функций. Первая часть называется void setup() (в переводе на русский – установка) и в ней прописывается код, который отработает всего один раз. Во второй обязательной функции void loop() прописывается код, работающий в бесконечном цикле. Сюда прописывается то, что будет происходить циклично (то есть с определенной частотой в определенный промежуток времени). Еще перед этими двумя функциями, то есть в самом начале кода, иногда прописываются различные директивы или переменные, которые будут необходимы для дальнейшей работы кода. Они будут постоянны на протяжении всего кода (это различные библиотеки, введенные названия устройств и т.д.)

Если перенестись на минутку в реальный мир, то эту структуру легко можно представить на простых вещах. Например, вы включаете свет в комнате, когда темно. Для этого, вы нажали на выключатель и лампочка загорелась. Также и в коде: сначала мы задаем постоянные данные, которые нам необходимы, то есть прописываем, что существует некое устройство (лампочка), прописываем для нее низкой значение

Таким образом, структура кода будет всегда одна и та же, вы ее сейчас видите ниже (от нее уже и нужно будет отталкиваться в дальнейшем, в зависимости от того, что вы хотите сделать и запрограммировать)

В нашем первом коде Blink есть некая функция PinMode(), а также delay() и digitalWrite()

Разберемся с каждой из них в отдельности.

В нашем коде встроенный светодиод мигает с частотой в одну секунду. Он подключается к выводу 13. В прошлом статье мы уже говорили, что на плате Arduino имеются выводы для подключения различных устройств и периферии – они делятся на цифровые и аналоговые. По отдельности их мы разберём чуть позднее, а пока скажем, что у каждого вывода есть номер. На плате Arduino Uno вверху расположены выводы, пронумерованные от 0 до 13. Это цифровые выводы, к ним подключают обычно различные светодиоды. Однако, вывод номер 13 отвечает за работу встроенного светодиода на плате и служит, чаще всего, для проверки ее работоспособности. Указав в скетче номер вывода, мы можем работать с устройством, которое подключено к нему.

Функция PinMode() служит для настройки этого самого вывода. Все выводы на плате могут работать, как входы, так и выходы. Потому пользователь это также должен учитывать. По умолчанию, все контакты являются входами, но для светодиода нужен выходной сигнал, так как на него идет рабочая команда и подается напряжение.

Функция PinMode(pin, mode); состоит из двух значений. Это pin — номер вывода (например у нас светодиод подключен к выводу 13) и mode — режим входа/выхода (INPUT/OUTPUT)

Дальше в функции void loop() прописывается сам цикл. После определения контакта, как выход — можно устанавливать ей высокое или низкое состояние, это 0 или 5 вольт напряжения (иногда бывает и 3,3 вольт, но об этом тоже позднее)

Изменять состояние выходного сигнала можно с помощью функции digitalWrite(pin, level); Она тоже состоит из двух значений. Это pin — номер вывода (например у нас светодиод подключен к выводу 13) и level — уровень выходного сигнала: он может быть низкий(HIGH) или высокий(LOW)

digitalWrite(13, HIGH); // подается высокое напряжение и светодиод включается.

digitalWrite(13, LOW); // напряжение не подается, светодиод выключен.

Функция delay() служит для установки задержки в программном коде между выполнением различных действий (так как контроллер не может одновременно выполнять несколько действий, а выполняет их последовательно). В самой функции прописывается время этой самой задержки в миллисекундах (1000мс=1с)

delay(1000); //устанавливаем задержку в 1 секунду

Пример кода Blink:

void loop()
<
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
>

На этом наш второй урок по программированию на Arduino подходит к концу. Сегодня мы познакомились со структурой кода на примере Blink, узнали о новых функциях и как их использовать, а впереди нас ожидает еще много всего интересного и познавательного. Всем удачной компиляции и отличного настроения!

Данная статья — является собственностью интернет-магазина РОБОТОТЕХНИКА

Источник

Функции void loop и void setup Ардуино

Функции void loop () и void setup () в Aduino IDE — это первое с чем сталкивается любой, кто начинает знакомство с языком программирования микроконтроллеров Ардуино. Разберем для чего нужны в скетче данные функции, что следует размещать внутри циклов. Данные правила относятся ко всем платам — от Arduino UNO до Arduino MEGA и перед изучением языка Aduino IDE, следует подробно изучить данные функции.

Процедуры void loop и void setup

Для этого занятия потребуется:

  • Arduino Uno / Arduino Nano / Arduino Mega

Данные циклы должны быть в каждом скетче и вызываться только один раз, даже если один из циклов не используется. Дело в том, что при запуске микроконтроллера Arduino, начинают работать встроенные микропрограммы, которые первым делом проверяют не началась загрузка новой программы с компьютера. Если пользователь не начал прошивку, то контроллер начинает выполнять ранее загруженный скетч.

Использовать два раза void loop Arduino нельзя

Оба цикла вызываются встроенной функцией main() из файла main.cpp. При этом функция void setup () вызывается один раз, а и void loop() вызывается в цикле for бесконечное количество раз. Если в вашем скетче будет присутствовать более одного раза функция void setup() или void loop(), то при компиляции Aduino IDE выдаст ошибку: redefinition of ‘void setup()‘ или redefinition of ‘void loop()’, соответственно.

Описание void setup () в Arduino

Функция setup в Aduino IDE имеет следующую конструкцию:

Фигурные скобки указывают, где начало и конец цикла, поэтому все команды должны располагаться между ними. Если вы случайно удалите или поставите лишнюю фигурную скобку, то при компиляции скетча будет выходить ошибка. Процедура void setup вызывается один раз и ее используют для назначения режима работы пинов или команд, которые необходимо выполнить только в момент загрузки программы.

Пример использования основных процедур в Arduino IDE

Описание void loop () в Arduino

После выполнения цикла setup, программа переходит в цикл loop, который будет повторяться до тех пор, пока на плату подано питание. Если цикл содержит одну команду, то она будет выполняться тысячи раз в секунду. Если вы решите написать скетч для мигания светодиодом на Arduino, то необходимо добавлять в код задержку для выполнения программы, иначе мигания светодиода не будет заметно.

Функция loop в Aduino IDE имеет следующую конструкцию:

Таким образом, если вам необходимо при запуске программы включить один раз светодиод для индикации работы устройства на микроконтроллере Arduino Nano, то команду лучше написать в цикле void setup(). Если в программе необходимо выполнять какое-то действие постоянно, например, получать данные с ультразвукового дальномера HC-SR04, то команду следует располагать в цикле void loop ().

Источник

Arduino Void Setup and Void Loop Functions [Explained]

When you open a new program in the Arduino IDE, you immediately get empty void setup and void loop functions written for you.

What are those void setup and void loop functions in Arduino?

In this tutorial I’ll explain to you the role of those functions and how to use them. At the end I’ll also give you some best practices to improve your Arduino programs.

Here is a quick video you can watch as an additional resource to this article:

If you like this video, subscribe to the Robotics Back-End Youtube channel so you don’t miss the next tutorials!

You are learning how to use Arduino to build your own projects?

Check out Arduino For Beginners and learn step by step.

Table of Contents

Void setup and void loop: mandatory functions in Arduino

The Arduino void setup and void loop functions are mandatory. Try to compile a code with one of those functions missing, and you’ll get an error.

When you run a “standard” C/C++ program, you have to write a “main” function. This main function will be called first, and from there, you will call other functions and execute the functionalities of your program.

In Arduino, there is no main function. This is replaced by setup and loop. Instead of one mandatory function, you have 2.

All your Arduino program must include those functions. On top of them, you can add any number of functions, variables, and create as many files as you want. You just need to make sure that the void setup and void loop are present.

How void setup and void loop work

Principle

As the “main” function is called when you run a C/C++ program, the setup and loop functions will be automatically called.

As soon as the program starts:

  1. Variables that you create on top of the program will be declared/initialized.
  2. The setup function will be called once.
  3. All the code you’ve written inside this function will be executed. After that, the setup function exits.
  4. Now the loop function will be called, so all the code inside the loop will be executed.
  5. When the loop function exists, go back to step 4.

The code inside the void setup will be executed once, and only once, at the beginning of the program.

Then, the code inside the void loop will be executed again and again (hence the name “loop”), until you:

  • Power off the Arduino board.
  • or Restart the Arduino program – by pressing the reset button / uploading a new sketch / re-opening the Serial Monitor on some Arduino boards.

After you start or restart the program, all the data – variable states and execution step – from the previous run will be lost. If you want to keep some data between different program runs, one easy way is to use the EEPROM memory if available.

Code Example

Let’s write a code example to see how the Arduino void setup and void loop work in detail.

And here’s the result when you compile the code, upload it to your Arduino board, and open the Serial Monitor.

Great, now let’s analyze this by breaking down the code line by line.

Init and void setup

First we create a global variable, so we can modify it inside a function and still be able to get its value in another function.

Note: even if you declare a variable without initializing it in Arduino, it will automatically get the value “0” (more info about the Arduino language). So, at this point of the program, the counter variable contains the value “0”.

This is the beginning of the void setup function. The execution will start with Serial.begin(9600); .

Still in the setup function, we set a new value (10) for the counter variable. And just after that we print the value in the Serial Monitor. In the output you get, this is where the line “Counter: 10” comes from.

And as you can notice, in line 9 we close the curly brackets for the void setup function. So, what’s happening now?

void loop

The void loop function is now called and every instruction you’ve provided here will be executed.

In this case, we increase the counter by 1 (so the first time we enter the loop, the counter goes from 10 to 11). Just after that, we print the value for the counter – this will be “Counter: 11”.

And finally, we add a 1 second pause to the program, so the output on the Serial Monitor will not be displayed to fast for our human eyes.

What happens when the void loop function exits?

Well, just after, it is called again. So, it means the line that comes after line 15 is line 12. The instruction just after delay(1000); is counter++; .

As the counter variable is a global variable, its value is not lost when we go out and enter the loop function again. So, now we increment it, it goes from 11 to 12.

And the cycle continues. Every time we enter the loop, we add 1 to the counter, print the value, and wait for 1 second.

Now, if you power off the Arduino, the program will stop. If you restart the program, any progress for the variables will be lost, and the entire program will start from the beginning.

Writing Arduino programs – best practices for void loop and void setup

Great, now that you understand how things work, I’m going to give you a few best practices you can implement right now in your Arduino programs, regarding those void setup and void loop functions.

Arduino void setup

As the void setup function is called only once at the very beginning of the program, this will be the place to:

  • Initialize variables’ values.
  • Setup communications (ex: Serial).
  • Setup modes for digital pins (input/output).
  • Initialize any hardware component (sensor/actuator) plugged to the Arduino.
  • Etc.

The void setup, as its name suggest, is made for you to do any setup required at the beginning of the program. Don’t write the core functionalities here, just the initialization code.

Depending on the complexity of your program, you may have a lot of instructions to write in that void function. You can create new functions that you call from the void setup, no problem with that.

Also, in general it’s better to avoid using delay(), but there’s no problem in the void setup: if a component needs 2 seconds to be initialized after being powered on, then wait 2 seconds!

Arduino void loop

Now, in the void loop you’ll write your main program, knowing that the initialization is already done. In this function, always keep in mind that the last line is followed by the first line!

Also, any variable you’ve declared inside the void loop will be lost when the program exits and enters the function again. So, if you want to be able to keep data between 2 void loop, make sure to declare variables in a more global scope.

As for void setup, there’s no need to write all the code directly in the function. You can create as many other functions as you want (and classes too), and call those functions in the void loop. Ideally, the void loop should contain just a few lines calling other functions. Don’t bloat your void loop, just as you don’t bloat your “main” in a standard C/C++ program.

Finally, pay attention to delay(). In the void loop (and any function called from the void loop) you don’t want to block the execution of the code too long, especially if you plan to do some kind of multi-threading with your Arduino.

Conclusion

Now you should have a better idea of the concept behind Arduino void setup and loop functions.

For now, focus on creating programs that work, and try to follow the best practices from this guide. As you progress with Arduino, you’ll get more understanding from your own experience. This experience will help you decide what you can/can’t do in your void setup and void loop functions – because in the end, every program is different.

Did you find this tutorial useful?

Do you want to learn Arduino from scratch?

If yes, this course is for you:

Did you find this tutorial useful?

Do you want to become better at programming robots, with Arduino, Raspberry Pi, or ROS2?

If yes, subscribe to receive exclusive content and special offers!

Источник

Adblock
detector