본문 바로가기
전자공학/LoRa 통신

EFM32 Starter Kit를 이용하여 Simplicity Studio 사용하기(6)-UART ,tera term 응용

by ohj921189 2020. 3. 2.
반응형

저번 포스팅에서는 이때까지 배운 humitemp 예제에 UART 예제를 응용해보기 위해 시리얼통신 프로그램인 tera term(테라 텀) 기본적인 설정 방법을 배웠고 UART에 대해 간단하게 알아보았습니다. 또한 UART 통신 관련 소스 코드를 Simplicity Studio에 불러오는 작업까지 해보았습니다.

이번 시간에는 실제로 소스코드를 이용하여 시리얼 화면에 온도 값을 띄워보도록 하겠습니다.

우선 usart 헤더 파일을 소스코드에 추가해줍시다.

#include "em_usart.h"

USART와 관련하여 설정해 주는 코드를 넣어줍니다.

 

USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

 

UART 통신이 제대로 되고 있는지 확인하기 위해 "Silicon Labs UART Code example!"을 화면에 띄워 봅시다. 우선 char 형식의 welcome_string을 만들어 줍니다.

 

char welcome_string[] = "Silicon Labs UART Code example!\r\f";

 

UART 통신을 하기 위해 적절한 오실레이터를 선택하고 CMU 클럭을 만들어 줍니다. 오실레이터 관련 코드는 저번 포스팅에 있는 UART 코드를 참고 한 것 입니다.

 

// Enable oscillator to GPIO and USART1 modules
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_USART1, true);

UART 통신을 위한 TX 핀과 RX 핀을 함수를 이용하여 설정해 줍니다. UART 통신 핀은 Port C의 0번과 1번입니다.

 

// set pin modes for UART TX and RX pins
  GPIO_PinModeSet(gpioPortC, 1, gpioModeInput, 0);
  GPIO_PinModeSet(gpioPortC, 0, gpioModePushPull, 1);

UART 통신을 사용하기 위해 초기 설정을 해줍니다.

 

 USART_InitAsync(USART1, &init);
 USART1->ROUTE |= USART_ROUTE_TXPEN | USART_ROUTE_RXPEN;

 

welcome_string을 시리얼 화면에 띄웁니다. UART 통신의 TX를 이용합니다.

 

// print welcome message
    for (i = 0 ; welcome_string[i] != 0; i++)
    {
      USART_Tx(USART1, welcome_string[i]);
    }

 

온도 센서를 통해 받아온 값을 계산하여 우리가 원하는 형태의 온도로 표시될 수 있게 해주는 함수를 추가합니다. 이 함수를 추가하면 섭씨온도로 값이 변환되어 시리얼 화면에 나타납니다.

 

static void GRAPHICS_CreateString(char *string, int32_t value)
{
  //추가
if (value < 0) {
    value = -value;
    string[0] = '-';
  } else {
    string[0] = ' ';
  }
  string[5] = 0;
  string[4] = '0' + (value % 1000) / 100;
  string[3] = '.';
  string[2] = '0' + (value % 10000) / 1000;
  string[1] = '0' + (value % 100000) / 10000;

  if (string[1] == '0') {
    string[1] = ' ';
  }
}

 

 

int main에 아래의 코드들을 추가해 줍니다. 

 

계산한 섭씨온도 값을 저장할 배열을 만들어 줍니다.

 

char string1[10]; 

 

함수를 이용해 섭씨온도 값을 받아옵니다.

 

GRAPHICS_CreateString(string1, tempData);
   

아래의 for문을 통해 UART의 TX를 수행하여 값을 컴퓨터의 시리얼 화면으로 보냅니다.

 

for (int i = 0 ; string1[i] != 0; i++)
 { USART_Tx(USART1, string1[i]); }

아래 함수는 동작을 지연시키는 함수입니다.

 

sl_sleeptimer_delay_millisecond(2000);

 

아래는 코드의 전문입니다.

/***************************************************************************//**
 * @file
 * @brief Relative humidity and temperature sensor demo for SLSTK3400A_EFM32HG
 *******************************************************************************
 * # License
 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * The licensor of this software is Silicon Laboratories Inc. Your use of this
 * software is governed by the terms of Silicon Labs Master Software License
 * Agreement (MSLA) available at
 * www.silabs.com/about-us/legal/master-software-license-agreement. This
 * software is distributed to you in Source Code format and is governed by the
 * sections of the MSLA applicable to Source Code.
 *
 ******************************************************************************/

#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "em_gpio.h"
#include "i2cspm.h"
#include "si7013.h"
#include "sl_sleeptimer.h"
#include "graphics.h"
#include "em_adc.h"
#include "bspconfig.h"
#include "em_usart.h"

/***************************************************************************//**
 * Local defines
 ******************************************************************************/
//추가
#define BUFFER_SIZE 80
int buffer[BUFFER_SIZE];

/** Time (in ms) between periodic updates of the measurements. */
#define MEASUREMENT_INTERVAL_MS      2000
/** Voltage defined to indicate dead battery. */
#define LOW_BATTERY_THRESHOLD   2800

/***************************************************************************//**
 * Local variables
 ******************************************************************************/
/* Variables used by the display callback. */
static void (*mem_lcd_callback_func)(void*) = 0;
static void *mem_lcd_callback_arg = 0;

/** Flag used to indicate ADC is finished */
static volatile bool adcConversionComplete = false;

/** This flag indicates that a new measurement shall be done. */
static volatile bool measurement_flag = true;

/** Timer used for periodic update of the measurements. */
sl_sleeptimer_timer_handle_t measurement_timer;

/** Timer used for periodic maintenance of the display **/
sl_sleeptimer_timer_handle_t display_timer;

/***************************************************************************//**
 * Local prototypes
 ******************************************************************************/
static void gpioSetup(void);
static uint32_t checkBattery(void);
static void adcInit(void);
static void measure_humidity_and_temperature(I2C_TypeDef *i2c, uint32_t *rhData, int32_t *tData, uint32_t *vBat);
static void measurement_callback(sl_sleeptimer_timer_handle_t *handle, void *data);
static void GRAPHICS_CreateString(char *string, int32_t value);//추가 

/***************************************************************************//**
 * @brief  Main function
 ******************************************************************************/
int main(void)
{
  I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;
  uint32_t         rhData;
  bool             si7013_status;
  int32_t          tempData;
  uint32_t         vBat = 3300;
  bool             lowBatPrevious = true;
  bool             lowBat = false;
  //추가
  USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
  char welcome_string[] = "Silicon Labs UART Code example!\r\f";
  int i,j;

  /* Chip errata */
  CHIP_Init();

  /* Use LFXO for rtc used by the sleeptimer */
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
  CMU_ClockEnable(cmuClock_HFLE, true);
//추가
  // Enable oscillator to GPIO and USART1 modules
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_USART1, true);

  // set pin modes for UART TX and RX pins
  GPIO_PinModeSet(gpioPortC, 1, gpioModeInput, 0);
  GPIO_PinModeSet(gpioPortC, 0, gpioModePushPull, 1);

  USART_InitAsync(USART1, &init);
  USART1->ROUTE |= USART_ROUTE_TXPEN | USART_ROUTE_RXPEN;

  // print welcome message
    for (i = 0 ; welcome_string[i] != 0; i++)
    {
      USART_Tx(USART1, welcome_string[i]);
    }

  /* Initalize peripherals and drivers */
  gpioSetup();
  adcInit();
  sl_sleeptimer_init();
  GRAPHICS_Init();
  I2CSPM_Init(&i2cInit);

  /* Get initial sensor status */
  si7013_status = Si7013_Detect(i2cInit.port, SI7021_ADDR, NULL);
  GRAPHICS_ShowStatus(si7013_status, false);
  sl_sleeptimer_delay_millisecond(2000);

  /* Set up periodic measurement timer */
  sl_sleeptimer_start_periodic_timer_ms(&measurement_timer, MEASUREMENT_INTERVAL_MS, measurement_callback, NULL, 0, 0);

  EMU_EnterEM2(false);

  while (true) {
    if (measurement_flag) {
      measure_humidity_and_temperature(i2cInit.port, &rhData, &tempData, &vBat);
      measurement_flag = false;
      if (lowBatPrevious) {
        lowBat = (vBat <= LOW_BATTERY_THRESHOLD);
      } else {
        lowBat = false;
      }
      lowBatPrevious = (vBat <= LOW_BATTERY_THRESHOLD);
      GRAPHICS_Draw(tempData, rhData, lowBat);

      /*for (i = 0 ; welcome_string[i] != 0; i++)
         {
           USART_Tx(USART1, welcome_string[i]);
         }
      USART_Tx(USART1, '\r');
      USART_Tx(USART1, '\f');*/

      char string1[10];
      GRAPHICS_CreateString(string1, tempData);

      for (i = 0 ; string1[i] != 0; i++)
        {
            USART_Tx(USART1, string1[i]);
               }
      USART_Tx(USART1, '\r');
      USART_Tx(USART1, '\f');
      sl_sleeptimer_delay_millisecond(2000);
    }
    EMU_EnterEM2(false);
  }
}

/***************************************************************************//**
 * @brief Setup GPIO interrupt for pushbuttons.
 *****************************************************************************/
static void GRAPHICS_CreateString(char *string, int32_t value)
{
  //추가
	if (value < 0) {
    value = -value;
    string[0] = '-';
  } else {
    string[0] = ' ';
  }
  string[5] = 0;
  string[4] = '0' + (value % 1000) / 100;
  string[3] = '.';
  string[2] = '0' + (value % 10000) / 1000;
  string[1] = '0' + (value % 100000) / 10000;

  if (string[1] == '0') {
    string[1] = ' ';
  }
}

static void gpioSetup(void)
{
  /* Enable GPIO clock */
  CMU_ClockEnable(cmuClock_GPIO, true);

  /* Enable si7021 sensor isolation switch */
  GPIO_PinModeSet(gpioPortC, 8, gpioModePushPull, 1);
}

/***************************************************************************//**
 * @brief This function is called whenever we want to measure the supply v.
 *        It is reponsible for starting the ADC and reading the result.
 ******************************************************************************/
static uint32_t checkBattery(void)
{
  uint32_t vData;
  /* Sample ADC */
  adcConversionComplete = false;
  ADC_Start(ADC0, adcStartSingle);
  while (!adcConversionComplete) EMU_EnterEM1();
  vData = ADC_DataSingleGet(ADC0);
  return vData;
}

/***************************************************************************//**
 * @brief ADC Interrupt handler (ADC0)
 ******************************************************************************/
void ADC0_IRQHandler(void)
{
  uint32_t flags;

  /* Clear interrupt flags */
  flags = ADC_IntGet(ADC0);
  ADC_IntClear(ADC0, flags);

  adcConversionComplete = true;
}

/***************************************************************************//**
 * @brief ADC Initialization
 ******************************************************************************/
static void adcInit(void)
{
  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef initSingle = ADC_INITSINGLE_DEFAULT;

  /* Enable ADC clock */
  CMU_ClockEnable(cmuClock_ADC0, true);

  /* Initiate ADC peripheral */
  ADC_Init(ADC0, &init);

  /* Setup single conversions for internal VDD/3 */
  initSingle.acqTime = adcAcqTime16;
  initSingle.input   = adcSingleInpVDDDiv3;
  ADC_InitSingle(ADC0, &initSingle);

  /* Manually set some calibration values */
  ADC0->CAL = (0x7C << _ADC_CAL_SINGLEOFFSET_SHIFT) | (0x1F << _ADC_CAL_SINGLEGAIN_SHIFT);

  /* Enable interrupt on completed conversion */
  ADC_IntEnable(ADC0, ADC_IEN_SINGLE);
  NVIC_ClearPendingIRQ(ADC0_IRQn);
  NVIC_EnableIRQ(ADC0_IRQn);
}

/***************************************************************************//**
 * @brief  Helper function to perform data measurements.
 ******************************************************************************/
static void measure_humidity_and_temperature(I2C_TypeDef *i2c, uint32_t *rhData, int32_t *tData, uint32_t *vBat)
{
  *vBat = checkBattery();
  Si7013_MeasureRHAndTemp(i2c, SI7021_ADDR, rhData, tData);
}

/***************************************************************************//**
 * @brief Callback from timer used to initiate new measurement
 ******************************************************************************/
static void measurement_callback(sl_sleeptimer_timer_handle_t *handle, void *data)
{
  (void) handle;
  (void) data;
  measurement_flag = true;
}

/***************************************************************************//**
 * @brief   The actual callback for Memory LCD toggling
 ******************************************************************************/
static void display_callback(sl_sleeptimer_timer_handle_t *handle, void *data)
{
  (void)handle;
  (void)data;
  mem_lcd_callback_func(mem_lcd_callback_arg);
}

/***************************************************************************//**
 * @brief   Register a callback function at the given frequency.
 *
 * @param[in] pFunction  Pointer to function that should be called at the
 *                       given frequency.
 * @param[in] argument   Argument to be given to the function.
 * @param[in] frequency  Frequency at which to call function at.
 *
 * @return  Always return 0
 ******************************************************************************/
int rtcIntCallbackRegister(void (*pFunction)(void*),
                           void* argument,
                           unsigned int frequency)
{
  mem_lcd_callback_func = pFunction;
  mem_lcd_callback_arg  = argument;
  uint32_t ticks = sl_sleeptimer_get_timer_frequency() / frequency;
  sl_sleeptimer_start_periodic_timer(&display_timer, ticks, display_callback, NULL, 0, 0);

  return 0;
}
반응형

댓글