apiotics_factory 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,207 @@
1
+ require 'i2c'
2
+
3
+ # Implements the I2C-Device BMP085/BMP180
4
+ # This code was inspired by https://github.com/adafruit/Adafruit_Python_BMP
5
+ #
6
+ # Datasheet: https://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
7
+ #
8
+ # Currently this code was tested on a Banana Pi with a BMP185 device. It should work on a Raspberry or any other Linux with I2C-Dev
9
+ #
10
+ # ==Example
11
+ # Using i2c-2 device (e.g. if you using a banana pi)
12
+ #
13
+ # bmp = I2CDevice::Bmp180.new(driver: I2CDevice::Driver::I2CDev.new("/dev/i2c-2"), mode: 0)
14
+ # puts "#{bmp.read_temperature / 10.0}°C"
15
+ # sleep 1
16
+ # puts "#{bmp.read_pressure / 100.0}hPa abs"
17
+ # sleep 1
18
+ # m_above_sealevel = 500 # position realtive to sealevel in m
19
+ # puts "#{bmp.read_sealevel_pressure(m_above_sealevel) / 100.0}hPa rel"
20
+ #
21
+ class I2CDevice::Bmp180 < I2CDevice
22
+ # BMP085 default address.
23
+ BMP085_I2CADDR = 0x77
24
+
25
+ # Operating Modes
26
+ BMP085_ULTRALOWPOWER = 0
27
+ BMP085_STANDARD = 1
28
+ BMP085_HIGHRES = 2
29
+ BMP085_ULTRAHIGHRES = 3
30
+
31
+ # BMP085 Registers
32
+ BMP085_CAL_AC1 = 0xAA # R Calibration data (16 bits)
33
+ BMP085_CAL_AC2 = 0xAC # R Calibration data (16 bits)
34
+ BMP085_CAL_AC3 = 0xAE # R Calibration data (16 bits)
35
+ BMP085_CAL_AC4 = 0xB0 # R Calibration data (16 bits) unsigned
36
+ BMP085_CAL_AC5 = 0xB2 # R Calibration data (16 bits) unsigned
37
+ BMP085_CAL_AC6 = 0xB4 # R Calibration data (16 bits) unsigned
38
+ BMP085_CAL_B1 = 0xB6 # R Calibration data (16 bits)
39
+ BMP085_CAL_B2 = 0xB8 # R Calibration data (16 bits)
40
+ BMP085_CAL_MB = 0xBA # R Calibration data (16 bits)
41
+ BMP085_CAL_MC = 0xBC # R Calibration data (16 bits)
42
+ BMP085_CAL_MD = 0xBE # R Calibration data (16 bits)
43
+ BMP085_CONTROL = 0xF4
44
+ BMP085_TEMPDATA = 0xF6
45
+ BMP085_PRESSUREDATA = 0xF6
46
+
47
+ # Commands
48
+ BMP085_READTEMPCMD = 0x2E
49
+ BMP085_READPRESSURECMD = 0x34
50
+
51
+ # initialize the device and read the calibration registers
52
+ #
53
+ # ==params
54
+ # * args : hash defaults to {}
55
+ # ** :mode : one of BMP085_ULTRALOWPOWER | BMP085_STANDARD | BMP085_HIGHRES | BMP085_ULTRAHIGHRES defaults to BMP085_STANDARD see datasheet for more information
56
+ # ** :address : device address defaults to 0x77
57
+ def initialize(args={})
58
+ @mode = args.delete(:mode) || BMP085_STANDARD
59
+ args = {
60
+ address: BMP085_I2CADDR
61
+ }.merge(args)
62
+
63
+ super args
64
+
65
+ raise "Mode must be between #{BMP085_ULTRALOWPOWER} and #{BMP085_ULTRAHIGHRES}" unless [BMP085_ULTRALOWPOWER, BMP085_STANDARD, BMP085_HIGHRES, BMP085_ULTRAHIGHRES].include?(@mode)
66
+
67
+ calibration
68
+ end
69
+
70
+ # read the current real temperature in 0.1°C
71
+ def read_temperature
72
+ return calc_real_temperature(read_raw_temperature)
73
+ end
74
+
75
+ # read the current relative pressure in Pa
76
+ def read_pressure
77
+ return calc_real_pressure(read_raw_temperature, read_raw_pressure)
78
+ end
79
+
80
+ # Read current temperature and realtive pressure
81
+ #
82
+ # ==return
83
+ # * temperature in 0.1°C, pressure in Pa
84
+ def read_temperature_and_pressure
85
+ ut = read_raw_temperature
86
+ up = read_raw_pressure
87
+
88
+ return calc_real_temperature(ut), calc_real_pressure(ut, up)
89
+ end
90
+
91
+ # calculate the current pressure at sealevel from the current relative pressure and the gitven altitude
92
+ #
93
+ # ==params
94
+ # * altitude : curren altitude above sealevel in m defaults to 0
95
+ def read_sealevel_pressure(altitude = 0.0)
96
+ pressure = read_pressure()
97
+ return cacl_sealevel_pressure(pressure, altitude)
98
+ end
99
+
100
+ # calculate the current pressure at sealevel from the given relative pressure and the gitven altitude
101
+ #
102
+ # ==params
103
+ # * altitude : curren altitude above sealevel in m
104
+ # * pressure : current relative pressure in Pa
105
+ def cacl_sealevel_pressure(pressure, altitude)
106
+ return pressure.to_f / ((1.0 - altitude.to_f / 44330.0) ** 5.255)
107
+ end
108
+
109
+ # get the calibration values
110
+ #
111
+ # ==return
112
+ # array of calibration data
113
+ def get_cal
114
+ return @cal_AC1, @cal_AC2, @cal_AC3, @cal_AC4, @cal_AC5, @cal_AC6, @cal_B1, @cal_B2, @cal_MB, @cal_MC, @cal_MD
115
+ end
116
+
117
+ private
118
+ # read the current raw temperature value
119
+ def read_raw_temperature
120
+ i2cset(BMP085_CONTROL, BMP085_READTEMPCMD)
121
+ sleep 0.005
122
+ return i2cget(BMP085_TEMPDATA, 2).unpack('s>')[0]
123
+ end
124
+
125
+ # read the current raw pressure value
126
+ def read_raw_pressure
127
+ i2cset(BMP085_CONTROL, BMP085_READPRESSURECMD + (@mode << 6))
128
+
129
+ if @mode == BMP085_ULTRALOWPOWER
130
+ sleep 0.005
131
+ elsif @mode == BMP085_HIGHRES
132
+ sleep 0.014
133
+ elsif @mode == BMP085_ULTRAHIGHRES
134
+ sleep 0.026
135
+ else
136
+ sleep 0.008
137
+ end
138
+
139
+ sleep 1 # safety for testing
140
+
141
+ msb, lsb, xlsb = i2cget(BMP085_PRESSUREDATA, 3).unpack('C*')
142
+ up = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - @mode)
143
+
144
+ return up
145
+ end
146
+
147
+ # load the calibration registers into instance variables
148
+ def calibration
149
+ @cal_AC1, @cal_AC2, @cal_AC3, @cal_AC4, @cal_AC5, @cal_AC6, @cal_B1, @cal_B2,
150
+ @cal_MB, @cal_MC, @cal_MD = i2cget(BMP085_CAL_AC1, 22).unpack('s>s>s>S>S>S>s>s>s>s>s>')
151
+ end
152
+
153
+ # calculate the read temperature using the calibration registers
154
+ #
155
+ # ==params
156
+ # * ut : raw templerature value
157
+ # ==return
158
+ # true temperature in 0.1°C -> 150 = 15.0 °C
159
+ def calc_real_temperature(ut)
160
+ x1 = ((ut - @cal_AC6) * @cal_AC5) / 2**15
161
+ x2 = (@cal_MC * 2**11) / (x1 + @cal_MD)
162
+ b5 = x1 + x2
163
+ t = (b5 + 8) / 2**4
164
+
165
+ return t
166
+ end
167
+
168
+ # calculate the read pressure using the calibration registers
169
+ #
170
+ # ==params
171
+ # * up : raw pressure value
172
+ # ==return
173
+ # true pressure in Pa
174
+ def calc_real_pressure(ut, up)
175
+ x1 = ((ut - @cal_AC6) * @cal_AC5) / 2**15
176
+ x2 = (@cal_MC * 2**11) / (x1 + @cal_MD)
177
+ b5 = x1 + x2
178
+
179
+ # Pressure Calculations
180
+ b6 = b5 - 4000
181
+ x1 = (@cal_B2 * (b6 * b6) / 2**12) / 2**11
182
+ x2 = (@cal_AC2 * b6) / 2**11
183
+ x3 = x1 + x2
184
+ b3 = (((@cal_AC1 * 4 + x3) << @mode) + 2) / 4
185
+
186
+ x1 = (@cal_AC3 * b6) / 2**13
187
+ x2 = (@cal_B1 * ((b6 * b6) / 2**12)) / 2**16
188
+ x3 = ((x1 + x2) + 2) / 2**2
189
+ b4 = (@cal_AC4 * (x3 + 32768)) / 2**15
190
+
191
+ b7 = (up - b3) * (50000 >> @mode)
192
+
193
+ if b7 < 0x80000000
194
+ pr = (b7 * 2) / b4
195
+ else
196
+ pr = (b7 / b4) * 2
197
+ end
198
+
199
+ x1 = (pr / 2**8) * (pr / 2**8)
200
+ x1 = (x1 * 3038) / 2**16
201
+ x2 = (-7357 * pr) / 2**16
202
+ pr += ((x1 + x2 + 3791) / 2**4)
203
+
204
+ return pr
205
+ end
206
+
207
+ end
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ class I2CDevice::D6T44L < I2CDevice
5
+ class InvalidParityException < Exception; end
6
+
7
+ def initialize(args={})
8
+ args[:address] = 0x0a
9
+ super
10
+ end
11
+
12
+ def read_data
13
+ data = i2cget(0x4c, 35)
14
+ unless checkPEC(data, false)
15
+ raise InvalidParityException
16
+ end
17
+
18
+ # PTAT はセンサ内部の参照温度データ
19
+ ptat, *pixels = data[0..-2].unpack("v*")
20
+ {
21
+ :PTAT => ptat,
22
+ :PIXELS => pixels.each_slice(4).to_a
23
+ }
24
+ end
25
+
26
+ private
27
+ def calc_crc(data)
28
+ 8.times do
29
+ tmp = data
30
+ data = (data << 1) & 0xff
31
+ if tmp & 0x80 != 0
32
+ data ^= 0x07
33
+ end
34
+ end
35
+ data
36
+ end
37
+
38
+ def checkPEC(data, userr=true)
39
+ crc = 0
40
+ if userr
41
+ crc = calc_crc(0x14)
42
+ crc = calc_crc(0x4c ^ crc)
43
+ crc = calc_crc(0x15 ^ crc)
44
+ else
45
+ crc = calc_crc(0x15)
46
+ end
47
+ (data.size - 1).times do |i|
48
+ crc = calc_crc(data[i].ord ^ crc)
49
+ end
50
+ data[data.size-1].ord == crc
51
+ end
52
+ end
@@ -0,0 +1,172 @@
1
+ # coding: utf-8
2
+
3
+ require "i2c"
4
+
5
+ # I2C interface with HD44780 compatible commands
6
+ class I2CDevice::HD44780 < I2CDevice
7
+ MAP = Hash[
8
+ [
9
+ "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚".split(//).map {|c|
10
+ c.force_encoding(Encoding::BINARY)
11
+ },
12
+ (0b10100001..0b11011111).map {|c|
13
+ c.chr
14
+ }
15
+ ].transpose
16
+ ]
17
+
18
+ def initialize(args={})
19
+ super
20
+ @lines = []
21
+ initialize_lcd
22
+ end
23
+
24
+ # Initialize LCD controller sequence
25
+ # Display is cleared.
26
+ def initialize_lcd
27
+ function_set(1, 1, 0)
28
+ sleep 4.1e-3
29
+ function_set(1, 1, 0)
30
+ sleep 100e-6
31
+ function_set(1, 1, 0)
32
+ function_set(1, 1, 0)
33
+ display_on_off_control(1, 0, 0)
34
+ clear
35
+ end
36
+
37
+ # <tt>line</tt> :: [Integer] Line number
38
+ # <tt>str</tt> :: [String] Display string
39
+ # <tt>force</tt> :: [true | false] Write data forcely.
40
+ #
41
+ # Note: This method keep previous put_line strings and does not write without change.
42
+ # You must specify _force_ to override this behaviour.
43
+ def put_line(line, str, force=false)
44
+ str.force_encoding(Encoding::BINARY)
45
+ str.gsub!(/#{MAP.keys.join('|')}/, MAP)
46
+
47
+ str = "%- 16s" % str
48
+
49
+ if force || str != @lines[line]
50
+ # set ddram address
51
+ set_ddram_address(0x40 * line)
52
+ sleep 60e-6
53
+ i2cset(*str.unpack("C*").map {|i| [0x80, i] }.flatten)
54
+ sleep 60e-6
55
+ end
56
+ @lines[line] = str
57
+ end
58
+
59
+ # <tt>n</tt> :: [Integer] Character code.
60
+ # <tt>array</tt> :: [Array[Integer]] Character data.
61
+ # Usage:
62
+ # lcd.define_character(0, [
63
+ # 0,1,1,1,0,
64
+ # 1,0,0,0,1,
65
+ # 1,1,0,1,1,
66
+ # 1,0,1,0,1,
67
+ # 1,1,0,1,1,
68
+ # 1,0,0,0,1,
69
+ # 1,0,0,0,1,
70
+ # 0,1,1,1,0,
71
+ # ])
72
+ def define_character(n, array)
73
+ raise "n < 8" unless n < 8
74
+ raise "array size must be 40 (5x8)" unless array.size == 40
75
+
76
+ array = array.each_slice(5).map {|i|
77
+ i.inject {|r,i| (r << 1) + i }
78
+ }
79
+ set_cgram_address(8 * n)
80
+ sleep 60e-6
81
+ i2cset(*array.map {|i| [0x80, i] }.flatten)
82
+ sleep 60e-6
83
+ end
84
+
85
+ def clear_display
86
+ @lines.clear
87
+ i2cset(0, 0b00000001)
88
+ sleep 2.16e-3
89
+ end
90
+
91
+ alias clear clear_display
92
+
93
+ def return_home
94
+ i2cset(0, 0b00000010)
95
+ sleep 1.52e-3
96
+ end
97
+
98
+ # <tt>i_d</tt> :: [Integer] Increment or decrement
99
+ # 0 :: Decrement
100
+ # 1 :: Increment
101
+ # <tt>s</tt> :: [Integer] Shift entire display
102
+ # 0 :: Right
103
+ # 1 :: Left
104
+ def entry_mode_set(i_d, s)
105
+ i2cset(0, 0b00000100 | (i_d<<1) | (s))
106
+ sleep 60e-6
107
+ end
108
+
109
+ # <tt>d</tt> :: [Integer] Set entire display on/off
110
+ # 0 :: Off
111
+ # 1 :: On
112
+ # <tt>c</tt> :: [Integer] Cursor on/off
113
+ # 0 :: Off
114
+ # 1 :: On
115
+ # <tt>b</tt> :: [Integer] Blink cursor
116
+ # 0 :: Off
117
+ # 1 :: On
118
+ def display_on_off_control(d, c, b)
119
+ i2cset(0, 0b00001000 | (d<<2) | (c<<1) | (b))
120
+ sleep 60e-6
121
+ end
122
+
123
+ # <tt>s_c</tt> :: [Integer] Cursor or display
124
+ # 0 :: Cursor shift
125
+ # 1 :: Display shift
126
+ # <tt>r_l</tt> :: [Integer] Direction
127
+ # 0 :: Left
128
+ # 1 :: Right
129
+ def cursor_or_display_shift(s_c, r_l)
130
+ i2cset(0, 0b00010000 | (s_c<<3) | (r_l<<2))
131
+ sleep 60e-6
132
+ end
133
+
134
+ # <tt>dl</tt> :: [Integer] Data length
135
+ # 0 :: 4bit
136
+ # 1 :: 8bit
137
+ # <tt>n</tt> :: [Integer] Number of display lines
138
+ # 0 :: 1-line
139
+ # 1 :: 2-line
140
+ # <tt>f</tt> :: [Integer] Character font
141
+ # 0 :: Normal
142
+ # 1 :: Double font
143
+ def function_set(dl, n, f)
144
+ i2cset(0, 0b00100000 | (dl<<4) | (n<<3) | (f<<2))
145
+ sleep 60e-6
146
+ end
147
+
148
+ # <tt>address</tt> :: [Integer] CGRAM address 6-bit
149
+ def set_cgram_address(address)
150
+ address = address & 0b00111111
151
+ i2cset(0, 0b01000000 | address)
152
+ sleep 60e-6
153
+ end
154
+
155
+ # <tt>address</tt> :: [Integer] DDRAM address 7-bit
156
+ def set_ddram_address(address)
157
+ address = address & 0b01111111
158
+ i2cset(0, 0b10000000 | address)
159
+ sleep 60e-6
160
+ end
161
+
162
+ # <tt>Returns</tt> :: [Hash] Result
163
+ # :busy :: [true | false] Busy flag
164
+ # :address_counter :: [Integer] Current address count. 7-bit
165
+ def read_busy_flag_and_address
166
+ read = i2cget(0b01000000)
167
+ {
168
+ :busy => (read & 0b10000000) != 0,
169
+ :address_counter => read & 0b01111111
170
+ }
171
+ end
172
+ end
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+
3
+ require "i2c"
4
+
5
+ # http://www.ti.com/product/HDC1000
6
+ # A Digital humidity/temperature sensor
7
+
8
+ class I2CDevice::HDC1000 < I2CDevice
9
+ def initialize(args = {})
10
+ args = {
11
+ address: 0x40
12
+ }.merge(args)
13
+ super args
14
+ configuration
15
+ end
16
+
17
+ def configuration
18
+ i2cset(
19
+ 0x02, # Configuration register
20
+ 0x10, # TRES 14bit
21
+ 0x00 # HRES 14bit
22
+ )
23
+ end
24
+
25
+ def get_data
26
+ i2cset(0x00)
27
+ sleep 6.35e-3 + 6.5e-3
28
+ raw = i2cget(nil, 4).unpack("C4")
29
+ {
30
+ temperature: calc_temperature(raw[0], raw[1]),
31
+ humidity: calc_humidity(raw[2], raw[3])
32
+ }
33
+ end
34
+
35
+ def calc_temperature(d1, d2)
36
+ ((d1<<8 | d2).to_f / 2**16 * 165) - 40
37
+ end
38
+
39
+ def calc_humidity(d1, d2)
40
+ (d1<<8 | d2).to_f / 2**16 * 100
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require "i2c"
2
+
3
+ class I2CDevice::MPL115A2 < I2CDevice
4
+ def initialize(args={})
5
+ args[:address] = 0x60
6
+ super
7
+ coefficient = i2cget(0x04, 8).unpack("n*")
8
+
9
+ @a0 = fixed_point(coefficient[0], 12)
10
+ @b1 = fixed_point(coefficient[1], 2)
11
+ @b2 = fixed_point(coefficient[2], 1)
12
+ @c12 = fixed_point(coefficient[3], 0) / (1<<9)
13
+ end
14
+
15
+ def fixed_point(fixed, int_bits)
16
+ msb = 15
17
+ deno = (1<<(msb-int_bits)).to_f
18
+ if (fixed & (1<<15)).zero?
19
+ fixed / deno
20
+ else
21
+ -( ( (~fixed & 0xffff) + 1) / deno )
22
+ end
23
+ end
24
+
25
+ def calculate_hPa
26
+ i2cset(0x12, 0x01) # CONVERT
27
+
28
+ sleep 0.003
29
+
30
+ data = i2cget(0x00, 4).unpack("n*")
31
+
32
+ p_adc = (data[0]) >> 6
33
+ t_adc = (data[1]) >> 6
34
+
35
+ p_comp = @a0 + (@b1 + @c12 * t_adc) * p_adc + @b2 * t_adc
36
+ hPa = p_comp * ( (1150 - 500) / 1023.0) + 500;
37
+ end
38
+ end