Електроника и Електротехника | Electronics and Electrical Engineering > Цифрово / дигитално управление | Digital Command Control
Измервателен вагон
IvanC:
В предните мнения показах измервателните вагони, направени от мен. В това мнение пускам снимките на втория измервателен вагон направен от брат ми Владо (VladoC). Коментарите са също неговите и понеже са много кратки, в края ще добавя и няколко коментара от мен.
Вагонът е на Piko, от хоби серията, кат. номер 58781:
Колоос и датчик на Хол:
Акумулаторът е LiIon 14500, 800 mAh, USB зарядно за една клетка и стабилизатор на напрежение за 5 V:
Владо
---------------------------------------------------------------------------------------
Виждам, че Владо не е използвал преобразувателна платка от USB батерия, а два отделни модула. Освен това неговият акумулатор не е от USB батерия. Най-вероятно затова не е използвал платка от USB батерия.
Вижда се по-различният подход при монтажа на елементите, датчика на Хол и магнитите, което е интересно и дава повече идеи.
На снимките не виждам обаче модула на акселерометъра. Виждам проводници, запоени към A4 и A5 на Ардуиното, така че предполагам има акселерометър, може би в средата под батерията и 4-те проводика с конектора до батерията са на този модул.
На снимките се вижда светодиодът, монтиран на покрива на вагона, който имитира въртящ се буркан и за който писах в първото мнение в темата. Ето и кратък клип от работата на вагона по време на настройване на декодера в Людмилата:
https://youtu.be/5TWFyj3nhME
Иван
IvanC:
Разглобих моя измервателен вагон 3, за да направя снимки на монтирания акселерометър. Бях забравил какъв кошмар е да се разглоби и после да се сглоби. При разглобяването имам чувството, че всички щипки се чупят, а при сглобяването, двете кулиси и техните пружинки изпадат при най-малкото сътресение, а две ръце не стигат да крепят двете кулиси на място и да сглобяват останалите части. Както и да е, с малко гресчица на пружинките на кулисите и много "сладки" думи казани на ум (за да не чуе жената и да се чуди защо си псувам сам...!) успях да сглобя обратно вагона успешно и без щети.
Иван
IvanC:
Ето кода на програмата за Ардуиното във вагона:
--- Код: ---#include <Wire.h> // i2c library Използвани библиотеки
#define baudRate 115200 // serial baud rate
#define sensPin 17 // sensor pin (initially 3)
#define heartbeat 13 // LED pin
#define heartbeatPeriod 19 // heartbeat period
#define beaconPin 11 // beacon pin; only 3, 5, 6, 9, 10 and 11 on ATmega328P
#define beaconMaxPwm 160 // beacon max PWM
#define beaconCycle 30 // beacon cycle time in 0.1s between 1 and 255
#define debounceTime 8500 // debounce time for mechanical contact in µs
#define sendPeriod 300000 // time to wait before sending another value in µs
#define sendStart ' ' // serial send start symbol
#define sendDelimiter ';' // serial send delimiter
#define sendTerminator '/' // serial send terminator symbol
#define beaconS max(1, 43 / beaconCycle)
#define beaconM beaconS * beaconCycle / 2.56
// MMA8452Q, MPU-6050
const byte accelAddress[] = { 0x1C , 0x68 }; // accelerometer I2C address
const byte accelID[] = { 0x2A , 0x68 }; // accelerometer ID
const byte accelStatusReg[] = { 0x00 , 0x3A }; // accelerometer status register
const byte accelXReg[] = { 0x01 , 0x3B }; // accelerometer X-axis register
const byte accelYReg[] = { 0x03 , 0x3D }; // accelerometer Y-axis register
const byte accelZReg[] = { 0x05 , 0x3F }; // accelerometer Z-axis register
const byte accelWhoAmIReg[] = { 0x0D , 0x75 }; // accelerometer device ID register
const byte accelCtrl1Reg[] = { 0x2A , 0x6B }; // accelerometer control register
const byte accelActive[] = { 0x01 , 0x00 }; // accelerometer activate
const byte accelXSeq[] = { 0 , 2 }; // accelerometer X-axis sequence
const byte accelYSeq[] = { 2 , 0 }; // accelerometer Y-axis sequence
const byte accelZSeq[] = { 4 , 4 }; // accelerometer Z-axis sequence
const long maxSamples = 610; // accelerometer number of samples
unsigned long const infinity = 1e9; // "infinity" constant
unsigned long const sensTimeout = 6e6; // pulse timeout
unsigned long timeToSend = infinity; // elapsed time between two pulses to send out
unsigned long currentTime = 0; // current time
unsigned long lastTime = 0; // last read time value
unsigned long pulseCounter = 0; // counter of total number of pulses
bool sensFlag = false; // last sensor state
unsigned long previousTrans = 0;
int heartbeatCounter = 0;
unsigned long beaconMillis = beaconM;
int beaconCounter = 0;
bool accelFound = false;
long accelX = 0;
long accelY = 0;
long accelZ = 0;
long tX = 0;
long tY = 0;
long tZ = 0;
long samples = 0;
long accelSamples = 0;
int accel = 0;
void setup() { // setup
pinMode(sensPin, INPUT_PULLUP); // set sensor pin as input with internal pull-ups
pinMode(heartbeat, OUTPUT); // set LED pin as output
Serial.begin (baudRate); // initialize serial port
Wire.begin(); // join i2c bus as master
for (accel = 0; accel < sizeof(accelAddress) / sizeof(byte); accel++) {
accelFound = (readRegister(accelAddress[accel], accelWhoAmIReg[accel]) == accelID[accel]); // check if accelerometer is present
if (accelFound) break;
} // for (accel)
writeRegister(accelAddress[accel], accelCtrl1Reg[accel], accelActive[accel]);
} // setup()
void loop() { // main cycle
if (digitalRead(sensPin) == LOW) { // sensor activated
currentTime = micros(); // read current time
if (sensFlag && (currentTime - lastTime > debounceTime)) { // debounce done
timeToSend = currentTime - lastTime; // load new pulse time
lastTime = currentTime; // remember current time
pulseCounter++; // increment pulse counter
sensFlag = false; // wait for next transition to LOW
} // if (sensFlag && (currentTime - lastTime > debounceTime))
} // if (digitalRead(sensPin) == LOW)
else if (!sensFlag && (micros() - currentTime > debounceTime)) sensFlag = true; // ignore bounce at transition to HIGH and prepare for debounce
if (micros() - lastTime > sensTimeout) timeToSend = infinity; // load infinity if pulse timed out
if ((micros() < previousTrans) || (micros() - previousTrans > sendPeriod)) { // send everything
previousTrans = micros(); // remember current time of transmission
Serial.print(sendStart); // send start symbol
Serial.print(timeToSend); // send pulse length
Serial.print(sendDelimiter); // send pulse length delimiter
Serial.print(pulseCounter); // send pulse counter
if (accelFound) { // send accelerometer data if accelerometer is present
Serial.print(sendDelimiter); // send delimiter
Serial.print(samples); // send number of samples acquired
Serial.print(sendDelimiter); // send pulse length delimiter
Serial.print(accelX); // send X-axis acceleration
Serial.print(sendDelimiter); // send delimiter
Serial.print(accelY); // send Y-axis acceleration
Serial.print(sendDelimiter); // send delimiter
Serial.print(accelZ); // send Z-axis acceleration
} // if (accelFound)
Serial.println(sendTerminator); // send transmission terminator
digitalWrite(heartbeat, LOW); // begin heartbeat logic
heartbeatCounter++;
if (heartbeatCounter > heartbeatPeriod) { // flash heartbeat
heartbeatCounter = 0;
digitalWrite(heartbeat, HIGH);
} // end of heartbeat logic
} // end of send everything
byte f = beaconCounter << 2; // beacon PWM is activated in quarters of the cycle
if (beaconCounter & 64) f = ~f; // invert PWM if fading out
if (millis() - beaconMillis > expo(beaconM, f)) { // check if beacon time has expired
beaconMillis = millis(); // get current time for next checks
beaconCounter += beaconS; // increment beacon cycle counter
if (beaconCounter & 128) analogWrite(beaconPin, 0); // turn off beacon in 3rd and last quarters
else { // 1st and 2nd quarters of beacon cycle
f = beaconCounter << 2; // calculate beacon PWM
if (beaconCounter & 64) f = ~f; // invert beacon PWM in 2nd quarter
f = highByte((unsigned int)f * (unsigned int)beaconMaxPwm); // apply beacon max PWM
analogWrite(beaconPin, f); // send PWM to beacon pin
} // done with 1st and 2nd beacon cycle quarters
} // done with beacon
if (accelFound) { // read accelerometer values if accelerometer is present and accumulate for averaging
byte rawData[6]; // initialize buffer
readRegisters(accelAddress[accel], accelXReg[accel], rawData, sizeof(rawData)); // read accelerometer raw data into buffer
tX += (int)(rawData[accelXSeq[accel]] << 8 | rawData[accelXSeq[accel]+1]); // accumulate accelerometer raw X
tY += (int)(rawData[accelYSeq[accel]] << 8 | rawData[accelYSeq[accel]+1]); // accumulate accelerometer raw Y
tZ += (int)(rawData[accelZSeq[accel]] << 8 | rawData[accelZSeq[accel]+1]); // accumulate accelerometer raw Z
accelSamples++; // increment sample counter
if (accelSamples >= maxSamples) { // desired number of samples are collected:
accelX = tX; // average and convert accelerometer raw X to ten thousands slope
accelY = tY; // average and convert accelerometer raw Y to ten thousands slope
accelZ = tZ; // average and convert accelerometer raw Z to ten thousands slope
samples = accelSamples; // get number of samples to be sent
tX = 0; // zero raw accumulators
tY = 0;
tZ = 0;
accelSamples = 0; // zero sample counter
} // if (accelSapmples > maxSamples)
} // if (accelFound)
} // loop()
unsigned long expo(unsigned long m, byte c) {
if (c < 51) return (m * 2);
if (c < 102) return (m * 1.290);
if (c < 153) return (m * 0.831);
if (c < 240) return (m * 0.535);
return (m * 0.345);
} // expo
byte readRegister(byte addr, int reg) { // read single byte from accelerometer
Wire.beginTransmission(addr); // initialize transmission
Wire.write(reg); // send register address
Wire.endTransmission(false); // send above and keep connection open
Wire.requestFrom(addr, (byte)1); // request 1 byte, bus is released when done by default
if (Wire.available()) { // wait for data to arrive
return Wire.read(); // return byte
} else {
return 0;
} // if (Wire.available())
} // byte readRegister(byte addr, int reg)
void readRegisters(byte addr, int reg, byte *buffer, byte len) { // read len bytes starting from reg; store bytes in buffer
Wire.beginTransmission(addr); // initialize transmission
Wire.write(reg); // send register address
Wire.endTransmission(false); // send above and keep connection open
Wire.requestFrom(addr, (byte)len); // request len bytes, bus is released when done by default
if (Wire.available()) { // wait for data to arrive
for (int i = 0; i < len; i++) buffer[i] = Wire.read(); // read len bytes into buffer
} // if (Wire.available())
} // void readRegisters(byte addr, int reg, byte *buffer, byte len)
void writeRegister(byte addr, byte reg, byte data) { // write single byte to accelerometer
Wire.beginTransmission(addr); // initialize transmission
Wire.write(reg); // send register address
Wire.write(data); // send data
Wire.endTransmission(); // send above and close connection
} // void writeRegister(byte reg, byte data)
--- Край на кода ---
Иван
IvanC:
Използваният Bluetooth модул е HC-05. Фабричните му настройки са за скорост на обмен по серийния интерфейс (бодрейт) 9600 бита в секунда, което е прекалено бавно за нуждите на измервателния вагон. Програмата в Ардуиното използва 115200 бита в секунда, заради което настройките на HC-05 трябва да се променят.
Това става в т.нар. "AT" режим, по подобие на едновремешните модеми. Влизането в "AT" режим е малко особено - при изключено захранване на модула, трябва да се натисне и задържи бутонът на модула и да се подаде захранването. След около секунда - две бутонът може да се отпусне и светодиодът на модула трябва да мига бавно, което показва, че модулът е в "AT" режим. Ако светодиодът мига бързо, модулът не е успял да влезе в "AT" режим и трябва да повторим процедурата наново.
След като модулът е влязъл в "AT" режим, стартираме серийния монитор на Ардуино средата. Разбира се предварително трябва да сме избрали верният COM порт за USB-Serial кабела/преобразувателя. Всъщност серийният монитор на Ардуино средата може да се стартира и преди да сме вкарали HC-05 модула в "AT" режима.
Важно е да настроим серийния монитор правилно. Това става, като изберем "38400 baud" долу вдясно на екрана на монитора и "Both NL & CR" отляво на скоростта. Сега за да тестваме връзката с HC-05 модула, цъкаме с мишката горе на екрана на серийния монитор, вляво от бутона "Send", за да се появи там мигащ курсор и написваме с ГЛАВНИ БУКВИ НА ЛАТИНИЦА (всичко, което пишем като команди на HC-05 модула е с главни латински букви):
AT
и натискаме бутона "Enter" на клавиатурата или бутона "Send" на серийния монитор. Въобще след всяка въведена команда, трябва да натиснем един от тези два бутона, за да бъде изпратена към модула.
Ако всичко работи както трябва, на екрана трябва да се изпише отговорът от модула
OK
Ако искаме да видим текущата настройка на скоростта на обмен на серийния интерфейс, написваме
AT+UART
и натискаме "Enter" на клавиатурата или "Send" на прозореца на серийния монитор, на което модулът ще отговори например с
AT+UART:9600,0,0
Отговорите от модула може да пропуснат "AT" преди плюса, в зависимост от техния фърмуер, така че това да не ни хвърля в оркестъра. Горният отговор показва, че скоростта на обмен на модула е 9600 бита в секунда (бода).
За да променим скоростта на 115200 бита в секунда, написваме
AT+UART=115200,0,0
и изпращаме тази команда към модула с натискане на един от двата бутона, както съм написал по-горе. Модулът трябва да отговори
OK
за да потвърди, че е възприел и изпълнил командата. Ако искаме може да изпратим пак командата
AT+UART
на която модулът трябва да отговори с
AT+UART:115200,0,0
което означава, че настройката е направена.
Ако модулът е вече използван, трябва да му проверим паролата, която ще ни трябва при свързване с модула от някое от устройствата/програмите за индициране на параметрите, измервани от вагона. Това става с командата
AT+PSWD
на което модулът ще отговори примерно
AT+PIN:"1234"
или
AT+PIN:1234
Важното тук е да обърнем внимание дали в отговора паролата (пинът) е заграден в кавички или не. Ако искаме да променим паролата, командата е
AT+PSWD="9876"
или
AT+PSWD=9876
като вместо 9876 въведем 4-цифрен пин по наше желание, който обаче трябва да запомним или още по-добре да си го запишем. Важното е да въведем новия пин в кавички или без такива в зависимост от това как модулът ни е отговорил преди това на комадната AT+PSWD - със или без кавички. Ако отговорът е с кавички, пишем ги и ние, ако е без - въвеждаме новия пин без кавички.
Ако модулът е възприел новата команда, трябва да ни отговори с "OK". Препоръчвам отново да запитаме модула за паролата му, за да сме напълно убедени, че е възприета правилно.
Друго, което може да искаме да променим е името на модула. Фабричната стойност (име) е "HC-05". След време, ако използвате повече модули в различни устройства, всичките ще се появяват на компютъра или на GSM-а/таблета с HC-05 и ще е трудно да ги разграничим. Проверката за името става с командата
AT+NAME
отговорът от модула ще е
AT+NAME:HC-05
За да променим името на модула изпращаме команда
AT+NAME=MESSWAGEN-1
като вместо MESSWAGEN-1 слагаме името, което желаем.
Друга важна настройка е за ролята на модула. Този в измервателния вагон трябва да е "SLAVE", т.е. подчинен. Заводската настройка е за "SLAVE", но е желателно да го проверим, а ако модулът вече е използван за други нужди и да го променим, ако трябва. Командата за проверка е
AT+ROLE
на което модулът трябва да отговори с
AT+ROLE:0 ако е "SLAVE"
или
AT+ROLE:1 ако е "MASTER"
Ние искаме първото. Ако модулът е отговорил с второто, изпращаме команда
AT+ROLE=0
При изпращане на команда за промяна на AT+ROLE, модулът ще излезе от "AT" режима и затова обикновено това е последната команда, която изпращаме. Ако искаме отново да вкараме модула в "AT" режим, изключваме му захранването и повтаряме процедурата, която съм описал в началото на мнението.
Това е по настройките на HC-05 модула. В следващо мнение ще спомена и за настройките на HC-05 за устройството за индициране на скоростта и изминатия път, които се различават само при AT+ROLE командата. Това е ако някой реши да си направи това устройство вместо да използва приложението за Андроид устройство или програмата за Windows. Аз лично предпочитам да използвам самоделната индикация.
Иван
IvanC:
Приемникът на информацията от измервателния вагон е също базиран на Ардуино Про-мини и HC-05 Bluetooth модул. За показване на измерените от вагона и изчислени параметри използвам течнокристална индикация с 16х2 символа, т.е. с 2 реда с 16 символа на ред. Индикацията има I2C към паралелен преобразувател. Така връзките към процесора се свеждат до минимум (4 проводника - маса, +5 V, SDA и SCL).
Ето схемата на приемника с индикацията:
Захранването е идентично на това в измервателните вагони 2 и 3 - литиево-йонен акумулатор и зарядно/преобразувател до 5 V от USB батерия и ключе за захранването.
Настройките на HC-05 Bluetooth модула са почти идентични с тези на модула във вагона. Единствената разлика е настройката за MASTER:
AT+ROLE=1
Важно е паролата/пинът на модула в индикацията да е еднакъв с този на модула във вагона, така че преди да направим настройката с AT+ROLE, трябва да сменим паролата/пина с тази, която сме записали в HC-05 модула на вагона.
Ето всички настройки за модула на индикацията:
AT+UART=115200,0,0
AT+PSWD="същата_парола_като_на_вагона"
AT+ROLE=1
Да припомня, че паролата се въвежда с или без кавички в зависимост от това как модулът е отговорил на запитването AT+PSWD - с или без кавички.
Няма нужда да се променя името на модула, защото модулът на индикацията няма да се свързва с компютър или Андроид устройство.
Иван
Навигация
[0] Списък на темите
Премини на пълна версия