October 20, 2017

디바이스마트 미디어:

[41호]Wearable 미세먼지 측정 자전거 헬멧 Good! : Get out of Dust!

2016 ictmain

2016 ICT 융합 프로젝트 공모전 입선

Wearable 미세먼지 측정 자전거 헬멧

Good! : Get out of Dust!

글 | 고려대학교 강병욱, 김도형, 송명근, 원준현, 장재현

 

심사평

JK전자 작품 구현의 완성도는 좋아 보입니다. 하지만 미세먼지 측정을 자전거 헬멧에 구현하는 것이 실용적인지는 한 번 생각해보아야 할 것 같습니다. 스마트폰만 켜도 기상청에서 제공하는 데이터로 바로 미세먼지 농도를 알 수도 있고, 헬멧이 아니더라도 항상 휴대하기 간편한 형태로 구현을 했으면 어떨까 합니다.

뉴티씨 매우 간단한 아이디어이지만 구현을 완료하였고, 또한 실용적으로 현재 매우 필요한 작품으로 보인다. 자전거 인구가 급증하고 있고, 또한 오토바이를 타는 사람들도 매우 많아져서, 현재의 미세먼지 농도를 안다면 적절히 조치하여 개인의 건강에 도움을 주게 될 것으로 생각한다.
바로 상품화를 진행하여도 좋은 아이디어로 생각된다.

칩센 아이디어는 재밌지만 미세먼지를 측정하는 순간 집으로 들어갈 것 같다. 운동을 시작하기 전 결정되어야 하지 않을까 싶다.

위드로봇 전체적인 기술 구현에 필요한 난이도는 높지 않아도 하나의 동작하는 시스템으로 구현하는 전체적인 완성도가 무척 뛰어난 작품입니다. 헬맷으로 1차 인터페이스를 사용하고, 스마트폰을 2차 인터페이스로 택하여 필요에 따라 정보를 사용자가 선택할 수 있도록 한 점이 훌륭합니다. 평균 수치가 로깅이 되어 활용할 수 있도록 한 점도 추후 IoT 관점에서 다양하게 활용할 수 있을 것 같습니다.

1. 작품 제목
Wearable 미세먼지 측정 자전거 헬멧 Good! : Get out of Dust!

2. 작품 개요
사용대상 : 자전거 운전자, 오토바이 운전자, 공사장 인부 등 헬멧을 착용하고 야외활동을 하는 사람.
배경 : 다음 기사에서 볼 수 있듯이 최근 미세먼지 문제가 큰 이슈가 되고 있으며, 각종 질병을 유발하는 등 인체에 치명적인 것을 알 수 있습니다.

Cap 2017-05-30 10-57-17-334

(자료1)에서 볼 수 있듯이, 최근 중국발 미세먼지에 의해서 한국의 미세먼지 수치가 세계기준의 두 배인 것을 알 수 있습니다. 또한 (자료2)에서 는 미세먼지로 인한 천식, 비염, 아토피의 연도별 유병률이 점점 증가하고 있는 것을 알 수 있습니다. 이런 상황에서도 건강을 위해 자전거를 이용하는 인구는 점차 증가하는 추세입니다. 이렇게 야외활동을 하는 사람들이 미세먼지를 흡입함으로서 피해를 입는 것을 줄이고자 아이디어를 제안하게 되었습니다.
예상효과 및 활용방안 : 자전거 헬멧 뒤편에 미세먼지 센서를 부착하여 미세먼지의 농도를 측정하고 앞부분에 부착된 LED를 통해 운전자에게 현재 수치를 알려줍니다. 또한 스마트폰으로 데이터를 전송하여 실제 수치를 확인할 수 있으며, 미세먼지 농도가 나쁨 수치에 도달하였을 때 푸쉬 메시지와 알람이 울리도록 하였습니다.

3. 작품 설명
3.1. 주요동작 및 특징
3.1.1. 주요기능
하드웨어 시스템에서 미세먼지 센서로 미세먼지 농도를 측정하여 UART 통신으로 MCU로 데이터를 전송해 기상청 발표기준(0~30㎍/㎥인 경우 초록색, 31~80㎍/㎥인 경우 노란색, 81~150㎍/㎥인 경우 빨간색, 150㎍/㎥ 이상인 경우 2개의 빨간색) LED를 켜줍니다. 동시에 데이터를 블루투스 통신을 통해 스마트폰 어플리케이션으로 전송하여, 스마트폰에서 실제 수치를 확인하고, 나쁨 수치에서 푸쉬 알림을 통해 알려줍니다. 아래는 그림을 통하여 한 눈에 주요 기능을 파악할 수 있도록 나타낸 것입니다.

Cap 2017-05-30 10-57-27-749

① 1단계에서는 MCU에서 미세먼지 센서로 측정값을 보내라는 command를 보내면, 센서에서 측정값을 Response합니다.
② 2단계에서는 측정된 값에 따라 LED를 다르게 켜주고, 값을 Bluetooth 모듈로 전송합니다.
③ 3단계에서는 Bluetooth에서 전송받은 데이터를 스마트폰 어플리케이션으로 전송합니다.
④ 스마트폰 어플리케이션은 그 데이터를 전송받아서 화면에 표시해주고, 측정값이 일정값 이상으로 올라갔을 때 푸쉬 알림을 받게 하여 사용자에게 알립니다.

3.1.2. 부가기능
부가기능으로 자전거를 타면서 필요한 정보, 예를 들면 날씨, 오존 농도, 자외선 농도를 함께 표시해주도록 하였습니다.

3.2. 전체 시스템 구성
2개의 UART 통신이 가능한 하드웨어 보드인 ARM-Cortex M3와 미세먼지 센서를 활용하여 회로를 구성하였습니다.

Cap 2017-05-30 10-57-39-249
전체적인 시스템을 System Schematic로 그려 보았습니다. 미세먼지 센서에서 UART 통신을 통하여 MCU(ARM Cortex – M3)로 데이터를 전송하고, MCU는 UART 통신으로 Bluetooth 모듈로 전송합니다. 그리고 블루투스 통신을 통하여 스마트폰 어플리케이션으로 데이터를 전송하며, 그 정보를 데이터베이스 서버에 저장합니다. 이를 통해 부가적인 정보와 함께 미세먼지 수치를 알려주는 것입니다.

3.2.1. ARM Cortex -M3 시스템

Cap 2017-05-30 10-57-49-033

Cap 2017-05-30 10-57-58-451

위 사진은 실제 테스트 중인 시스템을 찍은 사진으로, 사진 아래쪽에 향 연기를 피워 인위적으로 미세먼지 농도를 높여준 것을 볼 수 있습니다.

Cap 2017-05-30 11-19-58-483
착용하게 되면 위의 사진과 같이 현재의 미세먼지농도 수치를 LED를 통해 ‘좋음/보통/나쁨/매우 나쁨’의 4가지 상태로 알 수 있습니다. 자전거 운전자는 스마트폰을 이용하지 않고도 자신이 운전 중인 도로의 미세먼지수치를 파악할 수 있습니다. 스마트폰 어플리케이션에서 블루투스로 전송받은 측정 수치를 확인하는 것도 볼 수 있습니다.

3.2.2. 스마트폰 어플리케이션

Cap 2017-05-30 11-20-14-416

3.3. 개발 환경

Cap 2017-05-30 11-20-24-448

Hardware
· MCU: ARM-Cortex M3
· OS: Windows8
· Tool: IAR Embedded Workbench
· Language: C/C++

Software
· OS: Windows10
· Tool: Android Studio
· Graphic: Photoshop
· Language: JAVA(Android)

4. 단계별 제작 과정
4.1. 하드웨어 회로 구성

Cap 2017-05-30 11-20-30-815

4.1.1. ① 5V, 3.3V 출력 전원부 구성

Cap 2017-05-30 11-20-37-781

Cap 2017-05-30 11-20-47-076
위와 같이 회로를 구성하여 7V~40V 입력으로 5V를 출력하였습니다.
1117C를 사용하여 5V입력으로 3.3V를 출력하였습니다.

4.1.2. ARM Cortex M3 구성
블루투스 모듈에 UART1을 사용하기 위하여, TX/RX 각각 A포트 핀9번, 10번을 사용하였습니다.
미세먼지 센서에 UART2를 사용하기 위하여 TX/RX 각각 A포트 핀2번, 3번을 사용하였습니다.
4개의 LED에 신호를 주기 위하여, D포트 0번, 1번, 2번, 3번을 사용하였습니다.

4.1.3. 블루투스 모듈 구성

Cap 2017-05-30 11-21-06-100
1. GND
2. VCC에 3.3V 연결
3. STATUS에 LED 연결
7. 블루투스 TX에 ARM- UART1 RX(A10)연결
8. 블루투스 RX에 ARM- UART1 TX(A9)연결

4.1.4. 미세먼지센서 구성

Cap 2017-05-30 11-21-12-315
1. GND
2. TX에 ARM- UART2 RX(A3)연결
3. 5V
5. RX에 ARM-UART2 TX(A2)연결

5.참고문헌

Cap 2017-05-30 11-21-18-115

위 3개의 도서와 구글에서 검색한 오픈 소스코드를 참고하여 시스템을 구현하고 안드로이드 어플리케이션을 개발하였습니다.

6.부품목록

Cap 2017-05-30 11-21-24-166
Cap 2017-05-30 11-21-34-631

7. 소스코드
추가설명이 필요한 부분은 주석으로 설명을 달았습니다.

#include<stm32f10x.h>
#include<stdio.h>
#include”delay.h”
#include”LCD.h”
————————————————-
/* USART_1 & printf 관련 define*/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ascii)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ascii, FILE *f)
#endif
#define BUFFER_SIZE 200
————————————————
// BlueTooth 수신 데이터 저장 변수
volatile char control_data;
u8 RxBuf[BUFFER_SIZE];
u8 TxBuf[BUFFER_SIZE];
u8 TxInCnt=0;
u8 TxOutCnt=0;
u8 RxCnt=0;
// 먼지센서 수신 데이터 저장 변수
int Dust_value[16]={9,};
int Measured_value=0;
int _Value;
volatile u16 a=0;
————————————————-
void Rcc_Initialize(void) ;
void Gpio_Initialize(void);
void Nvic_Initialize(void);
void UART1_Initialize(void);
void USART1_IRQHandler(void);
void UART2_Initialize(void);
void Delay_ms(unsigned int Count);
void Delay_us(unsigned int Count);
void main(void){
Rcc_Initialize( );
Gpio_Initialize( );
Nvic_Initialize( );
UART1_Initialize( );
USART1_IRQHandler( );
UART2_Initialize( );
while(1){
Delay_us(2000);
//to 미세먼지 센서 , send
USART_SendData(USART2,0×11);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);

USART_SendData(USART2,0×01);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);

USART_SendData(USART2,0×01);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);

USART_SendData(USART2,0xED);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);

Delay_us(3000); //from 미세먼지 센서 , recieve
for(int temp=0; temp<16;temp++){ //시작 패킷 00 16 0d 01
Dust_value[temp]= USART_ReceiveData(USART2);
Delay_ms(1);
}
USART_ClearITPendingBit(USART2, USART_IT_RXNE); //미세먼지값 계산.
Measured_value=Dust_value[3]*256*256*256+Dust_value[4]*256*256+Dust_value[5]*256+Dust_value[6];
_Value=(Measured_value*3528)/100000; //to 블루투스 send.
printf(“{%d}”,_Value); //LED 색변경
if(_Value<=30)
GPIOD->ODR = 0×0001;
else if((_Value<=80)&&(_Value>30))
GPIOD->ODR = 0×0002;
else if((_Value<=150)&&(_Value>80))
GPIOD->ODR = 0×0004;
else if(_Value>150)
GPIOD->ODR = 0x000C;
}
}
RCC 설정—————————————-
void Rcc_Initialize(void)
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);//HCLK = SYSCLK

RCC_PCLK2Config(RCC_HCLK_Div1); // 72Mhz
RCC_PCLK1Config(RCC_HCLK_Div4); // 72/4 x2 = 36Mhz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLL 설정8Mhz*9=72Mhz
RCC_PLLCmd(ENABLE);

while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0×08);
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //GPIO A에 clock허용
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE); //GPIO D에 clock허용
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//UART1 clock허용.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); // 미세먼지 센서.
}

GPIO 설정—————————————–
void Gpio_Initialize(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

//블루투스 TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//핀 9추가
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//블루투스 RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//핀 10추가
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//미세먼지 센서 TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//미세먼지 센서 RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//핀 10추가
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//LED
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
// 핀 0,1,2,3
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}

Nvic 함수선언————————————–
void Nvic_Initialize(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

//USART1_IRQ enable
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

Printf를 사용하기 위한 정의——————————
PUTCHAR_PROTOTYPE
{
TxBuf[TxInCnt] = ascii;
if(TxInCnt<BUFFER_SIZE-1) TxInCnt++;
else TxInCnt = 0;

//Enable the USART1 Transmit interrupt
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

return ascii;
}

————————————————-
void UART1_Initialize(void){ //PCLK2를 사용한다.

USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);

NVIC_InitStructure.NVIC_IRQChannel = 37; //USART1_IRQChannel
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

}

(BLUETOOTH 통신)USART1 인터럽트 설정———————
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)// 비트에 0이 아닐 경우에 데이터가 수신.
{

control_data = USART_ReceiveData(USART1); //0이 아닐 경우에 데이터를 읽는다. control_data= 버퍼에 값을 저장하는 역할을 하는 변수.

/*Buffer룰 구현해야하는 이유.

수신시간에 비해 처리시간이 길어서 인터럽트 발생부분에서는 버퍼에 단순히 저장만하고 처리는 다른 곳에서 한다.
*/
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
// pending bit를 clear.(안해주면 인터럽트가 처리되었는지 알 수 없고 다시 인터럽트가 발생한것으로 인지해서 계속 핸들러 호출)

}

if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//비트에 0이 아닐 경우에 데이터가 송신
{

USART_SendData(USART1,TxBuf[TxOutCnt]);

if(TxOutCnt<BUFFER_SIZE-1) TxOutCnt++; // Txoutcount가 buffer size 보다 작으면 +1씩 샌다.
else TxOutCnt = 0;

if(TxOutCnt == TxInCnt)// Txoutcount가 Txincount가 되면 tx 끄고 RX 킨다.
{
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
}
}

//미세먼지 센서.
void UART2_Initialize(void)
{

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600 ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode =USART_Mode_Rx |USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
}
————————————————-
//딜레이 함수
void Delay_us(unsigned int Count)
{
Count *= 12;
for(; Count!=0; Count–);
}
void Delay_ms(unsigned int Count)
{
Count *= 12000;
for(; Count!=0; Count–);
}

 

 

 

Leave A Comment

*