Семисегментный индикатор | Блог им. Catethysis

Семисегментный индикатор

 

7–сегментный индикатор — одна из самых простых вещей в электронике. Тем не менее, у него есть некоторые интересности.

M4H07595

Один индикатор

Самый простой случай — использование одного индикатора. Уверен, вы справитесь с его подключением, нужно только обратить внимание на три вещи:

  1. Полярность — общие аноды или катоды
[<img class="alignnone size-full wp-image-1702" src="/wp-content/uploads/2014/06/common_anode.png" alt="common_anode" width="661" height="195" />](/wp-content/uploads/2014/06/common_anode.png) [<img class="alignnone wp-image-1703 size-full" src="/wp-content/uploads/2014/06/common_cathode.png" alt="common_cathode" width="661" height="195" />](/wp-content/uploads/2014/06/common_cathode.png)

В случае с общими анодами вы должны подать плюс на анод и минус на один или несколько катодов. Для общих катодов — наоборот.   2. Проверить ток и рассчитать токоограничительные резисторы.

Все микроконтроллеры STM32 имеют два ограничения тока: максимальный ток конкретного контакта ввода–вывода (20мА) и максимальный ток контактов питания (300мА). Таким образом, вы не должны выйти из предела по току сегмента и по общему току, потребляемому индикатором. Я поставил резисторы 470 Ом —  я их везде ставлю, потому что мне прислали упаковку 1000 штук в нагрузку к светодиодам для светодиодного куба.   3. Нужно нарисовать простую таблицу истинности для вывода всех возможных цифр. Я подключил сегменты к порту A по порядку, т.е. a/PA0 .. g/PA6. Сразу вычислим &#171;коды&#187; этих цифр, т.е. значения которые нужно будет отправлять в порт.

[<img class="alignnone size-full wp-image-1713" src="/wp-content/uploads/2014/06/7-seg.png" alt="7-seg" width="99" height="148" />](/wp-content/uploads/2014/06/7-seg.png)</p>
<table>
<tr>
<td>
Цифра
</td>

<td>
</td>

<td>
1
</td>

<td>
2
</td>

<td>
3
</td>

<td>
4
</td>

<td>
5
</td>

<td>
6
</td>

<td>
7
</td>

<td>
8
</td>

<td>
9
</td>
</tr>

<tr>
<td>
Картинка
</td>

<td>
<a href="/wp-content/uploads/2014/06/0.png"><img class="alignnone size-full wp-image-1705" src="/wp-content/uploads/2014/06/0.png" alt="0" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/1.png"><img class="alignnone size-full wp-image-1706" src="/wp-content/uploads/2014/06/1.png" alt="1" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/2.png"><img class="alignnone size-full wp-image-1707" src="/wp-content/uploads/2014/06/2.png" alt="2" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/3.png"><img class="alignnone size-full wp-image-1708" src="/wp-content/uploads/2014/06/3.png" alt="3" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/4.png"><img class="alignnone size-full wp-image-1709" src="/wp-content/uploads/2014/06/4.png" alt="4" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/5.png"><img class="alignnone size-full wp-image-1710" src="/wp-content/uploads/2014/06/5.png" alt="5" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/6.png"><img class="alignnone size-full wp-image-1711" src="/wp-content/uploads/2014/06/6.png" alt="6" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/7.png"><img class="alignnone size-full wp-image-1712" src="/wp-content/uploads/2014/06/7.png" alt="7" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/8.png"><img class="alignnone size-full wp-image-1714" src="/wp-content/uploads/2014/06/8.png" alt="8" width="40" /></a>
</td>

<td>
<a href="/wp-content/uploads/2014/06/9.png"><img class="alignnone size-full wp-image-1715" src="/wp-content/uploads/2014/06/9.png" alt="9" width="40" /></a>
</td>
</tr>

<tr>
<td>
Включены
</td>

<td>
abcdef
</td>

<td>
bc
</td>

<td>
abdeg
</td>

<td>
abcdg
</td>

<td>
bcfg
</td>

<td>
acdfg
</td>

<td>
acdefg
</td>

<td>
abc
</td>

<td>
abcdefg
</td>

<td>
abcdfg
</td>
</tr>

<tr>
<td>
Выключены
</td>

<td>
g
</td>

<td>
defg
</td>

<td>
cf
</td>

<td>
ef
</td>

<td>
ade
</td>

<td>
be
</td>

<td>
b
</td>

<td>
def
</td>

<td>
</td>

<td>
e
</td>
</tr>

<tr>
<td>
Код
</td>

<td>
64
</td>

<td>
121
</td>

<td>
36
</td>

<td>
48
</td>

<td>
25
</td>

<td>
18
</td>

<td>
2
</td>

<td>
120
</td>

<td>
</td>

<td>
16
</td>
</tr>

<tr>
<td>
HEX
</td>

<td>
0x40
</td>

<td>
0x79
</td>

<td>
0x24
</td>

<td>
0x30
</td>

<td>
0x19
</td>

<td>
0x12
</td>

<td>
0x02
</td>

<td>
0x78
</td>

<td>
0x00
</td>

<td>
0x10
</td>
</tr>
</table>

Простейшая программа для STM32, которая по очереди выводит на индикатор все цифры по кругу.

M4H07594

Кстати, я использую индикатор Kingbright SA56–11EWA.

void delay()
{
volatile unsigned long int i=0;
for(i=0; i<500000; i++);
}

void main()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIOA->ODR=GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->ODR=0;

unsigned short int digits[10] = {64, 121, 36, 48, 25, 18, 2, 120, 0, 16};
unsigned short int index = 0;

while(1)
{
GPIOA->ODR=digits[index++];
if(index>9) index=0;
delay();
}
}

Несколько индикаторов

Небольшое усложнение прошлого проекта, теперь подключим три семисегментных индикатора к плате STM32VLDiscovery. Потребуется 7 * 3 = 21 контакт ввода–вывода для катодов, а аноды всех индикаторов будут подключены к плюсу. Я не стану этого делать, потому что здесь мало что отличается от прошлого способа, перейду сразу к более интересному.

 

Динамическая индикация

Прошлый способ использовал очень много ножек ввода–вывода, и это быстро становится проблемой. Также цифры были очень тусклыми, поскольку теперь предельный ток питания МК делился на все индикаторы. Ставить же отдельный транзистор на каждый сегмент не то, чтобы дорого — но довольно неудобно. Этих недостатков лишена динамическая индикация.

Идея очень проста: заводим аноды индикаторов на ножки ввода–вывода и используем их как «выключатели» отдельных индикаторов, а одноимённые сегменты каждого индикатора параллелим и тоже подключаем к МК.

dyn

К счастью, это не нужно делать вручную — продаётся множество готовых индикаторов, сделанных по этому принципу. Я применяю CA56–12YWA.

Включив первый индикатор, выводим нужную цифру — она отображается только на первом индикаторе. Выключаем первый индикатор, включаем второй и выводим его цифру — и так далее по кругу. Если делать это с достаточной скоростью, мигание становится незаметным, и появляется ощущение постоянного отображения всех цифр.

M4H07595M4H07600M4H07603

Благодаря малому количеству контактов, в этом методе хорошо всё:

  • все линии можно включить через транзисторы и использовать большой ток сегмента
  • требуется мало дорожек на плате

Мерцание устраняется простым повышением частоты обновления, только не нужно делать десятки килогерц. К примеру, моим глазам достаточно FPS 50 Гц, в 4–цифровом варианте требуется переключать индикаторы с частотой 200 Гц.

void delay()
{
volatile unsigned long int i=0;
for(i=0; i<6000; i++);
}

void main()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIOA->ODR=GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->ODR=0;

unsigned short int digits[10] = {64, 121, 36, 48, 25, 18, 2, 120, 0, 16};
unsigned short int index = 0;

while(1)
{
GPIOA->ODR=digits[1]; GPIOC->ODR=GPIO_Pin_0; delay();
GPIOA->ODR=digits[2]; GPIOC->ODR=GPIO_Pin_1; delay();
GPIOA->ODR=digits[3]; GPIOC->ODR=GPIO_Pin_2; delay();
GPIOA->ODR=digits[4]; GPIOC->ODR=GPIO_Pin_3; delay();
}
}
Ссылка на основную публикацию
Optimized with PageSpeed Ninja