Делаем автоматический счетчик отжиманий на ардуино

Шаг 5. Интеграция Arduino

Теперь, когда мы можем считать свои отжимания и хранить данные о них, пришло время собрать всё вместе.

Во-первых, нам нужно использовать Wi-Fi Arduino для подключения к Интернету.

#include <WiFi.h>

char ssid[] = "yourNetwork";   //  your network SSID (name)
char pass[] = "12345678";  // your network password
int status = WL_IDLE_STATUS;   // the Wifi radio's status

void setup() {
  // initialize serial:
  Serial.begin(9600);

  // attempt to connect using WPA2 encryption:
  Serial.println("Attempting to connect to WPA network...");
  status = WiFi.begin(ssid, pass);

  // if you're not connected, stop here:
  if ( status != WL_CONNECTED) {
  Serial.println("Couldn't get a wifi connection");
  while(true);
  }
  // if you are connected, print out info about the connection:
  else {
  Serial.println("Connected to network");
  }
}

void loop() {
  // do nothing
}

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

void setup() {
// declare the ledPin as an OUTPUT:
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
pinMode(greenledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode (sensorPin, INPUT); // IR Sensor connected to A1
pinMode (buttonPin, INPUT); // Button Pin
// attempt to connect using WPA2 encryption:
Serial.println("Attempting to connect to WPA network...");
status = WiFi.begin(ssid, pass);
// if you're not connected, stop here:
if ( status != WL_CONNECTED) {
Serial.println("Couldn't get a wifi connection");
while(true);
}
// if you are connected, print out info about the connection:
else {
Serial.println("Connected to network");
//connected to network, blink it 3 times
digitalWrite(greenledPin, HIGH);
delay(500);
digitalWrite(greenledPin, LOW);
delay(500);
digitalWrite(greenledPin, HIGH);
delay(500);
digitalWrite(greenledPin, LOW);
delay(500);
digitalWrite(greenledPin, HIGH);
delay(500);
digitalWrite(greenledPin, LOW);
}
}

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

if (Detected == HIGH) { // Turn LED OFF if it was previous ON
Detected = LOW;
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, HIGH);
delay(200);
digitalWrite(buzzerPin, LOW);
pushupCount += 1;
}
else {
Detected = HIGH; // Turn LED ON if it was previous OFF
digitalWrite(ledPin, HIGH);
}

Кнопка используется для загрузки информации на локальный сервер и отправки ее в firebase. Мы также чистим флаг pushupCount, так как отправляем эту информацию на сервер.

while ((IR_sensed < 2)) { //Break after 2 good triggers
PyroRead = pulseIn(sensorPin, HIGH); //Measure trigger point
Serial.println(PyroRead);  // stop the autonomous robot
if (PyroRead > IR_threshold) { //Make sure trigger is over 198msec)
IR_sensed++; //Mark as a good trigger
}
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(greenledPin, HIGH);
String tmp;
tmp = String(pushupCount);
Serial.println("\nStarting connection to server...");
// if you get a connection, report back via serial:
if (client.connect(server, 3000)) {
Serial.println("connected to server");
// Make a HTTP request:
client.println("GET /?pushup=" + tmp + " HTTP/1.1");
client.println("Host: 192.168.1.12");
client.println("Connection: close");
client.println();
}
digitalWrite(greenledPin, LOW);
pushupCount = 0;
}
}

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

Объяснение программы для Arduino

Полный код программы приведен в конце статьи, здесь же мы рассмотрим его наиболее важные фрагменты.

Мы задействуем в плате Arduino один контакт для ввода данных (к нему подключен датчик Холла) и один для вывода данных (к нему подключен светодиод). На контакте, к которому подключен датчик Холла, мы будем использовать прерывание. Поэтому внутри функции setup нам необходимо инициализировать эти контакты и сконфигурировать контакт 2 таким образом, чтобы на нем можно было использовать прерывания.

Arduino

void setup() {
pinMode(LED, OUTPUT); //контакт, к которому подключен светодиод, в режим вывода данных
pinMode(Hall_sensor, INPUT_PULLUP); //контакт, к которому подключен датчик Холла, в режим ввода данных с внутренним подтягивающим резистором
attachInterrupt(digitalPinToInterrupt(Hall_sensor), toggle, CHANGE); //контакт 2 будет контактом прерывания, при возникновении прерывания будет вызываться функция toggle
}

1
2
3
4
5

voidsetup(){

pinMode(LED,OUTPUT);//контакт, к которому подключен светодиод, в режим вывода данных

pinMode(Hall_sensor,INPUT_PULLUP);//контакт, к которому подключен датчик Холла, в режим ввода данных с внутренним подтягивающим резистором

attachInterrupt(digitalPinToInterrupt(Hall_sensor),toggle,CHANGE);//контакт 2 будет контактом прерывания, при возникновении прерывания будет вызываться функция toggle

}

При обработке прерывания могут использоваться много параметров: Toggle (переключение), Change (изменение), Rise (высокий уровень), Fall (низкий уровень) и т.д. Мы в нашем проекте будем использовать изменение сигнала на выходе сигнального контакта датчика Холла.

Поэтому внутри функции toggle мы будем использовать переменную “state” которое будет изменять свое состояние на 0 если ее текущее состояние 1, и на 1 если ее текущее состояние 0. В дальнейшем значение этой переменной можно, соответственно, использовать для включения и выключения светодиода.

Arduino

void toggle() {
state = !state;
}

1
2
3

voidtoggle(){

state=!state;

}

Наконец, внутри функции loop нам необходимо просто управлять состоянием светодиода. Как мы уже обсудили, состояние переменной state будет изменяться каждый раз когда датчик Холла будет обнаруживать рядом с собой магнит, поэтому состояние этой переменной мы будем использовать для управления состоянием светодиода.

Arduino

void loop() {
digitalWrite(LED, state);
}

1
2
3

voidloop(){

digitalWrite(LED,state);

}

Step 16: Шкала От 0 До 99 На 20 Символьной Строке И Знакогенератор / Progressbar 100px

Цифры на дисплее довольно мелкие и их сложно разглядеть издалека. Поэтому на каком-то этапе я решил использовать одну из строк дисплея как шкалу.Дисплей имеет по 20 знакомест в строке. Каждое знакоместо может содержать в себе один символ: цифру, букву или знак. В таком случае я могу без труда разместить шкалу с ценой деления в одно знакоместо. Т.е. у меня будет 20 делений.

Мне показалось, что это маловато для дисплея, у которого по факту целых 100 пикселей в один ряд, ведь каждое знакоместо — это квадрат из 5 столбиков по 7 пикселей высотой. Итого, в одной строке у меня целых 100 столбиков. На шкале длиной в 1 kW я могу разместить шкалу с ценой деления 10 W. А это уже довольно наглядное разрешение.

Ошибки дребезга

Для устрашения вас предположу, что измеряем частоту вращения двигателя от индуктивного датчика зажигания. То есть, грубо говоря, на высоковольтный провод намотан кусок кабеля и мы измеряем индукцию в нём. Это довольно распространённый метод, не правда ли? Что же здесь сложного может быть? Самая главная проблема — современные системы зажигания, они дают не один импульс, а сразу пачку.

Примерно так:

Но даже обычная система зажигания даёт переходные процессы:

Старинные же кулачковые контактные вообще показывают замечательные картинки.

Как с этим бороться? Частота вращения не может вырасти мгновенно, не даст инерция. Кроме того, в начале статьи я предложил ограничить частоту сверху разумными рамками. Отсчёты, что происходят слишком часто можно просто игнорировать.

Другой вид помех — это пропадание отсчётов. Из-за той же инерции у вас не может измениться частота в два раза за одну миллисекунду. Понятно, что это зависит от того, что вы собственно измеряете. Частота биения крыльев комара может, вероятно и за миллисекунду упасть до нуля.

KY-002, датчик вибрации SW-18015P

KY-002 внешний вид

KY-002 схема датчика

 Датчик вибрации стоит около 7 р, сама плата датчика от 60 р за шт.
 Применяется в схемах где необходимо слежение за вибрацией, т.е., например, в схемах автосигнализации на вибрацию корпуса или в производственных схемах за слежением вибрации. У меня такого датчика нет но вероятно устройство следующее: представляет собой трубку в трубке, причем внутренняя трубка имеет некоторые свободный ход. Вероятно подвешена на пружине (в принципе изготовление «на коленке» займет от силы 10 минут). При вибрации внутренняя трубка начинает колебаться и, таким образом, касается стенок наружной трубки. Эти касания подают на выход датчика логический ноль, в то время как в состоянии отсутствия вибрации на выходе логическая единица. Пример обработки сигналов дачтчика вибрации можете посмотреть ЗДЕСЬ.

Исходный код программы

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

Arduino

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
int val=0;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), test, CHANGE);
Serial.begin(9600);
}
void loop() {
digitalWrite(ledPin, state);
Serial.println(val/2);
}
void test() {
state = !state;
val++;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

constbyteledPin=13;

constbyteinterruptPin=2;

volatilebytestate=LOW;

intval=;

voidsetup(){

pinMode(ledPin,OUTPUT);

pinMode(interruptPin,INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(interruptPin),test,CHANGE);

Serial.begin(9600);

}

voidloop(){

digitalWrite(ledPin,state);

Serial.println(val2);

}

voidtest(){

state=!state;

val++;

}

KY-032, модуль инфракрасного датчика

Модуль инфракрасного датчика

Модуль от 60 р в небольших партиях
Снова датчик 2 в 1. Данное устройство гибрид двух датчиков KY-005 (модуль инфракрасного светодиода) и KY-022 (датчик ИК приемника) в качестве датчика + плата управления на операционном усилителе.  Девайс имеет несколько настроек. 1. На яркость светодиода. 2. На порог срабатывания фотодиода. Чувствительность регулируется от 2 до 40 см. Следует учесть что срабатывание на темных поверхностях несколько хуже чем на светлых вследствие плохого отражения. Принцип работы: светодиод испускает инфракрасный свет и он, если на пути излучения находится препятствие, отражается в фотодиод.

Шаг 3: Код для Ардуино

Загрузите с помощью ПК на Ардуино код, который представлен ниже. Более подробную инструкцию по работе с программным обеспечением можно посмотреть а нашем материале «Класс Arduino Nano», где мы подробно прошли по всем шагам работы с микроконтроллерам Ардуино.

// Добавляем нужные библиотеки
#include <SPI.h>
#include <LiquidCrystal.h>
// это пины, используемые на модуле
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
// переменные, используемые для более чем 1 функции, должны быть объявлены здесь
unsigned long start, finished, elapsed;
boolean r = false;
// Переменные для времени отладки кнопки
long lastButtonPressTime = 0; // последний раз, когда была нажата кнопка
long debounceDelay = 50; // время отладки; установите как можно меньше

void setup()
{
lcd.begin(16, 2); // инициализировать ЖК (16 символов, 2 строки)

lcd.setCursor(4, 0); // установите курсор на первый символ в строке 1 - НЕ нужен (он автоматически устанавливается на lcd.begin ()
lcd.print("Arduino");
lcd.setCursor(3, 1); // установите курсор на 4-й символ в строке 2
lcd.print("StopWatch");
delay(2000); // ждать 2 секунды
lcd.clear(); // очистить дисплей
lcd.setCursor(3,0);
lcd.print("By Conor M");
lcd.setCursor(1,1);
lcd.print("Edited By Elac");
delay(2000);
lcd.clear();
lcd.print("Press select for");
lcd.setCursor(2, 1); // установите курсор на 3-й символ в строке 2
lcd.print("Start & Stop");
}

void loop()
{
CheckStartStop();
DisplayResult();
}

void CheckStartStop()
{
int x = analogRead (0); // назначьте «x» аналоговым входам Arduino (кнопки модуля)
if (x < 800 && x > 600 ) // если кнопка SELECT
{
if ((millis() - lastButtonPressTime) > debounceDelay)
{

if (r == false)
{
lcd.clear();
lcd.setCursor(3, 0); // нужно
lcd.print("Time Past");
start = millis(); // сохраняет время начала, чтобы вычислить прошедшее время
}
else if (r == true)
{
lcd.setCursor(2, 0); // нужно
lcd.print(" Final Time ");
}
r = !r;
}
lastButtonPressTime = millis();
}
}

void DisplayResult()
{
if (r == true)
{
finished = millis(); // сохраняет время остановки, чтобы вычислить прошедшее время.
// объявляем переменные
float h, m, s, ms;
unsigned long over;

// время
elapsed = finished - start;

h = int(elapsed / 3600000);
over = elapsed % 3600000;
m = int(over / 60000);
over = over % 60000;
s = int(over / 1000);
ms = over % 1000;
// показать результаты
lcd.setCursor(0, 1);
lcd.print(h, 0); 
lcd.print("h "); 
lcd.print(m, 0);
lcd.print("m ");
lcd.print(s, 0);
lcd.print("s ");
if (h < 10)
{
lcd.print(ms, 0);
lcd.print("ms ");
}
}
}

Принцип работы

Прибор функционирует по следующему принципу:

  1. Когда электроток проходит через сенсор, электроны прямо двигаются к нему.
  2. Когда на прибор действует внешнее поле, происходит отклонение носителей электрозаряда (сила Лоренца).
  3. Из-за отклонения отрицательно заряженные частички будут сдвигаться к одной стороне прибора, а частицы с положительным зарядом — к другой.
  4. Из-за подобного скопления отрицательно и положительно заряженных частиц на различных сторонах пластинки напряжение может наблюдаться промеж сторон пластинки. Данное напряжение прямо зависит от электротока и напряжения магнитного поля.

Сенсоры с аналоговым выводом включают в себя регулятор напряжения, элемент Холла, усилитель. Их чаще всего применяют, когда нужно измерить приближение. Также все сенсоры можно поделить на би- и униполярные. Первым для работы нужно частицы, которые заряжены как положительно, так и отрицательно. Вторым необходимы только частицы с положительным зарядом.

KY-013, аналоговый термодатчик

Модуль аналогового термодатчика

 Такой же терморезистор стоит от 3 р, в составе модуля- от 50 р
 За таким красивым названием кроется обыкновенный терморезистор! Опять же практически любые датчики изначально являются АНАЛОГЫВЫМИ. Только после соответствующей обработки сигнала они уже становятся ЦИФРОВЫМИ. Но в нашем случае изначально аналоговый датчик. Поэтому подключать его нужно к АНАЛОГОВЫМ входам ARDUINO. Диапазон рабочей температуры датчика -55…125 °C, т.е. на 1 бит 10 битного преобразования приходится (125+55)/1024= 0,17578125 градуса Цельсия ,что позволяет довольно точно измерять температуру. Кроме того датчик имеет малые размеры что позволяет снизить инерционность при измерении. Т.е. чем меньше датчик тем меньше нужно времени для достижения им температуры окружающей среды. Применяется, как и понятно из описания, для измерения температуры.

Загрузка кода расходомера в Arduino и измерение расхода воды

Ниже вы можете скачать или скопировать код Ардуино датчика расхода воды:

byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long oldTime;

void setup()
{
  
  // Initialize a serial connection for reporting values to the host
  Serial.begin(38400);
   
  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached
  
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
 * Main program loop
 */
void loop()
{
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
      
    unsigned int frac;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print(".");             // Print the decimal point
    // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
    frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC) ;      // Print the fractional part of the variable
    Serial.print("L/min");
    // Print the number of litres flowed in this second
    Serial.print("  Current Liquid Flowing: ");             // Output separator
    Serial.print(flowMilliLitres);
    Serial.print("mL/Sec");

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
    
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}

Загрузите код расходомера в свой Arduino. Код использует внешнее прерывание на цифровом выводе Arduino 2. Он используется для считывания импульсов, поступающих от расходомера. Когда Arduino обнаруживает импульс, он немедленно запускает функцию . Эта функция затем подсчитывает общее количество импульсов.

В этом датчике расхода Arduino на каждый литр жидкости, проходящей через него в минуту, он выдает около 4,5 импульсов. Разделив общее число импульсов на 4,5, вы получите общее количество жидкости, проходящей через него, в литрах в минуту. Умножив это на 60, вы получите скорость потока в литрах в час, которая даст нам общее количество или количество воды/жидкости, прошедшей через него. Датчик с точностью до 3%.

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

3Скетч для определения скорости вращения диска

Для того чтобы определить скорость вращения, будем использовать сигнал с цифрового канала сенсора. Такая схема пригодится,
например, для создания спидометра для велосипеда.

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

Установка для определения скорости вращения на основании показаний датчика Холла

Вспомним формулу угловой скорости:
ω = φ / tгде ω – угловая скорость, φ – угол поворота, t – время, за которое диск повернулся на этот угол. В нашем случае угол (1 оборот) будет равен 360° или 2π радиан. Всё,
что нам остаётся – это подсчитать время, за которое происходит один оборот диска.

В скетче мы будем отлавливать переход сигнала с датчика от HIGH к LOW и вычислять разницу между двумя последовательными переходами.

Временная диаграмма цифрового сигнала с датчика Холла для вращающегося диска

Для определения промежутка времени используем встроенную функцию millis(), которая возвращает количество миллисекунд, прошедших с момента включения платы Arduino.

int digitalPin = 12; // с цифрового выхода датчика Холла
unsigned long runTime; // время с запуска платы Arduino, мс
int prevValue = 0; // предыдущее считанное значение

void setup() {
  pinMode(digitalPin, INPUT);
  Serial.begin(9600);
  runTime = millis(); // запоминаем время запуска программы
}

void loop() {
  int digitalValue = digitalRead(digitalPin); // значение с цифрового канала  
  delay(50); // небольшая задержка чтобы исключить дребезг контактов
  if ((prevValue == HIGH) && (digitalValue == LOW)) { // ловим переход HIGH->LOW сигнала 
    unsigned long timeSpan = millis() - runTime; // время одного оборота, мс
    runTime = millis(); // запомним текущее время
    Serial.println("Период оборота = " + (String)timeSpan + " мс"); 
    double omega = 2 * PI / (timeSpan * 1.0E-3);
    Serial.println("Угловая скорость = " + (String)omega + " рад/с");  
  }
  prevValue = digitalValue; // запомним предыдущее значение датчика Холла
}

Загрузим скетч, и начнём вращать наш диск с магнитом. Период оборота и угловая скорость выводятся в окно консоли:

Скорость и период вращения диска выводятся в монитор последовательного порта

Кстати, если на небольшом расстоянии друг за другом на диске разместить два магнита, то можно будет определить не только скорость вращения, но и направление. Естественно, скетч придётся немного усложнить.

Возвращаясь к идее спидометра для велосипеда, нужно вспомнить ещё одну формулу – связь угловой и линейной скоростей:
v = ω r

Здесь v – линейная скорость, ω – угловая скорость, r – радиус колеса велосипеда. Теперь несложно дописать наш последний скетч с учётом этой формулы.

Вывод данных на LCD дисплей HD44780 с помощью arduino

Для работы с дисплеем HD44780 очень удобно использовать модуль I2C интерфейса. Бывают модули и LCD дисплеи продаются по отдельности, но зачастую и сразу в комплекте, спаянные. Я рекомендую, использовать уже собранные вместе, поскольку если подключать без I2C то придется подключать дисплей с помощью 16 проводов, когда через I2C их количество снижется до 4, два из которых это питание. А два других провода подключаются к пинам ардуино A4 и A5.
Чтобы управление выводом данных на дисплей, было более удобным и комфортным можно воспользоваться библиотекой LiquidCrystal_I2C.
Ниже приведена схема подключение дисплея, а также светодиода с фоторезистором к arduino.

Оцените статью:
Оставить комментарий