Эта история случилась уже лет семь тому назад. В результате болезни изображение в глазах у меня стало двоиться и, чтобы как-то оценить обстановку, приходилось закрывать один глаз.
Одно время вообще ходил как пират — с повязкой на глазу. Без нее пользоваться компьютером было вообще нереально. Ни о каком бинокулярном зрении, естественно, речи не было. Загнать машину в гараж — это был просто квест. Летом машину можно и около дома оставить, а в холода лучше бы в гараже держать — откопать ее из под снега или отскрести окна было не реально, кроме зрения проблем хватало. Одно время я вообще передвигался на инвалидной коляске — как можно в таком состоянии машину отрыть?
Короче, решил я подойти к делу технически и оборудовать гараж измерителем расстояния до машины и установить его на стене.
На Али были куплены крупные дисплеи и ультразвуковой измеритель расстояния.
Для начала на Ардуино был поставлен scmRTOS — ну, вы сами понимаете, как же можно что-то делать без операционной системы реального времени?
«Лучше день потерять, потом за пять минут долететь!» — как говаривал один гриф из мультика.
Ну а дальше — «Пошёл! Пошёл! Работаем, работаем, страус, пошёл». Готовых библиотек для MAX7219 сейчас хоть пруд пруди, тогда мне то ли не удалось найти подходящей, то ли они мне просто не понравились.
Там есть одна тонкость — надо было писать подпрограмму для переворота битовой матрицы, если хочется, например, иметь бегущую строку.
В большинстве библиотек это сделано очень тупо и прямолинейно. Сразу видно, люди в детстве хороших книжек не читали и игрушки у них были прибиты к полу гвоздями. Если бы читали «Hacker's Delight» (я ее на русском тоже видел под менее романтичным названием «Алгоритмические трюки для программистов», если склероз не подводит), очевидно, они бы сделали так:
void MAX7219SPI::ImageRotate()
{
for(int8_t i=0; i<SECTIONS_NUM; i++)
{
// Hacker's Delight
uint32_t x,y,t;
x = (uint32_t)ImageBuff[0+i*8]<<24;
x |= (uint32_t)ImageBuff[1+i*8]<<16;
x |= (uint32_t)ImageBuff[2+i*8]<<8;
x |= ImageBuff[3+i*8];
y = (uint32_t)ImageBuff[4+i*8]<<24;
y |= (uint32_t)ImageBuff[5+i*8]<<16;
y |= (uint32_t)ImageBuff[6+i*8]<<8;
y |= ImageBuff[7+i*8];
t = (x ^ (x>>7)) & 0x00AA00AA;
x = x ^ t ^ (t<<7);
t = (y ^ (y>>7)) & 0x00AA00AA;
y = y ^ t ^ (t<<7);
t = (x ^ (x>>14)) & 0x0000CCCC;
x = x ^ t ^ (t<<14);
t = (y ^ (y>>14)) & 0x0000CCCC;
y = y ^ t ^ (t<<14);
t = (x & 0xF0F0F0F0) | ((y>>4) & 0x0F0F0F0F);
y = ((x<<4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
x = t;
LineBuff[0+i*8] = x>>24;
LineBuff[1+i*8] = x>>16;
LineBuff[2+i*8] = x>>8;
LineBuff[3+i*8] = x;
LineBuff[4+i*8] = y>>24;
LineBuff[5+i*8] = y>>16;
LineBuff[6+i*8] = y>>8;
LineBuff[7+i*8] = y;
}
}
«Надёжно! Добротно! Хорошо!» — и никаких тебе циклов вообще. Тот, который для разрядов дисплея — к делу не относится и поэтому не считается.
После этого прикрутить ультразвуковой датчик расстояния — это даже не вопрос. Прерывание и таймер — наше все.
#include "scmRTOS.h"
#include "processes.h"
#include "Arduino.h"
/*
* sonar pins:
* 7 (PD7) trigger
* 8 (PB0) echo
*/
TProc1 Proc1;
OS::channel<uint16_t, 2> SonarTime;
int16_t Distance;
namespace OS
{
template<> void TProc1::exec()
{
tick_count_t next_tick;
tick_count_t current_tick;
DDRD |= 1<<PD7; // TRIG pin
DDRB &= ~(1<<PB0); // ECHO pin
TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS11); // noise canceler, rising edge. 16/8=2Mhz
TCCR1A = 0x00;
next_tick = OS::get_tick_count();
for (;;)
{
uint16_t SensorTime;
TIMSK1 |= 1<<ICIE1; // capture interruption enabled
PORTD |= 1<<PD7; // trigger sonar
OS::sleep(1);
PORTD &= ~(1<<PD7);
SonarTime.pop(SensorTime,200);
Distance=SensorTime/116;
next_tick += 500;
current_tick = OS::get_tick_count();
if (current_tick < next_tick) sleep(next_tick - current_tick);
}
}
}
// sonar ISP
ISR(TIMER1_CAPT_vect)
{
static uint16_t TimerData;
if (TCCR1B & (1<<ICES1))
{
TimerData = ICR1;
TCCR1B &= ~(1<<ICES1); // falling edge
}
else
{
OS::TISRW ISR;
TimerData = ICR1 - TimerData;
TCCR1B |= 1<<ICES1; // rising edge
TIMSK1 &= ~(1<<ICIE1); // interruption disabled
SonarTime.push(TimerData);
}
}
Встал вопрос, как это запитать — до ближайшей розетки провод тянуть было неудобственно. Хотел уже ставить литиевый аккумулятор и включать измерение и индикацию по срабатыванию датчика движения, ведь дисплей кушать изволит немерянно.
Пошел в гараж рассматривать на месте, что и как поставить.
Тут на глаза попался обрезок доски — и вуаля!
Проблема мгновенно решена. За прошедшие годы ни разу не понадобилась обновлять прошивку, батареи менять не надо, заряжать ничего не надо. Надежность и удобство пользования просто зашкаливает.
Еще одна проблема, правда, так и осталась нерешенной — я иногда задеваю зеркалами о проем, видимо, нужно какой-то лазерный гаражный прицел ставить.
Извиняюсь, статья почти не иллюстрирована своими фотографиями — они либо не делались, либо давно утеряны. В наличии остались только исходники программного обеспечения и до сих пор валяющиеся без дела модули.
P.S. A у вас вся спина белая! И до встречи на дорогах.
особенно на фоне вступительной части:
«В результате болезни изображение в глазах у меня стало двоиться» ))
Надеюсь, это тоже относиться к 1 апреля)
С 1 апреля…
За первоапрельский обзор плюс!
Про бруски, шутка. С 1 апреля.
И да, с первым апреля)
От себя хочу добавить (для всех муськовчан) — никогда не шутите насчёт своего здоровья (несуществующих болячек) и не лгите на эту тему («заболел, не могу что-то сделать») — можете накликать несчастье.
Он не умер, но видит бог, рано, или поздно может накликать
Хотя можно купить парктроник и прикрутить его к стене гаража, они по 1000 сейчас стоят.
Я несколько раз видел инвалидов-колясочников за рулем, иногда машина оборудована специальным краном (снаружи не виден), который коляску вытаскивает из машины и ставит рядом с водительским сиденьем).
С 1 Апреля всех !MYSKU
PS: да, матрица битовая, поэтому там не просто транспонирование — каждый выходной байт собирается из соответствующих битов 8-ми входных байт
Полностью согласен. Да и gcc очень плохо оптимизирует всякие там сдвиги — может для сдвига на 7 разрядов влепить цикл из 7 итераций (хотя, можно сдвинуть на 1 в другую сторону).
Сходу предположу, что самым быстрым вариантом будет 56 команд BST и 56 команд BLD — 112 тактов и 224 байта ПЗУ.
PS: в реальности этой проблемы вообще нет, так как современный модули на max7219 строго квадратные и сделаны именно под соединение в строку. Никакое транспонирование матрицы там не нужно
П.С. Помню, в далеком детстве мама обновляла прошивку моих носков при помощи такого прибора:
У самого кирпичи лежат.
Ну или направляющие вдоль колес.
У меня парктроники, но я внимательно стараюсь смотреть, потому что не зацепиться зеркалом при выезде парктроник не поможет.
ЗЫ: Метку на стене делал не я, но с удовольствием пользуюсь.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.