玩玩 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 第三方库。
这里使用的第三方库有:
- OneWire
- DallasTemperature
- IRremote
- DHT sensor library
- RTCLib
- SD
- 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);
}