LinkedIn YouTube Facebook
Szukaj

Wstecz
Artykuły

[PROJEKT] KA-NUCLEO-F411CE i Waveshare Accessory Shield – obsługa diody RGB i sterownika P9813

Programowanie funkcji obsługi sterownika

Włączenie zasilania diody LED RGB

Pierwszym etapem prac nad oprogramowaniem będzie ustawienie stanu wysokiego wyjścia oznaczonego jako ON_Pin (PA6). Spowoduje to włączenie zasilania +5 V, które zasili diodę LED. W tym celu dodajemy instrukcję:

  HAL_GPIO_WritePin(ON_GPIO_Port, ON_Pin, GPIO_PIN_SET);

Wprowadzamy ją w bloku:

  /* USER CODE BEGIN 2 */ 

  /* USER CODE END 2 */

Blok ten znajduje się w funkcji main przed pętlą nieskończoną while.

Modyfikacja częstotliwości występowania przerwania SysTick

Aby mieć możliwość generowania sygnału zegarowego o okresie 70 us, musimy wprowadzić modyfikację występowania przerwania timera systemowego SysTick. Dokonujemy tego dopisując funkcję konfiguracyjną w postaci:

void SysTick_Init(void)
{
	/****************************************
	 *SystemFrequency/1000      1ms         *
	 *SystemFrequency/100000    10us        *
	 *SystemFrequency/1000000   1us         *
	 *****************************************/
	while (SysTick_Config(SystemCoreClock / 1000000) != 0)
	{
	} // One SysTick interrupt now equals 1us
}

Dodajemy ją w bloku:

  /* USER CODE BEGIN 4 */ 

  /* USER CODE END 4 */

Dodatkowo powinniśmy dodać jej prototyp w sekcji:

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void SysTick_Init(void);
/* USER CODE END PFP */

W tej sekcji będziemy dodawali również prototypy do kolejnych pisanych przez nas funkcji.

Aby wszystko działało poprawnie, wywołujemy funkcję przed pętlą główną funkcji main:

  /* USER CODE BEGIN 2 */
  SysTick_Init();

  HAL_GPIO_WritePin(GPIOA, ON_Pin, GPIO_PIN_SET);
  /* USER CODE END 2 */

Generowanie sygnału zegarowego dla sterownika P9813

Zgodnie z interfejsem opisanym w dokumentacji sterownika, jak i wcześniejszymi założeniami, wygenerujemy sygnał prostokątny będący sygnałem zegarowym. Zostanie on wygenerowany na pinie oznaczonym przez nas jako CIN (PB4). W tym celu zdefiniujemy funkcję DelayClockTime. Jej argumentem jest czas w mikrosekundach. Aby czas oczekiwania wynosił dokładnie 35 us, należy od podanego czasu odjąć 3 us. Następnie program przechodzi do pętli while, w której pozostaje do momentu kiedy zmienna delayUsCounter osiągnie zadaną wartość.

void DelayClockTime(int _TIME_TO_DELAY)
{
	delayUsCounter = 0;

	if(_TIME_TO_DELAY > 3)
	{
		_TIME_TO_DELAY -= 3;
	}

	while(delayUsCounter < _TIME_TO_DELAY)
	{
		//Wait for correct value of delayUsCounter.
	}
}

Zmienna delayUsCounter została zdefiniowana na samym początku pliku stm32f4xx_it.c w bloku:

/* USER CODE BEGIN 0 */
uint8_t delayUsCounter = 0;
/* USER CODE END 0 */

oraz w pliku main.c:

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
extern uint8_t delayUsCounter;
/* USER CODE END PV */

Parametr extern oznacza, że zmienna została zdefiniowana w innym pliku, ale definicja umożliwia korzystanie z niej w pliku main.c.

Inkrementacja wartości zmiennej odbywa się w funkcji przerwania SysTick:

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  delayUsCounter++;
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

Aby wygodnie generować sygnał zegarowy, zdefiniowana została funkcja P9813_CLK():

void P9813_CLK()
{
	HAL_GPIO_WritePin(GPIOB, CIN_Pin, GPIO_PIN_SET);
	DelayClockTime(35);
	HAL_GPIO_WritePin(GPIOB, CIN_Pin, GPIO_PIN_RESET);
	DelayClockTime(35);
}

Umożliwia ona generowanie jednego okresu sygnału prostokątnego o czasie trwania 70 us.

Wysyłanie bajtu danych do sterownika P9813

Kolejną funkcją, którą zdefiniujemy i która jest niezbędna do pracy z układem P9813, jest funkcja przesyłająca jeden bajt danych. Będzie ona korzystać z wcześniej zdefiniowanej funkcji P9813_CLK(). Jej kod przedstawia się następująco:

void P9813_SendByte(uint8_t _BYTE_TO_SEND)
{
	int i = 0;
	for(i = 0; i < 8; i++)
	{
		if((_BYTE_TO_SEND & 0x80) != 0)
		{
			HAL_GPIO_WritePin(GPIOB, DIN_Pin, GPIO_PIN_SET);
		}
		else
		{
			HAL_GPIO_WritePin(GPIOB, DIN_Pin, GPIO_PIN_RESET);
		}

		P9813_CLK();

		_BYTE_TO_SEND <<= 1;
	}
}

Jej argumentem jest bajt, który zostanie wysłany do układu sterownika. Cała procedura ma za zadanie ustawić stan na wyjściu opisanym jako DIN, a następnie wygenerować pełen okres sygnału zegarowego dla sterownika P9813. Dane przesyłane są w kolejności od najstarszego do najmłodszego bitu. W tym celu została wykorzystana pętla for, która wykona się 8 razy (8 bitów w bajcie). Na początku pętli, wykonywana jest instrukcja sprawdzająca najstarszy bit zmiennej _BYTE_TO_SEND, a następnie w zależności od tego czy jest to 1 czy 0, ustawiany jest stan wysoki na wyjściu DIN. Po każdorazowym ustawieniu bitu następuje wykonanie funkcji P9813_CLK(). Jako ostatnia instrukcja w pętli wykonywana jest operacja przesunięcia bitowego z nadpisaniem o jeden bit w lewo. Dzięki takiemu zabiegowi sprawdzanie kolejnych bitów odbywa się za pomocą jednej i tej samej maski 0x80 (0b10000000).

Wysyłanie prefiksu do sterownika P9813

Zgodnie z protokołem komunikacyjnym, konieczne jest wysłanie do sterownika prefiksu będącego pierwszą częścią ramki danych. W tym celu została utworzona funkcja P9813_SendPrefix. Została ona przeciążona trzema argumentami o kolorze, jaki zostaje wysłany do sterownika diody LED RGB.

void P9813_SendPrefix(uint8_t _RED, uint8_t _GREEN, uint8_t _BLUE)
{
	uint8_t prefixToSend = 0;

	prefixToSend = 0xC0;

	if((_BLUE & 0x80) == 0)		prefixToSend |= 0x20;
	if((_BLUE & 0x40) == 0)		prefixToSend |= 0x10;
	if((_GREEN & 0x80) == 0)	prefixToSend |= 0x8;
	if((_GREEN & 0x40) == 0)	prefixToSend |= 0x4;
	if((_RED & 0x80) == 0)		prefixToSend |= 0x2;
	if((_RED & 0x40) == 0)		prefixToSend |= 0x1;

	P9813_SendByte(prefixToSend);
}

Zmienna wewnętrzna o nazwie prefixToSend zawiera kompletny prefix gotowy do wysłania. Na początku zmienna ta jest zerowana oraz zostają w niej zapisane dwa najstarsze bity o wartości „1” – 0xC0 (0b11000000). Następnie sprawdzane są dwa najstarsze bity każdego z podanych kolorów i ich negacja jest zapisana do zmiennej. Kolory zapisywane są w notacji BGR, zgodnie z opisanym w dokumentacji protokołem. Na końcu tak przygotowany prefix wysyłany jest do układu za pomocą wcześniej przygotowanej funkcji do przesyłania bajtu danych.

Wysyłanie ramki danych o kolorze do sterownika P9813

Ostatnia zdefiniowana funkcja przesyła kompletną ramkę danych do sterownika P9813 i umożliwia wyświetlenie danego koloru na diodzie LED RGB.

void P9813_SetColor(uint8_t _RED, uint8_t _GREEN, uint8_t _BLUE)
{
	P9813_SendByte(0x00);
	P9813_SendByte(0x00);
	P9813_SendByte(0x00);
	P9813_SendByte(0x00);

	P9813_SendPrefix(_RED, _GREEN, _BLUE);

	P9813_SendByte(_BLUE);
	P9813_SendByte(_GREEN);
	P9813_SendByte(_RED);
}

Zgodnie z protokołem wysyłane są 32 bity o wartości „0” oznaczające początek transmisji, następnie wysyłany jest prefix, a po nim trzy bajty opisujące natężenie koloru o wartości od 0…255 dla każdej z diod. Kolory również są wysyłane w notacji BGR.

Autor: Jakub Kuryło