№ 2965 В разделах: Electronics
Programming
от June 12th, 2011,
В подшивках: Displays, MSP430
?Я все не перестаю баловаться отладочной платкой MSP-EXP430G2 Launchpad, задаренной мне ZiB’ом (за что ему, кстати, огромное спасибо. я приобрел много опыта на ней).
Теорию и схему рекомендую прочитать в статье, общей для всех микроконтроллеров про вывод чисел на 7-сегментные индикаторы.
Способ первый и самый простой
В данном примере возможно выводить хоть и на все 3 цифры на индикаторе, но все равно одну и туже информацию. Подключение очень простое: через резисторы по 1 кОм подключены напрямую к всем 8 выводам микроконтроллера. Общий анод подключен к +3.5 на плате.
Этот способ не очень примечателен, т.к. малофункционален и забирает под себя все свободные пины у микроконтроллера, но ярко показывает принцип работы с такими индикаторами.
А вот и мой говнокод:
#include "io430.h"
void show(int num, int duration) {
unsigned char digits[]=
{
0xF7,
0xC4,
0x6B,
0xEE,
0xDC,
0xBE,
0xBF,
0xE4,
0xFF,
0xFE
};
P1OUT ^= digits[num];
for(double i=0; i <duration ; i++);
P1OUT ^= digits[num];
}
int main( void )
{
//Останавливаем watchdog
WDTCTL = WDTPW + WDTHOLD;
//Включаем вывод на пинах микроконтроллера
P1DIR |= 0xFF;
int n=0;
for(;;) {
show(n,1000);
n++;
if (n==10) n=0;
}
return 0;
}
Обратите внимание, что код неполный, т.к. подключен всего один индикатор из трех.
Теперь подключим сдвиговый регистр 74HC595
Здесь подключение индикатора к регистру также не выделяется ничем примечательным – пины данных индикатора подключаются к 8 выводам для данных на регистре. Сам регистр подключается к МК к любым выбранным вам выводам (я выбрал 0, 1, 2, 3). Итого имеем 4 ноги от регистра к МК для управления регистром и 3 ноги от общих анодов к остальным 3 выводам МК (остается еще 1 пин на МК, на который можно что-нибудь подключить, но об этом попозже).
Вначале все было хорошо, но меня огорчала проблема с точкой возле самой первой выводимой цифры, которая появлялась всего 1 раз при включении устройства. Конечно, я делал сброс регистра перед его использованием, но, как оказалось, помимо импульса защелки надо слать перед этим еще и 1 тактовый импульс.
#include "msp430g2231.h"
//ноги МК к которым подключен сдвиговый регистр
#define REG_MR 3
#define REG_SHCP 0
#define REG_STCP 1
#define REG_DS 2
//три цифры на индикаторе соединены с другими 3 ногами на МК
#define IND1 4
#define IND2 5
#define IND3 7
void show(int num) {
int num_ = num;
static unsigned char digits[]=
{
0x88, //0
0xBB, //1
0x94, //2
0x91, //3
0xA3, //4
0xC1, //5
0xC0, //6
0x9B, //7
0x80, //8
0x81 //9
};
unsigned char value;
value = digits[num];
for(int i = 8; i; --i)
{
if(value & 0x80)
P1OUT |= 1<<REG_DS; //1
else
P1OUT &= ~(1<<REG_DS); //0
P1OUT |= 1<<REG_SHCP;
P1OUT &= ~(1<<REG_SHCP);
value <<= 1;
}
P1OUT &= ~(1<<REG_DS);
P1OUT |= 1<<REG_STCP;
P1OUT &= ~(1<<REG_STCP);
P1OUT |= 1<<REG_STCP;
}
int main( void )
{
//Выключаем watchdog
WDTCTL = WDTPW + WDTHOLD;
//Настраиваем порт МК для вывода
P1DIR |= 0xFF;
//Инициализируем регистр и включаем только первую цифру на индикаторе
P1OUT |= (1<<REG_MR)|(1<<REG_SHCP)|(1<<REG_STCP)|(1<<REG_DS);
P1OUT &= ~(1<<IND1);
P1OUT &= ~(1<<IND2);
P1OUT &= ~(1<<IND3);
P1OUT |= (1<<IND1);
//Сбрасываем регистр
P1OUT |= 1<<REG_STCP;
P1OUT &= ~(1<<REG_MR); //включаем ногу сброса регистра
P1OUT |= 1<<REG_SHCP; //ГРАБЛИ! ВЫДАТЬ ТАКТ ОБЯЗАТЕЛЬНО!
P1OUT &= ~(1<<REG_SHCP);
P1OUT &= ~(1<<REG_STCP); //ДЕРГАЕМ ЗАЩЕЛКУ!
P1OUT |= 1<<REG_STCP;
P1OUT |= 1<<REG_MR; //выключаем сброс
//а тут мы выводим циклом цифры от 0 до 9
int n=0;
for(;;) {
show(n);
n++;
if (n==10) n=0;
//небольшая пауза. знаю, что правильней таймером
//попозже используем и его
for(double i=0; i <3000 ; i++);
}
return 0;
}
А теперь применим динамическую развертку с таймерами, прерываниями, блэкджеком и шлюхами
#include "msp430g2231.h"
#define REG_MR 3
#define REG_SHCP 0
#define REG_STCP 1
#define REG_DS 2
#define IND1 4
#define IND2 5
#define IND3 7
unsigned int C0=0, C1=0, C2=0; //индексы для массива знаков
void get_indexes(int num) {
//вывод обычного натурального числа (беззнаковое, целое)
int C0_=0, C1_=0, C2_=0; //это нужно чтобы переменная записалась в
//глобальные только после обсчета, а не во время его
while(num > 0) {
//отнимаем тысячи
if (num > 100) {
num = num - 100;
C0_++;
} else {
//отнимаем сотни
if (num > 10) {
num = num - 10;
C1_++;
} else {
//отнимаем десятки
if (num >= 1) {
num = num - 1;
C2_++;
}
if (C2_ > 9) { C2_=0; C1_++;}
}
if (C1_ > 9) { C1_=0; C0_++; }
}
if (C0_ > 9) { C0_=0; }
}
C0=C0_; C1=C1_; C2=C2_;
//если первая цифра 0, то не зажигаем ничего. последний 0 будет показываться!
//if (C0 == 0) { C0=11; }
//if ((C0 + C1) == 0) { C0=C1=11; }
//if ((C0 + C1 + C2) == 0) { C0=C1=C2=11; }
}
void show_symbol(int index) {
static unsigned char digits[]=
{
0x88, //0
0xBB, //1
0x94, //2
0x91, //3
0xA3, //4
0xC1, //5
0xC0, //6
0x9B, //7
0x80, //8
0x81, //9
0xFF //пусто
};
unsigned char value;
value = digits[index];
for(int i = 8; i; --i)
{
if(value & 0x80)
P1OUT |= 1<<REG_DS; //1
else
P1OUT &= ~(1<<REG_DS); //0
P1OUT |= 1<<REG_SHCP;
P1OUT &= ~(1<<REG_SHCP);
value <<= 1;
}
P1OUT &= ~(1<<REG_DS);
P1OUT |= 1<<REG_STCP;
P1OUT &= ~(1<<REG_STCP);
P1OUT |= 1<<REG_STCP;
}
int main( void )
{
// Останавливаем watchdog
WDTCTL = WDTPW + WDTHOLD;
//Инициализируем порт МК
P1DIR |= 0xFF;
//Настраиваем таймер
CCTL0 = CCIE;
CCR0 = 300;
TACTL = TASSEL_1 + MC_1;
__enable_interrupt();
P1OUT |= (1<<REG_MR)|(1<<REG_SHCP)|(1<<REG_STCP)|(1<<REG_DS);
P1OUT &= ~(1<<IND1);
P1OUT &= ~(1<<IND2);
P1OUT &= ~(1<<IND3);
//Сбрасываем сдвиговый регистр
P1OUT |= 1<<REG_STCP;
P1OUT &= ~(1<<REG_MR);
P1OUT |= 1<<REG_SHCP;
P1OUT &= ~(1<<REG_SHCP);
P1OUT &= ~(1<<REG_STCP);
P1OUT |= 1<<REG_STCP;
P1OUT |= 1<<REG_MR;
int n=0;
for(;;) {
get_indexes(n);
n++;
if (n==129) n=0;
for(double i=0; i <150 ; i++);
}
return 0;
}
//Обработка таймера
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0 (void) {
// 1
show_symbol(C2);
P1OUT |= (1<<IND1);
for(double i=0; i <15 ; i++);
P1OUT &= ~(1<<IND1);
// 2
show_symbol(C1);
P1OUT |= (1<<IND2);
for(double i=0; i <15 ; i++);
P1OUT &= ~(1<<IND2);
// 3
show_symbol(C0);
P1OUT |= (1<<IND3);
for(double i=0; i <15 ; i++);
P1OUT &= ~(1<<IND3);
}
Fortune cookie: A lady from Kalamazoo Once found she had nothing to do, So she sat on the stairs And she counted her hairs: 4,302.
а схемку приложить? не удобно на провода глядеть
нет там никакой изощреной схемки. 8 сегментов индикатора подключаются либо напрямую к чипу, либо к регистру. Ну а катоды подключаешь к чипу. В чипе и определяешь какому сегменту светиться.
вот пример подключения
8 проводов до регистра это сегменты твои, а 2 провода до МК определяют какому индикатору надо гореть в данный момент. алгоритм такой: отключаешь второй индикатор, заслал байт в регистр, нарисовав в памяти регистра нужную циферку, дергаешь “защелку” (latch – переключить ножки регистра на состояние, записанное в память регистра) и включаешь на 5 мс первый индикатор. потом загружаешь еще один байт в регистр, отключаешь первый индикатор, дергаешь защелку и ножки регистра опять переключаются на текущее состояние памяти, включаешь второй индикатор на 5 мс. вот и всё.
еще вопрос – хватает ли тока с ног msp430? у меня индикатор BA-5612-GWA
хватит. если вдруг не хватит, то подключай через транзисторы 🙂 не забудь подтяжки на 330 ом сунуть.
int C0_=0, C1_=0, C2_=0; //это нужно чтобы переменная записалась в глобальные только после обсчета, а не во время его
Боюсь что микроконтроллеру пофиг на то какая это переменная, глобальная или локальная. Компилятор распихает Ci по свободным регистрам, и их инкрементирование будет проводиться одной ассемблерной командой INC. Так что это overhead в данном случае…
Ну а так хороший примерчик, буду пробовать!
не, не все равно. присвоение будет только после того, как все посчитается.
А вы бы все же не могли прикрепить схему? Так как сделали все как у вас, но проект не работает. Только учимся работать…увы многого не понимаем. И еще у вас случайно индикатор не BA56-12GWA?
схему чего именно? там дофига всяких способов от прямого подключения 8 ножек к МК до объединения нескольких индикаторов через сдвиговые регистры.
хрен его знает какой он. любой подойдет.
Проблема вот в чем. Припаяли индикатор BA56-12GWA, поставили регистр 74HCT595. Начинаем отладку и уже вот после такой строчки WDTCTL = WDTPW + WDTHOLD; P1DIR |= 0xff; загорается индикатор. И все он горит так до позеленения. Ему абсолютно пофиг что потом должен выполняться другой кусок кода. Подскажите что может быть не так..
программу то покажете?
регистр подключен 8 ножками к катодам индикатора? 4 линии управления регистром подключены к МК? не забывай подключить общий анод к МК (лучше даже через транзистор как тут http://pic-avr.narod.ru/stend/7-SegmLCD-74HC595.GIF)
твоя задача оттарабанить ножкой DS и CTCP байт, дернуть защелкой и включить первый индикатор. потом сделать тоже самое для второго индикатора, выключив первый. переключения должны происходить так быстро, что глаз будет это воспринимать как постоянное свечение.
Вот так у меня все подключено. http://s2.ipicture.ru/uploads/20120506/RA79Wp7F.png
А код использую точь в точь как у вас. Что не так я хз.
Блин я тут у вас пытаюсь разместить картинку с подключением выводов. не получается..
Схема подключения http://s2.ipicture.ru/uploads/20120506/RA79Wp7F.png
Схема подключения
а подключены пины то правильно?
посмотрел схему, сравнил с программой. вроде правильно все. проверь все соединения. не должен гореть только 1 сегмент.