LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

玩玩 Arduino 和传感器

对于很多非硬件专业的软件开发者来说,玩 MCU,最好还是使用 Arduino 平台,因为它比起其他的开发平台来说,实在太简易和友好了,除了 Arduino 本身提供的板子(当然包括各种 For Arduino 的版本)资料多,价格低(非官方版本),好折腾外,stm32 和 esp32 慢慢地都可以迁入 Arduino 平台,所以不需要担心后续想继续深入硬件的问题。

前面买的传感器,本来是想给 SBC 使用的,后面一直荒废在一边,今天买了个非官方版 Arduino Nano 后,便拿出来,结果看着和当时卖家给的资料完全不一样,估计是翻版(毕竟便宜),型号各种对不上,所以整理一下,给有需要的人做下参考。

没有使用官方的 Arduino IDE,使用的是在 Linux Container(Nspawn)下的开发环境,然后使用 VScode Remote 开发。

VScode

安装 Arduino 插件:

ext install vscode-arduino

使用 Control-Shift-P 来调出 Arduino Libraray Manager 安装你想要的 Arduino 第三方库。

这里使用的第三方库有:

  1. OneWire
  2. DallasTemperature
  3. IRremote
  4. DHT sensor library
  5. RTCLib
  6. SD
  7. MPU6050

Arduino Nano 设备连接

因为开发版是非官方 Nano,需要内核支持 CH340 驱动,一般发行版都自带,Gentoo 的话要自己重新配置 sources 的 .config 然后编译。假如主机能够识别到 /dev/ttyUSBx 的设备,说明能连接到设备。

容器环境要给 /dev/ttyUSBx 配上权限,或者 DevicePolicy 设置为 auto,也要给予能够容器 mknod 的 cap,简单就是给容器 --capability=all,查看对应设备的值,如:

grep ttyUSB /proc/devices # 188

然后在容器里头创建,当然主机和容器的组可能对应不上,所以直接给予 other 也是组的权限:

mknod -m 666 /dev/ttyUSB0 c 188 0

传感器代码

  • 506 => DS18b20 数字温度
#include <DallasTemperature.h>
#include <OneWire.h>

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

void setup(void) {
  sensors.begin();
}

void loop(void) {
  sensors.requestTemperatures();
  Serial.println(sensors.getTempCByIndex(0));
  delay(1 * 1000);
}
  • 500 ⇒ 敲击开关
  • 513 ⇒ 震动开关
#define PORT 2

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(PORT, INPUT);
}

void loop() {
  if (digitalRead(PORT) == HIGH) {
    digitalWrite(LED_BUILTIN, LOW);
  } else {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
  }
}
  • 492 ⇒ 霍尔磁力
  • 483 ⇒ 按键开关
  • 506 ⇒ 水银开关
  • 501 ⇒ 倾斜开关
  • 497 ⇒ 磁环
  • 487 ⇒ 光遮断,拿纸片挡住中间
  • 488 ⇒ 红外避障
  • 494 ⇒ 金属触摸
  • 485 ⇒ 高感度声音检测
#define PORT 2

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(PORT, INPUT);
}

void loop() {
  digitalRead(PORT) == HIGH ? digitalWrite(LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);
}
  • 490 ⇒ 红外接收
#include <IRremote.h>

int IR_RECV_PIN = 2;

IRrecv irrecv(IR_RECV_PIN);
decode_results results;

void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn();
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume();
  }
}
  • 489 ⇒ 红外发射
#include <IRremote.h>

#define IR_SEND_PIN 2

IRsend irsend;

void setup() {
  irsend.begin(IR_SEND_PIN);
}

void loop() {
  irsend.sendSony(0xa90, 12);
  delay(1000);
}
  • 508 ⇒ 有源蜂鸣器 引脚的标识是错误的 - 是 gnd + 是 s 中间是 5v
  • 512 ⇒ 无源蜂鸣器 引脚的标识是错误的 - 是 gnd + 是 s 中间是 5v
  • 493 ⇒ 激光发射
  • 481 ⇒ 7 彩自动闪烁 LED
#define PORT 2

void setup() {
  pinMode(PORT, OUTPUT);
}

void loop() {
  digitalWrite(PORT, HIGH);
  delay(100);
  digitalWrite(PORT, LOW);
  delay(1000);
}
  • 478 ⇒ 5050 SMD RGB LED
#define BLUE_PORT 2
#define RED_PORT 3
#define GREEN_PORT 4

void setup() {
  Serial.begin(9600);
  pinMode(BLUE_PORT, OUTPUT);
  pinMode(RED_PORT, OUTPUT);
  pinMode(GREEN_PORT, OUTPUT);
}

void loop() {
  int ports[] = {BLUE_PORT, RED_PORT, GREEN_PORT};
  int port_i = 0;
  int value = 100, pre_value = 100;
  for ( ; ; port_i = (port_i + 1) % 3) {
    Serial.println(port_i);
    for (value = 100; value < 180; value += 10) {
      analogWrite(ports[port_i], value);
      delay(10);
    }
    for (; pre_value > 100; pre_value -= 10) {
      analogWrite(ports[(port_i + 3 - 1) % 3], pre_value);
      delay(10);
    }
    pre_value = value;
  }
}
  • 479 ⇒ RGB LED
#define BLUE_PORT 2
#define RED_PORT 3
#define GREEN_PORT 4

void setup() {
  Serial.begin(9600);
  pinMode(BLUE_PORT, OUTPUT);
  pinMode(RED_PORT, OUTPUT);
  pinMode(GREEN_PORT, OUTPUT);
}

void loop() {
  int ports[] = {BLUE_PORT, RED_PORT, GREEN_PORT};
  int port_i = 0;
  int value = 0, pre_value = 0;
  for ( ; ; port_i = (port_i + 1) % 3) {
    Serial.println(port_i);
    for (value = 0; value < 256; value += 1) {
      analogWrite(ports[port_i], value);
      delay(10);
    }
    for (; pre_value > 0; pre_value -= 1) {
      analogWrite(ports[(port_i + 3 - 1) % 3], pre_value);
      delay(10);
    }
    pre_value = value;
  }
}
  • 498 ⇒ 模拟温度 热敏电阻给出的温度参数不对,所以计算结果不准
  • 503 ⇒ 数字温度 LM 实际上连接的也是 AO 口,其实就是模拟,但是得出的公式也是错
#include <math.h>

#define PORT 2

double calc_steinhart_hart_thermistor(int value) {
  double result = log(((10240000 / value) - 10000));
  result = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * result * result))* result);
  result = result - 273.15;
  return result;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(calc_steinhart_hart_thermistor(analogRead(PORT)));
  delay(1000);
}
  • 507 ⇒ DHT11 数字温湿度
#include <DHT.h>

#define PORT 2

DHT dth(PORT, DHT11);

void setup() {
  Serial.begin(9600);
  dth.begin();
}

void loop() {
  Serial.print(dth.readHumidity());
  Serial.print(" ");
  Serial.println(dth.readTemperature());
  delay(1000);
}
  • 486 ⇒ 光敏电阻
  • 509 ⇒ 线性霍尔磁力 A
  • 484 ⇒ 磁环 A
  • 491 ⇒ 火焰
  • 496 ⇒ 麦克风
  • 511 ⇒ 寻迹
  • Water ⇒ 水
  • 土壤湿度
#define PORT 2

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(analogRead(PORT), DEC);
  delay(1000);
}
  • 482 ⇒ 继电器 让灯泡接到 3.3v 和 地线形成回路,然后再和继电器形成回路,中间为公共端
#define RELAY_PORT 2

void setup() {
  pinMode(RELAY_PORT, OUTPUT);
}

void loop() {
  digitalWrite(RELAY_PORT, HIGH);
  delay(1000);
  digitalWrite(RELAY_PORT, LOW);
  delay(1000);
}
  • 504 ⇒ 双轴摇杆
#define Y_PORT 2
#define X_PORT 3
#define Z_PORT 2

void setup() {
  Serial.begin(9600);
  pinMode(Z_PORT, OUTPUT);
}

void loop() {
  Serial.print(analogRead(X_PORT), DEC);
  Serial.print(" ");
  Serial.print(analogRead(Y_PORT), DEC);
  Serial.print(" ");
  Serial.println(digitalRead(Z_PORT), DEC);
  delay(1000);
}
  • 499 ⇒ 魔术光杯 需要两个,印错了,从下往上 GND VCC SIGN LED
#define A_PORT 2
#define A_LED_PORT 3
#define B_PORT 4
#define B_LED_PORT 5

void setup() {
  pinMode(A_PORT, INPUT);
  pinMode(A_LED_PORT, OUTPUT);
  pinMode(B_PORT, INPUT);
  pinMode(B_LED_PORT, OUTPUT);
  Serial.begin(9600);
}

int level = 0;

void loop() {
  
  if (digitalRead(A_PORT) == LOW && level < 255) {
    level++;
  }
  if (digitalRead(B_PORT) == LOW && level > 0) {
    level--;
  }
  Serial.println(level);
  analogWrite(A_LED_PORT, level);
  analogWrite(B_LED_PORT, 255 - level);
  delay(25);
}
  • 502 ⇒ 心跳,不准
#define PORT 2

double alpha=0.75;
double change=0.0;

double old_value = 0.0;
double old_change = 0.0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
	int value = analogRead(PORT) * (1 - alpha) + alpha * old_value;
	change = value - old_value;
	digitalWrite(LED_BUILTIN, (change < 0.0 &&old_change >0.0));
	old_value = value;
	old_change = change;
	delay(20);
}
  • 040 ⇒ 旋转编码器
#define CLK_PORT 2
#define DAT_PORT 3
#define BUTTON_PORT 4

const int interrupt = 0;
int count = 0;

void change() {
  if (digitalRead(DAT_PORT)) {
    count++;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(20);
  } else {
    count--;
    digitalWrite(LED_BUILTIN, LOW);
    delay(20);
   }
}

void setup() {
  attachInterrupt(interrupt, change, FALLING);
  pinMode(CLK_PORT, INPUT); 
  digitalWrite(2, HIGH);
  pinMode(DAT_PORT, INPUT);
  digitalWrite(3, HIGH);
  pinMode(BUTTON_PORT, INPUT);
  digitalWrite(4, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

void loop()  {
  if (!(digitalRead(BUTTON_PORT))) {
    count = 0;
    Serial.println("STOP COUNT = 0");
    delay (2000);
  }
  Serial.println(count);
}
  • HC-HR04 ⇒ 超声波测距
#define TRIG_PORT 2
#define ECHO_PORT 3

void setup() {
  pinMode(TRIG_PORT, OUTPUT);
  pinMode(ECHO_PORT, INPUT);
  Serial.begin(9600);
}

void loop()  {
  digitalWrite(TRIG_PORT, LOW);
  delayMicroseconds(2);

  digitalWrite(TRIG_PORT, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PORT, LOW);
  Serial.println(pulseIn(ECHO_PORT, HIGH) * 0.034 / 2);
  
  delay(1000);
}
  • Ds1302 ⇒ 时钟
#include "RTClib.h"

#define CLK_PORT 2
#define DAT_PORT 3
#define RST_PORT 4

DS1302 rtc = DS1302(RST_PORT, CLK_PORT, DAT_PORT);

void setup() {
  rtc.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  Serial.begin(9600);
}

void loop()  {
  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('-');
  Serial.print(now.month(), DEC);
  Serial.print('-');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.println(now.second(), DEC);
  delay(1000);
}
  • SD SD 卡是 fat32 格式,Arduno 官网 建议是 exfat,但是我试了 exfat 读不了
    • MOSI - pin 11
    • MISO - pin 12
    • CLK - pin 13
    • SS - pin 10
#include <SPI.h>
#include <SD.h>

File file;
char filename[] = "demo.txt";

void setup() {
  Serial.begin(9600);

  if (SD.begin(SS_PIN)) {
    Serial.println("Card OK");

    file = SD.open(filename, FILE_WRITE);
    if (file) {
      Serial.println("Write OK");
      file.println("1 2 3 a b c");
      file.close();
    }
  }
}

void loop() {
  file = SD.open(filename);
  if (file) {
    Serial.println("Read OK");
    while (file.available()) {
      Serial.write(file.read());
    }
    file.close();
  }
  delay(1000);
}
  • MPU6050 ⇒ 加速度计陀螺仪传
    • SCL - pin a5
    • SDA - pin a4
#include <I2Cdev.h>
#include <MPU6050.h>

MPU6050 mpu;

int16_t ax, ay, az;
int16_t gx, gy, gz;

void setup() {
  Serial.begin(115200);

  Wire.begin();

  mpu.initialize();
  Serial.println(mpu.testConnection() ? "YES" : "NO");
}

void loop() {
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  Serial.print("a/g:\t");
  Serial.print(ax); Serial.print("\t");
  Serial.print(ay); Serial.print("\t");
  Serial.print(az); Serial.print("\t");
  Serial.print(gx); Serial.print("\t");
  Serial.print(gy); Serial.print("\t");
  Serial.println(gz);
  delay(1000);
}