Pull to refresh
18
0
Валерий Шиманский @vertu77

User

Send message
Интересно, спасибо. А какие навыки приобретают школьники? Я понял, что здесь они выступают только операторами телеуправления. Когда робот в физической доступности — могут быть мастерами по сборке, ремонту, замене навесного оборудования. Или еще что то есть? Есть возможность что-то программировать?
Насколько выверена ваша матрица в облаке?
Навскидку
Вопрос 16 — возможность высказывать предложения касаемо организации или технического стека проекта. Первый вариант относится к мотивации 2 (общее руководство), а второй почему-то к мотивации 3 (самостоятельность, автономия).
Вопрос 21 — постоянная премия в размере 20% от заработка или отсутствие звонков и писем в нерабочее время. Второй пункт относится к мотивации 8 (стиль жизни), а первый почему-то к 2 (общее руководство).
Может, кому пригодится — недавно на Хабре была статья по вариантам поиска по открытым данным. Как проверить автомобиль перед покупкой: используем доступные в Интернете базы данных и логику
Спасибо за статью. Заинтересовали варианты повышения живучести при выключении питания.
В статье есть ссылка на решение с использованием UnionFS. Основная идея «Отсутствие какой-либо записи данных на флэш-память повышает надёжность устройства, приближая его к промышленному классу изделий.»
Может кто-нибудь дать инфу или подсказать где рыть, чтобы понять, какие решения используются в «промышленном классе изделий». Есть моноблок на AstraLinux (российский на основе дебиан). Диск SSD, использование компьютера в режиме «киоска» — на экране крутится одна программа, диск на запись используется для хранения небольших логов. Предполагается, что компьютер максимально необслуживаемый, возможные зависания предполагается лечить внешним watchdog по линии сброса или питания. Есть подозрения, что после такого сброса линукс может выкинуть предложение воспользоваться fsck и без человека не обойтись. Буду благодарен за любую подсказку.
Вызывают сомнения значения на вертикальной оси гистограммы.
50 тыс случаев на 100 тыс населения — по моему, в ссылке нет таких порядков. Уточните, пожалуйста.
Да, текущий проект — атомный плавучий энергоблок «Академик Ломоносов» для Певека, две реакторные установки по 150 МВт тепловой мощности, ввод в эксплуатацию в 2019 году.
ОКБМ Африкантов
Российская газета
Спасибо еще раз.
Попробую
Спасибо.
Может кто подскажет ответ на вопрос по близкой тематике?
Есть набор точек (отсчеты АЦП), расположенных на кривой, несколько напоминающей вершинку синусоиды (но крутизна переднего и заднего фронтов разная). Хотелось бы интерполировать эту кривую и найти ее экстремум.
В сторону каких алгоритмов смотреть с учетом ограниченных вычислительных ресурсов (предполагается использование в микроконтроллере)?
Приношу извинения — не заметил что автор предполагает цикл статей. Возможно, мой комментарий о CTMU тогда окажется ненужным.
У некоторых ПИКов (например PIC24KV32KA304) есть Charge Time Measurement Unit (CTMU). Принцип вроде примитивный (встроенный генератор тока 55 мкА, конденсатор 15 пФ и 10 битный АЦП), но результат интересный — обещают точность измерения короткого импульса около 1 нсек.

Примеры применения CTMU от Microchip
Небольшой перевод на русский
Интересный импульсный рефлектометрический уровнемер на ПИКе
В структуре DMA этого процессора есть возможность работы с «половинками» синусоиды (режим пинг-понг).
Ниже инициализация DMA-ЦАП для такого подхода с использованием библиотек Миландр.
За основу взят код примера из этой библиотеки.

DMA_ChannelInitTypeDef DMA_InitStr_TIM1;
DMA_CtrlDataInitTypeDef DMA_PriCtrlStr_TIM1;
DMA_CtrlDataInitTypeDef DMA_AltCtrlStr_TIM1;
........

// ФОРМИРОВАНИЕ СИНУСОИДЫ - ДМА И ЦАП
DMA_DeInit_();
DMA_StructInit(&DMA_InitStr_TIM1);
/* Set Primary Control Data */
DMA_PriCtrlStr_TIM1.DMA_SourceBaseAddr = (uint32_t)Sine12bit1;
DMA_PriCtrlStr_TIM1.DMA_DestBaseAddr = (uint32_t)(&(MDR_DAC->DAC2_DATA));
DMA_PriCtrlStr_TIM1.DMA_SourceIncSize = DMA_SourceIncHalfword;
DMA_PriCtrlStr_TIM1.DMA_DestIncSize = DMA_DestIncNo;
DMA_PriCtrlStr_TIM1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_PriCtrlStr_TIM1.DMA_Mode = DMA_Mode_PingPong;
DMA_PriCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
DMA_PriCtrlStr_TIM1.DMA_NumContinuous = DMA_Transfers_1;
DMA_PriCtrlStr_TIM1.DMA_SourceProtCtrl = DMA_SourcePrivileged;
DMA_PriCtrlStr_TIM1.DMA_DestProtCtrl = DMA_DestPrivileged;

/* Set Alternate Control Data */
DMA_AltCtrlStr_TIM1.DMA_SourceBaseAddr = (uint32_t)Sine12bit2;

DMA_AltCtrlStr_TIM1.DMA_DestBaseAddr   = (uint32_t)(&(MDR_DAC->DAC2_DATA));

DMA_AltCtrlStr_TIM1.DMA_SourceIncSize = DMA_SourceIncHalfword;
DMA_AltCtrlStr_TIM1.DMA_DestIncSize = DMA_DestIncNo;
DMA_AltCtrlStr_TIM1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_AltCtrlStr_TIM1.DMA_Mode = DMA_Mode_PingPong;
DMA_AltCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
DMA_AltCtrlStr_TIM1.DMA_NumContinuous = DMA_Transfers_1;
DMA_AltCtrlStr_TIM1.DMA_SourceProtCtrl = DMA_SourcePrivileged;
DMA_AltCtrlStr_TIM1.DMA_DestProtCtrl = DMA_DestPrivileged;

/* Set Channel Structure */
DMA_InitStr_TIM1.DMA_PriCtrlData = &DMA_PriCtrlStr_TIM1;
DMA_InitStr_TIM1.DMA_AltCtrlData = &DMA_AltCtrlStr_TIM1;
DMA_InitStr_TIM1.DMA_Priority = DMA_Priority_High;
DMA_InitStr_TIM1.DMA_UseBurst = DMA_BurstClear;
DMA_InitStr_TIM1.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;

/* Init DMA channel TIM2*/
DMA_Init(DMA_Channel_TIM1, &DMA_InitStr_TIM1);

/* Enable dma_req or dma_sreq to generate DMA request */
MDR_DMA->CHNL_REQ_MASK_CLR = DMA_SELECT(DMA_Channel_TIM1);
MDR_DMA->CHNL_USEBURST_CLR = DMA_SELECT(DMA_Channel_TIM1);

/* Enable DMA_Channel_TIM2 */
DMA_Cmd(DMA_Channel_TIM1, ENABLE);


В прерывании по таймеру заполняем размеры половинок:

   DMA_AltCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
   DMA_PriCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
   DMA_Init(DMA_Channel_TIM1, &DMA_InitStr_TIM1);


Хотелось бы использовать прерывание не таймера, а самого DMA — но там у этого кристалла оказалось много подводных камней, особенно когда DMA используется не только для канала ЦАП.
Дополню себя — жаль что этот способ неприменим, если плате разведен только JTAG_A.
Спасибо. Позволю, в свою очередь, немного уточнить — как теперь понял это я.
Дано — программа запускается из внутреннего ПЗУ, но в силу ошибок (неверное тактирование, блокировка пинов, еще что-то) после запуска не дает корректно работать с портом JTAG_B отладчику.
Выбираем режим 010 — после перезагрузки «процессор пытается начать выполнять программу из внешней памяти, установленной на внешней системной шине». Тут я думаю имеется в виду скорее внешнее ПЗУ чем ОЗУ, то есть это режим не микроконтроллера, а микропроцессора. Так как там ничего нет, JTAG порт остается рабочим. Дальше уже дело внутрисхемного отладчика, работа его ничем не отличается от режима 000. Он через JTAG порт загружает в ОЗУ с адреса 0x20000000 размером 0x0800 «algorithm for download». Загрузчик запускается в ОЗУ и делает то, что мы его попросили в настройках — например «Erase full chip» с адреса 0x08000000, то есть очищаем внутреннее ПЗУ.
Как отлаживаться, загружая прошивку в ОЗУ — не знаю. Видел упоминания, что есть такая возможность. Думаю, это будет полезно многим.
Сам делал на этом МК загрузку отдельных модулей программы в ОЗУ из ПЗУ после старта. Keil позволяет делать это достаточно легко. Это, в частности, необходимо если мы захотим использовать часть ПЗУ для хранения пользовательских данных.
Интересно про четвертый способ восстановления. Припоминаю, что у меня была похожая ситуация — после перебора всех положений перемычек процессор ожил. Подумал что случайность, что-то сам перепутал. Похоже что нет — получается что режим 010 «круче» с точки зрения прошивки чем режим 000?
По количеству таймеров согласен — на них сэкономили.
Про RTX и таймеры общего назначения упомянул для полноты картины, в рамках раздела — «Электроника для начинающих».
Когда не использую ОСРВ, тоже применяю SysTick. Но немного по другому — глобальная переменная счетчика миллисекунд наращивается в прерывании SysTick. В основном теле программы использую case c конечными автоматами — примерно так

int delay=500;
int State=BEGIN;

while (1) {
   switch (State) {
        case BEGIN:
            LocalTimer=GlobalTimer+delay;
            LedOn();    
            State=LED_ON;      
            break; 
        case LED_ON:
            if (LocalTimer>=GlobalTimer) {
               LocalTimer=GlobalTimer+delay;
               LedOff();    
               State=LED_OFF;      
            }
            break;
        case LED_OFF:
            if (LocalTimer>=GlobalTimer) {
               LocalTimer=GlobalTimer+delay;
               LedOn();    
               State=LED_ON;      
            }
            break;
   }
}


Код упрощенный, например нет запрета прерываний (надо предотвратить попытку одновременного изменения GlobalTimer). Также есть проблема в ограничении длины GlobalTimer.
Ничто не мешает сделать несколько конечных автоматов и переключаться между ними — получается подобие ОСРВ.
Спасибо за подсказку.
Про «Ножницы» в Windows7 никто не сказал — ссылка.
В Keil есть встроенная небольшая операционная система — RTX. Позволяет создать многозадачную систему с плюшками (события, мьютексы, приоритеты..). Таймер SysTick однозначно занимается под эту операционку, это основной таймер такой системы. Задача мигания светодиодом при использовании RTX могла бы вылядеть так:
__task void f_LED (void) {
while(1)
{ PORTС-RXTX!=1;
os_dly_wait (1000);
PORTС-RXTX&=~(1);
os_dly_wait (1000);
}

В периоды ожидания os_dly_wait МК выполняет другие задачи.

Для прикладных задач логичнее использовать таймеры общего назначения, внешние по отношению к ядру ARM. Они в этом микроконтроллере достаточно наворочанные, число регистров конфигурации гораздо больше 4-х.
Мигание можно реализовать через таймер несколькими способами
— с использованием аппаратного прерывания таймера. Состояние светодиода изменяется непосредственно в теле прерывания
— с использованием аппаратного прерывания таймера. В основное тело программы передается метка наступления события (вариант автора статьи).
— настройками таймера в режиме ШИМ. При этом не используются ни прерывания, ни код в основном теле программы.
Да, это я назвал «2.Залить прошивку через UART (штатный загрузчик)».
Для этого подойдут контакты, выведенные под JTAG (PD0-1 или PF0-1). Keil и J-Link тут уже не помогут, нужен преобразователь UART и отдельный загрузчик на компьютере (на форуме Миландра есть обсуждение).
Здорово что стали появляться такие статьи.

Один нюанс — надо внимательно смотреть на каком порту хотим мигать светодиодом.
Если этот порт используется для JTAG\SW (порты F и D) — даже если пин светодиода не пересекается с пинами JTAG, после первого мигания заливка прошивки и отладка по этому порту станет невозможна.
Чтобы такого не случилось, на форуме Миландра предлагают такой способ:
temp = MDR_PORTD->RXTX;
temp &= ~(31);
temp&=~( PORT_Pin_10 );
MDR_PORTD->RXTX=temp;

Способ рабочий, хотя несколько некрасивый. 31 — это 0b11111, то есть надо писать нули во все пины, относящиеся к JTAG/

Если все-таки JTAG порт умер — что делать:
1. Тогда может пригодится другой JTAG порт. Если он не разведен на плате, можно припаяться только к ножкам SW на другом порту (меньше возни)
2. Залить прошивку через UART (штатный загрузчик)
3. Использовать особенности зашитой программы — успеть прошить новую заливку после подачи питания до первого мигания. В варианте автора это практически невозможно. В реальных программах часто программа запускается от внутреннего генератора, затем инициализируется внешний кварц. Если при этом используется бесконечный цикл ожидания — можно отпаять кварц и прошиться до первого мигания.

/* Enable HSE */
RST_CLK_HSEconfig(RST_CLK_HSE_ON); // включили генератор на кварце
while (RST_CLK_HSEstatus() != SUCCESS) { }


В этом примере используются функции библиотеки Миландра для своих микроконтроллеров (есть на их сайте).
Инициализация портов с использованием этой библиотеки несколько отличается от решения автора статьи. Как пример:

PORT_InitStructure.PORT_PULL_UP = PORT_PULL_UP_ON;
PORT_InitStructure.PORT_PULL_DOWN = PORT_PULL_DOWN_ON;
PORT_InitStructure.PORT_PD_SHM = PORT_PD_SHM_OFF;
PORT_InitStructure.PORT_PD = PORT_PD_DRIVER;
PORT_InitStructure.PORT_GFEN = PORT_GFEN_OFF;
PORT_InitStructure.PORT_FUNC = PORT_FUNC_PORT;
PORT_InitStructure.PORT_SPEED = PORT_SPEED_MAXFAST;
PORT_InitStructure.PORT_MODE = PORT_MODE_DIGITAL;
PORT_InitStructure.PORT_OE = PORT_OE_OUT;
PORT_InitStructure.PORT_OE = PORT_OE_OUT;
PORT_InitStructure.PORT_Pin = PORT_Pin_10;
PORT_Init(MDR_PORTC, &PORT_InitStructure);
УЗО срабатывает, если разница токов в проводах «ноль» и «фаза», проходящих через него, превышает предел (обычно 10 или 30 мА). Дифференциальный ток в топике выше — это как раз разница токов между двумя проводами. УЗО можно устанавливать как в сети с заземляющим проводом, так и без него. Причем в сети без заземляющего провода (старые дома) необходимость установки УЗО выше.
Путаница в дискуссии выше могла возникнуть, так как сейчас часто продают не чистые УЗО, а так называемые дифавтоматы, которые включают в себя и УЗО и защиту от больших токов. «Большие» — это 6, 10, 16, 25 А через любой из двух проводов.
1

Information

Rating
Does not participate
Location
Рязань, Рязанская обл., Россия
Date of birth
Registered
Activity