PWM.zip
10.04MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

칩 설계를 공부하다 보니, 모터 제어가 필요한 경우가 있었습니다.

모터 제어 등에서 진동수 혹은 주기를 다룰 때는 PWM이 필요합니다.

 

 

 

이번에는 PWM과 Buzzer를 이용해 노래를 연주해보려고 합니다.

 

 

 

 

 

 

2. 보드 구성 및 소스코드

이번에도 역시 다른 분석 없이 PWM의 이론을 테스트할 것이기 때문에,

Board Select 방식으로 진행하겠습니다.

 

 

 

- 보드 세팅

 

 

 

- TIMER 세팅

 

 

Prescaler는 설정하기 나름입니다.

결과적으로 원하는 주파수만 계산할 수 있으면 됩니다.

 

 

 

- PV

/* USER CODE BEGIN PV */
#define c 261.63
#define c_sharp 277.18
#define d 293.66
#define d_sharp 311.13
#define e 329.63
#define f 349.23
#define f_sharp 369.99
#define g 392.00
#define g_sharp 415.30
#define a 440.00
#define a_sharp 466.16
#define b 493.88

#define C 523.25
#define C_SHARP 554.37
#define D 587.33
#define D_SHARP 622.25
#define E 659.25
#define F 698.46
#define F_SHARP 739.99
#define G 783.99
#define G_SHARP 830.61
#define A 880.00
#define A_SHARP 932.33
#define B 987.77
#define REST 0

float melody[] = {E       , D_SHARP, E      , D_SHARP, E      , b      , D      , C      ,
		a      , REST   , c      , e      , a      , b      , REST   ,
		e      , g_sharp, b      , C      , REST   , e      ,
		E       , D_SHARP, E      , D_SHARP, E      , b      , D      , C      ,
		a      , REST   , c      , e      , a      , b      , REST   , e      , C      , b      , a     };
int beats[] = 	 {200     , 200    , 200    , 200    , 200    , 200    , 200    , 200    ,
		400    , 200    , 200    , 200    , 200    , 400    , 200    ,
		200    , 200    , 200    , 400    , 200    , 200    ,
		200     , 200    , 200    , 200    , 200    , 200    , 200    , 200    ,
		400    , 200    , 200    , 200    , 200    , 400    , 200    , 200    , 200    , 200    , 800   };
int melody_size = sizeof(melody) / sizeof(melody[0]);

/* USER CODE END PV */

 

저는 "엘리제를 위하여" 곡의 일부를 연주하기 위해 melody를 구성하였습니다.

각 음들의 주파수 값들은 변수로 정의되어 있고,

beats는 그 음을 얼마나 유지할 것인지를 담고 있습니다.

 

 

 

- Main

 

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    for (int i = 0; i < melody_size; i++) {
      float frequency = melody[i];
      uint16_t value = (uint16_t)((1000000 / frequency) - 1); // ARR 계산
      TIM3->ARR = value;
      TIM3->CCR3 = value / 2; // 듀티 사이클 50%

      HAL_Delay(beats[i]);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

첫 음의 주파수를 가져와 ARR과 CCR을 계산하고,

부저는 해당 음을 내게 됩니다.

beats에 담긴 길이동안 음이 지속되고,

loop에 의해 노래가 연주됩니다.

 

 

3. 실습결과

 

 

기계음이라 어색하긴 하지만, 연주가 잘 됨을 확인할 수 있습니다.

 

RTC.zip
10.76MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

다양한 작업을 하다 보면 타이머가 필요한 경우가 있습니다.

RTC는 다양한 시간 단위로 컨트롤할 수 있고, 알람 인터럽트를 제공합니다.

 

간단하게 10초마다 알람을 울리는 알람시계를 만들어보도록 하겠습니다.

 

2. 보드 구성 및 소스코드

기본적으로, Board Select 선택 시 불필요한 기능이 포함되어

코드가 길어지고 보기 불편합니다.

 

이번에는, Oscillator 설정 등의 설정이 복잡하여

Board select로 선택하고 진행하도록 하겠습니다.

 

 

 

- 보드 세팅

 

 

- RCC 세팅

 

이번에도 LSE를 사용하도록 하겠습니다.

 

 

 

- NVIC 세팅

 

RTC Interrupt를 사용하기 위해 세팅해 줍니다.

 

 

- RTC 설정

 

이후에 코드에서도 바꿀 수 있지만, 여기서 보기 좋게 바꿀 수 있습니다.

Seconds 메뉴에 10 입력하여 10초마다 울리게 만들도록 하겠습니다.

 

 

 

 

- PV

/* USER CODE BEGIN PV */
//char ampm[2][3] = {"AM","PM"};
char *ampm[] = {"AM","PM"}; // 1d array
char temp[100];
char s1[100];

//#define RTC_HOURFORMAT12_AM = ((uint8_t)0x00)
//#define RTC_HOURFORMAT12_PM = ((uint8_t)0x40)

void get_time(void)
{
	RTC_DateTypeDef sDate;
	RTC_TimeTypeDef sTime;

	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

	sprintf(temp, "\r\n20%02d-%02d-%02d %s %02d:%02d:%02d", sDate.Year, sDate.Month,
	sDate.Date, ampm[sTime.TimeFormat >> 6], sTime.Hours, sTime.Minutes, sTime.Seconds);
	sprintf(s1,"%d",sTime.TimeFormat);
	sprintf(s1,"%d",sTime.Hours);
	sprintf(s1,"%d",5);
}
/* USER CODE END PV */

 

PV함수와 함께, get time 함수를 정의합니다.

시간에 대해 문자열을 만들어줍니다.

중간에 define 함수는 stm32f4xx_hal_rtc.h에서 바꿔줘도 됩니다.

 

 

 

 

- Main

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_RTC_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  get_time();
	  HAL_UART_Transmit(&huart3, (uint8_t *)&temp, strlen(temp), 1000);
	  HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

앞서 정의한 get_time 함수로 시간 정보를 받고,

UART를 통해 PC에 보여줍니다.

 

 

- HAL_RTC_Alarm Callback

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
	printf("\r\nAlarm Callback Occurred!! \r\n");

	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);

//	// load time
//	RTC_TimeTypeDef sTime;
//	HAL_RTC_GetTime(hrtc, &sTime, RTC_FORMAT_BIN);
//
//	// reset alarm
//	RTC_AlarmTypeDef sAlarm = {0};
//	sAlarm.AlarmTime.Hours = sTime.Hours;
//	sAlarm.AlarmTime.Minutes = sTime.Minutes;
//	sAlarm.AlarmTime.Seconds = (sTime.Seconds + 10) % 60;
//	if ((sTime.Seconds + 10) >= 60) {
//		sAlarm.AlarmTime.Minutes = (sTime.Minutes + 1) % 60;
//		if ((sTime.Minutes + 1) >= 60) {
//			sAlarm.AlarmTime.Hours = (sTime.Hours + 1) % 24;
//		}
//	}
//	sAlarm.AlarmTime.SubSeconds = 0;
//	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
//	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
//	sAlarm.AlarmMask = RTC_ALARMMASK_HOURS | RTC_ALARMMASK_MINUTES | RTC_ALARMMASK_DATEWEEKDAY;
//	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
//	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
//	sAlarm.AlarmDateWeekDay = 1;
//	sAlarm.Alarm = RTC_ALARM_A;
//
//	if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
//	{
//		Error_Handler();
//	}
}

 

주석은 다른 실험을 위해 작성하였습니다. 작동에는 지장이 없습니다.

 

 

3. 실습결과

 

 

 

10초가 되었을 때 알람이 잘 울리는 것을 알 수 있습니다.

실습 당시 날짜를 않고 실행하였는데, 보드 설정에서 설정하실 수 있습니다.

 

ADC.zip
10.47MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

ADC는 아날로그 신호를 디지털로 변환해 주는 장치입니다.

현실에서는 다 아날로그 신호로 되어 있죠.

우리가 사용할 디지털 신호로 바꾸는 방법은 굉장히 중요합니다.

 

저는 가지고 있는 LCM1602 IIC 쉴드 장치를 가지고 실습해보려고 합니다.

출처: https://www.devicemart.co.kr/goods/view?no=1279486

 

사진에 보이는 것처럼 버튼들이 있는데,

버튼들의 Digital 변환값을 확인할 것입니다.

 

 

 

위의 이론상의 계산값과 실습을 통한 결과값이 일치하는지 확인해보려고 합니다.

 

 

2. 보드 구성 및 소스코드

기본적으로, Board Select 선택 시 불필요한 기능이 포함되어

코드가 길어지고 보기 불편합니다.

따라서 MCU 방법으로 직접 세팅하겠습니다.

기본 상태에서 코딩이 필요한 부분만을 언급할 예정이며,

자세한 것은 첨부된 파일을 참고하시면 됩니다.

 

- 보드 세팅

 

- ADC 세팅

 

Polling 모드가 아닌 Interrupt 모드가 빠르기 때문에

저는 Interrupt 방식을 채택할 것입니다.

 

 

- Main

 

 

- ADC Callback

/* USER CODE BEGIN 4 */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  if(hadc -> Instance == ADC1)
  {
	  adc_value = HAL_ADC_GetValue(&hadc1);
	  memset(uart_buf, 0, sizeof(uart_buf));
	  sprintf(uart_buf,"ADC Value : %d \r\n", adc_value);
//	  sprintf(uart_buf,"ADC_Value\n%d", adc_value);
	  HAL_UART_Transmit(&huart3, (uint8_t *)uart_buf, sizeof(uart_buf), 1000);
//	  HAL_ADC_Start_IT(&hadc1);
	  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)uart_buf, 1);
  }
}

/* USER CODE END 4 */

 

인터럽트 함수를 찾는 법은 이전 글 참고 부탁드립니다.

memset 함수는 메모리를 원하는 사이즈로 조절하는 함수입니다.

sprintf 함수는 문자열을 생성해 버퍼에 저장하는 함수입니다.

HAL_ADC_Start_DMA 함수는 DMA 전송이 완료되면 인터럽트를 활성화하는 함수입니다.

 

 

- PV

 

 

3. 실습결과

 

좌측부터 Up, Down, Left, Right, Select 버튼을 눌렀을 때의 값입니다.

 

이론상의 값과 비슷한 것을 확인할 수 있습니다.

 

UART.zip
8.55MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

모든 칩에는 통신 모듈이 들어가 있습니다.

그래야 정보를 교환할 수 있으니까요.

UART는 PC와 소통할 때 가장 많이 사용하고,

직관적이고 간단합니다.

다른 작업에도 PC로 보기 위해 알아둘 필요가 있습니다.

 

 

제가 사용하는 STM32 F429 보드는 위와 같은 방식으로 PC와 통신합니다.

F103 파트에 데이터를 전달하고, USB로 바꿔주는 방식인데요.

 

 

 

회로도를 확인해 봐도, STLK_RX와 STLK_TX로 연결되어 있음을 확인할 수 있습니다.

따라서, 저는 많은 포트 중 UART 3번 포트를 활용하려고 합니다.

 

 

2. 보드 구성 및 소스코드

기본적으로, Board Select 선택 시 불필요한 기능이 포함되어

코드가 길어지고 보기 불편합니다.

따라서 MCU 방법으로 직접 세팅하겠습니다.

기본 상태에서 코딩이 필요한 부분만을 언급할 예정이며,

자세한 것은 첨부된 파일을 참고하시면 됩니다.

 

- 보드 세팅

 

 

- RCC 세팅

 

Nucleo 보드에서는 내부 클럭보다 외부 클럭이 더 정확하다고 하고,

ST-LINK MCO는 8 MHz를 사용합니다.

따라서, 위 사진과 같이 LSE를 사용해 줄 필요가 있습니다.

 

 

- NVIC 세팅

 

 

UART Interrupt를 사용하기 위해 세팅해 줍니다.

저희는 테스트를 위해 이 인터럽트가 가장 우선순위가 되도록 설정하겠습니다.

 

 

- UART 설정

 

이후에 코드에서도 바꿀 수 있지만, 여기서 통신 방식에 대해 설정하고 갈 수 있습니다.

 

 

- (참고) printf 사용을 위한 세팅

printf를 사용하기 위해서는 Syscalls.c에서 extern 처리되어 있는

위 _write 함수 혹은 __io_putchar 함수를 수정하여 main에 가져와 사용할 수 있습니다.

제가 마지막으로 보여드릴 예시에는 printf 함수가 필요하지 않습니다.

 

 

- UART_RxCPltCallback

 

stm32 f4 xx_hal_uart.c 에서 위와 같은 함수를 찾을 수 있습니다.

이것을 main으로 가져와 사용할 것입니다.

 

 

 

- Main

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */

  HAL_UART_Receive_IT(&huart3, (uint8_t *)&rx_data, 1);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//	  // printf Test
//	  printf("Hello, STM32World %d\n", i++);
//	  HAL_Delay(1000);
//
//	  // Create string test
//	  memset(data, 0, sizeof(data));
//	  sprintf(data, "%d. Hello STM32F249 World !!! \n", i++);
//	  HAL_UART_Transmit(&huart3, (uint8_t *)data, strlen(data), 500);
//	  HAL_Delay(1000);

// 	  // Echo Test
// 	  if (HAL_UART_Receive(&huart3, (uint8_t *)&data_echo, sizeof(data), 500))
//	  {
//	    HAL_UART_Transmit(&huart3, (uint8_t *)&data_echo, sizeof(data), 500);
//	  }

//	  // Polling Test
//	  if (HAL_UART_Receive(&huart3, (uint8_t *)&data, 1, 1000) == HAL_OK)
//	  {
//	  	HAL_UART_Transmit(&huart3, (uint8_t *)&data, 1, 1000);
//	  }
	  //
	  switch (led_mode)
	  {
	  	  case 1 : GPIOB -> ODR = 0x0001; break;
	  	  case 2 : GPIOB -> ODR = 0x0080; break;
	  	  case 3 : GPIOB -> ODR = 0x4000; break;
	  	  case 0 : GPIOB -> ODR = 0x0000; break;
	  }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

주석처리된 것에서 다른 예시를 확인할 수 있습니다.

while문 앞에 HAL_UART_Receive_IT 함수를 한번 초기화했습니다.

 

인터럽트로부터 변한 led_mode 변수에 따라

PB0, PB7, PB14에 HIGH 신호를 주게 됩니다.

 

ODR에 직접 값을 입력하면, 굉장히 빠르지만

어떤 경우에는 빠른 것이 좋지 않을 수 있습니다.

현재는 상관없으므로, ODR 방법을 사용하였습니다.

 

Reference Manual을 보면, ODR의 어떤 비트가 어떤 제어를 하는지 알 수 있고,

저는 상황에 맞게 16진수로 명령을 넣어주었습니다.

 

 

- HAL_UART_RxCpltCallback

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart -> Instance == USART3)
  {
	  HAL_UART_Receive_IT(&huart3, (uint8_t *)&rx_data, 1);
	  HAL_UART_Transmit(&huart3, (uint8_t *)&rx_data, 1, 500);
	  switch (rx_data)
	  {
	  case '1': led_mode = 1; break;
	  case '2': led_mode = 2; break;
	  case '3': led_mode = 3; break;
	  default: led_mode = 0;
	  }

  }

}

 

인터럽트는 UART통신을 통해 받은 문자가 1, 2, 3일 경우

led_mode 변수를 변화시키고, 이것이 main 함수의 작동을 돕습니다.

 

 

- PV

 

 

 

3. 실습결과

 

 

1을 입력하면 초록불(PB0)이,

2를 입력하면 파란불(PB7)이,

3을 입력하면 빨간불(PB14)이 켜집니다.

PC와 잘 통신하고 있음을 알 수 있습니다.

 

EXTI.zip
7.04MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

 

EXTI는 외부 인터럽트라는 뜻입니다.

인터럽트는 CPU의 효율이 떨어지지 않고

특정 이벤트들을 처리할 수 있도록 도와줍니다.

또한, 다른 방식보다 처리 속도가 굉장히 빠르기 때문에

사용을 위해 알아둘 필요가 있습니다.

 

 

2. 보드 구성 및 소스코드

기본적으로, Board Select 선택 시 불필요한 기능이 포함되어

코드가 길어지고 보기 불편합니다.

따라서 MCU 방법으로 직접 세팅하겠습니다.

기본 상태에서 코딩이 필요한 부분만을 언급할 예정이며,

자세한 것은 첨부된 파일을 참고하시면 됩니다.

 

- 보드 세팅

 

- NVIC 세팅

 

 

 

 

NUCLEO-F429ZI 매뉴얼을 참고하여

몇 가지 실험할 포트만 활성화하였습니다.

또한, 인터럽트 사용을 위해 NVIC 설정을 해주었습니다.

 

- 인터럽트 신호 선택

 

PC13으로 연결된 USER 버튼으로 인터럽트를 일으키겠습니다.

HAL_GPIO_EXTI_IRQHandler 함수를 블록 씌우고 F3을 누르면,

 

 

다음과 같은 함수를 확인할 수 있고,

아래에 있는 HAL_GPIO_EXTI_Callback 함수는 weak 처리되어 있습니다.

이제 이 함수를 main.c로 가져와 커스텀합니다.

 

- EXTI_Callback

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == GPIO_PIN_13)
		{
			EXTI_flag = 1;
		}
}
/* USER CODE END 4 */

 

위와 같이 버튼이 눌렸을 때 flag를 1로 주어 main 함수에서 활용할 수 있도록 합니다.

 

 

- Main

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  switch (currentState)
	      {
	        case STATE_SEG_DISPLAY:
	          if (EXTI_flag == 1)
	          {
	            currentState = STATE_EXTI_PROCESS;
	            EXTI_flag = 0;
	            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
//	            last_tick = HAL_GetTick();
	          }
	          else
	          {
//	            if (HAL_GetTick() - last_tick >= 1000)
//	            {
	              GPIOD->BSRR = seg[segment_index];
	              segment_index = (segment_index + 1) % 10;
	              HAL_Delay(1000);
//	              last_tick = HAL_GetTick();
//	            }
	          }
	          break;

	        case STATE_EXTI_PROCESS:
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
	          HAL_Delay(1000);
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
	          HAL_Delay(1000);
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
	          HAL_Delay(1000);
	          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);

	          currentState = STATE_SEG_DISPLAY;
//	          last_tick = HAL_GetTick();  // 상태가 복귀될 때 시간 재설정
	          break;

	  }
	  /* USER CODE END WHILE */

 

대기상태로 기다리다가, EXTI_flag 신호가 들어오면 EXTI Process로 전이합니다.

PB0, PB7, PB14 (LED들)을 차례대로 키고 끈 뒤, 다시 작업으로 복귀합니다.

 

flag가 0인 경우에는, FND의 숫자가 계속 증가하도록 하는데,

아래와 같이 변수로 정의해 둔 것을 사용합니다.

자세한 7-segment 설명은 생략합니다.

 

tick의 경우는 인터럽트 이후 시간을 기다렸다가 갈 건지 등을 조절하기 위해 만들었습니다만,

굳이 사용하지 않겠습니다.

 

- PV

/* USER CODE BEGIN PV */

typedef enum {
  STATE_SEG_DISPLAY,
  STATE_EXTI_PROCESS
} StateType;

StateType currentState = STATE_SEG_DISPLAY;
volatile uint8_t EXTI_flag = 0;
volatile uint8_t segment_index = 0;
// volatile uint32_t last_tick = 0;

uint32_t seg[10] = {
        0x003f00c0,  // 0
        0x000600f9,  // 1
        0x005b00a4,  // 2
        0x004f00b0,  // 3
        0x00660099,  // 4
        0x006d0092,  // 5
        0x007d0082,  // 6
        0x002700d8,  // 7
        0x007f0080,  // 8
        0x006f0090   // 9
};

/* USER CODE END PV */

 

 

 

3. 실습결과

 

 

시간에 따라 FND가 증가하다가,

버튼을 누르면 인터럽트에 의해 LED가 차례대로 켜지고,

다시 증가합니다.

 

Test_GPIO.zip
9.17MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

GPIO는 사용자가 다양한 목적으로 자유롭게 사용할 수 있도록 마련해둔 Pin입니다.

LED를 다룬다거나, 다른 Bread board에 실험을 하는 등

다양한 곳에서 사용하는 가장 기초이기 때문에 먼저 학습하겠습니다.

2. 보드 구성 및 소스코드

기본적으로, Board Select 선택 시 불필요한 기능이 포함되어

코드가 길어지고 보기 불편합니다.

따라서 MCU 방법으로 직접 세팅하겠습니다.

기본 상태에서 코딩이 필요한 부분만을 언급할 예정이며,

자세한 것은 첨부된 파일을 참고하시면 됩니다.

 

 

 

NUCLEO-F429ZI 메뉴얼을 참고하여

몇가지 실험할 포트만 활성화 하였습니다.

이 때, Closed 되어 있는 포트만 골라야 합니다.

아니라면 따로 납땜하여 달아야 사용이 가능한 경우도 있습니다.

 

 /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	     if (HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_14) == GPIO_PIN_SET)
	     {
	        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
	     }
	     else
	     {
	        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
	     }
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

 

포트 F14 에 HIGH 신호가 들어오면, 포트 B01를 LOW 신호로 바꾸고

그 외에는 HIGH 신호로 유지합니다.

 

 

3. 실습결과

 

 

 

스위치를 눌러 PF14에 HIGH 신호를 전달하면,

PB1에 연결된 전구의 불이 꺼짐을 확인할 수 있습니다.

 

+ Recent posts