STM32

버튼 누르면 1씩 올라가는 7세그먼트

찬영_00 2024. 11. 10. 09:59

저번 포스팅이 너무 길어져 2개로 나누었다.

 

일단 다음과 같이 세팅을 해주자

 

 

 

 

 

위와 같이 설정을 하고 코드를 입력하여 진행한다.

 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define HIGH 1
#define LOW 0

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void send(uint8_t X);
void send_port(uint8_t X, uint8_t port);
void display_number(int number, int repetitions);
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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();
  /* USER CODE BEGIN 2 */
  //counter
  int Index = 0;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  static uint8_t lastState = LOW;
	  uint8_t currentState = HAL_GPIO_ReadPin(GPIOB, PB_9_BUTTON_Pin);

	  if (currentState == HIGH && lastState == LOW) {
	      // 버튼이 눌린 순간
	      if(Index > 10000) {
	          Index = 0;
	      } else {
	          ++Index;
	      }
	      display_number(Index, 50, numCheckPosition);
	  }
	  display_number(Index, 50, numCheckPosition);
	  lastState = currentState;


    /* USER CODE END WHILE */

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

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, PB13_FND_DIO_Pin|PB_14_FND_RCLK_Pin|PB_15_FND_SCLK_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(PB_8_LED_GPIO_Port, PB_8_LED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : PB13_FND_DIO_Pin PB_14_FND_RCLK_Pin PB_15_FND_SCLK_Pin */
  GPIO_InitStruct.Pin = PB13_FND_DIO_Pin|PB_14_FND_RCLK_Pin|PB_15_FND_SCLK_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB_8_LED_Pin */
  GPIO_InitStruct.Pin = PB_8_LED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(PB_8_LED_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PB_9_BUTTON_Pin */
  GPIO_InitStruct.Pin = PB_9_BUTTON_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(PB_9_BUTTON_GPIO_Port, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
void send(uint8_t X){
	  for (int i = 8; i >= 1; i--)
	  {
	    if (X & 0x80)
	    {
	    	HAL_GPIO_WritePin(PB13_FND_DIO_GPIO_Port, PB13_FND_DIO_Pin, HIGH);
	    }
	    else
	    {
	    	HAL_GPIO_WritePin(PB13_FND_DIO_GPIO_Port, PB13_FND_DIO_Pin, LOW);
	    }
	    X <<= 1;

	    // make CLK
	    HAL_GPIO_WritePin(PB_15_FND_SCLK_GPIO_Port, PB_15_FND_SCLK_Pin, LOW);
	    HAL_GPIO_WritePin(PB_15_FND_SCLK_GPIO_Port, PB_15_FND_SCLK_Pin, HIGH);
	  }
}

void send_port(uint8_t X, uint8_t port){
	  send(X);
	  send(port);
	  HAL_GPIO_WritePin(PB_14_FND_RCLK_GPIO_Port, PB_14_FND_RCLK_Pin, LOW);
	  HAL_GPIO_WritePin(PB_14_FND_RCLK_GPIO_Port, PB_14_FND_RCLK_Pin, HIGH);
}

void display_number(int number, int repetitions) {
    int n1, n2, n3, n4;
    // 0~9
    uint8_t numArr[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8 ,0x80,0x90};
    // num_position
    uint8_t numPosition[4] = {0b0001, 0b0010, 0b0100, 0b1000};

    // 각 자릿수 분리
    n1 = number % 10;           // 1의 자리
    n2 = (number / 10) % 10;    // 10의 자리
    n3 = (number / 100) % 10;   // 100의 자리
    n4 = (number / 1000) % 10;  // 1000의 자리

    for(int i = 0; i < repetitions; i++) {
        send_port(numArr[n1], numPosition[0]);  // 1의 자리
        send_port(numArr[n2], numPosition[1]);  // 10의 자리
        send_port(numArr[n3], numPosition[2]);  // 100의 자리
        send_port(numArr[n4], numPosition[3]);  // 1000의 자리
    }
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

 

중요한 부분은 다음과 같다.

void display_number(int number, int repetitions) {
    int n1, n2, n3, n4;
    // 0~9
    uint8_t numArr[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8 ,0x80,0x90};
    // num_position
    uint8_t numPosition[4] = {0b0001, 0b0010, 0b0100, 0b1000};

    // 각 자릿수 분리
    n1 = number % 10;           // 1의 자리
    n2 = (number / 10) % 10;    // 10의 자리
    n3 = (number / 100) % 10;   // 100의 자리
    n4 = (number / 1000) % 10;  // 1000의 자리

    for(int i = 0; i < repetitions; i++) {
        send_port(numArr[n1], numPosition[0]);  // 1의 자리
        send_port(numArr[n2], numPosition[1]);  // 10의 자리
        send_port(numArr[n3], numPosition[2]);  // 100의 자리
        send_port(numArr[n4], numPosition[3]);  // 1000의 자리
    }
}

 

처음엔 다음과 같이 간단하게 코드를 구현했다.

if (Index < 10) {
    send_port(numArr[Index], numPosition[0]);  // 1's place
} else if (Index < 100) {
    for (int i = 0; i < 50; i++) {
        send_port(numArr[Index % 10], numPosition[0]);  // 1's place
        send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
    }
} else if (Index < 1000) {
    for (int i = 0; i < 50; i++) {
        send_port(numArr[Index % 10], numPosition[0]);  // 1's place
        send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
        send_port(numArr[(Index / 100) % 10], numPosition[2]);  // 100's place
    }
} else if (Index < 10000) {
    for (int i = 0; i < 50; i++) {
        send_port(numArr[Index % 10], numPosition[0]);  // 1's place
        send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
        send_port(numArr[(Index / 100) % 10], numPosition[2]);  // 100's place
        send_port(numArr[(Index / 1000) % 10], numPosition[3]);  // 1000's place
    }
} else {
    Index = 0;  // Reset the index
}

 

하지만 문제점이 발생했다.

 

높은 자릿수만 나타나고 뒤의 숫자들은 빠르게 깜박이고 사라지는 현상이 발생했다.

 

처음엔 7세그먼트 문제인줄알았는데, 다른 모듈로 바꿔도 상황은 같았다.

그래서 코드 문제라고 생각했다.

 

너무 빨리 지나가서 그런가? 해서 각 자릿수에 빠르게 50번 돌려보면 되겠다. 라고 생각했고,

방법은 틀렸다. 

위 코드는 50번 돌리는 것을 적용한 것이다.

 

그래서 다음으로 " 그럼 딜레이를 줘보자" 라는 생각으로 각각의 자릿수에 딜레이를 주었다.

 

	  if(HAL_GPIO_ReadPin(GPIOB, PB_9_BUTTON_Pin) == HIGH){
	      continue;
	  }else {
		  if (Index < 10) {
		      send_port(numArr[Index], numPosition[0]);  // 1's place
		  } else if (Index < 100) {
		      for (int i = 0; i < 50; i++) {
		          send_port(numArr[Index % 10], numPosition[0]);  // 1's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
		          HAL_Delay(2);
		      }
		  } else if (Index < 1000) {
		      for (int i = 0; i < 50; i++) {
		          send_port(numArr[Index % 10], numPosition[0]);  // 1's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 100) % 10], numPosition[2]);  // 100's place
		          HAL_Delay(2);
		      }
		  } else if (Index < 10000) {
		      for (int i = 0; i < 50; i++) {
		          send_port(numArr[Index % 10], numPosition[0]);  // 1's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 10) % 10], numPosition[1]);  // 10's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 100) % 10], numPosition[2]);  // 100's place
		          HAL_Delay(2);
		          send_port(numArr[(Index / 1000) % 10], numPosition[3]);  // 1000's place
		          HAL_Delay(2);
		      }
		  } else {
		      Index = 0;  // Reset the index
		  }
		  ++Index;
	  }

 

이것 또한 숫자가 조금더 오래 남아있지만 근본적인 해결 방법이 아니라는 것을 꺠달았다.

 

그러면서 코드를 유심히 보니, 버튼을 누르지 않을 땐 그냥 지나가게만 두었다..

 

이렇게 생각하니 간단하게 실험만 해볼 코드로는 안될것 같았다.

원인은 버튼을 누르지 않았을 때 LED를 표현하지 않아서 뒤에 숫자 부분이 빠르게 표시되었다가, 사라진것이다.

 

아래 코드를 복사해서 if문 안에도 넣어주니 해결되었지만, 코드가 너무 복잡하다.

 

따리서 함수로 구현하였다.

 

그것이


      
 // 함수부분
 
 void display_number(int number, int repetitions) {
    int n1, n2, n3, n4;
    // 0~9
    uint8_t numArr[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8 ,0x80,0x90};
    // num_position
    uint8_t numPosition[4] = {0b0001, 0b0010, 0b0100, 0b1000};

    // 각 자릿수 분리
    n1 = number % 10;           // 1의 자리
    n2 = (number / 10) % 10;    // 10의 자리
    n3 = (number / 100) % 10;   // 100의 자리
    n4 = (number / 1000) % 10;  // 1000의 자리

    for(int i = 0; i < repetitions; i++) {
        send_port(numArr[n1], numPosition[0]);  // 1의 자리
        send_port(numArr[n2], numPosition[1]);  // 10의 자리
        send_port(numArr[n3], numPosition[2]);  // 100의 자리
        send_port(numArr[n4], numPosition[3]);  // 1000의 자리
    }
}

 

이 부분이다.

 

적용해서 확인해보자

 

만약 앞에 0이 안나오게 하려면 조금 더 수정하면 될듯하다.

그건 본인이 원하는거에 맞게 수정하자

 

https://www.youtube.com/watch?v=H6uAf5l5KeE

 

 

 

'STM32' 카테고리의 다른 글

STM32으로 Fan을 제어해보자 1)  (0) 2024.11.12
7세그먼트 코드 수정  (0) 2024.11.10
HAL_Driver로 7세그먼트와 Button 다루기  (3) 2024.11.09
GPIO를 사용하여 LED 제어  (1) 2024.11.08
STM32 Cube IDE Install  (0) 2024.11.04