https://www.hackerrank.com/challenges/weather-observation-station-5/problem

 

Weather Observation Station 5 | HackerRank

Write a query to print the shortest and longest length city name along with the length of the city names.

www.hackerrank.com

 

Query the two cities in STATION with the shortest and longest CITY names, as well as their respective lengths (i.e.: number of characters in the name). If there is more than one smallest or largest city, choose the one that comes first when ordered alphabetically.
The STATION table is described as follows:

 

CITY 이름중에 가장 짧은 것과 가장 긴 것을 각각 찾고, 길이가 같은 것이 있을 경우 알파벳 순으로 가장 빠른 것을 찾는 문제 

반응형

https://www.hackerrank.com/challenges/weather-observation-station-4/problem

 

Weather Observation Station 4 | HackerRank

Find the number of duplicate CITY names in STATION.

www.hackerrank.com

 

Find the difference between the total number of CITY entries in the table and the number of distinct CITY entries in the table.  The STATION table is described as follows:

 

전체 CITY 수와 겹치지 않는 CITY 수를 빼는 문제

 

반응형

이동 평균 필터란?

->지정된 n개의 데이터만 가지고 평균을 구하는 방식

->새로운 데이터가 들어오면 가장 오래된 데이터는 버리고 n개로 평균을 구하는 방식

 

이번에도 굳이 구조체를 만들 필요는 없지만 구조체로 만들어보았다. 

만약 평균을 구할 데이터의 갯수 n이 정해져 있지 않고 사용자가 마음대로 초기화 할 수 있다고 가정하여, 

n이 정해지면 해당 갯수만큼 데이터를 담을 배열은 malloc을 사용하였다. 

#include <stdio.h>
#include <stdlib.h>
typedef struct 
{
    int cnt;
    int num;
    int *data;
    float preAvg;
    float nowAvg;
    int idx;
}mvAvg;

int init_mvAvgFilter(mvAvg *mvAvg, int num){
    mvAvg->cnt=0;
    mvAvg->num=num;
    mvAvg->data =(int*)malloc(sizeof(int)*num);
    mvAvg->preAvg=0;
    mvAvg->idx=0;
}

float mvAvgFilter(mvAvg *mvAvg,int data){
    if (mvAvg->cnt < mvAvg->num){
        mvAvg->data[mvAvg->cnt]=data;
        mvAvg->cnt++;
        
        int i=0;
        int sum=0;
        for (i=0;i<mvAvg->cnt;i++){
            sum+=mvAvg->data[i];
        }
        mvAvg->nowAvg=(float)sum/mvAvg->cnt;
        mvAvg->preAvg=mvAvg->nowAvg;
        return mvAvg->nowAvg;
    }

    mvAvg->nowAvg=(data-mvAvg->data[mvAvg->idx])/mvAvg->num+mvAvg->preAvg;
    mvAvg->data[mvAvg->idx]=data;
    mvAvg->idx++;
    if(mvAvg->idx == mvAvg->num){
        mvAvg->idx=0;
    }
    mvAvg->preAvg=mvAvg->nowAvg;
    return mvAvg->nowAvg;
}

int main(){
    mvAvg mvAvg;
    init_mvAvgFilter(&mvAvg,4);
    int i=0;
    for (i=1;i<=10;i++){
        printf("%d : %f\r\n",i,mvAvgFilter(&mvAvg,i));
    }
}

잘 되는 것 같은데.. 테스트가 부족하다.. 

 

반응형

'지식저장소 > C' 카테고리의 다른 글

[C] AverageFilter (평균 필터)  (0) 2022.04.28
[C] Ring Buffer / 링버퍼 구현  (0) 2022.03.29
[C/BOJ] 9012 괄호 - Stack이용  (0) 2022.02.16
[C]구조체를 이용한 Stack 구현  (0) 2022.02.16
[C/STM32] Uart로 printf 대신하기  (0) 2022.01.14

데이터들이 계속 들어올 때마다 평균을 갱신하는 AverageFilter 소스 

 

데이터의 수와 이전 평균만 전역 변수나 static 변수로 저장해도 되지만

구조체로 만들어보았다.

#include <stdio.h>

typedef struct 
{
    int dataCnt;
    float preAvg;
    float nowAvg;
}Avg;

float avgFilter(Avg *Avg,int data){
    if(Avg->dataCnt==0){
        Avg->dataCnt++;
        Avg->nowAvg=data;
        Avg->preAvg=data;
        return Avg->nowAvg;
    }
    Avg->preAvg=Avg->nowAvg;
    Avg->dataCnt++;
    Avg->nowAvg=(1 - (float)1/(Avg->dataCnt))*(Avg->preAvg)+((float)1/Avg->dataCnt)*data;
    return Avg->nowAvg;
}

int main(){
    Avg avg;
    avg.dataCnt = 0;
    avg.nowAvg = 0;
    avg.preAvg = 0;

    printf("%f\r\n", avgFilter(&avg,10));
    printf("%f\r\n", avgFilter(&avg,20));
    printf("%f\r\n", avgFilter(&avg,30));
    printf("%f\r\n", avgFilter(&avg,40));
    printf("%f\r\n", avgFilter(&avg,50));
    printf("%f\r\n", avgFilter(&avg,60));
    printf("%f %f\r\n",avg.preAvg,avg.nowAvg);
}

반응형

4월 10일 공주의 충남역사박물관에서 벚꽃구경

 

반응형

LED Dimming을 하기 위해서는 먼저 PWM을 생성해야 한다. 

 

PWM이란 무엇인가?

Pulse Width Modulation으로 쉽게 설명하면 펄스를 만들어 제어한다고 생각하면 될 것 같다.

PWM을 사용하려면 타이머를 설정해주어야한다. 

 

먼저 보드에서 PWM을 출력할 수 있는 단자를 확인하자

TIM3의 채널 1번이 CN4의 D4포트를 이용하여 사용할 수 있다는 것을 알 수 있다. 

Timers항목의 TIM3의 Channel1을 PWM Generation CH1로 선택한다. 

 

PWM의 주파수와 주기 등을 설정해야하는데 다음과 같은 항목들을 조정하여 가능하다.

 

먼저 사용한 클럭을 알아야하는데 클럭은 32MHz로 선택을 하였었다. (Clock Configuration 에서 설정 및 확인 가능)

 

그 다음 Prescaler , Counter Period, Pulse 등을 설정해야한다. 

Prescaler란?

단순히 생각하면 우리가 사용하는 타이머 클럭을 적정한 수로 나누어 사용하기 쉬운 값으로 변환하는 값이라고 생각하면 된다. 

예를 우리의 타이머 클럭은 32MHz인데 이는 너무 큰 주파수 값이므로

Prescaler를 32로 하면 1MHz , 320으로 하면 1000KHz, 3200으로 하면 100KHz등의 주파수로 변환할 수 있게된다. 

 

Counter Period?

Prescaler를 통해서 낮춘 타이머 클럭 펄스마다 타이머의 Counter가 1씩 증가된다.

설정한 Counter Period에 도달하면 Counter Period는 0이 되고 하나의 PWM 펄스를 출력한다.  

이렇게 Counter Period를 증가시키고 0을 만들고 반복하며 PWM 펄스를 만들 수 있다. 

 

클럭이 32Mhz일 때, 1Khz의 PWM을 만들고 싶다면?

1. Prescaler = 32, Counter Period = 1000 인 경우

- 타이머 클럭을 Prescaler로 나누면  32MHz / 32 = 1 MHz,  1/1000000초 마다 Count가 1씩 증가

- Counter Period가 1000이므로 1000까지 도달하는데 걸리는 시간은 1/1000000 * 1000 = 1/1000초

- Counter Period를 0으로 만들고 다시 Count 증가를 반복하며 PWM 펄스 출력

- Counter Period가 1000이되는데 걸리는 시간인 1/1000초 

- 1/1000초, 즉 1Khz마다 PWM 펄스를 출력 - > 1Khz의 PWM 생성

 

2. Prescaler = 3200, Counter Period = 10 인 경우

- 타이머 클럭을 Prescaler로 나누면  32MHz / 3200 = 10khz,  1/10000초 마다 Count가 1씩 증가

- Counter Period가 10이므로 10까지 도달하는데 걸리는 시간은 1/10000 * 10 = 1/1000초

- Counter Period를 0으로 만들고 다시 Count 증가를 반복하며 PWM 펄스 출력

- Counter Period가 1000이되는데 걸리는 시간인 1/1000초 

- 1/1000초, 즉 1Khz마다 PWM 펄스를 출력 - > 1Khz의 PWM 생성

 

등등  Prescaler와 Counter Period를 조정하여 PWM의 주기를 설정할 수 있다. 

 

1번 상황을 이용하여 PWM 세팅을 하였다.

Prescaler와 Count Period 모두 0부터 시작하므로 원하는 값에서 1을 빼주었다.

 

이제 PWM의 Duty를 설정해야한다. 

PWM의 Duty 는 PWM 펄스가 발생하였을 때, 얼마만큼 High의 상태로 유지할 것인가? 라고 생각하면 편할 것 같다. 

Pulse 항목에서 조절이 가능한데 Pulse의 범위는 Counter Period를 넘지 않도록 한다. 

쉽게 생각해서 타이머 클럭이 Counter Period를 Count할 때, 몇개의 클럭 펄스까지 PWM을 High로 할 것인가? 라고 보면 된다. 

즉 Counter Period를 1000, Pulse를 500으로 하면, Duty가 50%가 된다.  

Prescaler 32, Counter Period 1000, Pulse 500 으로 실제 Duty비가 50%인 1kHz가 만들어지는지 확인하기 위해서

Code Generation하여 코드를 생성해보자.

 

타이머를 초기화하고 HAL_TIM_PWM_Start()함수를 쓰면 PWM이 생성된다. 

HAL_TIM_PWM_Start 함수

 

main의 초기화 부분

실제 오실로스코프를 연결하여 확인하여 보자

(TIM3_CH1을 출력하는 CN4의 D3와 GND를 찍어서 확인하자)

1khz의 PWM이 잘 생성된 것을 확인할 수 있다. 

이 PWM을 LED에 연결하면... 

(저항은 220옴이 없어서 600옴 저항을 병렬로 연결하여 사용하였다)

1khz, 즉 1ms의 주기에 Duty가 50%이므로 0.5ms 간격으로 켜졌다 꺼졌다 하지만 사람 눈에는 계속 켜져있는 것으로 보인다.

 

이제 PWM을 만들었고, LED에 불도 켰으니...

PWM의 Duty를 요리조리 만지면 LED Dimming을 할 수 있을 것 같다. 

언제? 다음글에....

 

반응형

Uart Interrupt로 LED를 On/Off 할 수 있게 되었다. 

https://pilimage.tistory.com/20

 

[C/STM32] 5. LED ON/OFF - Uart Interrupt제어

Uart Polling으로 LED를 On/Off 할 수 있게 되었다. https://pilimage.tistory.com/19 [C/STM32] 4. LED ON/OFF - Uart Polling 제어 LED를 버튼으로도 제어를 할 수 있게 되었다. https://pilimage.tistory.com/1..

pilimage.tistory.com

 

이제 ring buffer를 이용하여 인터럽트를 수신해보자

https://pilimage.tistory.com/21

 

[C] Ring Buffer / 링버퍼 구현

링 버퍼란? 고정된 크기의 큐의 양 끝을 이어 원형 모양처럼 사용하는 버퍼 데이터를 넣었다가 빼는 역할을 할 수 있다 구현은 다음과 같이 하였다. ring_buffer.h #include #include typedef struct{ uint8_t *bu.

pilimage.tistory.com

 

ring_buffer.h를 Core의 Inc 폴더에 ring_buffer.c를 Core의 Src폴더에 넣고 main에 ring_buffer.h를 include 한다.

ring_buffer를 이용하여 데이터를 수신할 rx_buffer와 수신 받은 데이터를 pop하여 저장하는 rx_frame을 만든다. 

(전역 변수로 선언)

그 후 메인에 ring_buf를 초기화 시킨다.

이제 준비는 모두 끝났다. 

HAL_UART_RxCpltCallback 함수를 위와 같이 수정하였다.

PC와 연결된 uart1번으로 데이터가 수신되면 받은 데이터를 ring_buf에 push 한다. 

PC 콘솔에 입력한 데이터를 출력하기 위해서 HAL_UART_Transmit을 하였고,

HAL_UART_Receive_IT를 통해 다음 데이터 수신을 대기한다.

 

그리고 메인 함수의 루프에서 동작하다 use_console함수를 다음과 같이 수정하였다.

메인 루프에서 반복적으로 ring_buffer에 데이터가 있으면 pop하여 rx_frame에 넣는다. 

데이터의 끝을 알리는 \r나 \n이 아니면 rx_frame의 idx를 증가시키며 ring_buffer에서 꺼낸 데이터를 넣는다. 

데이터의 끝을 알리는 \r나 \n을 만나면 데이터에 맞게 LED를 On / Off 시키도록 수정하였다. 

 

이제 LED를 Uart를 이용하여 On/Off 할 수 있게 되었다...

 

단순히 LED를 On/Off 하는 것 말고도 LED를 서서히 밝아지고 서서히 어두워지게 할 수 있을까?

LED Dimming  / LED Dimmer 라고 하는 기능을 구현해보자

 

언제 ? 

다음글에... 

 

반응형

링 버퍼란? 

고정된 크기의 큐의 양 끝을 이어 원형 모양처럼 사용하는 버퍼

데이터를 넣었다가 빼는 역할을 할 수 있다 

 

구현은 다음과 같이 하였다.

 

ring_buffer.h

#include <stdint.h>
#include <string.h>

typedef struct{
	uint8_t *buffer;
	int front;
	int rear;
	int maxlen;
}ring_buffer_t;

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size);
uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data);
uint8_t ring_buf_pop(ring_buffer_t *rubf, uint8_t *data);
uint8_t ring_buf_is_full(ring_buffer_t *rbuf);
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf);
void ring_buf_clear(ring_buffer_t *rbuf);

ring_buffer_t는

사용할 버퍼를 담을 uint_t *buffer 와 큐를 사용하기 위한 fornt, rear와 사용할 버퍼의 크기를 maxlen으로 한다.  

 

ring_buffer.c

#include <stdint.h>
#include <string.h>

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size){
	memset(rbuf, 0x00, sizeof(ring_buffer_t));
	rbuf->buffer=buffer;
	rbuf->maxlen=size;
}

uint8_t ring_buf_is_full(ring_buffer_t *rbuf){
	if(rbuf->rear == ( rbuf->front+1 ) % rbuf->maxlen) return 1;
	else return 0;
}
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf){
	if( rbuf->rear == rbuf->front) return 1;
	else return 0;
}

uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data){
	if( ring_buf_is_full(rbuf) ) return 0;
	rbuf->buffer[rbuf->front] = data;
	rbuf->front = ( rbuf->front + 1) % rbuf->maxlen;
	return 1;

}
uint8_t ring_buf_pop(ring_buffer_t *rbuf, uint8_t *data){
	if( ring_buf_is_empty(rbuf) ) return 0;
	*data=rbuf->buffer[rbuf->rear];
	rbuf->rear = (rbuf->rear + 1) % rbuf->maxlen;
	return 1;
}

void ring_buf_clear(ring_buffer_t *rbuf){
	rbuf->front=0;
	rbuf->rear=0;
}

 

사용 예시

#include <stdio.h>
#include <stdint.h>
#include "ring_buffer.h"

int main(){
    uint8_t  i=0;
    uint8_t pop_data=0;
    ring_buffer_t ring_buffer;
    uint8_t rbuf[3];

    ring_buf_init(&ring_buffer, rbuf, 3);

    for(i=0;i<5;i++){
        if (ring_buf_push(&ring_buffer, i)){
             printf("push data : %d\r\n",i );
        }
    }

    for(i=0;i<5;i++){
        if (ring_buf_pop(&ring_buffer,&pop_data)){
            printf("pop %d \r\n", pop_data);
        }
    }
    return 0;
}

1. ring_buf_init(&ring_buffer, rbuf, 3);

    -> ring_buffer 구조체에 rbuf로 초기화 한다. 

2. 0~5를 ring buffer에 순차적으로 push 한다.

3.  ring_buffer의 데이터를 pop_data에 5번 pop한다. 

 

결과 

 

rbuf의 크기는 3인데 데이터는 2개를 넣은 후, 3개째에서 링 버퍼가 가득 찼다고 나온다. 

이는 링 버퍼의 경우,  empty와 full을 구분하기 위해 full의 경우 한 칸을 비워두기 때문이다.

 

나는 3개를 만들었으면 3개를 다 쓰고 싶다고 한다면 ring_buffer.h에서 ring_buffer_init 할 때 maxlen을 버퍼의 크기보다 1개 더 크게 해주면 된다. 

void ring_buf_init(ring_buffer_t* rbuf, uint8_t* buffer, uint16_t size){
    memset(rbuf,0x00,sizeof(ring_buffer_t));
    rbuf->buffer = buffer;
    rbuf->maxlen = size+1;
}

이렇게 고치고 똑같이 테스트를 하면

버퍼의 크기만큼 모두 이용할 수 있다. 

물론 테스트를 많이 안해봐서 오류가 있을 수도.....

 

반응형

+ Recent posts