В связи с возникшей потребностью, была написана библиотека для работы с 4-х разрядным семисегментным дисплеем
BQ-M322RD разработанным компанией Bright Led Electronics. Я также уверен что данная библиотека сможет работать и с другими аналогичными 4х-разрядными дисплеями, с общим анодом.
Внешний вид дисплея
Свечение сегментов тут практически не видно, так как сьёмка проходила на ярком дневном освещении. А так, не мешало бы приложить какое-нибудь тёмное стёклышко:)
Особенности данной библиотеки
При написании использовался ассемблер. Кроме этого, пытаясь максимально сократить размер кода, использованные алгоритмы были приближены к идеалу совершенства=) Для отображения цифр на сегментах дисплея был использован способ называемый динамической индикацией. Библиотека способна реализовывать этот режим двумя способами:
- Используя ресурсы таймера 0
- Используя функцию m322_loop() которую программа должна будет непрерывно вызывать в процессе своего выполнения
Библиотека занимает 264 байт памяти программ и 13 байт памяти данных при использовании первого способа, и соответственно 240 и 13 байт при использовании второго.
Выбрать один из способов можно отредактировав файл m322/conf.h
Примеры использования
Простой пример:
/*
программа использует библиотеку откомпилированную
с опцией #define USE_TIMER0
*/
#include "m322/m322.h"
int main(void)
{
m322_init(); // инициализировать семисегментный дисплей
m322_putn(1234); // вывести число 1234
m322_setdot(0, TRUE); // зажечь точку в разряде 0
for (;;)
;
}
Если библиотека откомпилирована вторым способом, то:
#include "m322/m322.h"
int main(void)
{
m322_init(); // инициализировать семисегментный дисплей
m322_putn(1234); // вывести число 1234 на семисегментный дисплей
m322_setdot(0, TRUE); // зажечь точку в разряде 0
for (;;)
m322_loop(80); // цикл динамической индикации
}
В данном случае добавлен вызов функции m322_loop() в бесконечный цикл, которая реализует динамическую индикацию. В качестве аргумента ей надо указать некоторое число. Частота мерцания дисплея будет зависеть от этого значения. Чем выше значение - тем меньше частота мерцания. Для моего 16мГц МК на котором я тестировал данный пример, оказалось оптимальным значение 80. Если брать больше - будет заметно мерцание, если меньше - разряды могут "поплыть".
Более интересный пример:
/*
программа использует библиотеку откомпилированную
с опцией #define USE_TIMER0
*/
#define F_CPU 16000000ULL /* частота работы мк (для _delay) */
#include <util/delay.h>
#include "m322/m322.h"
int main(void)
{
m322_init(); // инициализировать семисегментный дисплей
uint16_t number = 0;
uint8_t n_dot = 0;
for (;;) {
m322_setdot(n_dot, TRUE); // зажечь точку с заданным номером
m322_putn(number); // вывести десятичное число на индикатор
_delay_ms(100); // пауза 100мс
m322_setdot(n_dot, FALSE); // погасить точку с заданным номером
if (++n_dot == 5)
n_dot = 0;
if (++number == 10000)
number = 0;
}
}
Если попробовать выполнить программу на МК, то получим - на дисплее будет отображаться число, которое будет увеличиваться каждые 100 миллисекунд, а точка "зажигаясь" будет перемещаться циклически слева-направо.
Как настроить библиотеку под себяПеред компиляцией библиотеки необходимо задать порты к которым подключён дисплей, отредактировав файл m322/conf.h:
//
// Порты используемые для доступа к отдельным сегментам
//
#define PORT_SEGDATA _SFR_IO_ADDR(PORTD)
#define DDR_SEGDATA _SFR_IO_ADDR(DDRD)
/* номера пинов для каждого отдельного сегмента */
#define NPIN_DP PD7 /* точка */
#define NPIN_G PD6
#define NPIN_F PD5
#define NPIN_E PD4
#define NPIN_D PD3
#define NPIN_C PD2
#define NPIN_B PD1
#define NPIN_A PD0
//
// Порты используемые для доступа к отдельным разрядам
//
#define DDR_SEGCTL _SFR_IO_ADDR(DDRB)
#define PORT_SEGCTL _SFR_IO_ADDR(PORTB)
/* номера пинов для каждого отдельного разряда */
#define NPIN_SEGCTL0 PB4 /* D1 */
#define NPIN_SEGCTL1 PB1 /* D2 */
#define NPIN_SEGCTL2 PB2 /* D3 */
#define NPIN_SEGCTL3 PB3 /* D4 */
//
// Дополнительные настройки
//
// заккоментируйте следующую опцию если не хотите использовать
// ресурсы системного таймера0 для организации динамической
// индикации семисегментного дисплея:
/* использовать таймер */
#define USE_TIMER0
#ifdef USE_TIMER0
// частота мерцания семисегментного индикатора зависит
// от коэффициента предделителя таймера0,
// и вычисляется по формуле f = F_CPU/(P*256*4), где:
// F_CPU - тактовая частота мк, Гц
// P - коэффициент предделителя
/* значение предделителя для таймера */
#define TIMER0_PRESCALER ((1<<CS00)|(1<<CS01)) /* предделитель 64 */
#endif // USE_TIMER0
Я думаю здесь комментарии излишни=)
Схематическое изображение дисплея:
Полный перечень поддерживаемых функций
Библиотека поддерживает все самые необходимые функции, а именно:
- void m322_init()
Выполняет инициализацию семисегментного дисплея (настройка портов, таймера).
- void m322_puthd(uint8_t c, uint8_t n)
Выводит шестнадцатеричную цифру n в разряд с номером c индикатора.
- void m322_puthh(uint8_t n)
Выводит шестнадцатеричное число n в старшую часть индикатора (разряды 0 и 1)
- void m322_puthl(uint8_t n)
Выводит шестнадцатеричное число n в младшую часть индикатора (разряды 2 и 3)
- void m322_setdot(uint8_t c, uint8_t b)
Задаёт точку в разряд с номером c индикатора. Если b = TRUE - зажечь, иначе погасить.
- void m322_putn(uint16_t n)
Выводит на индикатор беззнаковое десятичное число n
- void m322_loop(uint16_t n)
Цикл для организации динамической индикации без использования таймера0
Совместимость
Думаю что библиотека будет совместима с большинством микроконтроллеров AVR серии Mega (в моём случае был использован Atmega8).
Скачать
Исходный код библиотеки вместе с примером можно скачать
здесь (или
здесь).