ИК датчик движения на STM32

    Приветствую, в этой статье вы узнаете: как сделать датчик движения с использованием ИК диода и ИК приемника на STM32 с минимальным использованием ядра (т.е. с максимальной загрузкой периферии) на регистрах, используя таймеры.

    В статье максимально подробно рассмотрены вопросы программирования. Материал рассчитан на начальный уровень подготовки, но также и подойдет для более опытных. Часть подробностей скрыта под спойлерами для снижения загруженности статьи.

    Оглавление:

    Общая картина

    Схемы устройств

    Работа ИК диода и ИК приемника

    Код для передатчика ИК сигнала

    Код для приемника ИК сигнала

    Полный код

    Дополнительно

    Заключение

    Общая картина

    Используются два устройства: передатчик ИК сигнала и приемник ИК сигнала.

    Общий принцип работы следующий: передатчик ИК сигнала излучает сигнал инфракрасного диапазона длин волн, а приемник ИК сигнала их принимает. Между этими устройствами образуется «луч», пересечение которого каким-либо объектом фиксируется приемным устройством.

    В качестве ИК диода используется TSAL6200, в качестве ИК приемника – TSOP4856.

    TSAL6200
    TSAL6200
    TSOP4856
    TSOP4856

    Схемы устройств

    Опустим цепи питания и другие элементы реальных устройств и рассмотрим только необходимые.

    Передатчик ИК сигнала состоит из микроконтроллера STM32L151C8T6, полевого транзистора 2N7002, резистора 1 Ом и ИК диода TSAL6200. Ниже представлена электрическая схема передатчика.

    Транзистор необходим для усиления тока, протекающего через ИК диод, так как выходной ток с пина МК ограничен (выходной ток с пина МК STM32L151C8T6 не более 25 мА, максимальный постоянный ток через ИК диод TSAL6200 100 мА).

    Выбор транзистора на ваше усмотрение. Здесь выбран транзистор 2N7002, потому что он дешевый и его характеристик достаточно для моего использования. Стоит выбирать транзистор с меньшим пороговым напряжением затвора (Gate Threshold Voltage), так как на затвор вы сможете подать напряжение не более напряжения питания без дополнительных цепей, в нашем случае 3.3 В.

    Точный расчет величины сопротивления резистора является трудным, конечно, существуют специальные формулы, но я предлагаю подобрать резистор опытным путем. Так в моем случае используется резистор 1 Ом, амплитуда тока цепи составляет 20 мА, дальность связи при таком токе достигает 14 м в зависимости от конфигурации передаваемого сообщения (количество импульсов в пачке, скважность, об этом ниже). Если вам требуется большая дальность, следует или подобрать резистор поменьше, или увеличить напряжение питания для диода, или выбрать транзистор с меньшим пороговым напряжением и меньшим падением напряжения на сток-истоке.

    Приемник ИК сигнала состоит из микроконтроллера STM32L151C8T6, ИК приемника TSOP4856, резистора 100 Ом и конденсатора 0.1 мкФ. Ниже представлена электрическая схема приемника.

    Работа ИК диода и ИК приемника

    При протекании тока через диод TSAL6200 излучается ИК сигнал с длиной волны 940 нм. Это излучение необходимо промодулировать меандром с частотой 56 кГц (приемник настроен на данную частоту, см. даташит). Передавать следует пачки таких импульсов с определенной скважностью.

    Эти пачки принимается устройством TSOP4856. Пока принимается одна пачка, на выходном выводе приемника низкое значение напряжения, как только на входе нет импульсов, приемник поднимает выходной вывод к напряжению питания. Ниже на картинках представлены временные диаграммы данного процесса. На первой картинке показана работа приемника во время приема одной пачки. На второй картинке показана работа приемника при приеме множества пачек.

    Остается только запрограммировать работу передатчика и приемника.

    Код передатчика ИК сигнала

    Будем использовать таймеры для формирования пачек импульсов с выводом сигнала на конкретный пин. Таким образом, ядро МК только инициализирует эти таймеры, а дальше может заниматься какой-нибудь другой работой.

    Выбор пина должен быть обоснован. Необходимо выбирать такой пин, к которому может быть подключен какой-либо канал (кроме четвертого) любого General-purpose таймера. В нашем случае выбран пин PB6, к нему подключается первый канал TIM4. Приемник же будет подключен к пину PB7, второй канал TIM4.

    Будем использовать два таймера: TIM4 будет генерировать меандр с частотой 56 кГц, TIM2 будет управлять таймером TIM4, т.е. создавать пачки из меандра. TIM2 будет работать в режиме Master, TIM4 – Slave. Почему именно таймер TIM2? Он выбран исходя из таблицы даташита подключений таймеров друг к другу.

    Приступим к написанию функции инициализации таймеров Tim_Init_Transmitter(). Код написан для пустого проекта. Сначала объявляем функцию, в теле main её инициализируем, а после мэйна прописываем уже саму функцию.

    #include "main.h"
    
    void Timer_Init_Transmitter(void);
    
    int main(void)
    {
       RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6;   // MSI 4.194 MHz enable
    
       Timer_Init_Transmitter();
    
       while(1)
       {
    
       }
    }
    
    void Timer_Init_Transmitter(void)
    {
    
    }
    

    RCC->ICSCR |= RCCICSCRMSIRANGE_6 - эта строчка просто устанавливает частоту 4.194 МГц МК. У вас может быть любая другая частота.

    Настраиваем пин. Включаем тактирование, включаем альтернативную функцию, выбираем скорость пина повыше (это не является необходимым), выбираем какую именно альтернативную функцию хотим подключить к пину. Под спойлерами описано все подробно.

    Подробнее про включение тактирования

    В даташите находим регистр RCC_AHBENR. Нужно прописать «1» в поле GPIOBEN.

    Для этого выбираем в библиотеке CMSIS строчку RCC_AHBENR_GPIOBEN, которая ставит данный бит в единицу.

    И изменяем регистр AHBENR следующим образом:

    RCC->AHBENR |= RCC_AHBENR_GPIOBEN; //GPIO port B clock enable

    Подробнее про включение альтернативной функции

    В даташите находим регистр GPIOx_MODER. Нужно прописать «10» в поле MODER6 (для пина PB6).

    Для этого выбираем в библиотеке CMSIS строчку GPIO_MODER_MODER6_1, которая ставит второй бит в единицу.

    В дальнейшем все такие обозначения будут браться аналогично.

    И изменяем регистр MODER следующим образом:

    GPIOB->MODER |= GPIO_MODER_MODER6_1;   //Alternative function mode enable

    Включение высокой скорости для пина делается аналогично включению альтернативной функции.

    Подробнее про выбор альтернативной функции

    Обозначение альтернативных функций представлено на картинке ниже.

    Нам нужна альтернативная функция для TIM4 – это AF2.

    Стоит отметить, что существует два регистра для выбора альтернативных функций: нижний GPIOx_AFRL для пинов с номерами от 0 до 7 и верхний GPIOx_AFRH для пинов с номерами от 8 до 15. Однако, в библиотеке CMSIS определен сдвоенный регистр AFR[2], прописав в скобки «0», мы выбираем нижний регистр, прописав «1», выбираем верхний регистр.

    В даташите находим регистр GPIOx_AFRL.

    Нам нужно прописать «0010» в поле AFRL6, для этого нам нужно число в шестнадцатеричной форме 0x2000000, «2» седьмая справа для пина PB6, потому что первые шесть цифр для пинов с номерами от 0 до 5.

    И изменяем регистр AFRL следующим образом:

    GPIOB->AFR[0] |= 0x2000000;     //Pin PB6 TIM4 alternative function AF2 enable

    Получили следующий код для настройки пина внутри нашей функции:

    void Timer_Init_Transmitter (void)
    {
       //Settings for GPIO PB6
       RCC->AHBENR |= RCC_AHBENR_GPIOBEN;             //GPIO port B clock enable
       GPIOB->MODER |= GPIO_MODER_MODER6_1;           //Alternative function mode enable
       GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6_1;	  //High speed
       GPIOB->AFR[0] |= 0x2000000;                    //Pin PB6 TIM4 alternative function AF2 enable
    }
    

    Теперь перейдем к настройке TIM4.

    Нам нужно выбрать прескейлер PSC (делитель частоты), рассчитать значения для регистров CCR1 (длительность импульса) и ARR (период импульсов), выбрать режим работы таймера ШИМ, выбрать входной управляющий сигнал от таймера TIM2, выбрать режим для Slave и подать выходной сигнал таймера на пин PB6.

    Включение тактирования осуществляется аналогично включению тактирования GPIO.

    Подробнее про выбор прескейлера PSC и расчет CCR1 и ARR

    Выберем значение преселлектора входной частоты равное 0, в этом случае частота тактирования таймера будет равна частоте МК.

    И изменяем регистр PSC следующим образом:

    TIM4->PSC = 0; //Prescaler value

    Перейдем к расчету ARR.

    Для расчета ARR нам нужно поделить тактовую частоту таймера 4.194 МГц (у вас своя) на 56 кГц. Получаем 74,89, округляем до целого. Я округлил до 75. И вписываем в регистр ARR:

    TIM4->ARR = 75 //Auto-reload value

    Осталось рассчитать CCR1.

    Так как у нас простой меандр, то в регистр CCR1 при режиме ШИМ нужно указать половину от значения ARR:

    TIM4->CCR1 = 37;   //Capture/Compare 1 value

    Подробнее про выбор режима работы ШИМ таймера

    Так как у нас первый канал, то используем регистр CCMR1. Нас интересует в этом регистре поле OC1M. Режим ШИМ позволяет настраивать длительность импульса при фиксированном периоде.

    Выберем PMW mode 1, вписав две единицы во второй и третий биты, т.е. «110»:

    TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1

    Подробнее про настройку подачи выходного сигнала на пин PB6

    В регистр CCER в поле CC1E нужно вписать «1», включив подачу выходного сигнала на пин.

    Вписываем следующую строчку:

    TIM4->CCER |= TIM_CCER_CC1E; //OC3 signal is output on the corresponding pin

    Подробнее про выбор управляющего сигнала и режима Slave

    Для управления TIM4 таймером TIM2 нужно выбрать входной сигнал ITR1. Для этого нужно вписать в поле TS регистра TIMx_SMCR «001». Также выберем режим для Slave, вписав «101» в поле SMS. В этом режиме пока входной сигнал ITR1 будет высоким, то TIM4 будет работать и выдавать меандр на пин, как только ITR1 станет низким, TIM4 выключается.

    Для этого вписываем:

    TIM4->SMCR |= TIM_SMCR_TS_0;    //choosing ITR1

    TIM4->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_2; //Gated Mode

    Добавим к уже существующему коду, и получим:

    void Timer_Init_Transmitter (void)
    {
       //Settings for GPIO PB6
       RCC->AHBENR |= RCC_AHBENR_GPIOBEN;             //GPIO port B clock enable
       GPIOB->MODER |= GPIO_MODER_MODER6_1;           //Alternative function mode enable
       GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6_1;	  //High speed
       GPIOB->AFR[0] |= 0x2000000;                    //Pin PB6 TIM4 alternative function AF2 enable
    
       //Settings for TIM4 - Slave
       RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;            //TIM4 clock enable
       TIM4->PSC = 0;                                 //Prescaler value
       TIM4->ARR = 75;                                //Auto-reload value
       TIM4->CCR1 = 37;                               //Capture/Compare 1 value
       TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1    enable
       TIM4->CCER |= TIM_CCER_CC1E;                   //OC3 signal is output on the corresponding output pin
       TIM4->SMCR |= TIM_SMCR_TS_0;                   //choosing ITR1
       TIM4->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_2; //Gated Mode
       TIM4->CR1 |= TIM_CR1_CEN;                      //TIM4 enable
    }
    

    Включение TIM4 можно производить, а можно и нет, так как управляющий сигнал с TIM2, всё равно включит его.

    Теперь перейдем к настройке TIM2.

    Необходимо подать тактирование на таймер, рассчитать PSC, CCR1 и ARR, выбрать режим работы таймера ШИМ, выбрать какой сигнал будет выходным (входным управляющим для TIM4) и включить таймер.

    Включение тактирования аналогично, как и для таймера TIM4.

    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;  //TIM2 clock enable

    Подробнее про расчет PSC, CCR1 и ARR для TIM2

    Так как по даташиту на диод в пачке следует использовать не менее 10 импульсов (на самом деле можно и меньше, но качество работы может быть не очень хорошим), то выберем тактирование таймера TIM2 в десять раз меньше, чем TIM4.

    Как видим в формуле для расчета частоты тактирования таймера в знаменателе уже есть «+1», т.е. нам нужно записать в регистр PSC «9», чтобы получить частоту в 10 раз меньшую, чем частоту МК.

    TIM2->PSC = 9;    //Prescaler value

    Теперь рассчитаем значение для CCR1: отправлять будем 10 импульсов, следовательно, нам нужно взять значение ARR для TIM4 (период одного импульса, это 75) и умножить на 10, т.е. получаем 750, однако, у нас есть прескейлер, который делит частоту на 10, т.е. нам нужно поделить 750 на 10, в итоге получаем снова 75 (как и в TIM4, но уже с другим прескейлером). Запишем это значение в регистр CCR1 таймера TIM2.

    TIM2->CCR1 = 75;  //Capture/Compare 1 value

    Перейдём к расчету ARR: тут всё просто, допустим, хотим «стрелять» пачками со скважностью 11.2, при этом период излучения пачек будет около 2 мс (из расчета, что 1 мс это 4194000/1000 = 4194 тика, и умножаем на 2, получаем округлённо 8400, а с прескейлером 10, получаем 840 тиков), умножаем длительность пачки 75 на 11.2 и получаем 840, как видите, значения совпадают. Запишем это в регистр ARR.

    TIM2->ARR = 840;   //Auto-reload value

    По даташиту скважность должна быть не менее 2, но при таких значениях стабильность работы будет хуже, и такая передача данных годится только для коротких посылок. Для длинных посылок и больших пачек скважность должна быть больше 4.

    Режим работы таймера TIM2 точно такой же, как и у TIM4 - ШИМ.

    TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1 enable

    Подробнее про выбор выходного сигнала TIM2 (управляющего для TIM4)

    Найдем регистр TIMx_CR2.

    Нам нужно подать сигнал с первого канала (мы же используем CCR1), на выход с таймера TIM2. Этим сигналом является OC1REF. Ниже на картинке можно найти комбинацию битов для этого сигнала – «100».

    В поле MMS необходимо вписать «1» в третий бит.

    TIM2->CR2 |= TIM_CR2_MMS_2;    //OC1REF signal is used as trigger output (TRGO)

    Теперь осталось включить TIM2, записав следующую строчку:

    TIM2->CR1 |= TIM_CR1_CEN;    //TIM2 enable

    В таком случае при включении МК, диод начнет излучать. Если вы хотите включать диод в определенное время, тогда вам в нашей функции необходимо убрать две строчки с включением таймеров, и просто в нужный момент включить TIM2.

    Добавим эти строчки к предыдущим и получим:

    void Timer_Init_Transmitter (void)
    {
       //Settings for GPIO PB6
       RCC->AHBENR |= RCC_AHBENR_GPIOBEN;             //GPIO port B clock enable
       GPIOB->MODER |= GPIO_MODER_MODER6_1;           //Alternative function mode enable
       GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6_1;	  //High speed
       GPIOB->AFR[0] |= 0x2000000;                    //Pin PB6 TIM4 alternative function AF2 enable
    
       //Settings for TIM4 - Slave
       RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;            //TIM4 clock enable
       TIM4->PSC = 0;                                 //Prescaler value
       TIM4->ARR = 75;                                //Auto-reload value
       TIM4->CCR1 = 37;                               //Capture/Compare 1 value
       TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1 enable
       TIM4->CCER |= TIM_CCER_CC1E;                   //OC3 signal is output on the corresponding output pin
       TIM4->SMCR &= ~TIM_SMCR_TS;                    //clear bits
       TIM4->SMCR |= TIM_SMCR_TS_0;                   //choosing ITR1
       TIM4->SMCR &= ~TIM_SMCR_SMS;                   //clear bits
       TIM4->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_2; //Gated Mode
       TIM4->CR1 |= TIM_CR1_CEN;                      //TIM4 enable
    
       //Settings for TIM2 - Master
       RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;            //TIM2 clock enable
       TIM2->PSC = 9;                                 //Prescaler value
       TIM2->ARR = 840;                               //Auto-reload value
       TIM2->CCR1 = 75;                               //Capture/Compare 1 value
       TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1 enable
       TIM2->CR2 |= TIM_CR2_MMS_2;                    //OC1REF signal is used as trigger output (TRGO)
       TIM2->CR1 |= TIM_CR1_CEN;                      //TIM2 enable
    }
    

    Теперь у нас ИК диод будет излучать пачки по 10 импульсов, у которых частота 56 кГц, со скважностью 11.2, т.е. с периодом следования пачек в 2 мс. Заметим, что момент пересечения каким-либо объектом внутри периода пачек не определен, т.е. мы можем судить о пересечении ИК луча только по отсутствию следующей пачки. Таким образом, погрешность измерения момента времени пересечения луча составляем 2 мс.

    Код приемника ИК сигнала

    Для приема ИК сигнала снова будем использовать таймеры, а точнее всего один. В микроконтроллерах STM32 таймеры могут быть не только Master или Slave, а могут быть Master/Slave, т.е. они могут управлять сами собой.

    В разделе статьи «Код передатчика ИК сигнала» мы уже выбрали пин PB7 для приемника ИК сигнала. Схему подключения см. выше. К этому пину подключается второй канал TIM4.

    Ниже на картинке представлена схема устройства таймера.

    Из схемы видно, что у каждого канала есть вход и выход, у таймера есть входной управляющий сигнал TRGI, также показаны тактирование и устройство Trigger controller.

    Принцип работы для нашего проекта заключается в следующем: пусть наш таймер будет просто считать время, допустим, равное 5 периодам излучаемых пачек ИК сигнала, следовательно, в ARR будет число, равное 5 периодам пачек, т.е. 840 * 5 = 4200. Настроим таймер так, чтобы при приеме каждой пачки таймер перезагружался и начинал считать заново. При достижении таймером числа в регистре ARR таймер выдает прерывание, которое означает, что на вход уже как 5 периодов не приходит пачка, следовательно, луч пересекается каким-то объектом. Вот и вся работа таймера. Осталось настроить TIM4.

    Создадим новый проект и функцию инициализации таймера:

    #iclude "main.h"
    
    void Timer_Init_Receiver(void);
    
    int main(void)
    {
       RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6;    // MSI 4.194 MHz enable
    
       Timer_Init_Receiver();
    
       while(1)
       {
    
       }
    }
    
    void Timer_Init_Receiver(void)
    {
    
    }
    

    Необходимо настроить пин PB7: включить тактирование порта B, настроить альтернативную функцию пина, настроить скорость и выбрать какую конкретную альтернативную функцию подключить к пину. Всё, как и в предыдущем случае.

    void Timer_Init_Receiver(void)
    {
    
    //Settings for GPIO PB7
    	RCC->AHBENR |= RCC_AHBENR_GPIOBEN;          // GPIO port B clock enable
    	GPIOB->MODER |= GPIO_MODER_MODER7_1;        // Alternative function mode enable
    	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1;	// High speed
    	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;        // pull-up PB7
    	GPIOB->AFR[0] |= 0x20000000;                // Pin PB7 TIM4 alternative function AF2 enable
    
    }
    

    Все настройки аналогичны, как и для передатчика, только альтернативная функция немного отличается, «2» нужно вписать уже на восьмое место справа. Еще необходимо подтянуть пин к плюсу прописав строчку:

    GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;

    Теперь настроим TIM4.

    Включим тактирование таймера. Так как у нас второй канал, то будем использовать CCR2. Прескейлер приравняем к 9, чтобы частота тактирования таймера была как у TIM2 передатчика. Для приемника можно приравнять CCR2 и ARR. Как уже рассчитали ранее, вписываем в эти регистры 4200.

    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;   // TIM4 clock enable

    TIM4->PSC = 9;   // Prescaler value

    TIM4->ARR = 4200;   // Auto-reload value

    TIM4->CCR2 = 4200;    // Capture/Compare 2 value

    Далее настроим режим работы таймера.

    Нам нужно, чтобы он просто считал, и всё. Для этого в даташите находим TIMx_CCMR1 и в поле OC2M вписываем «000», что соответствует Frozen mode. Изменим регистр, обнулив все биты:

    TIM4->CCMR1 &= ~TIM_CCMR1_OC2M;   // Frozen mode enable

    Настроим канал на выход, обнулив биты поля CC2S (более подробно написано в даташите), впишем нули в эти биты:

    TIM4->CCMR1 &= ~TIM_CCMR1_CC2S;   // Output mode

    Теперь обратимся к картинке со схемой устройства таймера (см. выше). Нам необходимо, чтобы входной сигнал с пина PB7 был управляющим для таймера TIM4, таким сигналом является TI2FP2. Проследите путь этого сигнала от TIMx_CH2 до TRGI. Чтобы выбрать данный сигнал в качестве управляющего, необходимо в регистр TIMx_SMCR в поле TS вписать «110». Сразу же выберем режим для Slave: Reset mode, вписав «100» в поле SMS. Для этого пропишем строчки:

    TIM4->SMCR |= TIM_SMCR_TS_1 | TIM_SMCR_TS_2;   // Choosing TI2FP2

    TIM4->SMCR |= TIM_SMCR_SMS_2;    // Reset mode

    Теперь нам нужно определиться, что будет являться триггером обновления таймера: передний или задний фронт входных импульсов (на самом деле не особо важно, но лучше выбрать по переднему фронту, в нашем случае, это фронт спада напряжения). Для этого нужно использовать пару битовых полей регистра CCER: CC2P и CC2NP, они работают в паре, более подробно написано о них в даташите.

    Для нашего случая вписываем «1» в CC2P и «0» в CC2NP. Делаем это так:

    TIM4->CCER &= ~TIM_CCER_CC2NP;  // This bit is used in conjunction with CC2P.

    TIM4->CCER |= TIM_CCER_CC2P;    // Inverted/falling edge

    Разрешим прерывание по переполнению. Для этого в регистре TIMx_DIER в поле CC2IE впишем «1».

    Для этого впишем строчку:

    TIM4->DIER |= TIM_DIER_CC2IE;  // Capture/Compare 2 interrupt enable

    Включаем таймер строчкой:

    TIM4->CR1 |= TIM_CR1_CEN;   // TIM4 enable

    Не забываем разрешить глобальное прерывание:

    NVIC_EnableIRQ(TIM4_IRQn);   // TIM4 global Interrupt enable

    Наша функция инициализации таймера выглядит следующим образом:

    void Timer_Init_Receiver(void)
    {
    
    //Settings for GPIO PB7
    	RCC->AHBENR |= RCC_AHBENR_GPIOBEN;           // GPIO port B clock enable
    	GPIOB->MODER |= GPIO_MODER_MODER7_1;         // Alternative function mode enable
    	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1;	 // High speed
    	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;         // pull-up PB7
    	GPIOB->AFR[0] |= 0x20000000;                 // Pin PB7 TIM4 alternative function AF2 enable
    
    
    	//Settings for TIM4
    	RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;          // TIM4 clock enable
    TIM4->PSC = 9;                                 // Prescaler value
    TIM4->ARR = 4200;                              // Auto-reload value
    TIM4->CCR2 = 4200;                             // Capture/Compare 2 value
    	
    	TIM4->CCMR1 &= ~TIM_CCMR1_OC2M;              // Frozen mode enable
    	TIM4->CCMR1 &= ~TIM_CCMR1_CC2S;              // Output mode
    	TIM4->CCER &= ~TIM_CCER_CC2NP;               // This bit is used in conjunction with CC2P.
    	TIM4->CCER |= TIM_CCER_CC2P;                 // Inverted/falling edge
    	TIM4->SMCR |= TIM_SMCR_TS_1 | TIM_SMCR_TS_2; // Choosing TI2FP2
    	TIM4->SMCR |= TIM_SMCR_SMS_2;                // Reset mode
    	TIM4->DIER |= TIM_DIER_CC2IE;                // Capture/Compare 2 interrupt enable
    	TIM4->CR1 |= TIM_CR1_CEN;                    // TIM4 enable
    	NVIC_EnableIRQ(TIM4_IRQn);                   // TIM4 global Interrupt enable
    }
    

    Теперь напишем обработчик прерываний:

    Первое что нужно сделать, это снять флаг в регистре статуса TIMx_SR:

    TIM4->SR &= ~TIM_SR_CC2IF;

    Далее можем делать, что хотим. Хоть ставить какой-нибудь флаг, хоть зажигать диод. Допустим будем зажигать светодиод. Настроим пин PB15 на выход, прописав в мэйне:

    GPIOB->MODER |= GPIO_MODER_MODER15_0;  // PB15 output mode

    Наш обработчик прерываний будет выглядеть следующим образом:

    void TIM4_IRQHandler(void)
    {
    	TIM4->SR &= ~TIM_SR_CC2IF;
    	GPIOB->ODR |= GPIO_ODR_ODR_15;  // Led red on
    }
    

    Готово! Теперь при пересечении ИК луча каким-либо объектом, на приемнике будет зажигаться светодиод.

    Полный код

    Код передатчика ИК сигнала
    void Timer_Init_Transmitter(void);
    
    
    int main(void)
    {
       RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6;             // MSI 4.194 MHz enable
    
       Timer_Init_Transmitter();
    
       while(1)
       {
    
       }
    }
    
    void Timer_Init_Transmitter(void)
    {
      //Settings for GPIO PB6
       RCC->AHBENR |= RCC_AHBENR_GPIOBEN;             //GPIO port B clock enable
       GPIOB->MODER |= GPIO_MODER_MODER6_1;           //Alternative function mode enable
       GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6_1;	  //High speed
       GPIOB->AFR[0] |= 0x2000000;                    //Pin PB6 TIM4 alternative function AF2 enable
    
       //Settings for TIM4 - Slave
       RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;            //TIM4 clock enable
       TIM4->PSC = 0;                                 //Prescaler value
       TIM4->ARR = 75;                                //Auto-reload value
       TIM4->CCR1 = 37;                               //Capture/Compare 1 value
       TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1 enable
       TIM4->CCER |= TIM_CCER_CC1E;                   //OC3 signal is output on the corresponding output pin
       TIM4->SMCR &= ~TIM_SMCR_TS;                    //clear bits
       TIM4->SMCR |= TIM_SMCR_TS_0;                   //choosing ITR1
       TIM4->SMCR &= ~TIM_SMCR_SMS;                   //clear bits
       TIM4->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_2; //Gated Mode
       TIM4->CR1 |= TIM_CR1_CEN;                      //TIM4 enable
    
       //Settings for TIM2 - Master
       RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;            //TIM2 clock enable
       TIM2->PSC = 9;                                 //Prescaler value
       TIM2->ARR = 840;                               //Auto-reload value
       TIM2->CCR1 = 75;                               //Capture/Compare 1 value
       TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; //Output compare PMW mode 1 enable
       TIM2->CR2 |= TIM_CR2_MMS_2;                    //OC1REF signal is used as trigger output (TRGO)
       TIM2->CR1 |= TIM_CR1_CEN;                      //TIM2 enable
    }
    

    Код приемника ИК сигнала
    #include “main.h”
    
    void Timer_Init_Receiver(void);
    
    int main(void)
    {
       RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6;         // MSI 4.194 MHz enable
    
      GPIOB->MODER |= GPIO_MODER_MODER15_0;        // PB15 output mode
    
       Timer_Init_Receiver();
    
       while(1)
       {
    
       }
    }
    
    void Timer_Init_Receiver(void)
    {
    //Settings for GPIO PB7
    	RCC->AHBENR |= RCC_AHBENR_GPIOBEN;           // GPIO port B clock enable
    	GPIOB->MODER |= GPIO_MODER_MODER7_1;         // Alternative function mode enable
    	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1;	 // High speed
    	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;         // pull-up PB7
    	GPIOB->AFR[0] |= 0x20000000;                 // Pin PB7 TIM4 alternative function AF2 enable
    
    
    	//Settings for TIM4
    	RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;          // TIM4 clock enable
    TIM4->PSC = 9;                                 // Prescaler value
    TIM4->ARR = 4200;                              // Auto-reload value
    TIM4->CCR2 = 4200;                             // Capture/Compare 2 value
    	
    	TIM4->CCMR1 &= ~TIM_CCMR1_OC2M;              // Frozen mode enable
    	TIM4->CCMR1 &= ~TIM_CCMR1_CC2S;              // Output mode
    	TIM4->CCER &= ~TIM_CCER_CC2NP;               // This bit is used in conjunction with CC2P.
    	TIM4->CCER |= TIM_CCER_CC2P;                 // Inverted/falling edge
    	TIM4->SMCR |= TIM_SMCR_TS_1 | TIM_SMCR_TS_2; // Choosing TI2FP2
    	TIM4->SMCR |= TIM_SMCR_SMS_2;                // Reset mode
    	TIM4->DIER |= TIM_DIER_CC2IE;                // Capture/Compare 2 interrupt enable
    	TIM4->CR1 |= TIM_CR1_CEN;                    // TIM4 enable
    	NVIC_EnableIRQ(TIM4_IRQn);                   // TIM4 global Interrupt enable
    
    }
    
    void TIM4_IRQHandler(void)
    {
    	TIM4->SR &= ~TIM_SR_CC2IF;
    	GPIOB->ODR |= GPIO_ODR_ODR_15;               // Led red on
    }
    
    

    Дополнительно

    Если хотите, чтобы диод на приемнике светился, когда ИК сигнал принимается, и не светился, когда на входе приемника нет сигнала, то нужно немного изменить код для приемника.

    Нужно добавить глобальную переменную, например, написав между "инклюдами" и мэйном такую строчку:

    int StatusDiode = 0;   // 0 - diode is off, 1 - diode is on

    Эта переменная необходима для запоминания статуса светодиода: выключен или включен.

    Далее в функции инициализации таймера нужно изменить строчку с разрешением прерывания по переполнению на разрешение прерывания по триггеру, такой строчкой:

    TIM4->DIER |= TIM_DIER_TIE;  // Trigger interrupt enable

    И последнее: изменим обработчик прерываний.

    Соответственно, если диод был выключен и у нас сработало прерывание по триггеру, то снимаем соответствующий флаг, включаем диод, выключаем разрешение прерывания по триггеру, включаем разрешение прерывания по переполнению, обнуляем счетчик (можно не делать этот пункт) и изменяем статус диода.

    Если диод был включен, делаем все наоборот: снимаем соответствующий флаг, выключаем диод, выключаем разрешение прерывания по переполнению, включаем разрешение прерывания по триггеру и изменяем статус диода.

    Стоит помнить, что счетчик не останавливается, если не выключить таймер, однако, при прерывании по переполнению он перезагружается (обновляется регистр CNT), а при прерывании по триггеру обновления не происходит, поэтому мы его и обнуляем.

    Получим такой обработчик прерываний:

    void TIM4_IRQHandler(void)
    {
    	if (StatusDiode == 0)
    	{
    	    TIM4->SR &= ~TIM_SR_TIF;
    	    GPIOB->ODR |= GPIO_ODR_ODR_15;         // Led red on
    	    TIM4->DIER &= ~TIM_DIER_TIE;           // Trigger interrupt disable
    	    TIM4->DIER |= TIM_DIER_CC2IE;          // Capture/Compare 2 interrupt enable
    	    TIM4->CNT = 0;
    	    StatusDiode = 1;
    	}
    	else
    	{
    	    TIM4->SR &= ~TIM_SR_CC2IF;
    	    GPIOB->ODR &= ~GPIO_ODR_ODR_15;        // Led red off
    	    TIM4->DIER &= ~TIM_DIER_CC2IE;         // Capture/Compare 2 interrupt disable
    	    TIM4->DIER |= TIM_DIER_TIE;            // Trigger interrupt enable
    	    StatusDiode = 0;
    	}
    }
    
    Полный код для приемника ИК сигнала
    #include “main.h”
    
    void Timer_Init_Receiver(void);
    
    int main(void)
    {
       RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6;      // MSI 4.194 MHz enable
    
      GPIOB->MODER |= GPIO_MODER_MODER15_0;     // PB15 output mode
    
       Timer_Init_Receiver();
    
       while(1)
       {
    
       }
    }
    
    void Timer_Init_Receiver(void)
    {
    //Settings for GPIO PB7
    	RCC->AHBENR |= RCC_AHBENR_GPIOBEN;           // GPIO port B clock enable
    	GPIOB->MODER |= GPIO_MODER_MODER7_1;         // Alternative function mode enable
    	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1;	 // High speed
    	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;         // pull-up PB7
    	GPIOB->AFR[0] |= 0x20000000;                 // Pin PB7 TIM4 alternative function AF2 enable
    
    
    	//Settings for TIM4
    	RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;          // TIM4 clock enable
    TIM4->PSC = 9;                                 // Prescaler value
    TIM4->ARR = 4200;                              // Auto-reload value
    TIM4->CCR2 = 4200;                             // Capture/Compare 2 value
    	
    	TIM4->CCMR1 &= ~TIM_CCMR1_OC2M;              // Frozen mode enable
    	TIM4->CCMR1 &= ~TIM_CCMR1_CC2S;              // Output mode
    	TIM4->CCER &= ~TIM_CCER_CC2NP;               // This bit is used in conjunction with CC2P.
    	TIM4->CCER |= TIM_CCER_CC2P;                 // Inverted/falling edge
    	TIM4->SMCR |= TIM_SMCR_TS_1 | TIM_SMCR_TS_2; // Choosing TI2FP2
    	TIM4->SMCR |= TIM_SMCR_SMS_2;                // Reset mode
    	TIM4->DIER |= TIM_DIER_TIE;                  // Trigger interrupt enable
    	TIM4->CR1 |= TIM_CR1_CEN;                    // TIM4 enable
    	NVIC_EnableIRQ(TIM4_IRQn);                   // TIM4 global Interrupt enable
    
    }
    
    void TIM4_IRQHandler(void)
    {
    	if (StatusDiode == 0)
    	{
    	    TIM4->SR &= ~TIM_SR_TIF;
    	    GPIOB->ODR |= GPIO_ODR_ODR_15;           // Led red on
    	    TIM4->DIER &= ~TIM_DIER_TIE;             // Trigger interrupt disable
    	    TIM4->DIER |= TIM_DIER_CC2IE;            // Capture/Compare 2 interrupt enable
    	    TIM4->CNT = 0;
    	    StatusDiode = 1;
    	}
    	else
    	{
    	    TIM4->SR &= ~TIM_SR_CC2IF;
    	    GPIOB->ODR &= ~GPIO_ODR_ODR_15;          // Led red off
    	    TIM4->DIER &= ~TIM_DIER_CC2IE;           // Capture/Compare 2 interrupt disable
    	    TIM4->DIER |= TIM_DIER_TIE;              // Trigger interrupt enable
    	    StatusDiode = 0;
    	}
    }
    

    Заключение

    Таким образом, разработали датчик движения, основанный на работе пересечения каким-либо объектом ИК луча. Система состоит из двух устройств, имеет минимум элементов, проста в реализации, имеет низкую стоимость и высокое быстродействие. При этом ядро МК свободно и может использоваться для других нужд.

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 58

      +3
      Очень странно подключено питание TSOP. Обычно конденсатор подключают к выводам питания микросхемы (TSOP), а потом уже резистор ставят (если нужен). Тогда получается RC-фильтр.
      В даташите на TSOP именно так и нарисовано.
        0
        О! Благодарю, исправил.
        +5

        Спасибо, что без HAL. Приятно код смотреть.

          0

          И вам Спасибо, что оценили труд.

          +2

          Без относительно к программной реализации. Просто замечание исходя из собственного практического опыта. Делал ИК линию на пересечение для видео фиксации подрооостков на даче, повадившейся пьянки на участке устраивать.


          Для заявленных целей "линия на пересечение" такая штука не очень подходит с использованием обычного ИК диода и TSOP4856. Ну естественно, не для "настольных" демонстраций, а для более менее больших дистанций и реального применения.


          Приемник TSOP4856 чувствительный и выход у него дискретный.
          Даже если сделать "трубки" (попытаться сделать луч) то не сильно помогает.
          Прекрасно ловит на переотраженный сигнал и нужно уже совсем "широко" закрыть/пересечь линию.
          ИК диод (что такой, что мощный на радиаторе) — это не лазер..


          А вот если заменить диод на ИК лазер… У ИК лазеров, как правило, есть вход на модулирующий сигнал.


          С ИК лазером у меня получилась линия на 30 метров в легкую. Можно наверное и больше, но размер дачного участка не позволял и пятно даже ночью уже сложнее наводить на приемник.
          (пятно света от лазера с камерой без ИК фильтра отлично видно)

            +1

            Интересное у вас решение, особенно интересно для чего оно применяется. Конкретно для моего применения достаточно 5-10 метров, а замеры показали, что данная реализация достигает 14 метров при полученном токе.
            Кстати, да, у лазеров труднее с наводкой, у диода луч расширяется, ДН 34 градуса. Все это я к чему, все зависит от конкретной цели. Конечно же, Спасибо вам за то, что делитесь своим опытом.

              +1

              Лазер я купил для проверки "Анти-Стокс эффекта" (https://habr.com/ru/post/401483/) но потом, ради интереса, поэкспериментировал и с сигнализацией на основе "линии". В общем то ничего сложного в сопряжении стандартного ИК приемника и модуляции сигнала для него нет. Дел на один вечер.


              Подростки постоянно лазили на участок и это было стимулом экспериментировать с "https://habr.com/ru/post/248327/". Но после того как детки случайно баню сожгли на даче, перестали лазить. Наверное испугались. Да и что им предъявить то. Объектив с переменной кратностью не успел сделать и четко опознать на кадрах кого то сложно особенно в темноте.

              +1

              На Али можно найти световозвращающую пленку, мы такую на соревнованиях по даунхиллу на финишном створе использовали, чтобы провода не тянуть. Лазер модулируется "из коробки", на приемнике стоит фильтр, нужно просто реагировать на триггерный выход.

              0

              "Так в моем случае используется резистор 1 Ом, амплитуда тока цепи составляет 20 мА..."
              Где-то ошибка. Падение напряжения на ИК-светодиоде, по памяти, — 1,1-1,3 В, падение на резисторе — 0,02 В. Значит ключ — в активном режиме.

                0

                Да, скорее всего вы правы, транзистор не в насыщении.
                В общем, в статье я обратил на это косвенно внимание, но больше это было про пороговое напряжение. Благодарю за заметку, кому-то она сильно поможет.

                  0
                  А вы поставьте обычный биполярный n-p-n транзистор в схеме с эмиттерным повторителем.
                    0

                    С общим эмиттером?


                    P.S. Хотя… всё равно напряжению надо где-то упасть, если светодиод управляется не током...


                    P.P.S. Vgs(th) для 2N7002 производства Diodes — 1,0-2,5 В при токе стока 0,25 мА.

                      0
                      Нет. :)
                      image
                    +1

                    У данного транзистора порог насыщения 1.0-2.5в при токе стока 25.мА Собственно вот и получается что в некотором роде ваша схема является неким источником тока, а не ключевой. Возьмите транзистор irlml2803 на нем ток будет около 150ма при 3В на затворе.

                    0
                    Значит ключ — в активном режиме.
                    У 2N7002 сопротивление канала 2.8-5 Ом и то при 10V на управлении. Нужно другой транзистор
                    +2
                    Так в моем случае используется резистор 1 Ом, амплитуда тока цепи составляет 20 мА
                    Светодиод TSAL6200, падение напряжения 1.35V, при 1 Ом получаем ток через светодиод (3.3 — 1.35) / 1 = почти 2A. О какой амплитуде идет речь? Там точно 1 Ом? Ничего, что у светодиода максимальный пиковый ток по даташиту 1.5А?
                    Кстати, там и у 2N7002 сопротивление в открытом состоянии будет существенно выше 1 Ом, а пиковый ток при Vgs = 3.3V будет, опять же по даташиту, в районе максимум 0.1А
                      0
                      Величина максимального тока диода зависит от длительностей импульсов: при коротком импульсе и большой скважности 1.5 А, при длительных импульсах и маленькой скважности 100 мА, это по даташиту.
                      А так вы сами же и ответили на свой вопрос во втором абзаце. Сопротивление транзистора немаленькое при 3.3 В на затворе, поэтому и ток небольшой. Сразу скажу, что у меня устройства мобильные, на батарейках работают, мне ток большой не нужен, и дальности в 14 м мне хватает. По даташиту можно выжать дальность, по-моему, до 40 м.
                        0
                        Сразу скажу, что у меня устройства мобильные, на батарейках работают, мне ток большой не нужен, и дальности в 14 м мне хватает. По даташиту можно выжать дальность, по-моему, до 40 м.


                        А можно скомбинировать вот с таким.

                        В дневное время дальность ИК линии связи достигает нескольких сотен метров. Ее ограничивает посторонняя засветка (прежде всего светлый фон за корреспондентом), увеличивающая уровень шума на приеме. В вечернее и ночное время она возрастает до 1,5 км.
                          0
                          Пожалуйста, прочитайте даташит на TSOP4856, там указана дальность.
                            +1
                            Так я же не про TSOP4856, а про резкое увеличение дальности, путём использования другой обвязки (декодер вам потребуется собственный, конечно).
                              0
                              Понятно, интересно.
                                0
                                Неужто советский ик-светодиод в режиме приёма будет лучше, чем специализированный ик-приёмник? Отчего-то вспоминается Станиславский.
                                  0
                                  А вы соберите и проверьте. ;)
                                    0
                                    Ну скажем так, я верю, что автор получал 1,5 км, но что-то мне подсказывает, что это в основном за счёт линз и прочих труб. Не думаю, что от применения более современных и специализированных излучателей/приёмников ситуация ухудшится.
                                      0
                                      Ясен пень, свето- и фотодиод ставятся в фокус линзы. ;)

                                      Не думаю, что от применения более современных и специализированных излучателей/приёмников ситуация ухудшится.


                                      Учитывая, что эти специализированные приёмники делались для конкретного применения (например, ИК-пульт телевизора, где 1.5 км вряд ли надо), ситуация легко может кардинально ухудшиться от их применения.
                            0
                            Вы отличаете амплитуду от среднего за период значения? И раз все учли в транзисторе, зачем тогда вообще резистор ставили, какой в нем стратегический замысел? И вообще очень сомневаюсь, что в даташите на фотодиод вы найдете хоть что-то про дальность, этот параметр зависит от кучи факторов, которые производителю фотодиода вообще неинтересны.
                              0
                              Я про амплитуду и говорю.
                              Резистор нужен для уменьшения тока в цепи и для повышения безопасности.
                              Тут используется не фотодиод, а приемник. Внутри этого приемника есть фотодиод, но так же есть и другие компоненты. В даташите на приемник указана дальность «Transmission distance».
                          +6
                          Точный расчет величины сопротивления резистора является трудным, конечно, существуют специальные формулы, но я предлагаю подобрать резистор опытным путем.


                            +2

                            Можете смело оперировать максимальным импульсным током светодиода не боясь его сжечь, это улучшит дальность прибора. Не забудьте поставить около светодиода батарею из керамических конденсаторов для уменьшения пульсаций по питанию. Так же бы я посоветовал поменять приемник на связку ОУ и компаратора в качестве детекторов импульсов, такой подход позволит использовать код Манчестера для кодирования. Для защиты от подделки сигнала с помощью записи и воспроизведения сигнала передатчика, попробуйте передавать закодированный сигнал алгоритмом cbc mac и случайным вектором инициализации.

                              0
                              У меня раньше была идея не просто модулировать луч пачками импульсов, а передавать какие-нибудь случайные данные. Типа, генерируем случайное значение, посылаем его, принимаем его, сравниваем с отправленным. Если совпало, сбрасываем счетчик ошибок, сбрасываем тревогу и начинаем сначала. Если не совпало, то инкрементируем счетчик ошибок и проверяем на максимально допустимое число ошибок. Если привысили порог, то выдаём тревогу и начинаем сначала. Если еще не превысили, то начинаем сначала.
                              Такой метод должен защитить фотоприемник от злонамеренного засвета другим диодом. Даже если он будет подключен к такому же генератору импульсов. Идея так и не дошла еще до реализации.
                                0

                                Я думаю, что это можно сделать.
                                Ещё в такой ситуации нужно учитывать мощность помехи, потому что при засветке приёмник уменьшает коэффициент усиления АРУ, и полезный сигнал может просто потеряться.

                                0

                                Зачем городить огород, есть готовые инфракрасные бареры,, к примеру,,, ИК-барьер Lightwell LBW-30-4

                                  +3

                                  Странный вопрос. Кто-то, знаете ли, городил огород с разработкой этих самых "готовых барьеров". Всё, ВООБЩЕ ВСЁ, кому-то приходится делать и этому нужно учиться.
                                  Ну и да, кому-то просто по фану заниматься изготовлением своих велосипедов. Это называется "хобби".

                                  0
                                  Очень странные впечатления от статьи, если честно…

                                  Во-первых, у stm32 есть USART IrDA SIR — то есть никаких таймеров не надо, все придумано и сделано до нас. И код, при использовании HAL, умещается в одну-единственную строку (для отправки данных). Ну можно с использованием DMA и циклического буфера организовать передачу любого сигнала, конечно.

                                  Во-вторых, выше уже писали про очень странную схему управления передатчиком. Обычно ставят mosfet типа irlmlXXXX и всё — ну если нужно ограничить ток потребляемый то да, можно ставить резистор, но уж не 1 Ом, конечно… при питании от 3.3 В и требуемом токе в 1А (а падение на светодиоде обычно 1-1.2В) нужно 2 Ома — но вот только даже наличие накопительного конденсатора на 200-1000 мкФ не спасет, если в качестве источника высокоомная батарейка… Но если поставить литий-ионный элемент — то да, вполне удастся сжечь светодиод :)
                                    –1

                                    Я не использую HAL. А так вариант интересный.

                                      +1
                                      А какова аргументация? Т.е. вы используете явно избыточный для данной задаче камень, но по каким-то причинам не используете простое в использовании готовое программное решение.
                                        –1
                                        Ну если так подходить, то тогда вообще достаточно мультивибратора и селективно-электронного реле. Никаких микроконтроллеров. :)
                                          +3
                                          Это и есть рациональный подход ) На глаза мои наворачиваются слезы, когда я вижу ардуинопроекты, программно эмулирующие RS-триггер. Нет, греха в таких проектах нет, но стоит ли выкладывать в сеть очередной хеллоуворд под соусом готового проекта, стоящего внимания почтенной публики?
                                            +1
                                            Ну так деталей будет несколько больше (и по цене будет больше, наверное). Да и совсем другой уровень «Hardware разработчика» потребуется. Вот и имеем мощный микроконтроллер на ерундовой задаче. Зато более-менее доступно для повторения совсем уж школьниками.
                                              0

                                              Два транзистора, vs МК. Четыре резюка вместо одного, два конденсатора. Именно школьники такое в радиокружках и собирают. По цене — точно ниже, не нужны стартовые расходы на программатор, паяется старым советским сороковаттным паяльником, выдерживает ядерный взрыв. Полученные при изготовлении навыки помогут эмбеддеру гораздо больше, чем настройка двух таймеров.

                                                0
                                                Так это только мультивибратор (и то его придётся посчитать для заданной частоты). Плюс ещё приёмную часть надо делать. Потом настраивать СЭР.
                                                Ну, а программатор можно взять у кого-нибудь.

                                                Полученные при изготовлении навыки помогут эмбеддеру гораздо больше, чем настройка двух таймеров.


                                                Навыки-то помогут, да только ситуация тут такая же, как с велосипедостроением. Велосипед тоже навыки развивает хорошо, да только не приветствуют его отчего-то. Данную задачу легко решает обычный микроконтроллер — это современно, в тренде, и доступно почти любому. Поэтому схема на нём. А собирать аналоговую игрушку не востребовано и вообще «прошлый век», коль есть специализированные микросхемы, решающие требуемые задачи (и пофиг, что разработчик не понимает, как эта задача решается на дискретке — на контроллере со специализированной обвязкой же он её решил). Примерно также пользуются всякими tensorflow, не особо понимая математику внутри.
                                                  +3

                                                  Так и появляются токоограничительные резисторы в 1 Ом.

                                                    0
                                                    Бинго! :-D
                                                      –1

                                                      Ну у кого-то они ток ограничивают, у кого-то просто ток понижают.

                                          0
                                          Может, ТС просто не хочет быть тупым абдуринщиком?
                                      +1
                                      Статья и правда неоднозначная. С одной стороны — автор молодец, что не убоялся регистров, но с другой стороны — очень странная схемотехника. По изложению есть вопросы. Описана работа таймеров но нет внятного объяснения, что же такое RCC_ICSCR и почему он настраивается именно так. Нет никакой политики энергосбережения — молотим вечный while, даже без __WFE(). А зачем тогда ставить камень из линейки UltraLowPower?
                                        –1

                                        Цель статьи была в том, чтобы показать способ создания «датчика движения» на STM32 с использованием простейшей схемотехникой из даташитов. В статье не даётся упор на идеальность и исключительность конкретно этого решения (почти в каждом абзаце написаны такие предложения: «у вас могут быть свои частоты МК», «можно поставить другой транзистор с лучшими параметрами, чтобы увеличить дальность», «можно увеличить напряжение питания» и тд
                                        Во-первых, главное было показать читателю способ формирования пачек импульсов определённой частоты на STM32, а также показать: как их принимать. Соответственно, люди будут брать код для своих проектов, со своими частотами и тд, в таком случае рассказывать про настройку тактирования самого МК — излишнее для этой статьи.
                                        Во-вторых, всегда нужно учитывать конкретную цель проекта или решения. Вот люди пишут «надо поставить другой транзистор, чтоб ток на максималку был и тд», да я и не спорю, что это хороший вариант, но вариант для чего? Конкретно мне надо было 5 м дальности, мое устройство работает от батареек, мне, вообще, большой ток не нужен, поэтому и транзистор выбран подешевле и попроще, более того, его характеристик хватило с запасом. Кому-то и метра будет достаточно. Кому-то придётся поменять намного схемотехнику, что бы добиться большей дальности.
                                        По поводу «использования слишком навороченных элементов для решения простейших задач»: соглашусь с комментариями выше, что уже в большинстве случаев проще использовать микроконтроллер. Да и врятли у вас будут просто платы с ИК диодом и ИК приемником, у кого-то ещё будут антенны с трансиверами для передачи данных в сеть или на другие устройства, у кого-то проводные интерфейсы, у кого-то платы будут решать ещё множество других задач. Поэтому вышеприведенное замечание про необоснованность использования МК в таких задачах теряет всякий смысл.
                                        Извините, что в одном комментарии ответил сразу на несколько.

                                          0
                                          с использованием простейшей схемотехникой из даташитов
                                          Точный расчет величины сопротивления резистора является трудным
                                          Вы понимаете, что это днище днищенское? Особенно после статьи про симуляцию антенны в HFSS такое вот писать. Да хоть калькулятор какой бесплатный скачайте, если не можете законами Кирхгофа на бумажке воспользоваться.

                                          Конкретно мне надо было 5 м дальности, мое устройство работает от батареек, мне, вообще, большой ток не нужен
                                          дальность связи при таком токе достигает 14 м в зависимости от конфигурации передаваемого сообщения
                                          Это тоже днище. Нельзя разрабатывать систему в которой дальность связи, т.е. параметры канального (физического) уровня зависят от протокола (а не наоборот). Поэтому вам и указали, что стоило выбрать нормальный транзистор, который будет пропускать через себя всё, а ток диода стабилизировать нормальным резистором, а не одноомником. Вы не задумывались над тем, что параметры транзистора в активной области могут плавать в зависимости от конкретного экземпляра? И где вы их достанете? Для резисторов хотя бы ТКС есть и всегда можно посчитать худший-лучший случай и подобрать что-то подходящее.

                                          Материал рассчитан на начальный уровень подготовки
                                          Нельзя такое неофитам показывать. Они потом будут бездумно повторять, а когда перестанет нормально работать, никто не будет в курсе, почему так.
                                            –2
                                            Спасибо за ваше мнение.
                                        –2
                                        «Отличный тост… прекрасный тост»… А на Atmege128 + «обычный» GCC нельзя это сделать?
                                        Даже за «живое» взяло)) Можно даже JacOS применить.
                                          +2
                                          А зачем? Оно будет:
                                          * проще
                                          * лучше
                                          * дешевле
                                          * быстрее?
                                          Не думаю.
                                          +1
                                          Точный расчет величины сопротивления резистора является трудным, конечно, существуют специальные формулы, но я предлагаю подобрать резистор опытным путем.

                                          O tempora, o mores! За такое в семидесятые в восьмом классе в далеко не самой лучшей школе Нижнего Зажопинска на краю империи мне бы влепили двойку на уроке физики и, возможно, вызвали родителей. Теперь это уровень инженера-разработчика электронных устройств на микроконтроллерах. Ну питание 3.3 вольта, при максимальном токе 0.1A на диоде примерно 1.5 вольта (уточняется в даташите), значит на резисторе примерно 1.8 вольта (на открытом транзисторе — практически 0). Спрашивается, какое сопротивление резистора, если при токе 0.1A падение напряжения на нем 1.5V? Ага, суперспециальная формула для особо одаренных — закон Ома.

                                          Дальше статью не читаю, хотя тема интересная. Можно было бы обсудить, что, возможно, не нужны два типа устройств — приемники и передатчики, а лучше приемник и передатчик в одном устройстве, — с одного столба принимает сигнал, на другой светит.

                                          TSAL6200 на фиг не нужна, так как стоит как микроконтроллер и очень ограничена в возможностях. Взять фотодиод и светодиод с углом градусов 6 (стоят копейки) и, возможно, даже не нужен будет аналоговый усилитель контроллера. А, если задействовать усилитель, то токи на светодиод будут вменяемые, что для батарейного питания принципиально.

                                          Вначале устройства светят на больших токах, а затем, раз у нас кольцевая сеть — договариваются об оптимальных токах светодиодов / усилениях ОУ, и, возможно, частоте модуляции. И т.д. и т.п.

                                          Епта, может эмбедеру лучше начинать не с кодирования суперустройств на рвзных языках, а тупо с закона Ома?
                                            0
                                            TSAL6200 на фиг не нужна, так как стоит как микроконтроллер и очень ограничена в возможностях.

                                            Зарапортовался… это TSOP'ку можно заменить. А TSAL6200 — как раз банальный светодиод.

                                              +1
                                              А TSAL6200 — как раз банальный светодиод.

                                              Ага, отвлекся, скопировал не то и не заметил. Спасибо.

                                              ***

                                              Чтобы два раза не вставать, карма ограничивает.
                                              Всё бы так, как вы написали, да только вы не учли, что транзистор не полностью открыт, а частично…
                                              То есть какой ток идет через него и через светодиод вы не знаете, — сгорят же они, если поставите полностью заряженные Li аккумуляторы. А если сильнотоковые поставите, то могут и взорваться и компоненты и сами аккумуляторы.

                                              Защитные очки хоть одевайте, без шуток. И держитесь подальше от того, что может легко загореться. Ведро с песком иметь под рукой не помешает.

                                              0
                                              Всё бы так, как вы написали, да только вы не учли, что транзистор не полностью открыт, а частично… Имеет смысл дальше что-то с вами обсуждать? Или вам было важнее принизить значимость автора и статьи?
                                                0
                                                Жаль не могу плюсовать. В рид-онли уже лет 10. Всё никак не соберусь накропать полезность. Но такие статьи… из разряда «из пушки по воробьям» )) Ну либо показать народу, как автор умеет этой «пушкой» управлять((

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                              Самое читаемое