Skocz do zawartości

Kurs STM32 F1 HAL - #9 - SPI w praktyce, ekspander IO


Pomocna odpowiedź

html_mig_img
Poznaliśmy już jeden interfejs szeregowy, który był asynchroniczny. Oczywiście chodzi o UART. Teraz dla odmiany pora na bardzo popularny, interfejs synchroniczny, którym jest  SPI.W tej części kursu STM32 wykorzystamy go do podłączenia ekspandera portów.

UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.

Przeczytaj całość »

Poniżej znajdują się komentarze powiązane z tym wpisem.

Link do komentarza
Share on other sites

Podobieństwo do UART bywa mylące.

MISO powinno zostać skonfigurowane na pinie PA6, natomiast pin PA3 jest podpięty pod RX z UART.

Ten sam błąd pojawia się w następnej części części kursu.

  • Lubię! 1
Link do komentarza
Share on other sites

Ja mam pytanie z kolei o "Identyfikator urządzenia" po co go w ogóle wysyłać do ekspandera? Czy to jest po prostu ułatwienie dla czytelności kodu? Nigdzie nie zauważyłem, aby było to wyjaśnione, a sprawa ciekawa 🙂 W dokumentacji scalaka też cisza jeśli chodzi o wartości 0x40 i 0x41.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

@Treker Serdecznie dziękuję za odpowiedź! Teraz wszystko jasne - po za CS, musi iść bajt kontrolny do samego układu. Dziękuję za wyjaśnienie i pokazanie w instrukcji - jak to często u mnie bywa, zbyt szybko ją przewertowałem 🙂

  • Lubię! 1
Link do komentarza
Share on other sites

Cześć!

Zrobiłem zadanie 9.3 Oto mój kod (działa na 4 diodach, bo ciasno mi było montować wszystkie... ;p):

/**
  ******************************************************************************
  * @file    main.c
  * @author  Ac6
  * @version V1.0
  * @date    01-December-2013
  * @brief   Default main function.
  ******************************************************************************
*/


#include "stm32f1xx.h"

#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

SPI_HandleTypeDef spi;

void mcp_write_reg(uint8_t addr, uint8_t value)
{
	uint8_t tx_buf[] = {0x40, addr, value};

	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&spi, tx_buf, 3, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
}

uint8_t mcp_read_reg(uint8_t addr)
{
	uint8_t tx_buf[] = {0x41, addr, 0xff};
	uint8_t rx_buf[3];

	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
	HAL_SPI_TransmitReceive(&spi, tx_buf, rx_buf, 3, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);

	return rx_buf[2];
}

int main(void)
{
	SystemCoreClock = 8000000;

	HAL_Init();

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_SPI1_CLK_ENABLE();

	/* SPI I/O config */

	/* SCK & MOSI */
	GPIO_InitTypeDef gpio;
	gpio.Mode = GPIO_MODE_AF_PP;
	gpio.Pin = GPIO_PIN_5 | GPIO_PIN_7;
	gpio.Pull = GPIO_NOPULL;
	gpio.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &gpio);

	/* MISO */

	gpio.Mode = GPIO_MODE_AF_INPUT;
	gpio.Pin = GPIO_PIN_6;
	HAL_GPIO_Init(GPIOA, &gpio);

	/* CS */

	gpio.Mode = GPIO_MODE_OUTPUT_PP;
	gpio.Pin = GPIO_PIN_0;
	HAL_GPIO_Init(GPIOC, &gpio);

	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);	/* idle state of the conection with slave */

	spi.Instance = SPI1;
	spi.Init.Mode = SPI_MODE_MASTER;
	spi.Init.NSS = SPI_NSS_SOFT;
	spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; /* 1MHz */
	spi.Init.Direction = SPI_DIRECTION_2LINES;
	spi.Init.CLKPhase = SPI_PHASE_1EDGE;
	spi.Init.CLKPolarity = SPI_POLARITY_LOW;
	spi.Init.DataSize = SPI_DATASIZE_8BIT;
	spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
	spi.Init.TIMode = SPI_TIMODE_DISABLE;
	spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
	spi.Init.CRCPolynomial = 7;
	HAL_SPI_Init(&spi);

	__HAL_SPI_ENABLE(&spi);

	mcp_write_reg(MCP_IODIR, ~0x0F);

	mcp_write_reg(MCP_GPPU, 0x10);

	while(1)
	{
		if ((mcp_read_reg(MCP_GPIO) & 0x10) == 0)
		{
			for (int i = 0x00; i<=0x0F; ++i)
			{
				mcp_write_reg(MCP_OLAT, i);
				HAL_Delay(1000);
			}
		}
		else
		{
			for (int i = 0x0F; i>=0x00; --i)
			{
				mcp_write_reg(MCP_OLAT, i);
				HAL_Delay(1000);
			}
		}
	}
}

Niby działa, ale nie jest to najwspanialsze rozwiązanie, gdyż odczyt stanu pinu ekspandera odbywa się po skończeniu pętli. Chciałbym użyć przerwań, aby wykrywać zmianę stanu tego pinu, lecz nie wiem jak się za to zabrać. :<

Czy moglibyście mi pomóc? Dać jakieś wskazówki?

  • Lubię! 1
Link do komentarza
Share on other sites

Dnia 1.02.2019 o 15:52, MaciejZyskowski napisał:

Chciałbym użyć przerwań, aby wykrywać zmianę stanu tego pinu, lecz nie wiem jak się za to zabrać. :<

Czy dobrze rozumiem, że chciałbyś wyzwalać przerwanie w mikrokontrolerze po zmianie stanu na pisanie ekspandera "bez" ciągłego odpytywania ekspandera o stan jego pinów?

Link do komentarza
Share on other sites

Dnia 2.02.2019 o 17:29, Treker napisał:

Czy dobrze rozumiem, że chciałbyś wyzwalać przerwanie w mikrokontrolerze po zmianie stanu na pisanie ekspandera "bez" ciągłego odpytywania ekspandera o stan jego pinów?

Dokładnie to mam na myśli. Obecnie zmiana "kierunku" pracy licznika może obyć się dopiero po zakończeniu pętli. Chciałbym, żeby mogła nastąpić natychmiast po zmianie stanu pinu wejściowego.

Link do komentarza
Share on other sites

@MaciejZyskowski przy takim standardowym podłączeniu nie będzie raczej takiej opcji, bo mikrokontroler nie ma pojęcia co dzieje się na pinach ekspandera (jeśli ich ciągle nie sprawdza). W Twoim przypadku rozwiązaniem może być chyba wykorzystaniu pinu INT, który należałoby osobno podłączyć do STM32. Fragment z noty katalogowej:

26105-2019-02-04_10-15-26-5710.png

Jeśli będziesz chciał zabrać się za ten temat to załóż proszę osobny temat na forum, aby nie "mieszać" tutaj w komentarzach do kursu 🙂

Link do komentarza
Share on other sites

@danielll witam na forum 🙂 Dlaczego uważasz, że taki zapis nie jest poprawny? Porównujemy zwyczajnie dwie wartości za pomocą operatora logicznego i sprawdzamy wynik. Co dokładnie wydaje Ci się tutaj nieodpowiednie? 

Link do komentarza
Share on other sites

Nie za bardzo rozumiem o co w tym chodzi

Gdy przewod laczacy PIN1 z masa jest zwarty to funkcja mcp_read_reg zwraca stan wysoki na tym pinie czyli wartosc 0x02 (00000010). Po co nastepnie ta koniunkcja. Sluzy moze do tego zeby wyzerowac najmlodszy bit gdy dioda jest zaswiecona  (bo wtedy tez jest na niej stan wysoki wiec zostanie odczytana wartosc 0x03) ? 

Edytowano przez danielll
Link do komentarza
Share on other sites

1 godzinę temu, danielll napisał:

Gdy przewod laczacy PIN1 z masa jest zwarty to funkcja mcp_read_reg zwraca stan wysoki na tym pinie czyli wartosc 0x02 (00000010). Po co nastepnie ta koniunkcja

W wyniku działania funkcji otrzymujemy cały bajt, a nas interesuje tylko wartość z konkretnego bitu (drugi od prawej). Taki zapis pozwala uzyskać właśnie taki efekt. Załóżmy, że funkcja zwraca bajt 01011011, porównujemy go więc z bajtem 00000010. W wyniku działania tego operatora otrzymamy liczbę, w której jedynki będą jedynie na tych pozycjach, na których jedynka wystąpiła w obu porównywanych liczbach. W wyniku operacji: "010110X1 & 00000010" otrzymujemy więc: 000000X0, czyli wyciągamy z całego bajta tylko jeden, interesujący nas bit. Pozostały bity nie wpłyną na wynik i o to nam właśnie chodzi, bo w programie chcemy sprawdzić stan jednego I/O. Pozostałe nas w tym przypadku nieinteresującą. Czy teraz jest to trochę jaśniejsze?

To nie jest bezpośrednio związane z STMami, ani nawet tym przykładem, to ogólne zagadnienie z logiki. Warto potrenować korzystanie z różnych operatorów logicznych, ponieważ przy mikrokontekstach bardzo często się z tego korzysta 😉

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Poza tym warto odróżnić koniunkcję (czyli operację na wartościach logicznych) od operacji na bitach.

Ot, taka niewielka różnica między && i &

Edytowano przez ethanak
  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.