#include "nixie_driver_process.h" #include "nixie_driver_config.h" #include "indicate_modes_task.h" #include "light_sensor_task.h" #include // FreeRTOS includes #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" // - массив для цифр дешифратора // - массив для номера лампы // - счетчик номера текущей лампы // - таймер1 для времени горения // - таймер2 для времени затухания #define TUBE_HEATING_UP 0 static const uint16_t tube_off_digit = 0; // Символ для дешифратора, чтобы лампа не горела // Массив значений цифр для дешифратора. Если старший байт вперед. // И учтено, что все значения сдвинуты на 1 влево const uint16_t tube_digits [MAX_DIGITS] = { // Цифра на лампе TUBE_DIGIT_0, // 0 TUBE_DIGIT_1, // 1 TUBE_DIGIT_2, // 2 TUBE_DIGIT_3, // 3 TUBE_DIGIT_4, // 4 TUBE_DIGIT_5, // 5 TUBE_DIGIT_6, // 6 TUBE_DIGIT_7, // 7 TUBE_DIGIT_8, // 8 TUBE_DIGIT_9, // 9 TUBE_DIGIT_DP1, // dp1 TUBE_DIGIT_DP2, // dp2 TUBE_DIGIT_EMPTY // лампа не горит }; // Лампы на плате идут слева направо. Значение ячейки массива с учетом, если // старший байт идет вперед в SPI // И учтено, что все значения сдвинуты на 1 влево static const uint16_t tube_num [ MAX_TUBES ] = { TUBE_NUM_1, // 1-я лампа TUBE_NUM_2, // 2-я лампа TUBE_NUM_3, // 3-я лампа TUBE_NUM_4, // 4-я лампа TUBE_NUM_5, // 5-я лампа TUBE_NUM_6 // 6-я лампа }; // Текущий буфер с данными-цифрами на лампы static uint16_t curr_tube_bufer [ MAX_TUBES ] = { TUBE_DIGIT_1, // 0 TUBE_DIGIT_1, // 1 TUBE_DIGIT_1, // 2 TUBE_DIGIT_1, // 3 TUBE_DIGIT_1, // 4 TUBE_DIGIT_1 // 5 }; // Яркость ------------------------------------------------------------------ // // горит / не горит // time1 / time2 // 1 9 // 2 8 // 3 7 // 4 6 // 5 6 // 6 4 // 7 3 // 8 2 // 9 1 // 10 0 #define TIME_PERIOD_TCONST (uint32_t)80 // Время полного периода частоты работы ламп. Единица измерения зависит от настройки // таймера. В данном случае таймер тикает раз в 100 мкс, значит Т = 80 => T = 80*100 = 8000мкс = 8мс #define TIME_MIN (uint32_t)1 // Минимальный шаг времени таймера = 100 мкс. Минимальное время горения лампы // - добавить состояния DARK и LIGHT // (по сути это только комбинации TIME_ON и TIME_OFF) #define TIME_ON 2//5//20 #define TIME_OFF 23//22 // Время паузы после вкл/выкл всез ламп поочереди #define TIME_OFF_BRIGHT 0 #define TIME_OFF_DARK 100 #define TIME_TEST 10000 static uint32_t time_on = TIME_ON; // Время горения лампы static uint32_t time_off = TIME_OFF; // Время на угасание лампы ( чтобы она успела погаснуть полностью ) static uint32_t time_off2 = TIME_OFF_DARK; // static uint32_t time_on = TIME_OFF; // static uint32_t time_off = TIME_ON; // static uint32_t time_off2 = TIME_OFF_BRIGHT; //static uint32_t coef_brightness = 1; // Коэффициент яркости. Не может быть нулем! // Переменная для проверки первая или вторая пара байт ушла в отправку // Нужна т.к. нужно оправить именно 2 пары байт на динам. индикацию //static uint8_t first_byte; // Для сохранения номера лампы при отправке второй пары байт //static uint16_t tube_nbr_second_value; // Сообщения очереди ОСРВ QueueHandle_t queue_new_value; QueueHandle_t queue_new_data; static LightSensorState_t light_sensor_state; extern QueueHandle_t queue_light_sensor; // Прототипы функций файла -------------------------------------------------- // // Открытые void NixieDriver_SendValue ( uint8_t *value_arr ); // Закрытые static void SwitchOnTube ( uint8_t tube_nbr ); static void SwitchOffTube ( uint8_t tube_nbr ); // - функция начальной конфигурации времени ( чтение яркости из памяти EE ) // void NixieDriver_LoadBrightnessFromMemory ( void ); // Ф-я читает из памяти значение коэффициента яркости coef_brightness //static void NewTimeCalculate ( uint32_t *time_on, uint32_t *time_off ); // - ф-я NixieDriver_SetBrightness ( uint32_t ??? ); // Какие будут пределы и количество уровней яркости? // - ф-я NixieDriver_IncreaseBrighntness ( void ); // Увеличить яркость на один шаг ( то есть увеличится коэф. яркости на +1 ) // - ф-я NixieDriver_DecreaseBrighntness ( void ); // Уменьшить яркость на один шаг ( то есть уменьшится коэф. яркости на -1 ) #if TUBE_HEATING_UP == 0 static uint8_t LoadNextValueToTubes ( void ); #else static uint8_t LoadNextValueToTubes ( void ); #endif //static void TestLoadNewValueToClock ( void ); static void UpdateValueForClock ( void ); static void CheckLightSensor (void); // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void NixieDriverInitProcess ( void ) { //first_byte = 0; queue_new_value = xQueueCreate ( 1, sizeof (uint8_t*) ); configASSERT( queue_new_value ); queue_new_data = xQueueCreate ( 1, sizeof (DataToIndicate_t) ); configASSERT( queue_new_value ); } // ---------------------------------------------------------------------------- // Ф-я, реализующая беспрерывный процесс динамической индикации ламп Nixie // Ф-я вызывается из прерывания таймера, настроенного на 100 мкс // ---------------------------------------------------------------------------- void ProcessNixieDriverFromISR ( void ) { static uint8_t process_indic_state = 0; static uint32_t timer = TIME_ON; static uint8_t curr_tube_num = 0; timer++; //timer_test++; #if TUBE_HEATING_UP == 0 switch ( process_indic_state ) { case 0: if ( timer >= time_off ) // Ждем время горения лампы { curr_tube_num = LoadNextValueToTubes (); SwitchOnTube ( curr_tube_num ); timer = 0; process_indic_state = 1; /* if ( curr_tube_num == (MAX_TUBES - 1) ) { UpdateValueForClock (); CheckLightSensor(); // SwitchOffTube ( curr_tube_num ); //process_indic_state = 2; //timer = 0; } */ } break; case 1: if ( timer >= time_on ) { SwitchOffTube ( curr_tube_num ); timer = 0; process_indic_state = 0; if ( curr_tube_num == (MAX_TUBES - 1) ) { UpdateValueForClock (); CheckLightSensor(); SwitchOffTube ( curr_tube_num ); process_indic_state = 2; timer = 0; } } break; case 2: if ( timer >= time_off2 ) { //SwitchOnTube ( curr_tube_num ); timer = time_off; process_indic_state = 0; } break; } // end switch #else /* switch ( process_indic_state ) { case 0: SwitchOnTube ( curr_tube_num ); timer = 0; process_indic_state = 1; break; case 1: if ( timer >= time1 ) // Ждем время горения лампы { curr_tube_num = LoadNextValueToTubes (); timer = 0; process_indic_state = 0; } break; } // end switch */ #endif } // ---------------------------------------------------------------------------- // Ф-я подготовки и запуска передачи байт по SPI в сдвиговые регистры // управеления динамической индикацией. По сути включает нужную лампу // Ф-я принимает текущий номер лампы, для которой будет формироваться // пакет-кадр // ---------------------------------------------------------------------------- static void SwitchOnTube ( uint8_t tube_nbr ) { // - сначала отправляем пару байт с номером лампы // - затем отправляем пару байт с номером цифры static uint16_t temp; temp = 0; temp = tube_num [ tube_nbr ]; //(uint16_t)curr_tube_bufer [ tube_nbr ]; temp |= curr_tube_bufer [ tube_nbr ]; NIX_DRIVER_RESET_ST_PIN; // Т.к. точки на лампах управляются напрямую с МК через GPIO, // то нужно проверять вручную идет ли в пакете точка // Маленький нюанс: // Если мы выставим сигнал на точки раньше, чем передадим пакет на включение ламп по SPI, // то по идее точки включатся раньше, чем подастся сигнал ST if (curr_tube_bufer [ tube_nbr ] & TUBE_DIGIT_DP1) { NIX_DRIVER_SET_TUB_DP1_PIN; } else { NIX_DRIVER_RESET_TUB_DP1_PIN; } if (curr_tube_bufer [ tube_nbr ] & TUBE_DIGIT_DP2) { NIX_DRIVER_SET_TUB_DP2_PIN; } else { NIX_DRIVER_RESET_TUB_DP2_PIN; } SPI_I2S_SendData16 ( NIX_SPIx, temp ); SPI_I2S_ITConfig ( NIX_SPIx, SPI_I2S_IT_TXE, ENABLE ); } // ---------------------------------------------------------------------------- // Ф-я отключает лампу // ---------------------------------------------------------------------------- static void SwitchOffTube ( uint8_t tube_nbr ) { //static uint16_t value_to_spi1; //static uint16_t temp1; //value_to_spi1 = (uint16_t)tube_off_digit; //value_to_spi1 <<= 8; //temp1 = 0; //temp1 = (uint16_t)tube_num [ tube_nbr ]; //value_to_spi1 |= temp1; //first_byte = 1; //tube_nbr_second_value = tube_off_digit; NIX_DRIVER_RESET_ST_PIN; NIX_DRIVER_RESET_TUB_DP1_PIN; NIX_DRIVER_RESET_TUB_DP2_PIN; SPI_I2S_SendData16 ( NIX_SPIx, tube_off_digit ); SPI_I2S_ITConfig ( NIX_SPIx, SPI_I2S_IT_TXE, ENABLE ); } // ---------------------------------------------------------------------------- // Ф-я проверяет нужно ли зажечь точку на индикаторах сразу после отправки // двух байт по SPI // Ф-я вызываетяс из прерывания после ухода двух байт из SPI // Если есть точка, то зажигаем ее с помощью GPIO // ---------------------------------------------------------------------------- // void NixieDriverCheckDPPins (void) // { // ; // } // ---------------------------------------------------------------------------- // Ф-я проверяет первые ли 2 байта отправлены по SPI // Ф-я вызывается из прерывания NIX_SPIx_IRQHandler // ---------------------------------------------------------------------------- // uint8_t NixieDriverProcessCheckIsFirstByte (void) // { // //return first_byte; // return 0; // } // ---------------------------------------------------------------------------- // Ф-я отправляет вторую пару байт со значением цифр // ---------------------------------------------------------------------------- // void NixieDriverProcessSendSecondByte ( void ) // { // first_byte = 0; // SPI_I2S_SendData16 ( NIX_SPIx, tube_nbr_second_value ); // } #if TUBE_HEATING_UP == 1 // ---------------------------------------------------------------------------- // Временная ф-я для прогрева каждой лампы по каждому катоду // ---------------------------------------------------------------------------- static uint8_t LoadNextValueToTubes ( void ) { static uint8_t curr_tube_num = 0; static uint8_t curr_digit = 0; if ( curr_digit == 10 ) { if ( curr_tube_num == 5 ) { curr_tube_num = 0; } else { curr_tube_num++; if ( curr_tube_num == 1 ) { curr_tube_num++; } } curr_digit = 0; } curr_tube_bufer [ curr_tube_num ] = tube_digits [ curr_digit ]; curr_digit++; return curr_tube_num; } #else static uint8_t LoadNextValueToTubes ( void ) { static uint8_t curr_tube_num = 5; if ( curr_tube_num == 5 ) { curr_tube_num = 0; //NIX_TEST_PIN_PB11_TOGGLE; } else { curr_tube_num++; } return curr_tube_num; } #endif // ---------------------------------------------------------------------------- // Ф-я проверки и расчета нового значения яркости для динамической индикации // ламп // ---------------------------------------------------------------------------- //static void NewTimeCalculate ( uint32_t *time_on, uint32_t *time_off ) //{ //// uint32_t time_check; //// //// time_on = TIME_MIN*coef_brightness; //// //// if ( time_on > TIME_PERIOD_TCONST ) { return; } // //} // ---------------------------------------------------------------------------- // Тестовая ф-я перебирает последовательно все цифры одновременно на каждом // индикаторе // ---------------------------------------------------------------------------- //static void TestLoadNewValueToClock ( void ) //{ // static uint8_t digit_num = 0; // // //curr_tube_bufer [] = tube_digits []; // // Зугружаем в каждую лампу одно и то же значение // for ( uint8_t tube_num = 0; tube_num < MAX_TUBES; tube_num++ ) // { // curr_tube_bufer [tube_num] = tube_digits [digit_num]; // } // digit_num++; // // if ( digit_num == MAX_DIGITS ) // { // digit_num = 0; // } //} // ---------------------------------------------------------------------------- // Обновления значения выводимого на индикаторы // Ф-я вызывается из ф-ии ProcessNixieDriverFromISR () после вывода одного // цикла ( то есть 6-ти индикаторов ) // ---------------------------------------------------------------------------- // - внимание! нужно сделать два буфера, из которых в прерывании берутся // данные на передачу в лампы в SPI. Это нужно, чтобы не тратить время на // заполнение данных буфера. Сделать флаг или семафор. Пока из одного // буфера данные уходят, то в другой заполняют новые данные. А когда они // заполнятся, то просто поменять указатель на массив. // - сделать защиту от выхода за границы массива tube_digits [10] // (не больше 10) static void UpdateValueForClock ( void ) { // - проверяем сообщение очереди с новыми данными для отображения // если есть, то заполняем буфер curr_tube_bufer [] новыми значениями //uint8_t *value_arr; DataToIndicate_t data_struct; // if ( pdPASS == xQueueReceive ( queue_new_value, &value_arr, 0 ) ) // { // for ( uint8_t tube_num = 0; tube_num < MAX_TUBES; tube_num++ ) // { // curr_tube_bufer [tube_num] = tube_digits [ value_arr [tube_num] ]; // } // } if ( pdPASS == xQueueReceive ( queue_new_data, &data_struct, 0 ) ) { curr_tube_bufer [0] = tube_digits [ data_struct.indic_1 ]; curr_tube_bufer [1] = tube_digits [ data_struct.indic_2 ]; curr_tube_bufer [2] = tube_digits [ data_struct.indic_3 ]; curr_tube_bufer [3] = tube_digits [ data_struct.indic_4 ]; curr_tube_bufer [4] = tube_digits [ data_struct.indic_5 ]; curr_tube_bufer [5] = tube_digits [ data_struct.indic_6 ]; } } // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- static void CheckLightSensor (void) { //LightSensorState_t light_sensor_state; if ( pdPASS == xQueueReceive ( queue_light_sensor, &light_sensor_state, 0 ) ) { if (light_sensor_state == LIGHT_SENSOR_STATE_LIGHT ) { time_on = TIME_OFF; time_off = TIME_ON; time_off2 = TIME_OFF_BRIGHT;//TIME_OFF_DARK; } else { time_on = TIME_ON; time_off = TIME_OFF; time_off2 = TIME_OFF_DARK;//TIME_OFF_BRIGHT; } } } // ---------------------------------------------------------------------------- // Ф-я кладет сообщение в очередь ОС и передает указатель на массив с данными // Размер массива всегда 6 (количество ламп) // ---------------------------------------------------------------------------- void NixieDriver_SendValue ( uint8_t *value_arr ) { xQueueSend ( queue_new_value, &value_arr, 0 ); } //void NixieDriver_SendValue2 ( uint8_t *value_arr ) //{ // xQueueSend ( queue_new_value, &value_arr, 0 ); //}