Авторизация
Регистрация

Напомнить пароль

LOST MARY BM1600. Бесплатная отладочная плата PUYA PY32F002B

Теперь и с адресными RGB-светодиодами!
Подробности под катом.
Добро пожаловать!

Изначально это был заряжаемый вейп на 16 тысяч затяжек.
Дешевизна 32-битных МК на ядре Cortex-M0 от PUYA позволяет напихивать в функционал разное. На этот раз многосегментного индикатора сюда не положили. Зато положили светодиодную ленту.
Она переключает 6 цветовых оттенков после каждой затяжки и сигнализирует красным о низком уровне жидкости.
Вскрывается корпус довольно просто. Поворачиваем его набок, ставим лезвие ножа в щель между дном и крышкой, нажимаем и покачиваем, пока дно не выйдет примерно на миллиметр.
Потом переворачиваем на другую сторону и повторяем процедуру.
После этого начинку можно вытянуть наружу:
Аккумуляторная ячейка щедро облеплена абсорбентом на случай протечки жидкости:
Она имеет типоразмер 16350 и заявленную емкость 650 мАч. Плата под ней лишена дополнительной защиты — нет ни накладной пластины, ни герметика:
В корпусе её держат два маааленьких таких саморезика.
Линейка светодиодов при зарядке светится белым:
А вот, собственно, и индикация опустошеннности:
На нижней стороне платы размещены зарядный разъём USB-C, переключатель режимов накурки и часть элементов схемы:
Сверху — светодиодная лента и МК:
Нижняя сторона крупным планом:
За зарядку аккумуляторной ячейки отвечает микросхема LP4068:
Ключ Q3 управляет питанием светодиодной ленты.
Верхняя сторона крупным планом:
Светодиоды тут применены WS2812-совместимые. Их тут 9, но нумерация почему-то начинается со второго.
Микроконтроллер PY32F002BF крупным планом:
МК довольно фаршированный — 24K Flash/3KRAM, тактовая частота до 48 MHz, 128 байт однократно программируемой памяти, 3 16-битных таймера, 12-битный АЦП (8+2ch,0,75 Msps); и наконец-то USART, SPI и I2C. Всё это счастье стоит 11 центов в оптовой партии — в полтора раза дороже, чем предыдущий подопытный экземпляр:)
Его распиновка:
Вывод 5(SWD) выведен на контактную площадку PD, вывод 15(SWCLK) — на контактную площадку PC. Вывод 1(NRST) на плате не разведен, поэтому его придётся выносить отдельно тонкой эмалированной проволочкой примерно вот так:
Ну или просто тыкаться в него иголкой с припаянным проводом при прошивке. Символичненько так, да:)
Программирование успешно выполняется слегка доработанным дешевым и доступным программатором ST-Link V2, перешитым в J-Link.
Вот тут можно найти некоторые шаблоны для программирования для этих МК, дополнительная информация здесь.
Изначально на плате вход светодиодной ленты подключен к 7 выводу МК (PB5). Это позволяет управлять ею при помощи ШИМа на таймере. Для упрощения управления её можно перевесить на SPI. Для этого нужно перерезать дорожку от вывода 7 и подключить ленту к выводу 20 МК(PA7), он соединен с резистором R15.
Пример исходного кода для работы с адресной светодиодной лентой:
Дополнительная информация
#include "main.h"
#include "py32f002b_hal.h"

#include "ws2812_spi.h"
#include <py32f002bx5.h>


/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
SPI_HandleTypeDef Spi1Handle;


// Structures for ADC settings
ADC_HandleTypeDef             AdcHandle;
ADC_HandleTypeDef             AdcHandle_t;
ADC_ChannelConfTypeDef        sConfig;
ADC_ChannelConfTypeDef        sConfig_t;
// Variable for storing ADC
volatile uint16_t             aADCxConvertedData;
// Arrays for ADC
uint32_t adc_value[6]; // Battary voltage
uint32_t adc_temp[6];  // temoperature
float T_VCC; // This for conversions formlas from DS, in this case im no use it
float Temperature;


static void APP_AdcConfig(void);   // Config for battary measurements
static void APP_AdcConfig_t(void); // Config for temperature measurements
static void policeLights(void);    // Red-blue simple effect
static void showPower(void);       // To display battary voltage by leds
static void showTemp(void);        // To display temperature by leds 
static void APP_GpioConfig(void);  // GPIO for power up leds

/**
  * @brief  Application Entry Function.
  * @retval int
  */
int main(void)
{
  

  float factor1, factor2; // For rainbow effect
  uint16_t ind;           // For rainbow effect, how many rainbows on line
  int i;                  // This switch rainbow step
  HAL_Init();
    __HAL_RCC_GPIOA_CLK_ENABLE();
  
 uint8_t delay=0;
  APP_GpioConfig();
  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,0); // turn on leds - 0, off - 1
    // Set leds off, you must set up all array of data for leds
    ws2812_pixel(0, 0, 0, 0);
    ws2812_pixel(1, 0, 0, 0);
    ws2812_pixel(2, 0, 0, 0);
    ws2812_pixel(3, 0, 0, 0);
    ws2812_pixel(4, 0, 0, 0);
    ws2812_pixel(5, 0, 0, 0);
    ws2812_pixel(6, 0, 0, 0);
    ws2812_pixel(7, 0, 0, 0);
 
  while (1)
  {
    // Use adc channel for battary measurements
    APP_AdcConfig();
    HAL_ADC_Start(&AdcHandle);
    HAL_ADC_PollForConversion(&AdcHandle,1000000);
    adc_value[0]=HAL_ADC_GetValue(&AdcHandle);
    T_VCC=adc_value[0];
    // Use adc channel for temperature measurements
    APP_AdcConfig_t();
    HAL_ADC_Start(&AdcHandle_t);
    HAL_ADC_PollForConversion(&AdcHandle_t,1000000);
    adc_temp[0]=HAL_ADC_GetValue(&AdcHandle_t);
    Temperature=adc_temp[0];
    // If battary > 2.9 V and temperature < 27 deg C
    if ((T_VCC<1600) & (Temperature<950))
    {
      for (size_t k = 0; k < 1800; k++) // Raibow cycle
        {
        // This speed up rainbow
        if (k<100) {delay=14;}
        if ((k<400)&(k>100)) {delay=10;}
        if ((k<1200)&(k>400)) {delay=9;}
        if ((k<2000)&(k>1200)) {delay=5;}
        // Raindow effect begin. Thanks https://adrianotiger.github.io/Neopixel-Effect-Generator/
        i++;
      for(uint16_t j=0;j<WS2812_NUM_LEDS;j++) {
        ind = i+j * 1;
        switch((int)((ind % WS2812_NUM_LEDS) / 3)) {
          case 0: factor1 = 1.0 - ((float)(ind % WS2812_NUM_LEDS - 0 * 3) / 3);
                  factor2 = (float)((int)(ind - 0) % WS2812_NUM_LEDS) / 3;
                  ws2812_pixel(j, 128 * factor1 + 0 * factor2, 0 * factor1 + 128 * factor2, 0 * factor1 + 0 * factor2);
                  ws2812_send_spi();
                  HAL_Delay(delay);
                  break;
          case 1: factor1 = 1.0 - ((float)(ind % WS2812_NUM_LEDS - 1 * 3) / 3);
                  factor2 = (float)((int)(ind - 3) % WS2812_NUM_LEDS) / 3;
                  ws2812_pixel(j, 0 * factor1 + 0 * factor2, 128 * factor1 + 0 * factor2, 0 * factor1 + 128 * factor2);
                  ws2812_send_spi();
                  HAL_Delay(delay);
                  break;
          case 2: factor1 = 1.0 - ((float)(ind % WS2812_NUM_LEDS - 2 * 3) / 3);
                  factor2 = (float)((int)(ind - 9) % WS2812_NUM_LEDS) / 3;
                  ws2812_pixel(j, 0 * factor1 + 128 * factor2, 0 * factor1 + 0 * factor2, 128 * factor1 + 0 * factor2);
                  ws2812_send_spi();
                  HAL_Delay(delay);
                  break;
        }
      }
      // RAinbow effect end. Consume 47 mA approx
    }     
    policeLights();
    ws2812_pixel(0, 0, 0, 0);
    ws2812_pixel(1, 0, 0, 0);
    ws2812_pixel(2, 0, 0, 0);
    ws2812_pixel(3, 0, 0, 0);
    ws2812_pixel(4, 0, 0, 0);
    ws2812_pixel(5, 0, 0, 0);
    ws2812_pixel(6, 0, 0, 0);
    ws2812_pixel(7, 0, 0, 0);
    ws2812_pixel(8, 0, 0, 0);
    ws2812_send_spi();
    // 30 sec wait
    HAL_Delay(30000);
   
    }
    
    
    APP_AdcConfig();
    showPower();

    APP_AdcConfig_t(); 
    showTemp();

  }
}


/**
  * @brief  GPIO configuration.
  * @param  None
  * @retval None
  */
static void APP_GpioConfig(void)
{
   GPIO_InitTypeDef GPIO_InitStruct;

  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_SPI1_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
   
    /* PA7 -> AF0 -> MOSI */
    GPIO_InitStruct.Pin       = GPIO_PIN_7;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Вывод для управления транзистором Q3*/
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode =  GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


  Spi1Handle.Instance               = SPI1;
  Spi1Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  Spi1Handle.Init.Direction         = SPI_DIRECTION_1LINE;
  Spi1Handle.Init.CLKPolarity       = SPI_POLARITY_LOW;
  Spi1Handle.Init.CLKPhase          = SPI_PHASE_1EDGE;
  Spi1Handle.Init.DataSize          = SPI_DATASIZE_8BIT;
  Spi1Handle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
  Spi1Handle.Init.NSS               = SPI_NSS_SOFT;
  Spi1Handle.Init.Mode              = SPI_MODE_MASTER;

  HAL_SPI_Init(&Spi1Handle);

  if (HAL_SPI_DeInit(&Spi1Handle) != HAL_OK)
  {
    APP_ErrorHandler();
  }
  if (HAL_SPI_Init(&Spi1Handle) != HAL_OK)
  {
    APP_ErrorHandler();
  }               
}

// >>>> ADC begin
static void APP_AdcConfig(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
  __HAL_RCC_ADC_FORCE_RESET();
  __HAL_RCC_ADC_RELEASE_RESET();                                                  /* Reset ADC */
  __HAL_RCC_ADC_CLK_ENABLE();                                                     /* Enable ADC clock */

  AdcHandle.Instance = ADC1;
  if (HAL_ADCEx_Calibration_Start(&AdcHandle) != HAL_OK)                         
  {
    APP_ErrorHandler();
  }
  AdcHandle.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV2;                /* ADC clock no division */
  AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;                      /* 12bit */
  AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;                     /* Right alignment */
  AdcHandle.Init.ScanConvMode          = ADC_SCAN_DIRECTION_FORWARD;             /* Backward */
  AdcHandle.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;                     /* End flag */
  AdcHandle.Init.LowPowerAutoWait      = ENABLE;
  AdcHandle.Init.ContinuousConvMode    = DISABLE;
  AdcHandle.Init.DiscontinuousConvMode = DISABLE;
  AdcHandle.Init.ExternalTrigConv      = ADC_SOFTWARE_START;            /* External trigger: TIM1_TRGO */
  AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;  /* Triggered by both edges */
  
  //AdcHandle.Init.DMAContinuousRequests = DISABLE;                                 /* No DMA */
  AdcHandle.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;
  AdcHandle.Init.SamplingTimeCommon    = ADC_SAMPLETIME_41CYCLES_5;
  if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  {
    APP_ErrorHandler();
  }

  sConfig.Rank         = ADC_RANK_CHANNEL_NUMBER;
  sConfig.Channel      = ADC_CHANNEL_VREFINT;
  




  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)                      
  {
    APP_ErrorHandler();
  }
  /* Start ADC with Interrupt 
  if (HAL_ADC_Start_IT(&AdcHandle) != HAL_OK)                                     
  {
    APP_ErrorHandler();
  }*/
}

static void APP_AdcConfig_t(void)
{
  ADC_ChannelConfTypeDef sConfig_t = {0};
  __HAL_RCC_ADC_FORCE_RESET();
  __HAL_RCC_ADC_RELEASE_RESET();                                                  /* Reset ADC */
  __HAL_RCC_ADC_CLK_ENABLE();                                                     /* Enable ADC clock */

  AdcHandle_t.Instance = ADC1;
  if (HAL_ADCEx_Calibration_Start(&AdcHandle_t) != HAL_OK)                         
  {
    APP_ErrorHandler();
  }
  AdcHandle_t.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV2;                /* ADC clock no division */
  AdcHandle_t.Init.Resolution            = ADC_RESOLUTION_12B;                      /* 12bit */
  AdcHandle_t.Init.DataAlign             = ADC_DATAALIGN_RIGHT;                     /* Right alignment */
  AdcHandle_t.Init.ScanConvMode          = ADC_SCAN_DIRECTION_FORWARD;             /* Backward */
  AdcHandle_t.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;                     /* End flag */
  AdcHandle_t.Init.LowPowerAutoWait      = ENABLE;
  AdcHandle_t.Init.ContinuousConvMode    = DISABLE;
  AdcHandle_t.Init.DiscontinuousConvMode = DISABLE;
  AdcHandle_t.Init.ExternalTrigConv      = ADC_SOFTWARE_START;            /* External trigger: TIM1_TRGO */
  AdcHandle_t.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;  /* Triggered by both edges */
  
  //AdcHandle_t.Init.DMAContinuousRequests = DISABLE;                                 /* No DMA */
  AdcHandle_t.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;
  AdcHandle_t.Init.SamplingTimeCommon    = ADC_SAMPLETIME_41CYCLES_5;
  if (HAL_ADC_Init(&AdcHandle_t) != HAL_OK)
  {
    APP_ErrorHandler();
  }

  sConfig_t.Rank         = ADC_RANK_CHANNEL_NUMBER;
 // sConfig.Channel      = ADC_CHANNEL_VREFINT;
  sConfig_t.Channel      = ADC_CHANNEL_TEMPSENSOR;




  if (HAL_ADC_ConfigChannel(&AdcHandle_t, &sConfig_t) != HAL_OK)                      
  {
    APP_ErrorHandler();
  }
  /* Start ADC with Interrupt 
  if (HAL_ADC_Start_IT(&AdcHandle) != HAL_OK)                                     
  {
    APP_ErrorHandler();
  }*/
}

// <<<< ADC  end
static void showPower(void) {
    HAL_ADC_Start(&AdcHandle);
    HAL_ADC_PollForConversion(&AdcHandle,1000000);
    adc_value[0]=HAL_ADC_GetValue(&AdcHandle);
    //T_VCC=(4095*1.2)/adc_valie[0];
    T_VCC=adc_value[0];
        //T_VCC=11;

 
      if (T_VCC < 1600) {
      ws2812_pixel(7, 128, 0, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

      if (T_VCC < 1590) {
      ws2812_pixel(6, 128, 0, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

      if (T_VCC < 1550) {
      ws2812_pixel(5, 90, 30, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (T_VCC < 1500) {
      ws2812_pixel(4, 10, 60, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }  

    if (T_VCC < 1400) {
      ws2812_pixel(3, 10, 90, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (T_VCC < 1300) {
      ws2812_pixel(2, 5, 120, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    } 

    if (T_VCC < 1200) {
      ws2812_pixel(1, 0, 128, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (T_VCC < 1100) {
      ws2812_pixel(0, 0, 0, 90);
      ws2812_send_spi();
      HAL_Delay(100);
    } 
    
    HAL_Delay(5000);
              ws2812_pixel(0, 0, 0, 0);
              ws2812_pixel(1, 0, 0, 0);
              ws2812_pixel(2, 0, 0, 0);
              ws2812_pixel(3, 0, 0, 0);
              ws2812_pixel(4, 0, 0, 0);
              ws2812_pixel(5, 0, 0, 0);
              ws2812_pixel(6, 0, 0, 0);
              ws2812_pixel(7, 0, 0, 0);
              ws2812_send_spi();
    HAL_Delay(1000);          
              


    if (T_VCC < 1650) {
              ws2812_pixel(0, 0, 0, 0);
              ws2812_pixel(1, 0, 0, 0);
              ws2812_pixel(2, 0, 0, 0);
              ws2812_pixel(3, 0, 0, 0);
              ws2812_pixel(4, 0, 0, 0);
              ws2812_pixel(5, 0, 0, 0);
              ws2812_pixel(6, 0, 0, 0);
              ws2812_pixel(7, 0, 0, 0);
              ws2812_send_spi();
              HAL_Delay(200);
              ws2812_pixel(8, 255, 0, 0);
              ws2812_send_spi();
              HAL_Delay(200);
              ws2812_pixel(8, 0, 0, 0);
              ws2812_send_spi();
              T_VCC=0;
    }




}

static void showTemp(void) {
    HAL_ADC_Start(&AdcHandle_t);
    HAL_ADC_PollForConversion(&AdcHandle_t,1000000);
    adc_temp[0]=HAL_ADC_GetValue(&AdcHandle_t);
    //T_VCC=(4095*1.2)/adc_valie[0];
    Temperature=adc_temp[0];
        //T_VCC=11;
      ws2812_pixel(8, 0, 0, 128);
      ws2812_send_spi();
      HAL_Delay(100);



       if (Temperature < 965) {
      ws2812_pixel(7, 128, 0, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

      if (Temperature < 960) {
      ws2812_pixel(6, 128, 10, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

      if (Temperature < 955) {
      ws2812_pixel(5, 120, 10, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (Temperature < 952) {  // aprox 25 deg
      ws2812_pixel(4, 120, 20, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }  

    if (Temperature < 949) { // aprox 26 deg
      ws2812_pixel(3, 120, 30, 0);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (Temperature < 944) { // aprox 27 deg
      ws2812_pixel(2, 0, 30, 50);
      ws2812_send_spi();
      HAL_Delay(100);
    } 

    if (Temperature <  942) {
      ws2812_pixel(1, 0, 0, 50);
      ws2812_send_spi();
      HAL_Delay(100);
    }

    if (Temperature< 940) {
      ws2812_pixel(0, 0, 0, 90);
      ws2812_send_spi();
      HAL_Delay(100);
    } 


    HAL_Delay(5000);
              ws2812_pixel(0, 0, 0, 0);
              ws2812_pixel(1, 0, 0, 0);
              ws2812_pixel(2, 0, 0, 0);
              ws2812_pixel(3, 0, 0, 0);
              ws2812_pixel(4, 0, 0, 0);
              ws2812_pixel(5, 0, 0, 0);
              ws2812_pixel(6, 0, 0, 0);
              ws2812_pixel(7, 0, 0, 0);
              ws2812_send_spi();
    HAL_Delay(1000);          
              Temperature=0;

}

static void policeLights(void) {
    for (size_t i = 0; i < 10; i++)
  {
    
  
  
   ws2812_pixel(0, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(1, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(2, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(3, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(4, 0, 0, 0); ////
   ws2812_send_spi();
   ws2812_pixel(5, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(6, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(7, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(8, 0, 0, 255);
   ws2812_send_spi();

   HAL_Delay(500);

   ws2812_pixel(8, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(7, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(6, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(5, 255, 0, 0);
   ws2812_send_spi();
   ws2812_pixel(4, 0, 0, 0); ////
   ws2812_send_spi();
   ws2812_pixel(3, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(2, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(1, 0, 0, 255);
   ws2812_send_spi();
   ws2812_pixel(0, 0, 0, 255);
   ws2812_send_spi();

   HAL_Delay(500);
  }
}

/**
  * @brief  Error executing function.
  * @param  None
  * @retval None
  */
void APP_ErrorHandler(void)
{
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* Users can add their own printing information as needed,
     for example: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
}
#endif /* USE_FULL_ASSERT */
Полностью исходники тут

Пример проекта в работе:Между тем 9 светодиодов точно соответствуют набору игл матричного принтера, так что из данной платы можно сделать дисплей с механической разверткой. Разумеется, передавать произвольный текст на подвижную плату несколько сложно, так что обычно функциональность такого дисплея ограничивается отображением времени. Такая конструкция так и называется — «часы-пропеллер»:
Бывают они как с осевым отображением, так и с боковым:
В качестве привода и основы такой конструкции удобно использовать 120-140-мм вентилятор от компьютера. Для передачи питания на подвижную часть лучше использовать не вращающиеся контактные кольца, а трансформатор, первичная обмотка которого размещается на раме вентилятора, а вторичная — на кольцевом бумажном каркасе, надетом на крыльчатку, или же непосредственно на самой крыльчатке без использования каркаса:
Для реализации термометра уже всё-таки придется ставить беспроводной интерфейс термодатчика.
Добавить в избранное
+24 +27
свернутьразвернуть
Комментарии (4)
RSS
+
avatar
0
Хорошие часы у вас получились.
На каком вентиляторе делали?
+
avatar
0
Часы из вентилятора… Дожили

+
avatar
0
  • denisss
  • 29 сентября 2026, 12:18
Повезло что контроллер незалоченный, я пытался считать ST-Link-ом какого-то похожего покемона, но без надписи PUYA в одноразке Vozol, но не пошло — не реагирует даже на Reset, похоже ножка переназначена и контроллер залочен.
+
avatar
0
  • Demonik
  • 29 сентября 2026, 13:06
А в курилке точно был табак или что то повеселее?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.