wtorek, 1 grudnia 2015

[9] STM32 M3 - Nucleo - F103RB - Wyświetlacz 7-seg

Tym razem przedstawię obsługę wyświetlacza 7-segmentowego za pomocą mikrokontrolera STM32.

Wstęp


Do obsługi wyświetlacza wykorzystuje gotowy moduł zaprezentowany razem z podpisanymi wyprowadzeniami na rysunku 1.1.

Rys. 1. Wyświetlacz 7 segmentowy


Określony segment zostanie zapalony po wybraniu danego wyświetlacza, oraz podaniu stanu niskiego na określone wyprowadzenie od a do h.

Podłączenie


Poszczególne wyprowadzanie modułu zostały podłączone do następujących pinów:
  • VCC - 3,3V
  • a - GPIOA Pin1
  • b - GPIOA Pin12
  • c - GPIOA Pin11
  • d - GPIOA Pin4
  • e - GPIOA Pin6
  • f - GPIOA Pin7
  • g - GPIOA Pin8
  • h - GPIOA Pin9
  • 1 - GPIOB Pin5
  • 2 - GPIOB Pin6
  • 3 - GPIOB Pin13
  • 4 - GPIOB Pin14
Wszystkie wyprowadzenia można zmieniać korzystając z deklaracji znajdujących się na samym początku kodu. Można dodatkowo wprowadzić rezystory ograniczają płynące prąd. Wtedy należy je połączyć szeregowo do każdej z linii.

Program


Pierwszy program pozwala na wyświetlenie odpowiednio zdefiniowanych cyfr na wybranym wyświetlaczu.

W programie głównym wyświetlana jest cyfra 9 z częstotliwością pozwalającą na złudzenie działania czterech segmentów na raz.

Działanie programu opiera się na odpowiednim ustawieniu dwóch rejestrów BSRR oraz BRR. Pierwszy z nich podaje stan wysoki na wybrany pinie, drugi natomiast podaje stan niski.

#include "stm32f10x.h"
 
#define SegLine GPIOA
#define SegA GPIO_Pin_1
#define SegB GPIO_Pin_12
#define SegC GPIO_Pin_11
#define SegD GPIO_Pin_4
#define SegE GPIO_Pin_6
#define SegF GPIO_Pin_7
#define SegG GPIO_Pin_8
#define SegH GPIO_Pin_9
 
#define WysLine GPIOB
#define Wys1 GPIO_Pin_5
#define Wys2 GPIO_Pin_6
#define Wys3 GPIO_Pin_13
#define Wys4 GPIO_Pin_14
 
volatile uint32_t timer = 0;
 
void GPIOInit(void);
void Wyswietlacz(char);
void Cyfra(char);
void DelayMs(uint32_t);
void SysTick_Handler();
void DelayInitial(void);
 
int main(void)
{
 GPIOInit();
 DelayInitial();
 
 while(1)
 {
   //Cyfra 9 na wszystkich
   Wyswietlacz('1');
   Cyfra('9');
   DelayMs(5);
 
   Wyswietlacz('2');
   Cyfra('9');
   DelayMs(5);
 
   Wyswietlacz('3');
   Cyfra('9');
   DelayMs(5);
 
   Wyswietlacz('4');
   Cyfra('9');
   DelayMs(5);
 }
}
 
void GPIOInit(void)
{
    //inicjalizacja obiektu GPIO
    GPIO_InitTypeDef GpioInit;
 
    //Włączenie zegara
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
 
    GPIO_StructInit(&GpioInit);
    GpioInit.GPIO_Pin = SegA | SegB | SegC | SegD | SegE | SegF |SegG | SegH;
    //Ustawienie pinu jak wyjście PushPull
    GpioInit.GPIO_Mode = GPIO_Mode_Out_PP;
    //Ustawienie częstotliwości portu
    GpioInit.GPIO_Speed = GPIO_Speed_50MHz;
    //Inicjalizacja linii z podanymi ustawieniami
    GPIO_Init(SegLine, &GpioInit);
 
    GpioInit.GPIO_Pin = Wys1 | Wys2 | Wys3 | Wys4;
    //Ustawienie pinu jak wyjście PushPull
    GpioInit.GPIO_Mode = GPIO_Mode_Out_PP;
    //Ustawienie częstotliwości portu
    GpioInit.GPIO_Speed = GPIO_Speed_50MHz;
    //Inicjalizacja linii z podanymi ustawieniami
    GPIO_Init(WysLine, &GpioInit);
}
 
void DelayInitial(void)
{
 //Ustawienie opóźnień co 1ms = 64000000 / 1000
 SysTick_Config(SystemCoreClock / 1000);
}
 
void SysTick_Handler()
{
 if(timer)
 {
  timer--;
 }
}
 
void DelayMs(uint32_t time)
{
 timer = time;
 while(timer)
 {}
}
 
//Odpalenie wyswietlacza następuje po przez podanie stanu wysokiego na wyprowadzenie
//Wybór od 1 do 4, wpisanie O wylacza wszystkie wyswietlacze
void Wyswietlacz(char i)
{
 switch (i)
 {
  case '1':
  {
   WysLine->BSRR = Wys1;
   WysLine->BRR = Wys2;
   WysLine->BRR = Wys3;
   WysLine->BRR = Wys4;
   break;
  }
  case '2':
  {
   WysLine->BRR = Wys1;
   WysLine->BSRR = Wys2;
   WysLine->BRR = Wys3;
   WysLine->BRR = Wys4;
   break;
  }
  case '3':
  {
   WysLine->BRR = Wys1;
   WysLine->BRR = Wys2;
   WysLine->BSRR = Wys3;
   WysLine->BRR = Wys4;
   break;
  }
  case '4':
  {
   WysLine->BRR = Wys1;
   WysLine->BRR = Wys2;
   WysLine->BRR = Wys3;
   WysLine->BSRR = Wys4;
   break;
  }
  case 'O':
  {
   WysLine->BRR = Wys1;
   WysLine->BRR = Wys2;
   WysLine->BRR = Wys3;
   WysLine->BRR = Wys4;
   break;
  }
  default:
   break;
 }
}
 
//Wyswietlenie wybranej cyfry od 0 do 9, kropki wpisz(.) lub samej kropki (wpipsz k),
//wylaczenie wszystkich segmentów po wpisaniu O
void Cyfra(char i)
{
 switch (i)
 {
  case '0':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BSRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '1':
  {
   SegLine->BSRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BSRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BSRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '2':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BSRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '3':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '4':
  {
   SegLine->BSRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BSRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '5':
  {
   SegLine->BRR = SegA;
   SegLine->BSRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '6':
  {
   SegLine->BRR = SegA;
   SegLine->BSRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '7':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BSRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BSRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '8':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '9':
  {
   SegLine->BRR = SegA;
   SegLine->BRR = SegB;
   SegLine->BRR = SegC;
   SegLine->BRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BRR = SegF;
   SegLine->BRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case 'O':
  {
   SegLine->BSRR = SegA;
   SegLine->BSRR = SegB;
   SegLine->BSRR = SegC;
   SegLine->BSRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BSRR = SegG;
   SegLine->BSRR = SegH;
   break;
  }
  case '.':
  {
   SegLine->BRR = SegH;
   break;
  }
  case 'k':
  {
   SegLine->BSRR = SegA;
   SegLine->BSRR = SegB;
   SegLine->BSRR = SegC;
   SegLine->BSRR = SegD;
   SegLine->BSRR = SegE;
   SegLine->BSRR = SegF;
   SegLine->BSRR = SegG;
   SegLine->BRR = SegH;
   break;
  }
  default:
   break;
 }
}

Podłączony układ przedstawiłem na rysunku 2. 

Rys. 2. Wyświetlacz działanie - wyświetlanie cyfry 9

Może się tak zdarzyć, że ustawiona częstotliwość będzie odpowiednia do obserwacji wszystkich cyfr zapalonych na wyświetlaczu przez oko ludzkie, natomiast będzie można zaobserwować przełączania np. podczas nagrywania filmu. Ma to związek z niedopasowaniem częstotliwości nagrywania do zmian segmentów wyświetlacza. Przez to w niektórych miejscach może się ona rozjeżdżać.

Jeśli chodzi o sterowanie wyświetlanymi danymi, to można wykorzystać do tego pętle while, for czy do..while.