DAC는 ADC의 반대로, Digital값을 Analog 값으로 변환하는 모듈입니다.

 

STM32F103에는 12bit DAC 모듈을 가지고 있습니다.

0부터 Vref+ 에 인가된 전압을 4096(2^12)개로 쪼개어 출력으로 보냅니다.

 

DAC 출력 공식(출처: Reference Manual)

DACoutput:  DAC 출력

VREF: VREF+ 핀에 인가된 전압

DOR: Data Output Register로 여기에 0~4095값이 쓰여짐

 

 

Vref+ 가 3.3V일경우

3.3*1 / 4095 = 0.000806 이 됩니다.

 

즉 Digital Value 1당 0.000806V가 출력으로 나가게 됩니다.

 

 

CubeMX 설정

CubeMX에서 DAC 설정화면

 

여기서 Output Buffer는 DAC 출력핀의 버퍼를 두어 출력 임피던스를 줄이는 역할을 합니다.

 

* DAC Output Buffer를 Enable로 했을 경우, 200mV 이하로 내려가지 않는 이슈가 있습니다.

community.st.com/s/question/0D50X00009XkXzE/minimum-dac-output-voltage-on-stm32f30x

 

PA4와 PA5핀에 DAC 기능이 활성화된 화면

 

HAL

HAL 드라이버에서 초기화를 제외한 DAC에 필요한 함수는 아래와 같습니다.

HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel);
// DAC Output Enable 함수
// hdac: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2

HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t Channel);
// DAC Output Disable 함수
// hadc: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2

HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data);
// DAC Value 설정 함수
// hadc: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2
// Alignment: DAC_ALIGN_12B_R or DAC_ALIGN_12B_L or DAC_ALIGN_8B_R
// data: 0 ~ 4095 값

 

Alignment 설정에 따라 데이터가 정렬되는 모습

 

사용법

 

목표: DAC 채널 1의 출력을 2V로 설정하고 싶다.

 

DOR = 2V * 4095 / 3.3V = 2481.82 ≒ 2482 

 

HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2482);

HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

 

반응형

사용 MCU: STM32F103RETx

컴파일러: Truestudio 9.3.0

 

 

목표: Timer8의 4번 채널을 사용해서 3KHz의 클럭을 생성

 

 

저는 Output Compare기능을 클럭 신호와 같이 일정 시간마다 출력을 토글시켜주어야 할 때 사용합니다.

 

아래는 클럭 설정입니다. 최대 클럭 72MHz로 설정합니다.

MCU 클럭 설정

 

타이머를 설정합니다.

 

CubeMX에 Timers 카테고리에 TIM8을 선택 해 줍니다.

 

 

 

Clock Source를 Internal Clock으로 설정해서 내부 클럭에 의해 타이머가 카운트 되도록 설정하고

채널 4번에 클럭을 생성한다고 했으니 Channel4에 Output Compare CH4를 선택해줍니다.

그러면 다음과 같이 MCU 핀에 TMI8_CH4 라벨이 붙었습니다.

 

 

Output Compare Channel 4의 Mode를 Toggle on match를 선택하여 OC가 될 때 GPIO가 토글되도록 합니다.

 

Timer 주기를 선택해 줍니다.

3KHz의 주파수를 만들기 위해서 

 

72MHz / 1000 / 24 = 3000 가 나옵니다. 즉 숫자를 3000번 세면 Output Compare 인터럽트가 발생하여 토글 시키는데 그러면 GPIO 출력으로 나오는 클럭이 1500Hz가 되기 때문에  2를 더 나누어서 설정합니다

 

72MHz / 1000 / 24 / 2 = 1500 라서 

 

Prescaler 에 12 - 1,

Counter Period에 1000 - 1을 넣습니다

 

 

 

코드는 while에 들어가기전에 HAL_TIM_OC_Start(타이머 번호, 채널 번호) 값을 넣어 호출해주면 PC9번 핀에 클럭이 나오는 것을 볼 수 있습니다.

int main()
{
 ...
 MX_TIM8_Init();

 ...
 
 // Timer8 Output Compare 시작
 HAL_TIM_OC_Start(&htim8, TIM_CHANNEL_4);
 
 
 while(1)
 {
 
 
 }
}
반응형

'MCU > STM32:HAL' 카테고리의 다른 글

[STM32F]FSMC와 LCD  (0) 2021.02.28
[STM32F]FSMC로 LCD(SSD1963) 제어하기  (2) 2021.02.07
[STM32F][HAL] USART Interrupt  (0) 2020.12.23
[STM32F][HAL] DAC (Digital to Analog Converter)  (0) 2020.12.22
[STM32F][HAL] USB CDC (Virtual Port Com) 사용하기  (1) 2020.05.28
[STM32F][HAL] HAL_Delay  (0) 2020.05.21
[STM32F][HAL] ADC - ADC Calibration  (4) 2020.05.17
[STM32F][HAL]GPIO  (0) 2020.05.10

HAL드라이버 내에 일정시간동안 지연시켜주는 HAL_Delay 함수가 있습니다.

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)

지연 시간은 (Delay + 1)ms입니다.

 

즉 HAL_Delay(0);을 호출하면 1ms의 딜레이가 발생됩니다. 

 

함수 내부를 보면

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}

 함수가 호출된 시점부터 wait동안 while에 묶여있도록 코드가 작성되어있습니다.

 

default로 HAL 드라이버는 1ms마다 1Tick씩 증가하도록 코딩되어 있습니다.

 

또 mininum wait로 1ms(uwTickFreq)가 추가되도록 되어있어 Delay에 0을 넣으면 1ms의 딜레이가 발생되는 것 입니다.

 

HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT;  /* 1KHz */

typedef enum
{
  HAL_TICK_FREQ_10HZ         = 100U,
  HAL_TICK_FREQ_100HZ        = 10U,
  HAL_TICK_FREQ_1KHZ         = 1U,
  HAL_TICK_FREQ_DEFAULT      = HAL_TICK_FREQ_1KHZ
} HAL_TickFreqTypeDef;

 

1넣었을 때 1ms 딜레이가 걸리게 하고 싶다!

1000 넣었을 때 1초 딜레이가 걸리게 하고 싶다!

 

하시는 분은 HAL_Delay 함수를 아래처럼 따로 작성하시면 됩니다.

 

/* main.c */
void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  while ((HAL_GetTick() - tickstart) < Delay)
  {
  }
}
​

 

하지만 HAL_Delay 함수를 사용하게 되면

그 위치에서 멈춰있기 때문에 저는 잘 사용하지 않습니다.

반응형

HAL Driver 중에 GPIO에 대해서 소개하겠습니다.

 

 

stm32f1xx_hal_gpio.c

 

 

  • void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)

      CubeMX로 생성한 코드는 아래와 같이 GPIOx 페리페럴을 초기화한다.

 

      GPIO Mode

          GPIO_MODE_INPUT: 입력모드

          GPIO_MODE_OUTPUT_PP: 출력 (Push Pull) 모드

          GPIO_MODE_OUTPUT_OD: 출력 (Open Drain) 모드

          GPIO_MODE_AF_PP: 대체 기능(Alternate Function), (Push Pull)모드

          GPIO_MODE_AF_OD: 대체 기능(Alternate Function), (Open Drain)모드

 

          GPIO_MODE_ANALOG: 아날로그 모드

 

          GPIO_MODE_IT_RISING: 외부 인터럽트(External Interrupt)모드, Rising Edge

          GPIO_MODE_IT_FALLING: 외부 인터럽트(External Interrupt)모드, Falling Edge

          GPIO_MODE_IT_RISING_FALLING: 외부 인터럽트(External Interrupt)모드, Rising & Falling Edge

          

          GPIO_MODE_EVT_RISING: 외부 이벤트(External Event)모드, Rising Edge

          GPIO_MODE_EVT_FALLING: 외부 이벤트(External Event)모드, Falling Edge

          GPIO_MODE_EVT_RISING_FALLING: 외부 이벤트(External Event)모드, Rising & Falling Edge

            * Event모드는 인터럽트 발생시키지 않고 저전력모드에서 Wake-up하는데 사용된다.

          

      GPIO Pull

          GPIO_NOPULL

          GPIO_PULLUP

          GPIO_PULLDOWN

 

      GPIO Speed

          GPIO_SPEED_FREQ_LOW

          GPIO_SPEED_FREQ_MEDIUM

          GPIO_SPEED_FREQ_HIGH

/* GPIO 초기화 */
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIOD APB2 Clock ENABLE */
    __HAL_RCC_GPIOD_CLK_ENABLE();
    
    /* Configure GPIO pins : PD13 PDPin */
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
    /* 외부 인터럽트(EXTI) 설정 */
    HAL_NVIC_SetPriority(EXTI9_5_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}

 

  • void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)

      GPIO 설정을 초기화 한다

 

  • void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

      GPIOx의 Pin의 상태를 설정한다.

      GPIO_PinState에는 GPIO_PIN_RESET(0) 과 GPIO_PIN_SET(1) 이 있다.     

/* HAL_GPIO_WritePin 예시 */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); // GPIO OUTPUT LOW
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);   // GPIO OUTPUT HIGH

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, 0); // GPIO OUTPUT LOW
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, 1); // GPIO OUTPUT HIGH

 

  • GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

      GPIOx의 GPIO_Pin의 상태를 가져온다. 이때 GPIO Pin의 mode는 GPIO_MODE_INPUT 이어야 한다.

GPIO_PinState state;

state = HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_5); // GPIOE5 의 상태를 읽는다

 

  • void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

      GPIO의 상태를 반전(Toggle)시킨다.

HAL_GPIO_TogglePin(GPIOE, GPIO_Pin_5); // GPIOE5 핀의 출력 상태를 반전시킨다.

 

  • HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

      GPIO Pin의 설정을 고정시킨다.

반응형

+ Recent posts