embedded-systems-labs/prekol-display/tm1637.c
2025-12-25 11:09:27 +03:00

202 lines
5.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "tm1637.h"
// Глобальные переменные (используются и в main)
uint32_t last_display_update;
uint16_t counter;
// Таблица кодов для 7-сегментного индикатора (0-9, A-F)
static const uint8_t digit_codes[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x77, // A
0x7C, // b
0x39, // C
0x5E, // d
0x79, // E
0x71 // F
};
// Дополнительные символы
#define SEG_BLANK 0x00
#define SEG_MINUS 0x40 // только сегмент g
#define SEG_H 0x76 // буква H
#define SEG_L 0x38 // буква L
// Простая задержка (для временных диаграмм TM1637)
void delay_us(uint32_t us) {
volatile uint32_t cycles = us * 24; // ~1 мкс при 48 МГц
while (cycles-- > 0) {
__asm__("nop");
}
}
// Инициализация TM1637
void tm1637_init(void) {
// PA6, PA7 - выход с открытым стоком
GPIOA->MODER = (GPIOA->MODER & ~(0xF << (TM1637_CLK_PIN * 2)))
| (0x5 << (TM1637_CLK_PIN * 2));
GPIOA->OTYPER |= (1U << TM1637_CLK_PIN) | (1U << TM1637_DIO_PIN);
GPIOA->OSPEEDR |= (0x3 << (TM1637_CLK_PIN * 2))
| (0x3 << (TM1637_DIO_PIN * 2));
// Линии в 1
GPIOA->BSRR = (1U << TM1637_CLK_PIN) | (1U << TM1637_DIO_PIN);
// Команда 1: режим данных
tm1637_start();
tm1637_write_byte(TM1637_CMD1);
tm1637_stop();
// Команда 3: включить дисплей
tm1637_start();
tm1637_write_byte(TM1637_CMD3);
tm1637_stop();
tm1637_clear();
last_display_update = 0;
counter = 0;
}
// Старт
void tm1637_start(void) {
GPIOA->BSRR = (1U << TM1637_DIO_PIN) | (1U << TM1637_CLK_PIN);
delay_us(2);
GPIOA->BRR = (1U << TM1637_DIO_PIN);
delay_us(2);
GPIOA->BRR = (1U << TM1637_CLK_PIN);
delay_us(2);
}
// Стоп
void tm1637_stop(void) {
GPIOA->BRR = (1U << TM1637_CLK_PIN);
delay_us(2);
GPIOA->BRR = (1U << TM1637_DIO_PIN);
delay_us(2);
GPIOA->BSRR = (1U << TM1637_CLK_PIN);
delay_us(2);
GPIOA->BSRR = (1U << TM1637_DIO_PIN);
delay_us(2);
}
// Запись байта
void tm1637_write_byte(uint8_t byte) {
for (uint8_t i = 0; i < 8; i++) {
GPIOA->BRR = (1U << TM1637_CLK_PIN);
delay_us(2);
if (byte & 0x01) {
GPIOA->BSRR = (1U << TM1637_DIO_PIN);
} else {
GPIOA->BRR = (1U << TM1637_DIO_PIN);
}
delay_us(2);
GPIOA->BSRR = (1U << TM1637_CLK_PIN);
delay_us(2);
byte >>= 1;
}
// ACK (упрощённо, без чтения)
GPIOA->BRR = (1U << TM1637_CLK_PIN);
GPIOA->BSRR = (1U << TM1637_DIO_PIN);
delay_us(2);
GPIOA->BSRR = (1U << TM1637_CLK_PIN);
delay_us(2);
GPIOA->BRR = (1U << TM1637_CLK_PIN);
delay_us(2);
}
// Вывод одного разряда по адресу digit (0..3)
void tm1637_display_digit(uint8_t digit, uint8_t data) {
tm1637_start();
tm1637_write_byte(TM1637_CMD2 | digit);
tm1637_write_byte(data);
tm1637_stop();
tm1637_start();
tm1637_write_byte(TM1637_CMD3);
tm1637_stop();
}
// Очистка
void tm1637_clear(void) {
tm1637_display_raw(SEG_BLANK, SEG_BLANK, SEG_BLANK, SEG_BLANK);
}
// Вывод сырых сегментов (d3 - левый, d0 - правый)
void tm1637_display_raw(uint8_t d3, uint8_t d2,
uint8_t d1, uint8_t d0) {
uint8_t digits[4] = { d0, d1, d2, d3 };
tm1637_start();
tm1637_write_byte(0x40); // автоинкремент
tm1637_stop();
tm1637_start();
tm1637_write_byte(0xC0); // стартовый адрес
for (int i = 3; i >= 0; i--) {
tm1637_write_byte(digits[i]);
}
tm1637_stop();
tm1637_start();
tm1637_write_byte(0x8F); // яркость
tm1637_stop();
}
// Десятичное число (0..9999)
void tm1637_display_number(int number) {
if (number < 0) number = 0;
if (number > 9999) number = 9999;
uint8_t d0 = digit_codes[number % 10];
uint8_t d1 = (number >= 10) ? digit_codes[(number / 10) % 10] : SEG_BLANK;
uint8_t d2 = (number >= 100) ? digit_codes[(number / 100) % 10] : SEG_BLANK;
uint8_t d3 = (number >= 1000) ? digit_codes[(number / 1000) % 10] : SEG_BLANK;
tm1637_display_raw(d3, d2, d1, d0);
}
// 8-битное число в шестнадцатеричном виде (00..FF)
void tm1637_display_hex(uint8_t value) {
uint8_t high = (value >> 4) & 0x0F;
uint8_t low = value & 0x0F;
uint8_t d3 = SEG_BLANK;
uint8_t d2 = SEG_BLANK;
uint8_t d1 = digit_codes[high];
uint8_t d0 = digit_codes[low];
tm1637_display_raw(d3, d2, d1, d0);
}
// Отображение канала в двоичном режиме: "N - h"/"N - 0"
void tm1637_display_channel_state(uint8_t ch, uint8_t state) {
if (ch > 7) ch = 7;
uint8_t ch_digit = digit_codes[ch]; // номер канала (0..7)
uint8_t dash = SEG_MINUS;
uint8_t v = state ? SEG_H : digit_codes[0]; // 'h' или '0'
// [пусто] [N] [-] [h/0]
tm1637_display_raw(SEG_BLANK, ch_digit, dash, v);
}
// Оставлено для совместимости с шаблоном — ничего не делает
void tm1637_update(void) {
(void)counter;
}