1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
#include "nixie_driver_process.h"
#include "nixie_driver_config.h"
#include "light_sensor/light_sensor_task.h"
#include <stdint.h>
// 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;
// Сообщения очереди ОСРВ
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 );
static uint8_t LoadNextValueToTubes ( void );
static void UpdateValueForClock ( void );
static void CheckLightSensor (void);
// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------
void NixieDriverInitProcess ( void )
{
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++;
#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;
}
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 )
{
timer = time_off;
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 ];
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 )
{
(void) tube_nbr;
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 );
}
#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;
}
else
{
curr_tube_num++;
}
return curr_tube_num;
}
#endif
// ----------------------------------------------------------------------------
// Обновления значения выводимого на индикаторы
// Ф-я вызывается из ф-ии ProcessNixieDriverFromISR () после вывода одного
// цикла ( то есть 6-ти индикаторов )
// ----------------------------------------------------------------------------
// - внимание! нужно сделать два буфера, из которых в прерывании берутся
// данные на передачу в лампы в SPI. Это нужно, чтобы не тратить время на
// заполнение данных буфера. Сделать флаг или семафор. Пока из одного
// буфера данные уходят, то в другой заполняют новые данные. А когда они
// заполнятся, то просто поменять указатель на массив.
// - сделать защиту от выхода за границы массива tube_digits [10]
// (не больше 10)
static void UpdateValueForClock ( void )
{
// - проверяем сообщение очереди с новыми данными для отображения
// если есть, то заполняем буфер curr_tube_bufer [] новыми значениями
DataToIndicate_t data_struct;
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 );
}
|