воскресенье, 27 декабря 2009 г.

Библиотека для семисегментного дисплея BQ-M322RD

В связи с возникшей потребностью, была написана библиотека для работы с 4-х разрядным семисегментным дисплеем BQ-M322RD разработанным компанией Bright Led Electronics. Я также уверен что данная библиотека сможет работать и с другими аналогичными 4х-разрядными дисплеями, с общим анодом.
Внешний вид дисплея


Свечение сегментов тут практически не видно, так как сьёмка проходила на ярком дневном освещении. А так, не мешало бы приложить какое-нибудь тёмное стёклышко:)
Особенности данной библиотеки
При написании использовался ассемблер. Кроме этого, пытаясь максимально сократить размер кода, использованные алгоритмы были приближены к идеалу совершенства=) Для отображения цифр на сегментах дисплея был использован способ называемый динамической индикацией. Библиотека способна реализовывать этот режим двумя способами:
  1. Используя ресурсы таймера 0
  2. Используя функцию 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).

Скачать
Исходный код библиотеки вместе с примером можно скачать здесь (или здесь).

1 комментарий:

ilsmolencev комментирует...

ссылки устарели. где скачать файлы с примерами?