【Arduino】坐姿检测器

  • Post author:
  • Post category:其他





前言

这也是帮人做的毕设之一,功能完善,资料也完备,相对以往代码写的规范,代码相对以往变得更加简洁好看,视频也有录制。



项目下载链接



一、所需材料



1、硬件

HC-SR04超声波测距模块
带IIC转换板LCD1602
JQ8400FL10P语音模块
UNO R3开发板
三色LED灯
LCD1602 IIC
积木按键
小面包板
木板若干
杜邦若干



2、软件

Arduino IDE
微信语音合成小程序



3、接线

RGB三色彩灯接线

UNO
R 4
G 5
B 6

超声波传感器接线

超声波传感器 UNO
Tr 2
Ech 3

JQ8400语音模块

JQ8400 UNO
7 ONE LINE

按键接线

按键 UNO
OUT A0

LCD1602接线

LCD1602 UNO
SDA SDA
SCL SCL
  • 在这里插入图片描述



二、Arduino部分



1、库函数引入

在这里插入图片描述



2、选择开发板

在这里插入图片描述



3、代码

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); //0x27

#define TrigPin 2
#define EchoPin 3
float distance;
int alarmvalue = 6; //设置初始警报值为15cm
#define BUF_LEN 10
char Dis_Buf[BUF_LEN];

//LED灯
#define rled  4 //红灯io
#define yled  5 //黄灯io
#define gled  6 //绿灯io
//语音模块
#define SDAPin 7 //语音模块onewrite io

#define RLED_Read digitalRead(rled)
#define YLED_Read digitalRead(yled)
#define GLED_Read digitalRead(gled)

//按键变量
int adc_key_val[5] = {30, 80, 165,  350, 500 };
int NUM_KEYS = 5;
int adc_key_in;
int key = -1;
int oldkey = -1;

boolean Page;
#define Home    true
#define Setting false
boolean Dis_Sta;
#define Safe    true
#define Alarm   false

#define S1 0
#define S2 1
#define S3 2
#define S4 3
#define S5 4

unsigned long Timing = 0; //用于定时读取

void setup()
{ // 初始化串口通信及连接SR04的引脚
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();

  pinMode(TrigPin, OUTPUT);
  // 要检测引脚上输入的脉冲宽度,需要先设置为输入状态
  pinMode(EchoPin, INPUT);

  pinMode(SDAPin, OUTPUT);
  pinMode(rled, OUTPUT);
  pinMode(yled, OUTPUT);
  pinMode(gled, OUTPUT);
  digitalWrite(rled, LOW);
  digitalWrite(yled, LOW);
  digitalWrite(gled, LOW);

  Dis_Sta = Safe;
  Page = Home;
  Home_Page();
}

void loop()
{
  switch (Page) {
    case Home:
      if (millis() - Timing >= 300) {
        Timing = millis();
        Get_Distance();     //测距
        if (distance < alarmvalue) {  //小于安全距离
          if (Dis_Sta == Safe) {      //上一次为安全距离,这次为过近距离
            Dis_Sta = Alarm;
            //警告界面,语音播报
            lcd.clear();
            Alarm_Page();
            //语音播报
            say_control();
            LED_ON();
          } else {                    //上一次依然是过近距离
            LED_REVERSE();            //反转LED状态,达到闪烁的效果
          }
        } else {                      //安全距离
          if (Dis_Sta == Alarm) {
            LED_OFF();
            Dis_Sta = Safe;
            lcd.clear();
            Home_Page();
          }
          uint8_t integer = distance * 100 / 100;
          uint8_t decimal = int(distance * 100) % 100;
          snprintf(Dis_Buf, BUF_LEN, "%02d.%02d", integer, decimal);
          lcd.setCursor(4, 1);
          lcd.print(Dis_Buf);
          Serial.print("Dis_Buf: ");
          Serial.println(Dis_Buf);
        }
      }
      Home_Ctrl();    //Home_Page下的按键控制
      break;

    case Setting:
      Setting_Ctrl(); //Setting_Page下的按键控制
      break;
  }
}

/*
    0123456789012345
   "    Distance:   "
   "    xx.xx cm    "
*/
void Home_Page() {
  lcd.setCursor(4, 0);
  lcd.print("Distance:");
  lcd.setCursor(10, 1);
  lcd.print("cm");
}

void Home_Ctrl() {
  adc_key_in = analogRead(0);   // 读取模拟A0数值
  key = get_key(adc_key_in);    // 转化成按键
  if (key != oldkey) {
    delay(50);                  //等待反弹时间
    adc_key_in = analogRead(0); // 读取模拟口A0数值
    key = get_key(adc_key_in);  // 转换成按键
    if (key != oldkey) {
      oldkey = key;
      if (key > 0) {
        if (key = S5) {         //5#按键进入设置界面
          Serial.println("S5 OK");
          Page = Setting;
          lcd.clear();
          Setting_Page();
        }
      }
    }
  }
}

/*
    0123456789012345
   "The setting page"
   "  alarm: xx cm  "
*/
void Setting_Page() {
  lcd.setCursor(0, 0);
  lcd.print("The setting page");//
  lcd.setCursor(2, 1);
  lcd.print("alarm:");
  LCD_Setting_Num();
  lcd.setCursor(12, 1);
  lcd.print("cm");
}

void Setting_Ctrl() {
  adc_key_in = analogRead(0);   //读取模拟A0数值
  key = get_key(adc_key_in);    //转化成按键
  if (key != oldkey) {
    delay(50);                  //等待反弹时间
    adc_key_in = analogRead(0); //读取模拟口A0数值
    key = get_key(adc_key_in);  //转换成按键
    if (key != oldkey) {
      oldkey = key;
      if (key > 0) {
        switch (key) {
          case S1:
            alarmvalue += 1;
            LCD_Setting_Num();
            break;
          case S2:
            alarmvalue += 1;
            LCD_Setting_Num();
            break;
          case S3:
            alarmvalue -= 1;
            LCD_Setting_Num();
            break;
          case S4:
            alarmvalue -= 1;
            LCD_Setting_Num();
            break;
          case S5:
            Page = Home;
            lcd.clear();
            Home_Page();
            break;
        }
      }
    }
  }
}

void LCD_Setting_Num() {
  snprintf(Dis_Buf, BUF_LEN, "%02d", alarmvalue);
  lcd.setCursor(9, 1);
  lcd.print(Dis_Buf);
}

/*
    0123456789012345
   "The distance is "
   "   too short    "
*/
void Alarm_Page() {
  lcd.setCursor(0, 0);
  lcd.print("The distance is");
  lcd.setCursor(3, 1);
  lcd.print("too short");
}

void Get_Distance() {
  // 产生一个10us的高脉冲去触发TrigPin
  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TrigPin, LOW);
  // 检测脉冲宽度,并计算出距离
  distance = pulseIn(EchoPin, HIGH) / 58.00;
  Serial.print(distance);
  Serial.println("cm");
}

// 将ADC值转换为键数
int get_key(unsigned int input) {
  int k;
  for (k = 0; k < NUM_KEYS; k++) {
    if (input < adc_key_val[k]) {
      return k;
    }
  }
  if (k >= NUM_KEYS)k = -1;  // 没有按下有效的键
  return k;
}

//发送语音模块串口指令函数
void S(bool s) {
  digitalWrite(SDAPin, s);
}

void sendData(unsigned char addr) {
  S(1);
  delayMicroseconds(1000);
  S(0);
  delayMicroseconds(3200);
  for (int i = 0; i < 8; i++) {
    S(1);
    if (addr & 0x01) {
      delayMicroseconds(600);
      S(0);
      delayMicroseconds(200);
    } else {
      delayMicroseconds(200);
      S(0);
      delayMicroseconds(600);
    }
    addr >>= 1;
  }
  S(1);
}

//语音指令
void say_control() {
  sendData(0x11);//发送语音指令
  delay(2200);//语音时长
}

void LED_ON() {
  digitalWrite(rled, HIGH);
  digitalWrite(yled, HIGH);
  digitalWrite(gled, HIGH);
}

void LED_OFF() {
  digitalWrite(rled, LOW);
  digitalWrite(yled, LOW);
  digitalWrite(gled, LOW);
}

void LED_REVERSE() {
  digitalWrite(rled, !RLED_Read);
  digitalWrite(yled, !YLED_Read);
  digitalWrite(gled, !GLED_Read);
}



4、演示视频


bilibili链接



三、使用说明



1、项目方案

功能1:(坐姿提醒)

使用超声波模块检测距离,当坐姿不端时,测距小于标准距离,语音提示,有灯光提示,屏幕文字显示提醒

功能2:(调节报警距离)

屏幕实时显示当前的测距,按键可以调节报警距离

功能3:

自定义语音提示



2、页面切换

各页面切换实现方法:

主界面:

显示距离

距离过小进入报警界面

S5进入设置界面

设置界面:

按键控制±,

S5返回主界面

报警界面:

怎么返回

测距大于安全距离则返回

小于安全距离且原本为安全时

警告界面

小于安全距离且原本时警告界面时

不作反应

大于安全距离且原本为安全时

不做反应

大于安全距离且原本为警告界面时

返回主页



页面设计

功能介绍:

  1. LCD共有三个界面

     主界面(Home_Page)

     警报界面(Alarm_Page)

     设置界面(Setting_Page)

  2. 主界面

     在主界面之下,时刻显示着当前超声波传感器的读值

     Distance:

     xx.xx cm

  3. “设置界面”

     在设置界面时刻显示着当前的警报设置距离

     The setting page

     alarm:xx cm

  4. “警报界面”

     The distance is

     Too short

按键使用:

 S1 :可进入设置状态

 S2 :可增加设置距离

 S3 :可减少设置距离

 S4 :可减少设置距离

 S5 :可自由切换两个页面



版权声明:本文为silver_lf原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。