202 lines
5.2 KiB
C
202 lines
5.2 KiB
C
#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;
|
||
}
|