之前还没玩树莓派之前,网上经常看到 python 与树莓派成对出现,我一直很奇怪难道别的语言就不能在树莓派上调用 Gpio 了吗?之前别人说用 python 写爬虫比较方便的时候,我也不是用 node 写爬虫了吗?
昨天帮一个做测量的朋友做一个树莓派检测热偶数值的工具。我是电气自动化毕业,对热偶还是听说过的。但是学校都没教过怎么样去把电偶的电势差信号转为数字信号。于是朋友就给了一份 C++的树莓派驱动 Max6675 芯片代码。代码不长,所以我想用 node 重写一份,到时候写 api 也比较容易。
写代码前的思考
因为之前没有实战过物联网(IoT),虽然一直想玩,买了树莓派,但没买线材和元器件,所以以前一直是看别人做。
在写代码之前,会涉及到两个问题:
要用软件和硬件通信,首先要解决数模转换和模数转换的问题。就目前这么简单的项目来说,主要是模数转换。从电势信号转** 0/1 **信号,会涉及到一个问题:模拟值要转电频值,精度丢失。因为芯片内存是有限的,模拟值虽然有取值范围,但是范围内有无限个数值。抛开精度问题,模拟信号转换电信号就使用 Max6675 芯片解决。
nodejs 在 npmjs 上面有树莓派 Gpio 调用库,我找了一个 onoff 来写。
Max6675 芯片
好久都没接触过电子元件了,上网找这个芯片的驱动说明,很多都不懂啊。但是我是能看懂代码的,反推芯片工作原理还是可以的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
#define CLK 5 #define DBIT 6 #define CS 7
#include <wiringPi.h> #include <stdlib.h> #include <stdio.h>
int Thermal_Couple_Read(void); int SENSOR_VALUE = 0; float Ctemp = -100.0;
int main() {
if (wiringPiSetup() == -1) { exit(1); }
pinMode(CLK, OUTPUT); pinMode(DBIT, INPUT); pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); digitalWrite(CLK, LOW);
SENSOR_VALUE = Thermal_Couple_Read(); if (SENSOR_VALUE == -1) { printf ("No sensor connected.\n"); } else { while(1) { printf ("C = %4.2f°C\n", Thermal_Couple_Read()*0.25); delay(200); } }
return 0; }
int Thermal_Couple_Read() { int value = 0; digitalWrite(CS, LOW); delay(2); digitalWrite(CS, HIGH); delay(200);
digitalWrite(CS, LOW); digitalWrite(CLK, HIGH); digitalWrite(CLK, LOW);
int i; for (i = 14; i >= 0; i--) { digitalWrite(CLK, HIGH); value += digitalRead(DBIT) << i; digitalWrite(CLK, LOW); }
if ((value & 0x04) == 0x04) return -1; return value >> 3; }
|
另外我还找到一个 python 版的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False)
def set_pin (CS, SCK, SO, UNIT): global sck sck= SCK global so so = SO global unit unit = UNIT
GPIO.setup(CS, GPIO.OUT, initial = GPIO.HIGH) GPIO.setup(SCK, GPIO.OUT, initial = GPIO.LOW) GPIO.setup(SO, GPIO.IN)
def read_temp(cs_no):
GPIO.output(cs_no, GPIO.LOW) time.sleep(0.002) GPIO.output(cs_no, GPIO.HIGH) time.sleep(0.22)
GPIO.output(cs_no, GPIO.LOW) GPIO.output(sck, GPIO.HIGH) time.sleep(0.001) GPIO.output(sck, GPIO.LOW) Value = 0 for i in range(11, -1, -1): GPIO.output(sck, GPIO.HIGH) Value = Value + (GPIO.input(so) * (2 ** i)) GPIO.output(sck, GPIO.LOW)
GPIO.output(sck, GPIO.HIGH) error_tc = GPIO.input(so) GPIO.output(sck, GPIO.LOW)
for i in range(2): GPIO.output(sck, GPIO.HIGH) time.sleep(0.001) GPIO.output(sck, GPIO.LOW)
GPIO.output(cs_no, GPIO.HIGH)
if unit == 0: temp = Value if unit == 1: temp = Value * 0.25 if unit == 2: temp = Value * 0.25 * 9.0 / 5.0 + 32.0
if error_tc != 0: return -cs_no else: return temp
GPIO.cleanup()
|
C++源码和 Max6675 封装模块可以得到下面几个信息
- 树莓派通过设置** CS **针脚来设置芯片是获取数据状态还是读取信息状态
- 树莓派从 Max6675 的** SO **针脚获取二进制状态
- 树莓派通过设置 Max6675 的** SCK 针脚的高低电平来获取 SO **针脚的状态
- **CS **针脚为高电平时,需要 200ms 时间来收集数据
- 二进制数可以通过移位累加来转换十进制数
- Max6675 芯片的精度是 0.25°C,有十二位有效读数,其中有两位是小数点后面的。
onoff
nodejs 也有树莓派 Gpio 库,onoff 就是其中一个。
具体使用方法可以看 npmjs 上面的文档,这里就不对文档做翻译了。
我实现的源码在 Max6675-Raspberry-pi-nodejs,英语实在太蹩脚了,等有空写个完整的中文文档吧,到时候翻译成英文再发布到 npmjs,方便大家使用(万把块钱的 K 型热偶想必没人会拿来做室内温度计吧?)。
效果
实际操作