개인 설계

STM32 첫 설계

안녕 나의 20대 2024. 6. 28.
반응형

최초 종이 설계도

Schematic

 

PCB 설계도 (실제 회로랑 다름 설계 후 잘못된걸 인지해서 바꿈)

STM32 연결도

PCB 실물 (쌩 보드)

완성 후 모습

코딩하기 전 시프트 연산 구상도

코딩

#include "main.h"

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;  // UART 핸들러 정의

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN 0 */
// #define SWITCH_ADDRESS 0x00 // 스위치의 초기 주소 값 설정
/* USER CODE END 0 */

/**
  * @brief  애플리케이션 시작점.
  * @retval int
  */
int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

  /* 모든 주변 장치 초기화, Flash 인터페이스 및 Systick 초기화 */
  HAL_Init();

  /* 시스템 클록 구성 */
  SystemClock_Config();

  /* 모든 설정된 주변 장치 초기화 */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  /* 무한 루프 */
  while (1)
  {
    // 초기 데이터 배열 설정
    uint8_t data[5];
    data[0] = 0x55;
    data[1] = 0xAA;
    data[2] = 0xF0;
    data[3] = 0x0F;
    data[4] = 0; // 초기 주소 값

    uint8_t switch_pressed = 0; // 스위치가 눌렸는지 확인하는 플래그

    // 각 스위치의 상태를 확인하고 데이터를 설정
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
      data[4] |= (1 << 0); // 스위치 1
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET) {
      data[4] |= (1 << 1); // 스위치 2
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET) {
      data[4] |= (1 << 2); // 스위치 3
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET) {
      data[4] |= (1 << 3); // 스위치 4
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) {
      data[4] |= (1 << 4); // 스위치 5
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET) {
      data[4] |= (1 << 5); // 스위치 6
      switch_pressed = 1; // 스위치가 눌렸음을 표시
    }

    // UART로 항상 데이터 전송
    HAL_UART_Transmit(&huart1, data, 5, 100); // UART로 데이터 전송

    // 스위치가 하나라도 눌렸을 때 LED 켜기
    if (switch_pressed) {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // LED 켜기
    } else {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // LED 끄기
    }

    // 디바운싱을 위한 짧은 지연
    HAL_Delay(50); // 지연 시간 조정 (50ms)
  }
}

/**
  * @brief 시스템 클록 구성
  * @retval 없음
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 메인 내부 레귤레이터 출력 전압 구성 */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** RCC 오실레이터 초기화, 지정된 매개변수에 따라 오실레이터 구성 */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** CPU, AHB 및 APB 버스 클록 초기화 */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

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

/**
  * @brief USART1 초기화 함수
  * @param 없음
  * @retval 없음
  */
static void MX_USART1_UART_Init(void)
{
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;  // UART 보레이트 설정
  huart1.Init.WordLength = UART_WORDLENGTH_8B;  // 데이터 비트 길이 설정
  huart1.Init.StopBits = UART_STOPBITS_1;  // 정지 비트 설정
  huart1.Init.Parity = UART_PARITY_NONE;  // 패리티 비트 없음
  huart1.Init.Mode = UART_MODE_TX_RX;  // 송신 및 수신 모드 설정
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;  // 하드웨어 흐름 제어 없음
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;  // 오버샘플링 설정
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;  // 한 비트 샘플링 비활성화
  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;  // 클록 프리스케일러 설정
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_SWAP_INIT;  // 고급 기능 초기화 - 핀 스왑
  huart1.AdvancedInit.Swap = UART_ADVFEATURE_SWAP_ENABLE;  // 핀 스왑 활성화

  if (HAL_RS485Ex_Init(&huart1, UART_DE_POLARITY_HIGH, 0, 0) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO 초기화 함수
  * @param 없음
  * @retval 없음
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO 포트 클록 활성화 */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /* GPIO 핀 출력 레벨 설정 */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // LED를 처음부터 끔

  /* PA0 ~ PA5 핀 구성 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP; // 풀업 저항 사용
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* PA6 핀 구성 */
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
  * @brief  오류 발생 시 실행되는 함수.
  * @retval 없음
  */
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  assert_param 오류가 발생한 소스 파일과 소스 라인 번호를 보고합니다.
  * @param  file: 소스 파일 이름에 대한 포인터
  * @param  line: assert_param 오류 소스 번호
  * @retval 없음
  */
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 */

주요 구성 요소

  1. 시스템 초기화
    • HAL_Init(): 하드웨어 추상화 계층(HAL) 라이브러리를 초기화하여 MCU의 기본 설정을 초기화합니다.
    • SystemClock_Config(): 시스템 클럭을 설정하여 MCU가 안정적으로 작동할 수 있도록 합니다.
    • MX_GPIO_Init(): GPIO 핀들을 초기화합니다.
    • MX_USART1_UART_Init(): UART1를 초기화하여 시리얼 통신을 설정합니다.
  2. 메인 루프
    • 프로그램이 무한 루프(while (1)) 내에서 지속적으로 실행됩니다.
    • GPIO 핀의 상태를 읽어 각 스위치의 상태를 확인합니다.
    • 스위치의 상태에 따라 UART를 통해 데이터를 전송하고, LED를 제어합니다.

동작 원리

  1. GPIO 초기화
    • MX_GPIO_Init(): GPIO 핀을 입력 모드와 출력 모드로 설정합니다. 스위치 입력 핀은 풀업 저항을 사용하여 초기 상태를 설정합니다. LED 핀은 출력 모드로 설정합니다.
  2. UART 초기화
    • MX_USART1_UART_Init(): UART1를 115200 보드레이트, 8비트 데이터 길이, 1비트 정지 비트, 패리티 비트 없음 등으로 설정합니다. UART 통신을 위해 FIFO 모드와 고급 기능도 설정합니다.
  3. 스위치 상태 확인 및 데이터 전송
    • 각 스위치(GPIO 핀)의 상태를 확인합니다. 스위치가 눌리면 해당 비트를 데이터 배열의 마지막 바이트에 설정합니다.
    • 모든 스위치 상태를 확인한 후, 데이터 배열을 UART를 통해 전송합니다.
  4. LED 제어
    • 하나 이상의 스위치가 눌린 경우 LED를 켭니다. 모든 스위치가 눌리지 않은 경우 LED를 끕니다.
  5. 디바운싱
    • 짧은 지연(HAL_Delay(50))을 추가하여 스위치 디바운싱을 처리합니다.

코드 실행 흐름

  1. 초기화 단계
    • HAL 라이브러리를 초기화하고 시스템 클럭과 주변 장치를 설정합니다.
  2. 무한 루프
    • GPIO 핀을 읽어 스위치 상태를 확인합니다.
    • 스위치 상태에 따라 데이터를 설정하고, UART를 통해 전송합니다.
    • 스위치 상태에 따라 LED를 제어합니다.
    • 디바운싱을 위해 짧은 지연을 추가합니다.

UART 485 결과 및 검증


특이사항

UART 설계 실수로 반대 설계해서 TX RX Swapping (switching 해둠)

+ 설계 초기 실수해서 10핀 핀헤더 거꾸로 달아서 아래로 달아야함

24.04.11.first pt.zip
8.53MB
J.H BOM.xlsx
0.01MB

반응형

'개인 설계' 카테고리의 다른 글

ESP32와 Api를 이용한 실시간 일기 디스플레이  (2) 2024.07.16

댓글

💲 추천 글