sobota, 12 grudnia 2015

[10b] STM32 M3 - Nucleo - F103RB - Ekspander portów GPIO cz. 2 - obsługa przycisku

Ten post będzie kontynuacją poprzedniego, który dotyczył obsługi ekspandera portów GPIO. Tym razem przedstawię jak obsługiwać za jego pomocą przyciski.

Wszystkie istotne informacje zostały umieszczone bezpośrednio w programie w formie komentarzy.

Działanie polega na tym, że w momencie przyciśnięcia przycisku następuje zapalenie kolejnej diody. Zostały one podłączone poprzez rezystor 1kOhm do wyprowadzeń od GP0 do GP3. Do portu GP4 został podłączony przycisk.

W celu odczytania stanu panującego na linii należy wystawić stan niski na linię CS, po czym wysłać dane do rejestru, informując układ, że nastąpi odczytywanie danych. Dana z rejestu zostaje odczytana i przesłana i wysłana do mikrokontrolera.  Jeżeli przycisk został wciśnięty, czyli linia została zwarta do masy nastąpi wykonywanie zadania w pętli.


#include "stm32f10x.h"
 
//Deklaracja rejestrów
#define MCP_IODIR  0x00
#define MCP_IPOL  0x01
#define MCP_GPINTEN  0x02
#define MCP_DEFVAL  0x03
#define MCP_INTCON  0x04
#define MCP_IOCON  0x05
#define MCP_GPPU  0x06
#define MCP_INTF  0x07
#define MCP_INTCAP  0x08
#define MCP_GPIO  0x09
#define MCP_OLAT  0x0a
 
//Deklaracja pinów
#define CS_PIN   GPIO_Pin_0
#define CS_LINE   GPIOC
 
#define SCK_PIN   GPIO_Pin_5
#define SCK_LINE  GPIOA
 
#define MISO_PIN  GPIO_Pin_6
#define MISO_LINE  GPIOA
 
#define MOSI_PIN  GPIO_Pin_7
#define MOSI_LINE  GPIOA
 
void SPIInit(void);
void GPIOInit(void);
uint8_t SPI_SEND(uint8_t);
void MCP_WRITE(uint8_t, uint8_t);
uint8_t MCP_READ(uint8_t);
void Delay(int);
 
int main(void)
{
 volatile int wcisniecie = 0;
 
 GPIOInit();
 SPIInit();
 
 MCP_WRITE(MCP_IODIR, ~0x0F);
 //Podłączenie rejestu podciągającego do linii GP4                                                                                             MCP_WRITE(MCP_GPPU, 0x10);
 
 while (1)
 {
  if ((MCP_READ(MCP_GPIO) & 0x10) == 0)
  {
   Delay(200);
   wcisniecie++;
    switch(wcisniecie)
    {
    case 1: {
     MCP_WRITE(MCP_OLAT, 0x01);
     break;
    }
    case 2:
    {
     MCP_WRITE(MCP_OLAT, 0x03);
     break;
    }
    case 3:
    {
     MCP_WRITE(MCP_OLAT, 0x07);
     break;
    }
    case 4:
    {
     MCP_WRITE(MCP_OLAT, 0x0f);
     break;
    }
    case 5:
    {
     MCP_WRITE(MCP_OLAT, 0x00);
     Delay(10);
     wcisniecie = 0;
    }
   }
  }
 }
}
 
void SPIInit(void)
{
  SPI_InitTypeDef SPIInit;
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
 
  SPI_StructInit(&SPIInit);
  //Transmisja z wykorzystaniem dwóch linii
  SPIInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  //Tryb pracy mikrokontrolera
  SPIInit.SPI_Mode = SPI_Mode_Master;
  //Stan sygnału taktującego przy braku transmisji
  SPIInit.SPI_CPOL = SPI_CPOL_Low;
  //Aktywne zbocze sygnału taktującego
  SPIInit.SPI_CPHA = SPI_CPHA_1Edge;
  //Wylaczenie sprzetowej obslugi linii CS
  SPIInit.SPI_NSS = SPI_NSS_Soft;
  //Szybkośc transmisji 64MHz/16 = 4MHz
  SPIInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
  //Inicjalizacja SPI
  SPI_Init(SPI1, &SPIInit);
  //Włączenie SPI
  SPI_Cmd(SPI1, ENABLE);
}
 
//Ustawienie pinów SPI
void GPIOInit(void)
{
  GPIO_InitTypeDef GPIOInit;
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
 
  GPIO_StructInit(&GPIOInit);
 
  //piny SCK, MOSI
  GPIOInit.GPIO_Pin = SCK_PIN|MOSI_PIN; // SCK, MOSI
  GPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SCK_LINE, &GPIOInit);
 
  //Pin Miso
  GPIOInit.GPIO_Pin = MISO_PIN; // MISO
  GPIOInit.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIOInit.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(MISO_LINE, &GPIOInit);
 
  //Pin CS
  GPIOInit.GPIO_Pin = CS_PIN;
  GPIOInit.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIOInit.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(CS_LINE, &GPIOInit);
 
  //Ustawienie pinu CS na niski, następuje wybranie urządzenia
  GPIO_SetBits(GPIOC, GPIO_Pin_0);
}
 
//Wyslanie danych
uint8_t SPI_SEND(uint8_t byte)
{
  //Sprawdzanie zajętości bufora nadawczego, jak będzie wolny nastąpi wysłanie danych
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPI1, byte);
 
  //Sprawdzanie, czy dane są w buforze odbiorczym, jeśli tak to zostaną zwrócone
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
  return SPI_I2S_ReceiveData(SPI1);
}
 
//Wpisanie danych do rejestrów
void MCP_WRITE(uint8_t rejestr, uint8_t wartosc)
{
  //Ustawienie pinu CS na stan niski, wybranie urządzenia
  GPIO_ResetBits(CS_LINE, CS_PIN);
  //wpisanie danych do CS.
  SPI_SEND(0x40);
  //wyslanie informacji do którego rejestru dane zostaną przesłane
  SPI_SEND(rejestr);
  //wysłanie ustawienia wartości
  SPI_SEND(wartosc);
  //Zakończenie transmisji, zmiana stanu linii CS na wysoki
  GPIO_SetBits(CS_LINE, CS_PIN);
}
 
//Odczytanie danych z rejestru
uint8_t MCP_READ(uint8_t addr)
{
 //Inicjalizacja zmiennej
 uint8_t VAL = 0;
 //Stan niski na pic CS wybranie urządzenia
 GPIO_ResetBits(CS_LINE, CS_PIN);
 //Tym razem wprowadzamy dane, więc bit R/W z 0 na 1 co daje 0x41 całościowo
 SPI_SEND(0x41);
 SPI_SEND(addr);
 //Przypisanie wartości do zmiennej
 VAL = SPI_SEND(0xff);
 //Zmiana stanu na linii CS
 GPIO_SetBits(CS_LINE, CS_PIN);
 return VAL;
}
 
void Delay(int czas)
{
    int i;
    for (i = 0; i < czas * 5000; i++) {}
}