Удаленное управление. I2C. Гироскоп.
-
И снова здравствуйте.Раз уже сайт совсем умер, то напишу, пожалуй, ещё...А ну, как оживет.
По случаю достал гироскоп на чипе L3G4200D, которым можно управлять как по I2C, так и по SPI. Даташит приводить на него, думаю, не стоит, потому как это легко гуглится. При помощи интерфейса i2c буду получить от него какие-нибудь сведения. Например значения по x, y и z. Что ж еще нужно от гироскопа?
Сначала некоторые константы:
адрес по-умолчанию = 0x69 (можно обнаружить прямо на малине при помощи, например i2cdetect)
5 контрольных регистров 0x20..0x24
Регистры значений X, Y, Z соответственно (0х28, 0х29), (0х2A, 0х2B), (0х2C, 0х2D). Значения занимают каждый по 2 байта в таком виде (Low, High).
Lua:
device_address = 0x69 ctrl_regs = { 0x20, 0x21, 0x22, 0x23, 0x24 } R_xL = 0x28 R_xH = 0x29 R_yL = 0x2A R_yH = 0x2B R_zL = 0x2C R_zH = 0x2D
Чтоб было интереснее сделаем метатаблицу lua для работы с данным чипом. Чтоб работать с гироскопом, как с отдельным объектом.
i2c = fr.client.smbus -- псевдоним для клиента smbus -- пустая таблица без ничего. L3G4200D = { } -- метод new, который вернут новый экземпляр таблицы L3G4200D.new = function( ) inst = { } for k, v in pairs(L3G4200D) do inst[k] = v end -- откроем девайс и сохраним его в нашей таблице. inst.i = assert(i2c.open( 1, device_address )) -- это метатаблица setmetatable( inst, L3G4200D ) return inst end
теперь можно сделать что-то типа
local r = L3G4200D.new( )
Код создаст экземпляр таблицы, откроет девайс и если все нормально, с ним можно работать.
для того, чтоб настроить на работу устройство, добавлю функцию setup
-- настройка состоит в том, чтоб записать нужные регистры нужными значениями. L3G4200D.setup = function( self, scale ) -- настроим таблицу. write_bytes ожидает таблицу, в которой указано [регистр]=значение local data = { [ctrl_regs[1]] = 15, -- включим [ctrl_regs[2]] = 0, -- нормальный режим. По-умолчанию [ctrl_regs[3]] = 8, [ctrl_regs[4]] = scale_values[scale], -- установка scale [ctrl_regs[5]] = 0 -- по-умолчанию } -- запишем. assert(self.i:write_bytes(data)) end
Если не сработал assert, то гироскоп будет включен и готов к чтению данных. Функция для чтения тоже довольно проста
-- табица для чтения. read_bytes ожидает в таблице номера регистров для чтения. read_xyz_data = { R_xL, R_xH, R_yL, R_yH, R_zL, R_zH } L3G4200D.read_xyz = function( self ) -- читаем local res = assert(self.i:read_bytes( read_xyz_data )) -- возвращаем таблицу с уже поправленными значениями { x = ..,y = .., z = .. } return { x = res[R_xH] << 8 | res[R_xL], y = res[R_yH] << 8 | res[R_yL], z = res[R_zH] << 8 | res[R_zL] } end
Теперь есть полный инструмент для получения данных с гироскопа. Далее я приведу скрипт, который раз в 100 миллисекунд вычитывает данные и выбрасывает их на консоль.
i2c = fr.client.smbus eq = fr.client.event_queue -- для работы с очередью событий клиента eqt = eq.timer -- таймеры клиента device_address = 0x69 ctrl_regs = { 0x20, 0x21, 0x22, 0x23, 0x24 } scale_values = { [250]=0, [500]=16, [2000]=48 } R_xL = 0x28 R_xH = 0x29 R_yL = 0x2A R_yH = 0x2B R_zL = 0x2C R_zH = 0x2D read_xyz_data = { R_xL, R_xH, R_yL, R_yH, R_zL, R_zH } L3G4200D = { } L3G4200D.new = function( ) inst = { } for k, v in pairs(L3G4200D) do inst[k] = v end inst.i = assert(i2c.open( 1, device_address )) setmetatable( inst, L3G4200D ) return inst end L3G4200D.setup = function( self, scale ) -- setup table for write local data = { [ctrl_regs[1]] = 15, [ctrl_regs[2]] = 0, [ctrl_regs[3]] = 8, [ctrl_regs[4]] = scale_values[scale], [ctrl_regs[5]] = 0 } -- write registry assert(self.i:write_bytes(data)) end L3G4200D.read_xyz = function( self ) local res = assert(self.i:read_bytes( read_xyz_data )) return { x = res[R_xH] << 8 | res[R_xL], y = res[R_yH] << 8 | res[R_yL], z = res[R_zH] << 8 | res[R_zL] } end -- функция таймера, которая вычитает данные и выведет их на консоль function show_values( err, dev ) -- первый параметр - ошибка таймера. при нормальной работе err=nil if nil == err then local values = dev:read_xyz( ) -- вычитаем print( "X:", values.x, "Y:", values.y, "Z:", values.z ) -- ... и выведем eqt.post( show_values, {milli=100}, dev ) -- поставим новое задание в таймер на 100 milliсекунд else -- если ошибка fr.exit(err) -- завершимся. fr.exit( ) остановит очередь end end function main( ) fr.run( ) -- запустим очередь событий local r = L3G4200D.new( ) -- откроем устройство r:setup(2000) -- настроем устройство show_values( nil, r ) -- запустим вывод. end
теперь можно проверить: 192.168.1.3:12345 - адрес и порт агента на малине. Запущу и подвигаю железку немного.
$ ./lua_client -s 192.168.1.3:12345 -e L3G4200D.lua X: 129 Y: 500 Z: 65489 X: 50 Y: 65468 Z: 65508 X: 26 Y: 4 Z: 14 ............... X: 34869 Y: 37125 Z: 21348 X: 57781 Y: 65259 Z: 3636 X: 32752 Y: 32752 Z: 32832 ............... X: 76 Y: 78 Z: 23 X: 73 Y: 7 Z: 11 X: 78 Y: 62 Z: 65519 X: 48 Y: 65495 Z: 45 X: 14 Y: 4 Z: 6 ^C
На этом все, спасибо за внимание.
PS: скрипт можно взять тут
PPS: Добавил в пример получение значения температурного регистра: 0x26