INT 21h

Select language

Управление 7-сегментным индикатором, динамическая развертка, MSP430G2231 (MSP430) и регистр 74HC595

№ 2965 В разделах: Electronics Programming от June 12th, 2011,
В подшивках: ,

?Я все не перестаю баловаться отладочной платкой 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);
}

17 комментариев »

17 responses to “Управление 7-сегментным индикатором, динамическая развертка, MSP430G2231 (MSP430) и регистр 74HC595”

  1. nomad says:

    а схемку приложить? не удобно на провода глядеть

  2. 21h says:

    нет там никакой изощреной схемки. 8 сегментов индикатора подключаются либо напрямую к чипу, либо к регистру. Ну а катоды подключаешь к чипу. В чипе и определяешь какому сегменту светиться.

    вот пример подключения

    8 проводов до регистра это сегменты твои, а 2 провода до МК определяют какому индикатору надо гореть в данный момент. алгоритм такой: отключаешь второй индикатор, заслал байт в регистр, нарисовав в памяти регистра нужную циферку, дергаешь “защелку” (latch – переключить ножки регистра на состояние, записанное в память регистра) и включаешь на 5 мс первый индикатор. потом загружаешь еще один байт в регистр, отключаешь первый индикатор, дергаешь защелку и ножки регистра опять переключаются на текущее состояние памяти, включаешь второй индикатор на 5 мс. вот и всё.

  3. nomad says:

    еще вопрос – хватает ли тока с ног msp430? у меня индикатор BA-5612-GWA

  4. 21h says:

    хватит. если вдруг не хватит, то подключай через транзисторы 🙂 не забудь подтяжки на 330 ом сунуть.

  5. nomad says:

    int C0_=0, C1_=0, C2_=0; //это нужно чтобы переменная записалась в глобальные только после обсчета, а не во время его
    Боюсь что микроконтроллеру пофиг на то какая это переменная, глобальная или локальная. Компилятор распихает Ci по свободным регистрам, и их инкрементирование будет проводиться одной ассемблерной командой INC. Так что это overhead в данном случае…
    Ну а так хороший примерчик, буду пробовать!

  6. 21h says:

    не, не все равно. присвоение будет только после того, как все посчитается.

  7. Gruzil0 says:

    А вы бы все же не могли прикрепить схему? Так как сделали все как у вас, но проект не работает. Только учимся работать…увы многого не понимаем. И еще у вас случайно индикатор не BA56-12GWA?

  8. 21h says:

    схему чего именно? там дофига всяких способов от прямого подключения 8 ножек к МК до объединения нескольких индикаторов через сдвиговые регистры.

    хрен его знает какой он. любой подойдет.

  9. Gruzil0 says:

    Проблема вот в чем. Припаяли индикатор BA56-12GWA, поставили регистр 74HCT595. Начинаем отладку и уже вот после такой строчки WDTCTL = WDTPW + WDTHOLD; P1DIR |= 0xff; загорается индикатор. И все он горит так до позеленения. Ему абсолютно пофиг что потом должен выполняться другой кусок кода. Подскажите что может быть не так..

  10. 21h says:

    программу то покажете?

    регистр подключен 8 ножками к катодам индикатора? 4 линии управления регистром подключены к МК? не забывай подключить общий анод к МК (лучше даже через транзистор как тут http://pic-avr.narod.ru/stend/7-SegmLCD-74HC595.GIF)

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

  11. Gruzil0 says:

    Вот так у меня все подключено. http://s2.ipicture.ru/uploads/20120506/RA79Wp7F.png

  12. Gruzil0 says:

    А код использую точь в точь как у вас. Что не так я хз.

  13. Gruzil0 says:

    Блин я тут у вас пытаюсь разместить картинку с подключением выводов. не получается..

  14. Gruzil0 says:

    Схема подключения http://s2.ipicture.ru/uploads/20120506/RA79Wp7F.png

  15. Gruzil0 says:

    Схема подключения

  16. 21h says:

    а подключены пины то правильно?

  17. 21h says:

    посмотрел схему, сравнил с программой. вроде правильно все. проверь все соединения. не должен гореть только 1 сегмент.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Облачная платформа
Яндекс.Метрика

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.