Передмова
Цей допис роблю для себе, як документацію на пристрій. Пристрій робився на замовлення в одному екземплярі. Як кому згодиться то дуже добре.
Призначення
Лічильник подій 4х4 фіксує і показує на екрані поточні показники лічильників, різницю між поточними показами лічильників і попереднім зняттям показів лічильників. Показання лічильників виводяться на чотироьохрозрядний семисегментний індикатор по черзі.
Слугує заміною застарілим електромеханічним лічильникам, які вже використали свій ресурс і працюють з великою похибкою.
Як користуватись
Після зняття показів всіх лічильників, натиснути кнопку для фіксації, що значення лічильників занесено до журналу і розрахунок різниці ведеться вже з поточних показів лічильників.
Схеми блоків
Блок фіксації події, гальванічної розв'язки та антибрязкіт.
Архів зі схемами. Живлення пристрою від акумуляторів 24 Вольта великої ємності в режимі "буфер". Зарядний пристрій до акумуляторів живиться від гарантованої мережі 220В. Додаткового резервного живлення не потребує.
Програмне забезпечення
Початкова ініціалізація периферії згенерована програмою CubeMX. Програма написана мовою C в засобі розробки CooCox CoIDE 1.7. Архів з проектом.
Прототипи функцій.
Деякі змінні.
Функції для роботи 7-сегментного дисплею
Виклик функції для виводу інформації на дисплей. Або в безкінечному циклі, або по перериванням.
Оголошуємо масиви. Створюємо структуру і оголошуємо масив структур.
В циклі опитуємо входи на подію. Якщо прапорець "flag_bounce" в true.
Увімкнено два таймери. Таймер TIM2 в перериванні скидає прапорець "flag_lock_screen" для зміни інформації на екрані що 3 секунди. Таймер TIM4 в перериванні встановлює прапорець "flag_bounce" для дозволу опитування входів на подію через кожні 25 мілісекунд (програмний антибрязкіт).
- mxconstants.h - константи, структури
- main.c - головна програма
- stm32f1xx_it.c - обробник переривань
Дещо з коду під спойлером.
Прототипи функцій.
/* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ static void DigitToPort (uint8_t digit); // виставляє в відповідні розряди індикатора числа-розряди. static void ShowScreen(uint8_t* number, uint8_t number_of_digits, const uint16_t* pDigitPin); // Вивід числа на екран. Аргументи: масив з чисел-розрядів після функції SplitToDigit, та кількість розрядів. static void SplitToDigit(uint32_t counter, uint8_t* digit, uint8_t number_of_digits); // число з лічильника розбиває на окремі розряди. вхідні аргументи: значення лічильника, масив для розрядів, кількість розрядів. /* USER CODE END PFP */
Деякі змінні.
/* USER CODE BEGIN 2 */ uint8_t digit[NUM_DIGIT] = {}; // Масив для символів в кожен розряд індикатора окремо static const uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin}; /* USER CODE END 2 */
Функції для роботи 7-сегментного дисплею
//Функція відображення інформації на дисплей static void ShowScreen(uint8_t* number, uint8_t number_of_digits, const uint16_t* pDigitPin) { for(uint8_t i = 0; i < number_of_digits; i++) { IND_PORT -> BRR = (D0_Pin|D1_Pin|D2_Pin|D3_Pin);//Вимикаємо всі розряди IND_PORT -> BSRR = pDigitPin[i];//Вмикаємо потрібний розряд індикатора DigitToPort(*(number+i));//Виводимо цифру у потрібний розряд HAL_Delay(1);//Невеличка затримка. Хай цифра світиться якийсь час } }
// число з лічильника розбиває на окремі розряди. вхідні аргументи: значення лічильника, масив для розрядів, кількість розрядів. static void SplitToDigit(uint32_t counter, uint8_t* digit, uint8_t number_of_digits) { uint32_t tmp = counter; for (uint8_t i = 0; i < number_of_digits; i++) { *(digit+i) = tmp % 10; tmp = tmp / 10; } }
//Функція виставляє в порт потрібну цифру static void DigitToPort (uint8_t digit) { static const uint8_t digitsp[]={DIG0,DIG1,DIG2,DIG3,DIG4,DIG5,DIG6,DIG7,DIG8,DIG9,SEG_G_Pin,LITA,~DIG8,LITP,LITH,LITPE}; //оголошуємо масив з можливими варіантами символами на індикатор IND_PORT -> ODR &= ~DIG8; //Вимикаємо всі сегменти IND_PORT -> ODR |= digitsp[digit]; //Запалюємо потрібні }
Виклик функції для виводу інформації на дисплей. Або в безкінечному циклі, або по перериванням.
ShowScreen(digit,sizeof(digit)/sizeof(digit[0]),digitPin);
Оголошуємо масиви. Створюємо структуру і оголошуємо масив структур.
bool flag_button[NUM_COUNTER] = {}; // Масив з прапорцями стану отримання імпульсу на лічильник typedef struct { uint32_t current; uint32_t previous; }CounterTypeDef; CounterTypeDef AI_Counter[NUM_COUNTER] = {}; // Масив з кількістью структур для лічильників static const uint16_t ButtonPin[] = {AI_COUNTER1_Pin,AI_COUNTER2_Pin,AI_COUNTER3_Pin,AI_COUNTER4_Pin, AI_COUNTER5_Pin,AI_COUNTER6_Pin,AI_COUNTER7_Pin,AI_COUNTER8_Pin, AI_COUNTER9_Pin,AI_COUNTER10_Pin,AI_COUNTER11_Pin,AI_COUNTER12_Pin, AI_COUNTER13_Pin,AI_COUNTER14_Pin,AI_COUNTER15_Pin,AI_COUNTER16_Pin}; static GPIO_TypeDef* ButtonPort[] = {AI_COUNTER1_GPIO_Port,AI_COUNTER2_GPIO_Port,AI_COUNTER3_GPIO_Port,AI_COUNTER4_GPIO_Port, AI_COUNTER5_GPIO_Port,AI_COUNTER6_GPIO_Port,AI_COUNTER7_GPIO_Port,AI_COUNTER8_GPIO_Port, AI_COUNTER9_GPIO_Port,AI_COUNTER10_GPIO_Port,AI_COUNTER11_GPIO_Port,AI_COUNTER12_GPIO_Port, AI_COUNTER13_GPIO_Port,AI_COUNTER14_GPIO_Port,AI_COUNTER15_GPIO_Port,AI_COUNTER16_GPIO_Port};
В циклі опитуємо входи на подію. Якщо прапорець "flag_bounce" в true.
if (flag_bounce) { flag_bounce = false; for (uint8_t i = 0; i < NUM_COUNTER; i++) { if (!HAL_GPIO_ReadPin(ButtonPort[i],ButtonPin[i]) && !flag_button[i]) { flag_button[i] = true; ++AI_Counter[i].current; } else if(HAL_GPIO_ReadPin(ButtonPort[i],ButtonPin[i]) && flag_button[i]) { flag_button[i] = false; } } }
Увімкнено два таймери. Таймер TIM2 в перериванні скидає прапорець "flag_lock_screen" для зміни інформації на екрані що 3 секунди. Таймер TIM4 в перериванні встановлює прапорець "flag_bounce" для дозволу опитування входів на подію через кожні 25 мілісекунд (програмний антибрязкіт).
Немає коментарів:
Дописати коментар