648 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			648 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* USER CODE BEGIN Header */
 | ||
| /**
 | ||
|   ******************************************************************************
 | ||
|   * @file           : main.c
 | ||
|   * @brief          : Main program body
 | ||
|   ******************************************************************************
 | ||
|   * @attention
 | ||
|   *
 | ||
|   * Copyright (c) 2025 STMicroelectronics.
 | ||
|   * All rights reserved.
 | ||
|   *
 | ||
|   * This software is licensed under terms that can be found in the LICENSE file
 | ||
|   * in the root directory of this software component.
 | ||
|   * If no LICENSE file comes with this software, it is provided AS-IS.
 | ||
|   *
 | ||
|   ******************************************************************************
 | ||
|   */
 | ||
| /* USER CODE END Header */
 | ||
| /* Includes ------------------------------------------------------------------*/
 | ||
| #include "main.h"
 | ||
| #include "can.h"
 | ||
| #include "iwdg.h"
 | ||
| #include "tim.h"
 | ||
| #include "usart.h"
 | ||
| #include "gpio.h"
 | ||
| 
 | ||
| /* Private includes ----------------------------------------------------------*/
 | ||
| /* USER CODE BEGIN Includes */
 | ||
| #include "package.h"
 | ||
| #include "message.h"
 | ||
| #include "lampa.h"
 | ||
| #include "boot_jump.h"
 | ||
| /* USER CODE END Includes */
 | ||
| 
 | ||
| /* Private typedef -----------------------------------------------------------*/
 | ||
| /* USER CODE BEGIN PTD */
 | ||
| 
 | ||
| /* USER CODE END PTD */
 | ||
| 
 | ||
| /* Private define ------------------------------------------------------------*/
 | ||
| /* USER CODE BEGIN PD */
 | ||
| 
 | ||
| /* USER CODE END PD */
 | ||
| 
 | ||
| /* Private macro -------------------------------------------------------------*/
 | ||
| /* USER CODE BEGIN PM */
 | ||
| 
 | ||
| /* USER CODE END PM */
 | ||
| 
 | ||
| /* Private variables ---------------------------------------------------------*/
 | ||
| 
 | ||
| /* USER CODE BEGIN PV */
 | ||
| 
 | ||
| FLAG flag;
 | ||
| 
 | ||
| 
 | ||
| static long Falling_asleep;
 | ||
| uint8_t CanGO=0, timGo=0;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| /* USER CODE END PV */
 | ||
| 
 | ||
| /* Private function prototypes -----------------------------------------------*/
 | ||
| void SystemClock_Config(void);
 | ||
| /* USER CODE BEGIN PFP */
 | ||
| 
 | ||
| /* USER CODE END PFP */
 | ||
| 
 | ||
| /* Private user code ---------------------------------------------------------*/
 | ||
| /* USER CODE BEGIN 0 */
 | ||
| 
 | ||
| /* USER CODE END 0 */
 | ||
| 
 | ||
| /**
 | ||
|   * @brief  The application entry point.
 | ||
|   * @retval int
 | ||
|   */
 | ||
| int main(void)
 | ||
| {
 | ||
| 
 | ||
|   /* USER CODE BEGIN 1 */
 | ||
| 	static int i,j,n,z,mask,qua;
 | ||
|   static int cancount[2]={1,2},cancell[2]={0,0},candid[2]={0,0};
 | ||
|   static unsigned int masca[8];
 | ||
|   static uint16_t precom=0;
 | ||
|   App_Init();
 | ||
|   /* USER CODE END 1 */
 | ||
| 
 | ||
|   /* MCU Configuration--------------------------------------------------------*/
 | ||
| 
 | ||
|   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 | ||
|   HAL_Init();
 | ||
| 
 | ||
|   /* USER CODE BEGIN Init */
 | ||
| 
 | ||
|   /* USER CODE END Init */
 | ||
| 
 | ||
|   /* Configure the system clock */
 | ||
|   SystemClock_Config();
 | ||
| 
 | ||
|   /* USER CODE BEGIN SysInit */
 | ||
| 	MX_IWDG_Init();
 | ||
|   /* USER CODE END SysInit */
 | ||
| 
 | ||
|   /* Initialize all configured peripherals */
 | ||
|   MX_GPIO_Init();
 | ||
|   MX_CAN_Init();
 | ||
|   MX_TIM2_Init();
 | ||
|   MX_TIM4_Init();
 | ||
|   MX_UART4_Init();
 | ||
|   /* USER CODE BEGIN 2 */
 | ||
| 	HAL_TIM_Base_Start(&htim2);
 | ||
| 	LED_0_ON;
 | ||
| 	LED_1_OFF;
 | ||
| 	LED_2_ON;
 | ||
| 	LED_3_OFF;
 | ||
| 
 | ||
| 	for(i=0;i<10;i++)
 | ||
| 	{
 | ||
| 		LED_0_TGL;
 | ||
| 		LED_1_TGL;
 | ||
| 		LED_2_TGL;
 | ||
| 		LED_3_TGL;	
 | ||
| 		HAL_Delay(50);
 | ||
| 	}
 | ||
| 	
 | ||
| 	Mode = ReadJumpers()+1;
 | ||
| 	Setup_CAN_addr(Mode-1);
 | ||
| 	Load_params();	
 | ||
| 	LastMode = Mode;
 | ||
| 	Protokol = PROTOKOL;
 | ||
| 	
 | ||
| 	command=0;
 | ||
| 	
 | ||
| 	for(i=0;i<0x80;i++)
 | ||
| 	county[i]=1;
 | ||
| 	for(i=0;i<8;i++)
 | ||
| 	masca[i]=0;
 | ||
| 	for(i=0;i<2;i++)
 | ||
| 	CanRound[i]=
 | ||
| 	CanCycle[i]=0;
 | ||
| 
 | ||
| 	timGo=1;
 | ||
| 
 | ||
| 	
 | ||
| 	
 | ||
|   /* USER CODE END 2 */
 | ||
| 
 | ||
|   /* Infinite loop */
 | ||
|   /* USER CODE BEGIN WHILE */
 | ||
|   while (1)
 | ||
| {
 | ||
|     //=== БЛОК ПРИНУДИТЕЛЬНОЙ ПАУЗЫ ===//
 | ||
|     if (flag.force_pause)
 | ||
|     {
 | ||
|         __disable_irq();    // Отключаем все прерывания
 | ||
|         for(int i = 0; i < flag.pause; i++); // Пустой цикл для задержки
 | ||
|         __enable_irq();     // Включаем прерывания обратно
 | ||
|     }
 | ||
|     
 | ||
|     //=== ОБРАБОТКА CAN-ШИНЫ ===//
 | ||
|     if (CanGO)  // Флаг разрешения работы с CAN-шиной
 | ||
|     {	
 | ||
|         CanGO = 0;  // Сбрасываем флаг
 | ||
|         
 | ||
|         // Увеличиваем счетчики ожидания для всех элементов (ограничение 30000)
 | ||
|         for(i = 0; i < 0x80; i++)
 | ||
|             if(espero[i] < 30000) 
 | ||
|                 espero[i]++;
 | ||
|                 
 | ||
|         // Уменьшаем счетчики задержки для двух CAN-каналов
 | ||
|         for(i = 0; i < 2; i++)
 | ||
|             if(cancount[i]) 
 | ||
|                 cancount[i]--;
 | ||
|             else 
 | ||
|                 cancell[i] = 0;  // Сброс позиции, если счетчик обнулился
 | ||
|     }
 | ||
|     
 | ||
|     //=== ОБРАБОТКА КАНАЛОВ CAN ===//
 | ||
|     for(i = 0; i < 2; i++)  // Для каждого из двух CAN-каналов
 | ||
|     {
 | ||
|         if (Cancount[i] && !cancount[i])  // Если есть задержка и счетчик обнулился
 | ||
|         {
 | ||
|             // Поиск следующего элемента для обработки
 | ||
|             while(1)
 | ||
|             {
 | ||
|                 if (cancell[i] >= 0x80)  // Если достигли конца диапазона
 | ||
|                 {	
 | ||
|                     cancell[i] = 0;  // Сброс позиции
 | ||
|                     
 | ||
|                     if (candid[i])  // Если есть кандидат для обработки
 | ||
|                     {	
 | ||
|                         candid[i] = 0;          // Сброс флага кандидата
 | ||
|                         CanCycle[i]++;           // Увеличиваем счетчик циклов
 | ||
|                         cancount[i] = CanWait[i]; // Устанавливаем задержку
 | ||
|                         goto Next;               // Переход к следующей итерации
 | ||
|                     }	
 | ||
|                 }	
 | ||
|                 
 | ||
|                 // Проверка маски для определения активных элементов
 | ||
|                 mask = Maska[i][cancell[i] / 0x10] >> (cancell[i] & 0x0F);
 | ||
|                 if (!mask)  // Если маска пустая
 | ||
|                     cancell[i] = (cancell[i] + 0x10) & 0xFFF0;  // Переход к следующей группе
 | ||
|                 else
 | ||
|                 {
 | ||
|                     // Поиск первого установленного бита в маске
 | ||
|                     while (!(mask & 1))
 | ||
|                     {
 | ||
|                         cancell[i]++; 
 | ||
|                         mask >>= 1;
 | ||
|                     }
 | ||
|                     break;  // Найден активный элемент
 | ||
|                 }	
 | ||
|             }
 | ||
|             
 | ||
|             z = 1;  // Флаг нормального состояния
 | ||
|             // Проверка превышения времени ожидания
 | ||
|             if (espero[cancell[i]] > CanRestart[i])
 | ||
|             {
 | ||
|                 county[cancell[i]] = 1;  // Установка флага необходимости отправки
 | ||
|                 z = 0;                   // Флаг аварийного состояния
 | ||
|             }
 | ||
|             
 | ||
|             // Проверка изменения данных для отправки
 | ||
|             if (modbus[cancell[i]] != archiv[cancell[i]])
 | ||
|             {	
 | ||
|                 if (cancell[i] == keys)  // Если это ключевой элемент
 | ||
|                 {
 | ||
|                     // Установка флагов для группы элементов
 | ||
|                     for(j = 0; j < CanRptLen; j++)
 | ||
|                         county[cancell[i] + j] = CanRptVez;
 | ||
|                 }
 | ||
|                 else	
 | ||
|                 {
 | ||
|                     county[cancell[i]] = 1;  // Установка флага для одиночного элемента
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             // Обработка элементов, требующих отправки
 | ||
|             if (county[cancell[i]])
 | ||
|             {
 | ||
|                 // Поиск границ группы измененных элементов
 | ||
|                 for(j = 3; j > 0 && !Isit(cancell[i] + j, i, z); j--);
 | ||
|                 for(n = j - 3; n < 0 && !Isit(cancell[i] + n, i, 1); n++);
 | ||
| 
 | ||
|                 qua = 1 + j - n;  // Расчет количества элементов в группе
 | ||
|                 cancell[i] += n;   // Корректировка позиции
 | ||
| 
 | ||
|                 // Обработка каждого элемента в группе
 | ||
|                 for(j = 0; j < qua; j++)
 | ||
|                 {
 | ||
|                     n = cancell[i] + j;
 | ||
|                     archiv[n] = modbus[n];  // Сохранение текущего значения
 | ||
|                     espero[n] = 0;          // Сброс счетчика ожидания
 | ||
|                     
 | ||
|                     if (county[n])  // Если элемент требует обработки
 | ||
|                     {	
 | ||
|                         county[n]--;  // Уменьшение счетчика
 | ||
|                         // Если счетчик обнулился и это не циклический элемент
 | ||
|                         if (!county[n] && n != cancyclo + i)	
 | ||
|                             candid[i] = 1;  // Установка флага кандидата
 | ||
|                     }	
 | ||
|                     // Обновление маски активных элементов
 | ||
|                     if (!county[n]) 
 | ||
|                         masca[n / 0x10] |= (1 << (n & 0x0F));
 | ||
|                 }	
 | ||
| 
 | ||
|                 // Отправка данных через CAN-шину
 | ||
|                 CAN_send(archiv, cancell[i], qua);
 | ||
| 
 | ||
|                 cancount[i] = Cancount[i];  // Установка задержки
 | ||
|                 cancell[i] += qua;          // Переход к следующей позиции
 | ||
| 
 | ||
|                 // Проверка завершения обработки всех элементов
 | ||
|                 for(j = 0; j < 8; j++)
 | ||
|                     if ((masca[j] & Maska[i][j]) != Maska[i][j]) 
 | ||
|                         break;
 | ||
|                 
 | ||
|                 if (j == 8)  // Если все элементы обработаны
 | ||
|                 {
 | ||
|                     // Сброс соответствующих битов маски
 | ||
|                     for(j = 0; j < 8; j++) 
 | ||
|                         masca[j] &= ~Maska[i][j];
 | ||
|                     CanRound[i]++;  // Увеличение счетчика раундов
 | ||
|                 }
 | ||
| 
 | ||
|                 // Управление параллельной обработкой каналов
 | ||
|                 if (Cancount[i] > 1 && !cancount[!i])
 | ||
|                     cancount[!i] = 1;  // Запуск другого канала
 | ||
|             }
 | ||
|             else	
 | ||
|             {
 | ||
|                 cancell[i]++;  // Переход к следующему элементу
 | ||
|             } 
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
|     Next:  // Метка для перехода к следующей части цикла
 | ||
|     
 | ||
|     //=== ЧТЕНИЕ ВХОДНЫХ СИГНАЛОВ ===//
 | ||
|     ReadEnteres();  // Функция чтения дискретных входов
 | ||
|     
 | ||
|     //=== УПРАВЛЕНИЕ ВЫХОДНЫМИ СИГНАЛАМИ ===//
 | ||
|     if (Errors.all | Alarms.all)
 | ||
|         Pvt4_OFF;  // Выключение сигнала "Система ВЭП в норме"
 | ||
|     else			
 | ||
|         Pvt4_ON;   // Включение сигнала "Система ВЭП в норме"
 | ||
|         
 | ||
|     if (Errors.all)	
 | ||
|         Pvt3_ON;   // Включение сигнала "Авария системы ВЭП"
 | ||
|     else			
 | ||
|         Pvt3_OFF;  // Выключение сигнала "Авария системы ВЭП"
 | ||
|         
 | ||
|     if (Falling_asleep)	
 | ||
|         Pvt2_ON;   // Включение сигнала управления
 | ||
|     else				
 | ||
|         Pvt2_OFF;  // Выключение сигнала управления
 | ||
| 
 | ||
|     //=== ОБРАБОТКА КОМАНД ===//
 | ||
|     if (Commands != precom)  // Если команды изменились
 | ||
|     {
 | ||
|         command = (~precom | command) & Commands;  // Обновление активных команд
 | ||
|     }
 | ||
|     precom = Commands;  // Сохранение текущих команд для следующей итерации
 | ||
|     
 | ||
|     //=== ОБРАБОТКА СИСТЕМНЫХ КОМАНД ===//
 | ||
|     if (cDefParam)  // Команда сброса параметров по умолчанию
 | ||
|     {
 | ||
|         cDefParam = 0;
 | ||
|         Default_params();  // Вызов функции сброса параметров
 | ||
|     }
 | ||
| 
 | ||
|     if (cSaveParam)  // Команда сохранения параметров
 | ||
|     {
 | ||
|         cSaveParam = 0;
 | ||
|         Save_params();  // Вызов функции сохранения параметров
 | ||
|     }
 | ||
| 
 | ||
|     if (cLoadParam)  // Команда загрузки параметров
 | ||
|     {
 | ||
|         cLoadParam = 0;
 | ||
|         Load_params();  // Вызов функции загрузки параметров
 | ||
|     }
 | ||
| 
 | ||
|     if (cCanReset)  // Команда сброса CAN-системы
 | ||
|     {
 | ||
|         cCanReset = 0;
 | ||
| 
 | ||
|         // Сброс всех счетчиков и состояний CAN-системы
 | ||
|         for(i = 0; i < 0x80; i++)
 | ||
|             county[i] = 1;  // Установка флагов отправки для всех элементов
 | ||
|             
 | ||
|         for(i = 0; i < 2; i++)
 | ||
|         {
 | ||
|             CanCycle[i] = 0;  // Сброс счетчиков циклов
 | ||
|             CanRound[i] = 0;  // Сброс счетчиков раундов
 | ||
|             cancount[i] = 0;  // Сброс счетчиков задержки
 | ||
|             cancell[i] = 0;   // Сброс позиций
 | ||
|         }
 | ||
|             
 | ||
|         for(i = 0; i < 8; i++)
 | ||
|             masca[i] = 0;  // Сброс масок
 | ||
|     }	
 | ||
| 	
 | ||
| 
 | ||
| 				
 | ||
|     /* USER CODE END WHILE */
 | ||
| 
 | ||
|     /* USER CODE BEGIN 3 */
 | ||
| 	}
 | ||
|   /* USER CODE END 3 */
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   * @brief System Clock Configuration
 | ||
|   * @retval None
 | ||
|   */
 | ||
| void SystemClock_Config(void)
 | ||
| {
 | ||
|   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 | ||
|   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 | ||
| 
 | ||
|   /** Initializes the RCC Oscillators according to the specified parameters
 | ||
|   * in the RCC_OscInitTypeDef structure.
 | ||
|   */
 | ||
|   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
 | ||
|   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 | ||
|   RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
 | ||
|   RCC_OscInitStruct.LSIState = RCC_LSI_ON;
 | ||
|   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 | ||
|   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
 | ||
|   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
 | ||
|   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 | ||
|   {
 | ||
|     Error_Handler();
 | ||
|   }
 | ||
| 
 | ||
|   /** Initializes the CPU, AHB and APB buses clocks
 | ||
|   */
 | ||
|   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
 | ||
|                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
 | ||
|   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 | ||
|   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 | ||
|   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
 | ||
|   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 | ||
| 
 | ||
|   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
 | ||
|   {
 | ||
|     Error_Handler();
 | ||
|   }
 | ||
|   HAL_RCC_MCOConfig(RCC_MCO, RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_1);
 | ||
| }
 | ||
| 
 | ||
| /* USER CODE BEGIN 4 */
 | ||
| //////////////// USER FUNC ////////////////////
 | ||
| /**
 | ||
|  * @brief Проверяет, активен ли указанный элемент для обработки в CAN-шине
 | ||
|  * @param num Номер элемента (0x00-0x7F)
 | ||
|  * @param i Номер CAN-канала (0 или 1)
 | ||
|  * @param z Флаг дополнительных проверок (1 - включить доп. проверки, 0 - только маска)
 | ||
|  * @return 1 - элемент активен, 0 - элемент не активен
 | ||
|  */
 | ||
| int Isit(int num, int i, int z)
 | ||
| {
 | ||
|     int res, pls;
 | ||
|     
 | ||
|     //=== ПРОВЕРКА ДИАПАЗОНА ===//
 | ||
|     // Если номер элемента вне допустимого диапазона (0x00-0x7F)
 | ||
|     if((num < 0) || (num >= 0x80)) 
 | ||
|         return 0;  // Элемент не активен
 | ||
|     
 | ||
|     //=== ПРОВЕРКА МАСКИ КАНАЛА ===//
 | ||
|     // Определяем битовую маску для данного элемента
 | ||
|     // num/0x10 - определяем индекс в массиве масок (0-7)
 | ||
|     // num&0x0F - определяем позицию бита в слове (0-15)
 | ||
|     res = Maska[i][num / 0x10];        // Получаем маску для группы элементов
 | ||
|     res &= (1 << (num & 0x0F));        // Проверяем конкретный бит в маске
 | ||
|     
 | ||
|     //=== ДОПОЛНИТЕЛЬНЫЕ ПРОВЕРКИ (если z != 0) ===//
 | ||
|     if(z)
 | ||
|     {
 | ||
|         // Проверка времени ожидания: если превышена половина времени перезапуска
 | ||
|         pls = (espero[num] > CanRestart[i] / 2);
 | ||
|         
 | ||
|         // ИЛИ проверка счетчика отправки (если county[num] != 0)
 | ||
|         pls = pls || county[num];
 | ||
|         
 | ||
|         // Комбинированная проверка: должен быть установлен в маске И выполнять условия
 | ||
|         res = res && pls;
 | ||
|     }
 | ||
|     
 | ||
|     return res;  // Возвращаем результат проверки
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * @brief Функция обработки милисекундных событий системы
 | ||
|  * @note Вызывается каждую миллисекунду из SysTick_Handler
 | ||
|  */
 | ||
| void Millisecond()
 | ||
| {
 | ||
|     // Статические переменные для хранения состояния между вызовами
 | ||
|     static int CanPowse;  // Счетчик для управления CAN-шиной
 | ||
|     static unsigned int count_blink = 0,     // Счетчик для мигания
 | ||
|                        count_bright = 0,    // Счетчик для управления яркостью
 | ||
|                        count_mode,          // Счетчик режимов мигания
 | ||
|                        blink_over,          // Флаг переключения состояния мигания
 | ||
|                        blink_alarm,         // Флаг мигания аварии
 | ||
|                        power_lamp,          // Состояние силовой лампы
 | ||
|                        work_diod,           // Состояние рабочего светодиода
 | ||
|                        norm_diod;           // Состояние нормального светодиода
 | ||
|     static int preTest;   // Предыдущее состояние теста
 | ||
|     int TST;              // Текущее состояние теста
 | ||
| 
 | ||
|     // Константы времени
 | ||
|     #define CANPOWSE 10      // 10 msec - период обновления CAN
 | ||
|     #define BLINK_TIME 250   // 0.25 sec - период мигания
 | ||
| 
 | ||
|     //=== ОБНОВЛЕНИЕ WATCHDOG ===//
 | ||
|     if(!cReset)
 | ||
|         IWDG->KR = 0xAAAA;  // Сброс watchdog таймера
 | ||
| 
 | ||
|     //=== ПРОВЕРКА АКТИВНОСТИ ТАЙМЕРА ===//
 | ||
|     if(!timGo) return;  // Если таймер не активен - выход
 | ||
| 
 | ||
|     //=== ЧТЕНИЕ ПЕРЕКЛЮЧАТЕЛЕЙ И КНОПОК ===//
 | ||
|     Jumpers.byt.byte_1 = ReadJumpers();        // Чтение состояния переключателей
 | ||
|     Jumpers.bit.bit0 = Buttons.bit.bit0 = TestJumper();  // Чтение состояния кнопки
 | ||
| 
 | ||
|     //=== УПРАВЛЕНИЕ CAN-ШИНОЙ ===//
 | ||
|     if(++CanPowse >= CANPOWSE)
 | ||
|     {
 | ||
|         CanPowse = 0;    // Сброс счетчика
 | ||
|         CanGO = 1;       // Установка флага разрешения работы CAN
 | ||
|     }
 | ||
|     
 | ||
|     //=== УПРАВЛЕНИЕ РЕЖИМОМ "ЗАСЫПАНИЯ" ===//
 | ||
|     if(Alarms.bit.bit8)  // Разряд батареи
 | ||
|     {
 | ||
|         if (Falling_asleep) Falling_asleep--;  // Уменьшение времени до "сна"
 | ||
|     }
 | ||
|     else    
 | ||
|         Falling_asleep = 1000L * Sleep_time;   // Установка времени до "сна"
 | ||
|     
 | ||
|     //=== ОБРАБОТКА ТЕСТОВОГО РЕЖИМА ===//
 | ||
|     TST = TestJumper() | cTestLamp;  // Текущее состояние теста (кнопка или команда)
 | ||
|     
 | ||
|     if(TST & !preTest)  // Обнаружение фронта нажатия кнопки
 | ||
|     {
 | ||
|         count_blink = BLINK_TIME;  // Сброс счетчика мигания
 | ||
|         count_mode = 0;            // Сброс счетчика режимов
 | ||
|     }
 | ||
|     preTest = TST;  // Сохранение состояния для следующего вызова
 | ||
| 
 | ||
|     //=== УПРАВЛЕНИЕ МИГАНИЕМ ИНДИКАТОРОВ ===//
 | ||
|     if(++count_blink >= BLINK_TIME)
 | ||
|     {
 | ||
|         count_blink = 0;        // Сброс счетчика
 | ||
|         count_mode++;           // Переключение режима
 | ||
|         blink_over = (count_mode & 1) ? 1 : 0;     // Мигание 1:1 (50%)
 | ||
|         blink_alarm = (count_mode & 7) ? 1 : 0;    // Мигание 1:7 (12.5%)
 | ||
|     }
 | ||
| 
 | ||
|     //=== УСТАНОВКА СТАНДАРТНЫХ СОСТОЯНИЙ ИНДИКАТОРОВ ===//
 | ||
|     power_lamp = 1;     // Силовая лампа включена
 | ||
|     norm_diod = 1;      // Нормальный светодиод включен
 | ||
|     work_diod = !blink_over;  // Рабочий светодиод синхронизирован с миганием
 | ||
|     
 | ||
|     //=== РЕЖИМ ТЕСТИРОВАНИЯ ===//
 | ||
|     if(TST)
 | ||
|     {
 | ||
|         power_lamp = blink_over;  // Мигание силовой лампы
 | ||
|         norm_diod = blink_over;   // Мигание нормального светодиода
 | ||
|         work_diod = blink_over;   // Мигание рабочего светодиода
 | ||
|     }
 | ||
|     //=== РЕЖИМ ОСВЕЩЕНИЯ ===//
 | ||
|     else if(Lightness)
 | ||
|     {
 | ||
|         power_lamp = norm_diod = 0;  // Базовое состояние - выключено
 | ||
|         
 | ||
|         // Уровень освещенности 2: постоянно включено
 | ||
|         if(Lightness == 2) power_lamp = norm_diod = 1;
 | ||
|         
 | ||
|         // Уровень освещенности 3: медленное мигание (50%)
 | ||
|         if(Lightness == 3) power_lamp = norm_diod = blink_over;
 | ||
|         
 | ||
|         // Уровень освещенности 4: быстрое мигание (12.5%)
 | ||
|         if(Lightness == 4) power_lamp = norm_diod = blink_alarm;
 | ||
|         
 | ||
|         // Уровень освещенности 5: инверсное быстрое мигание (87.5%)
 | ||
|         if(Lightness == 5) power_lamp = norm_diod = !blink_alarm;
 | ||
|     }
 | ||
|     //=== РЕЖИМ ОШИБОК ===//
 | ||
|     else if(Errors.all)
 | ||
|     {
 | ||
|         power_lamp = blink_over;  // Мигание при ошибках
 | ||
|         norm_diod = blink_over;   // Мигание при ошибках
 | ||
|     }    
 | ||
|     //=== РЕЖИМ ТРЕВОГ ===//
 | ||
|     else if(Alarms.all)
 | ||
|     {
 | ||
|         power_lamp = blink_alarm;  // Быстрое мигание при тревогах
 | ||
|         norm_diod = blink_alarm;   // Быстрое мигание при тревогах
 | ||
|     }
 | ||
|     
 | ||
|     //=== ШИМ УПРАВЛЕНИЕ ЯРКОСТЬЮ СИЛОВОЙ ЛАМПЫ ===//
 | ||
|     if(++count_bright == 10) // maximum_bright (100%)
 | ||
|     {   
 | ||
|         count_bright = 0;
 | ||
|         if(power_lamp) Pvt1_ON;   // Включение на полную яркость
 | ||
|         else Pvt1_OFF;            // Выключение
 | ||
|     }
 | ||
|     
 | ||
|     //=== УПРАВЛЕНИЕ ЯРКОСТЬЮ ===//
 | ||
|     if(count_bright == Brightness)
 | ||
|         if(!TST) Pvt1_OFF;  // Отключение лампочки с регулировкой яркости
 | ||
|     
 | ||
|     //=== УПРАВЛЕНИЕ СВЕТОДИОДАМИ ===//
 | ||
|     if(work_diod) LED_2_ON;   // Включение рабочего светодиода
 | ||
|     else LED_2_OFF;           // Выключение рабочего светодиода
 | ||
| 
 | ||
|     if(norm_diod) LED_3_ON;   // Включение нормального светодиода
 | ||
|     else LED_3_OFF;           // Выключение нормального светодиода
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /////////////////////////////////////////////
 | ||
| 
 | ||
| /* USER CODE END 4 */
 | ||
| 
 | ||
| /**
 | ||
|   * @brief  Period elapsed callback in non blocking mode
 | ||
|   * @note   This function is called  when TIM8 interrupt took place, inside
 | ||
|   * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
 | ||
|   * a global variable "uwTick" used as application time base.
 | ||
|   * @param  htim : TIM handle
 | ||
|   * @retval None
 | ||
|   */
 | ||
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
 | ||
| {
 | ||
|   /* USER CODE BEGIN Callback 0 */
 | ||
| 
 | ||
| 	if(htim->Instance == TIM4) //check if the interrupt comes from TIM4
 | ||
| 	ReadSeanus();
 | ||
| 
 | ||
|   /* USER CODE END Callback 0 */
 | ||
|   if (htim->Instance == TIM8) {
 | ||
|     HAL_IncTick();
 | ||
| 	Millisecond();
 | ||
|  }
 | ||
|   /* USER CODE BEGIN Callback 1 */
 | ||
|   /* USER CODE END Callback 1 */
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   * @brief  This function is executed in case of error occurrence.
 | ||
|   * @retval None
 | ||
|   */
 | ||
| void Error_Handler(void)
 | ||
| {
 | ||
|   /* USER CODE BEGIN Error_Handler_Debug */
 | ||
|   /* User can add his own implementation to report the HAL error return state */
 | ||
|   __disable_irq();
 | ||
|   while (1)
 | ||
|   {
 | ||
|   }
 | ||
|   /* USER CODE END Error_Handler_Debug */
 | ||
| }
 | ||
| 
 | ||
| #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)
 | ||
| {
 | ||
|   /* USER CODE BEGIN 6 */
 | ||
|   /* User can add his own implementation to report the file name and line number,
 | ||
|      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 | ||
|   /* USER CODE END 6 */
 | ||
| }
 | ||
| #endif /* USE_FULL_ASSERT */
 |