【Arduino】坐姿检测器


前言

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

一、所需材料

1、硬件

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

2、软件

Arduino IDE
微信语音合成小程序

3、接线

RGB三色彩灯接线

UNO
R4
G5
B6

超声波传感器接线

超声波传感器UNO
Tr2
Ech3

JQ8400语音模块

JQ8400UNO
7ONE LINE

按键接线

按键UNO
OUTA0

LCD1602接线

LCD1602UNO
SDASDA
SCLSCL
  • 在这里插入图片描述

二、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 :可自由切换两个页面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值