Busan IT/ARM Controller2015. 9. 9. 09:12

==================================Outline=====================================

ARM 타이머/카운터 소스 

초음파 센서 거리측정식

----------------------------------------------------------------------------


ARM 타이머/카운터 소스


20150908.zip


** main.c에서 TIMER_Init을 호출하지 않아 1초마다 LED 깜빡이는 코드가 작동하지 않았다.

/*** timer.c ***/

#include "timer.h"

static volatile unsigned int uiMSec;    //milli second

// 0번 타이머 접두어: TC0 // 1번 타이머 접두어: TC1 // 2번 타이머 접두어: TC2
// 예: #define TC0_CCR    ((volatile unsigned int *)0xFFFA0000)
// 인터럽터 관련 : AT91C_BASE_AIC
// 0번 타이머 관련 : AT91C_BASE_TC0
// PMC 관련   : AT91C_BASE_PMC

void TIMER_Init(void)
{
// 타이머 카운터 0 사용을 위한 PMC 활성화(AT91C_ID_TC0) // p33 : // p204 : //p20 : 주소 
  *AT91C_PMC_PCER = 1 << AT91C_ID_TC0;
// 1.시작 : 타이머 클럭 비활성화 ------------------
// 타이머 클럭 비활성화(TC_CCR 설정)
  *AT91C_TC0_CCR = AT91C_TC_CLKDIS;

// 2. 시작 : 타이머 인터럽트 비활성화 -------------
// 타이머 인터럽트 비활성화(TC_IDR 설정)
  *AT91C_TC0_IDR = 0xFF;  
// 인터럽트 상태 정보 초기화(TC_SR 읽기)
  *AT91C_TC0_SR;  // 초기화 :: 수행되면 레지스터가 초기화된다.

// 분주비 128, 비교 방식 레지스터 설정(TC_CMR, DIV4_CLOCK, AT91C_TC_CPCTRG) 
// MCKR divided by 4096 => 12, 0.25us(TC_RC 설정) 
  *AT91C_TC0_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_CPCTRG;  
  

// 타이머 카운터 0 인터럽트 비활성화(AIC_IDCR, AT91C_ID_TC0)
  *AT91C_AIC_IDCR = 1 << AT91C_ID_TC0; 
  
// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------

// 타이머 카운터 0 인터럽트 핸들러 등록(AIC_SVR[AT91C_ID_TC0], timer_handler)
  AT91C_AIC_SVR[AT91C_ID_TC0] = (unsigned int)Timer_ISR;  

// 타이머 카운터 0 인터럽트 모드 설정(AIC_SMR[AT91C_ID_TC0], AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, AT91C_AIC_PRIOR_LOWEST)
  AT91C_AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST;

// 타이머 카운터 0 인터럽트 클리어(AIC_ICCR, AT91C_ID_TC0)
  *AT91C_AIC_ICCR = 1 << AT91C_ID_TC0;

// TC_RC 값 비교 타이머 인터럽트 활성화(TC_IER, AT91C_TC_CPCS)
  *AT91C_TC0_IER = AT91C_TC_CPCS;
// MCKR divided by 128 => 375, 0.001sec(TC_RC 설정) 
  *AT91C_TC0_RC = 375;
// 2. 끝 : 타이머 인터럽트 비활성화 ---------------

// 타이머 카운터 0 인터럽트 활성화(AIC_IECR, AT91C_ID_TC0)
  *AT91C_AIC_IECR = 1 << AT91C_ID_TC0;

// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------

// 타이머 클럭 활성화(TC_CCR, AT91C_TC_CLKEN)
  *AT91C_TC0_CCR = AT91C_TC_CLKEN;
// 1. 끝 : 타이머 클럭 비활성화 ------------------

// 타이머 시작(TC_CCR, AT91C_TC_SWTRG)
  *AT91C_TC0_CCR = AT91C_TC_SWTRG;


}


void ms_delay(unsigned int uiMS)
{
  uiMSec = 0;
  while(uiMSec < uiMS);
}

void Timer_ISR(void)
{
// 인터럽트 상태 정보 초기화(TC_SR 읽기)
  *AT91C_TC0_SR;  // 초기화 :: 수행되면 레지스터가 초기화된다.
  ++uiMSec;

}


초음파 센서 거리측정식


초음파 센서가 1cm 앞에 있는 물체를 감지하는데를 걸리는 시간(클럭)을 측정 해보자.

소리의 속도는 340m/s 이고 이를 cm로 표현하기 위해 100을 곱하면 34,000cm/s 이다. 


비례식으로 나타내면 1초 : 34,000cm = x초 : 1cm이다.

외항과 내항을 곱하면 1cm/초 = (34,000)(x)cm/초 이므로

x = 1/34,000임으로 값은 0.00002941176470588240이다. 초음파를 측정하기 위해서 보낸 초음파를 다시 받아야 하기 때문에 곱하기 2를 해주어야 한다.

소리의 속도(m/s)소리의 속도(cm/s)1cm 이동시간 * 2

340

     34,000

0.00005882352941176470


즉 주파수가 분주비에 의해 0.00005882352941176470 가 되는 수를 찾아야 한다.


128분주의 오차가 가장 작음으로 128분주를 사용할 것이다. 128분주의 오차를 계산하면 아래 표와 같다.


반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

초음파 센서 동작  (0) 2015.09.10
초음파 센서  (0) 2015.09.09
Timer/Counter  (0) 2015.09.07
주파수와 ARM 메모리맵  (0) 2015.08.28
Interrupt Code, 초음파 센서 SRF05, Timer/Counter  (0) 2015.08.19
Posted by newind2000
Busan IT/ARM Controller2015. 9. 7. 17:40

==================================Outline====================================
Timer/Counter

----------------------------------------------------------------------------

 

flash는 모델에 따라 크기가 달라지며 AT91SAM7256의 경우는 256kb 사용할 수 있다.

 

Internal Memory는 3가지 영역으로 나뉜다 :: flashSRAM 그리고 remap을 기준으로 flash()SRAM()


remap이 수행되면 cstartup.s 코드(주파수 변환)가 동작한다.

 

AT91SAM7256에서 Timer/Counter는 총 3(TC0 ~ TC2)가 있으며 카운터는 모두 16bit이다. , 0에서 65535까지 셀 수 있는 카운터이다.

 

현재 우리가 사용하는 ARM의 주파수는 48Mhz이므로 분주비와 카운터를 사용하며 원하는 단위 카운터의 시간을 만들 수 있다.



 

의사코드(psudo code)를 보고 Timer/Counter를 사용해보자.

 

//정의된 헤더파일이 없더라도 메모리맵을 보고 코딩을 할 수 있는 소양을 길러야 한다.



 // Timer.c

// 0번 타이머 접두어: TC0 // 1번 타이머 접두어: TC1 // 2번 타이머 접두어: TC2
// 예: #define TC0_CCR    ((volatile unsigned int *)0xFFFA0000)
// 인터럽터 관련 : AT91C_BASE_AIC
// 0번 타이머 관련 : AT91C_BASE_TC0
// PMC 관련   : AT91C_BASE_PMC

static unsigned int uiMsec;   //카운팅을 위한 전역 변수, 외부 접근을 막기 위해 static 선언

void Timer_Init(void)
 {
//p/33 장치번호표, p/20 memory map, T/C 주요 레지스터 p/463

// 타이머 카운터 0 사용을 위한 PMC 활성화(AT91C_ID_TC0)
   *AT91C_PMC_PCER = AT91C_ID_TC0;
// 1.시작 : 타이머 클럭 비활성화 ------------------
// 타이머 클럭 비활성화(TC_CCR 설정)
   *AT91C_TC0_CCR = AT91C_TC_CLKDIS;
   
   

// 2. 시작 : 타이머 인터럽트 비활성화 -------------

// 타이머 인터럽트 비활성화(TC_IDR 설정)
   *AT91C_TC0_IDR = 0xFF;   //타이머 인터럽트 모두 비활성화
   
// 인터럽트 상태 정보 초기화(TC_SR 읽기)
   *AT91C_TC0_SR;  //읽으면 자동으로 지워 지기 때문에 읽기만 하면 초기화 된다.  

// 분주비 128, 비교 방식 레지스터 설정(TC_CMR, DIV4_CLOCK, AT91C_TC_CPCTRG)
   *AT91C_TC0_CMR = 1<<AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_CPCTRG;

// MCKR divided by 128 => 2.7us(TC_RC 설정)
   

// 타이머 카운터 0 인터럽트 비활성화(AIC_IDCR, AT91C_ID_TC0)
   *AT91C_AIC_IDCR = 1<<AT91C_ID_TC0; 

// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------
// 타이머 카운터 0 인터럽트 핸들러 등록(AIC_SVR[AT91C_ID_TC0], timer_handler)
   AT91C_AIC_SVR[AT91C_ID_TC0] = (volatile unsigned int)Timer_ISR;
   
// 타이머 카운터 0 인터럽트 모드 설정(AIC_SMR[AT91C_ID_TC0], AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, AT91C_AIC_PRIOR_LOWEST)
   AT91C_AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST;

// 타이머 카운터 0 인터럽트 클리어(AIC_ICCR, AT91C_ID_TC0)
   *AT91C_AIC_ICCR = 1<<AT91C_ID_TC0;    인터럽트 초기화

// TC_RC 값 비교 타이머 인터럽트 활성화(TC_IER, AT91C_TC_CPCS)
   *AT91C_TC0_IER = AT91C_TC_CPCS;
   *AT91C_TC0_RC = 375;

// 2. 끝 : 타이머 인터럽트 비활성화 ---------------

// 타이머 카운터 0 인터럽트 활성화(AIC_IECR, AT91C_ID_TC0)
   *AT91C_AIC_IECR =1 <<  AT91C_ID_TC0;

// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------

// 타이머 클럭 활성화(TC_CCR, AT91C_TC_CLKEN)
   *AT91C_TC0_CCR = AT91C_TC_CLKEN;

// 1. 끝 : 타이머 클럭 비활성화 ------------------

// 타이머 시작(TC_CCR, AT91C_TC_SWTRG)
   *AT91C_TC0_CCR = AT91C_TC_SWTRG;

 }


void Timer_ISR(void)  //0.001초마다 호출
{
// 인터럽트 상태 정보 초기화(TC_SR 읽기)
   *AT91C_TC0_SR;

   ++uiMsec;

   
 }

void ms_Delay(unsigned int uiMs)
 {
   uiMsec = 0;
   while(uiMsec < uiMs);  
 }   
  


반응형
Posted by newind2000
Busan IT/센서 제어2015. 9. 4. 17:28

==================================Outline====================================

C#을 활용한 NTC 온도 센서

---------------------------------------------------------------------------



/*** 소스 코드 ***/

Embeded C

#include "LCD.h"
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>
#include "smart.h"


#define BCOEFFICIENT 3950    // The beta coefficient of the thermistor (usually 3000-4000)
#define THERMISTORNOMINAL 10000  // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25  // temp. for nominal resistance (almost always 25 C)
#define SERIESRESISTOR 10000  // the value of the 'other' resistor

float fCalcNtc(int wADCVal)  // from ADC

  double fRntc;

    fRntc = ((SERIESRESISTOR *  ( 1023.0  - (float) wADCVal) /(float) wADCVal));  // SERIESRESISTOR = pullup resistor
  return(fRntc);
}
// calculate temperature from resistorvalue
float fCalcTemp( float fRntc)
{
  float fTemp;

    fTemp = (1.0 / ( (log(fRntc/THERMISTORNOMINAL))/BCOEFFICIENT  + 1.0/298.0)) - 273.0//log = ln 
  return( fTemp);
}
/*const unsigned int ad_table[] = {
991,989,987,985,983,980,978,975,973,970, //-40'C ~-31'C
966,963,960,957,953,949,945,941,937,932, //-30'C ~-21'C
927,922,918,912,907,900,895,889,882,875, //-20'C ~-11'C
868,861,854,847,839,830,822,814,806,796, //-10'C ~ -1'C

786,778,769,759,749,737,728,718,707,696, //  0'C ~  9'C
684,674,663,652,640,627,617,606,595,582, // 10'C ~ 19'C
569,559,548,536,524,511,501,490,478,466, // 20'C ~ 29'C
454,444,434,423,411,400,390,381,370,360, // 30'C ~ 39'C
349,341,332,322,313,303,295,287,279,270, // 40'C ~ 49'C
262,254,247,240,232,225,219,212,206,199, // 50'C ~ 59'C
193,187,182,176,170,165,160,155,151,146, // 60'C ~ 69'C
141,137,133,129,124,120,117,113,110,106, // 70'C ~ 79'C
103,100, 97, 94, 91, 88, 85, 83, 80, 78, // 80'C ~ 89'C
 75, 73, 71, 69, 66, 64, 62, 61, 59, 57, // 90'C ~ 99'C
 55, 53, 50, 47, 44, 42, 41, 41, 41, 41, //100'C ~109'C
 41, 40, 39, 38, 36, 35, 34, 33, 32, 32, //110'C ~119'C
 31 };
*/

volatile unsigned int uiCnt;
char cBuf[5= {0, };
char cFlag = 0;

void TC1_Init()
{
  /*  레지스터 설정 */

  // 16 BIT Timer/Counter //

  TCCR1A   = 0X00;//0B 0000 0000 -> NORMAL MODE, NO PWM MODE
  TCCR1B   = 0X83;//0B 1000 0011 -> FALLING EDGE, NORMAL MODE, 64 분주
  TCCR1C  = 0X00;//0B 0000 0000 -> BLOCK COMPARE MODE
  TCNT1H  = 0X00;//0B 0000 0000 -> START FROM 0
  TCNT1L  = 0X00;//0B 0000 0000 -> START FROM 0
  TIMSK1   = 0X01;//0B 0000 0001 -> OVERFLOW REGISTER ENABLE
  TIFR1  = 0X00;//0B 0000 0000 ->BIT CLEAR, FLACK BIT CLEAR
  SREG   |=0X80;//0B 1000 0000 -> GLOBAL INTERRUPT ENABLE
  

  TCNT1H = TCNT1L >> 8;
  SREG   |=0X80;// 0B 1000 0000 -> GLOBAL INTERRUPT ENABLE
}  


void ADC_Init()
{
  ADCSRA = 0x00;     // init
  ADCSRA = 0x85;     // Enable adc, 분주비 32
  ADCSRB = 0x00;    // free running mode
  ADMUX  = 0x40;     // select adc input 0
}

void MTW()
{
  char cBuffer[20]={0, };
  char cCS[3= {0, };
  int iCnt;
  char ucCS;

  cBuffer[0= '$';
  cBuffer[1= 'J';
  cBuffer[2= 'H';
  cBuffer[3= 'M';
  cBuffer[4= 'T';
  cBuffer[5= 'W';
  cBuffer[6= ',';
  cBuffer[7= '0';
  cBuffer[8= cBuf[0];
  cBuffer[9= cBuf[1];
  cBuffer[10= cBuf[2];
  cBuffer[11= cBuf[3];
  cBuffer[12= ',';
  cBuffer[13= 'C';
  cBuffer[14= '*';
  

  //checksum - from $ to * XOR
  for(iCnt = 1; iCnt < 14; ++iCnt)
  {
    ucCS ^= cBuffer[iCnt];
  }

  itoa(ucCS, cCS, 16);



  cBuffer[15= cCS[0];   
  cBuffer[16= cCS[1];     

  /*itoa( (ucCS & 0xF0), cBuffer[15], 16); 
  itoa( (ucCS & 0x0F), cBuffer[16], 16);*/


  
  cBuffer[17= 10;   
  cBuffer[18= 13;
  ucCS = 0;
  USART_PRINT(cBuffer);
}

int main(void)
{
  unsigned int uiSum=0;
  int iCnt;
  int uiTemp=0;  
  unsigned char i;
  double steinhart, Res, Temp;

  LCD_Init();
  ADC_Init();
  TC1_Init();
  USART0_INIT();


  LCD_Print("  Current Temp.");
  LCD_INST(0x0C);
  LCD_INST(0x40);
  LCD_Symbol();



  while(1)
  {  
    uiSum = 0;    
    ADCSRA = 0xD5;
    while((ADCSRA & 0x10) != 0x10);
    for(i=0; i<100; ++i)
    {
      ADCSRA = 0xD5;
      while((ADCSRA & 0x10) != 0x10);
      uiSum += (  (int)ADCL + ((int)ADCH<<8) ) ;
    }
    uiSum /= 100;  // uiSum = uiSum / 100, 아날로그 신호의 평균값을 내준다.
    Res = fCalcNtc(uiSum);      // calculate temperature from resistorvalue 
    Temp = fCalcTemp(Res);      // calculate temperature from resistorvalue
    Temp = Temp * 10;
    itoa(Temp, cBuf, 10);
    cBuf[3= cBuf[2]; 

    cBuf[2= '.';

    
    
    

    LCD_INST(0xC5);    
    LCD_Print(cBuf);
    LCD_Data(0x00);
    LCD_Data('C');
    _delay_ms(1000);
  }

  return 0;
}

void __vector_20(void)
{
  
  cFlag ^= 0x01;   
  
  if(cFlag == 0)  
    MTW();
      
    
}

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace _20150904
{
    public partial class Form1 : Form
    {
        int iCnt = 0;
        public Form1()
        {
            InitializeComponent();
            bt_OFF.Enabled = false;
            string[] port_arr = SerialPort.GetPortNames();
            foreach (string portno in port_arr)
            {
                cb_PORT.Items.Add(portno);
            }                      
        }


        private void cb_PORT_SelectedIndexChanged(object sender, EventArgs e)
        {            
            serialPort1.PortName = cb_PORT.Text;
            serialPort1.BaudRate = 4800;
            serialPort1.Parity = 0;            
            serialPort1.DataBits = 8;            
            
        }

        private void bt_ON_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            serialPort1.Write(tb_Log.Text);
            bt_ON.Enabled = false;
            bt_OFF.Enabled = true;
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try { 
                string sText = tb_Log.Text = serialPort1.ReadLine();
                if(iCnt != 0)
                { 
                    string sCel = sText.Substring(94);
                    tb_C.Text = sCel;
                    var iF = Convert.ToDouble(sCel);

            
                    double dF = (iF * 1.8 + 32);
                    string sF = null;
                    sF = Convert.ToString(dF);

                    tb_F.Text = sF;
                }
                ++iCnt;
            }
            catch 
            {
                MessageBox.Show("Port Closed""Notice", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            
        }
        private void bt_OFF_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            bt_ON.Enabled = true;
            bt_OFF.Enabled = false;
        }
   
        
    }

}


반응형

'Busan IT > 센서 제어' 카테고리의 다른 글

자동차 후진 경고 센서  (0) 2015.09.14
온도계 섭씨 화씨 변경, 초음파의 특성  (0) 2015.09.10
NTC 온도계 저항값 변환  (0) 2015.09.04
NTC 센서를 활용한 온도계  (0) 2015.09.02
NTC 온도 센서  (0) 2015.09.01
Posted by newind2000
Busan IT/센서 제어2015. 9. 4. 08:57

==================================Outline====================================

NTC 온도계 저항값 변환

----------------------------------------------------------------------------

 

NTC의 저항 값을 온도로 변환시키는 공식에 대해서 알아보자.

 

우선 저항 값을 구하는 공식이다.

 

<<1>>

float fCalcNtc(short wADCVal) // from ADC
{
    float fRntc;
    fRntc = 10000 * (float) wADCVal / ( 1023.0 - (float) wADCVal); // 10000 = pullup resistor
    return(fRntc);
}

<<2>>

float fCalcNtc(int wADCVal) // from ADC
{

    double fRntc;
    fRntc = ((SERIESRESISTOR * ( 1023.0 - (float) wADCVal) /(float) wADCVal)); // SERIESRESISTOR = pullup resi    stor
    return(fRntc);

}

 

회로구성에 따라 NTCGND로 들어가는 경우는 <<1>>, NTC의 회로가 MCU에 직접적으로 들어가는 구성은 <<2>>이다.

 

저항 값이 나오면 이 값을 Steinhart-Hart equation에 넣어서 값을 구하면 된다.

float fCalcTemp( float fRntc)
{

    float fTemp;
    fTemp = (1.0 / ( (log(fRntc/THERMISTORNOMINAL))/BCOEFFICIENT + 1.0/298.0)) - 273.0//log = ln

    return( fTemp);
}

이것을 활용하여 온도 값을 통신으로 넘겨주는 프로그래밍을 해보자.


//'--'DC(Don't care) 영역

통신으로 받은 값은 UI를 활용하여 표시해 주어야 한다.

무조건 아스키코드로 전송된다.







 

 

 

 

 

 

반응형

'Busan IT > 센서 제어' 카테고리의 다른 글

자동차 후진 경고 센서  (0) 2015.09.14
온도계 섭씨 화씨 변경, 초음파의 특성  (0) 2015.09.10
C#을 활용한 NTC 온도 센서  (0) 2015.09.04
NTC 센서를 활용한 온도계  (0) 2015.09.02
NTC 온도 센서  (0) 2015.09.01
Posted by newind2000
Busan IT/센서 제어2015. 9. 2. 17:41

==================================Outline====================================

NTC 센서를 활용한 온도계

----------------------------------------------------------------------------

 





 


NTC(Negative Temperature Coefficient)에서 주변 온도에 따라 반환하는 저항 값을 실제 온도 값으로 고치기 위해서는 계산식이 필요하다.

 

선형식을 대입할 수 있으나 구간에 따라 비례식이 달라지기 때문에 정확한 값을 구하고자하면 SteinhartHart equation을 적용시켜야 한다.

 

//절대온도(k)에서 섭씨(c)로 변환하고자 할 때, c = k -273.15를 적용하면 된다.

//자연로그는 밑수를 e(2.718282)로 한다.

//C에서 <math.h> 헤더파일을 사용하면 'log'함수와 'exp'함수를 사용할 수 있다.

 

저항 값을 온도 값으로 변환해주기 전에 사용자의 편의를 위해 특수문자를 CGROM에 저장하여 온도 값(c)을 표시해주자.

 

 

 

아날로그 온도 센서로는 Thermistor, Pt 100, TC가 있다. Pt 100옴은 산업용으로 쓰인다.

//pt는 백금(platinum)의 원소기호이다.



반응형

'Busan IT > 센서 제어' 카테고리의 다른 글

자동차 후진 경고 센서  (0) 2015.09.14
온도계 섭씨 화씨 변경, 초음파의 특성  (0) 2015.09.10
C#을 활용한 NTC 온도 센서  (0) 2015.09.04
NTC 온도계 저항값 변환  (0) 2015.09.04
NTC 온도 센서  (0) 2015.09.01
Posted by newind2000
Busan IT/센서 제어2015. 9. 1. 17:37

==================================Outline====================================

NTC 온도 센서

 ----------------------------------------------------------------------------

 

서브모터는 주로 기동기계의 속도를 표시해주는데 사용된다.

 

센서는 생물체에 비유하자면 감각기관과 같은 것이다.

 

LM35, NTC(thermistor)는 많이 쓰이는 센서 중에 하나이다.

 

 

//절대온도(k) = C + 273

//표준온도 = 0C

//상온 = 섭시 25C

 

센서는 감지한 아날로그 값을 ADC를 거쳐 디지털로 프로세서에 전송하게 된다.

ADC는 주변 환경의 간섭을 많이 받게 된다. 때문에 감지 값을 통신신호(UART, TWI, SPI)로 변환하여 전송하는 방법도 있다.

 

//SPIAVRstudio에서 ATmega로 데이터를 전송할 때 사용된다.

//SPI stands for Serial Peripheral Interface Bus

SPI는 동기화 방식이며 Master에서 Slave쪽으로 클럭 신호를 기준으로 데이터를 전송하게 된다.

 

//MOSI(Master Out Slave In), MISO(Master In, Slave Out), /RESET, VCC, GND

 

센서시간에 온도센서, 초음파 센서, 일산화탄소 감지센서를 사용한 코딩을 해보겠다.

 

SPI통신은 4가닥의 선으로 구성된다. CLK, MISO, MOSI, CS.

 

CS는 슬레이브가 2개일 경우 경로를 지정해주는 역할을 한다. 슬레이브의 수가 늘어날 경우 CS선의 개수도 슬레이브의 객체 수를 2진수로 표현할 수 있는 선의 개수만큼 늘어나야 한다.

 

USARTSPI의 차이점 - USART1:1 통신, SPI1:통신

 

NTC 온도 센서

 

온도가 높으면 저항이 낮아진다. 이를 활용하여 온도계를 만들어보자.

 

ATmega2560ADC기능을 사용하여 thermistor로 받은 값을 LCD에 출력해주자.





#include "LCD.h"
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>


/*const unsigned int ad_table[] = {
991,989,987,985,983,980,978,975,973,970, //-40'C ~-31'C
966,963,960,957,953,949,945,941,937,932, //-30'C ~-21'C
927,922,918,912,907,900,895,889,882,875, //-20'C ~-11'C
868,861,854,847,839,830,822,814,806,796, //-10'C ~ -1'C

786,778,769,759,749,737,728,718,707,696, //  0'C ~  9'C
684,674,663,652,640,627,617,606,595,582, // 10'C ~ 19'C
569,559,548,536,524,511,501,490,478,466, // 20'C ~ 29'C
454,444,434,423,411,400,390,381,370,360, // 30'C ~ 39'C
349,341,332,322,313,303,295,287,279,270, // 40'C ~ 49'C
262,254,247,240,232,225,219,212,206,199, // 50'C ~ 59'C
193,187,182,176,170,165,160,155,151,146, // 60'C ~ 69'C
141,137,133,129,124,120,117,113,110,106, // 70'C ~ 79'C
103,100, 97, 94, 91, 88, 85, 83, 80, 78, // 80'C ~ 89'C
 75, 73, 71, 69, 66, 64, 62, 61, 59, 57, // 90'C ~ 99'C
 55, 53, 50, 47, 44, 42, 41, 41, 41, 41, //100'C ~109'C
 41, 40, 39, 38, 36, 35, 34, 33, 32, 32, //110'C ~119'C
 31 };
*/

volatile unsigned int uiCnt;

void ADC_Init()
{
  ADCSRA = 0x85;     // Enable adc, 분주비 32
  ADCSRB = 0x00;    // free running mode
  ADMUX  = 0x40;     // select adc input 0
}


int main(void)
{
  unsigned int uiSum=0;
  int iCnt;
  LCD_Init();
  ADC_Init();
  char cBuf[10];
  int uiTemp=0;
  int i;

  LCD_Print("  Current Temp.");


  while(1)
  {
  
    uiSum = 0;    
    _delay_ms(2000);
    ADCSRA = 0xD5;
    while((ADCSRA & 0x10) != 0x10);
    for(i=0; i<16; ++i)
    {
      ADCSRA = 0xD5;
      while((ADCSRA & 0x10) != 0x10);
      uiSum += (  (int)ADCL + ((int)ADCH<<8) ) ;
    }
    uiSum >>= 4;  // sum = sum / 16, 아날로그 신호의 평균값을 내준다.
    
    uiSum = (uiSum/6.4) - 55;
    
    


    itoa(uiSum, cBuf, 10);

    LCD_INST(0xC0);
    LCD_Print("      ");
    LCD_Print(cBuf);
    LCD_Data('C');
    _delay_ms(2000);

  }

  return 0;
}



 

 

반응형
Posted by newind2000
Busan IT/모터제어2015. 8. 31. 13:37

==================================Outline====================================

스테핑 모터

SE-SM243 스테핑 모터 구동

----------------------------------------------------------------------------

 

스테핑 모터

 

중간 프로젝트가 끝나고 다음 과목인 센서제어로 넘어가기 전에 스테핑 모터를 구동시켜 보겠다.

 

스텝핑 모터는 UN2803APG 칩을 사용하여 구동 시킬 것이다.

 

 

그 전에 이론수업...

 

스테핑 모터는 STEP-BY-STEP모터라고도 불리며 1920년 영국 군함에서 어뢰, 포신 방향의 조정을 위해 사용하게 되었다.

** 펄스 모터라고도 한다. 펄스에 따라 회전이 결정되기 때문이다.

** 스테핑 모터의 장점은 위치결정이 손쉽다는 것이다.

 

영구자석을 중심에 놓고 주변 전도체에 전류를 가함으로써 극성을 변동하여 중심자석을 회전시키는 것이 구동 원리이다.

 

스테핑 모터는 기계적 구조나 전자회로가 간단하고 디지털 제어에 적합하다.

 

스테핑 모터를 사용하는 대표적인 기계는 시계이다.

 

시중에서 스테핑모터의 드라이버를 구할 수 있지만 가격이 만원 대에 육박하기 때문에 회사에서는 드라이버를 사용하는 것을 지양한다. 드라이버의 사용 이유는 전압레벨을 맞춰주기 위함이다.

 

스테핑 모터는 펄스와 동기화되어 1pulse1step을 회전하게 된다. 5상 모터에서는 1pulse를 입력했을 시 0.72도가 회전한다.

** 펄스는 on/off가 반복되어지는 전기신호이다.

 

 

 

상에 따른 각도 변화

 

1상은 3.6, 2상은 1.8... 식이다. [3.6/x]으로 펄스에 대한 각도 변화를 알 수 있다.

 

 

주파수와 스테핑모터의 속도는 정비례한다.

 

회전각을 위한 feedback이 불필요하다. 오차가 적고 회전각이 펄스에 비례하여 일정하기 때문이다. 입력 값에 따라 동작이 충실하여 feedback이 필요 없는 방식을 open loop control이라고 한다.

 

** 토크(torque)는 회전력이다.


스테핑 모터를 쓰는 주요인은 회전각도의 오차가 적고, 오차가 누적되지 않는다는 점이다.

 

드라이버를 사용하지 않더라도 증폭기를 사용하여 스테핑 모터를 구동할 수 있다.

stator의 수는 상 * 2이다.

 

스테핑 모터는 자석의 성질에 따라 3가지 유형으로 나뉜다.

- VR(Variable Reluctance Type)

- PM(Permanent Magnet Type)

- HB(Hybrid Type)





구동회로는 권선에 흐르는 전류의 방향에 따라 유니폴라(unipolar)방식과 바이폴라(bipolar)방식으로 나뉜다.


 

 

스테핑 모터에서 상이 몇 개인지 따라서 1상 여자방식과 2상 여자방식 그리고 1-2상 여자방식으로 나뉜다.

 


SE-SM243 스테핑 모터 구동


스테핑 모터 구동을 위해 데이터 시트를 살펴보자.

 

 

전압을 맞춰주기 위해 5v 전압에 다이오드를 사용하여 감압을 할 것이다. 다이오드가 0.7v 정도 감압을 시켜줄 것이기 때문에 4.3v가 출력될 것이고 오차 범위가 5%미만임으로 사용에 지장이 없을 것이다.

 



 

상위의 정보를 참조하여 스테핑 모터를 구동시켜 보자.

 

 

스테핑 모터는 SE-SM243은 유니폴라 방식에 2상 여자 방식이다. 스퀸스는 다음과 같다.




코드는 간단하다. 

 /*** 코드 ***/

 #include <avr/io.h>

#include <util/delay.h>

#define A 0
#define Ab 1
#define B 2
#define Bb 3
int main(void)
{
  DDRF = 0x0F;
  while(1)
  {
    //A = 0, /A = 1, B = 2 /B = 3
    PORTF = 1 << A | 1 << B;
    _delay_ms(3);
    PORTF = 1 << B | 1 << Ab;
    _delay_ms(3);
    PORTF = 1 << Ab | 1 << Bb;
    _delay_ms(3);
    PORTF = 1 << A | 1 << Bb;
    _delay_ms(3);
       

  }


  return 0;
}





반응형
Posted by newind2000
Busan IT/ARM Controller2015. 8. 28. 17:35


 

회로를 작동 시키기 위해서는 명령 전달의 기준이 되는 클럭 신호가 필요하다. 시간 단위당 클럭 신호의 횟수를 주파수라고 한다.

 

PMC(Power Management Controller)는 주파수를 만들어주는 회로이다. PMC는 회로 작동을 발전기이다.

 

MCU마다 주파수는 정해져 있지만 이것을 소프트웨어적으로 변환할 수 있다. 이것이 PLL이다. 현재 사용하고 있는 소스코드에서 lowlever.c가 주파수를 변환시키는 코드를 가지고 있다.

 

USB의 클럭 신호와 회로 구성이다.

//어셈블리의 확장자: 윈도우에서는 asm, linux에서는 s

 

데이터시트에서 메모리맵은 코딩을 하는데 필수적인 요소이다. ATmegaARM의 데이터 시트는 비교적 친절하게 레지스터나






메모리맵이 설명되어 있다. Cortex 데이터시트는 형편없다.

 

 

 

firmware를 만들 때 가장 먼저 시작되는 함수는 load함수이다.

cstarup.s파일에서 ldrload를 명령으로써 프로그램을 시작하는 기준점이 된다.

pc는 어셈블리 레지스터에서 EIP역할, 즉 다음 수행할 명령어를 가리키는 포인터 역할을 한다.



반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

ARM 타이머/카운터 소스, 초음파 센서 거리측정식  (0) 2015.09.09
Timer/Counter  (0) 2015.09.07
Interrupt Code, 초음파 센서 SRF05, Timer/Counter  (0) 2015.08.19
ARM UART Interrupt  (0) 2015.08.14
ARM USART(2)  (0) 2015.08.12
Posted by newind2000
Busan IT/공장내 Network2015. 8. 27. 17:23

==================================Outline====================================

Select 함수를 사용한 채팅프로그램

- 초과 접속자 발생 시 차단

- ctrl + d 입력 시 정상종료

- 포트 설정

- ctrl + c 정상종료

----------------------------------------------------------------------------

초과 접속자 발생 시 차단

 

지난 시간에 이어...

 

접속자 제한을 3으로 하자. 서버에 접속자가 초과 된 상황을 만들기 위한 작업이다.

 

** 코딩내용을 수정할 때 우선 코딩의 전체 흐름을 살펴본다.

수정한 코드가 전체 프로그램에 미치는 영향을 파악한 후 작업을 진행해야 한다.

눈에 실핏줄 터지기 싫으면...

 

smartsock.h에서 MAX_USER 값을 30에서 3으로 줄인다.

 

 

접속 제한 숫자를 초과하는 클라이언트의 접속을 막아야 한다. 하지만 영문도 모르고 접속이 안되는 접속자의 속상함 방지를 위해, 일단 접속은 허가한 후 넌 팅길거라는 메시지를 보내준다. 초과 접속작의 접속 처리를 위해 접속자의 대화 소켓을 담는 icSock변수를 icSock[MAX_USER+1]로 처리해준다.

 

 

 

accept후 조건문을 만들어 uiUser의 크기가 MAX_USER가 크거나 같을 때 사용자의 접속을 끊고 안내 메시지(꺼져)를 보내준다.

 

 

컴파일 후 클라이언트를 접속시키면 서버와 제한 숫자 내 클라이언트는 정상 작동하지만, 초과 접속한 클라이언트에게 무한반복으로 버퍼에 있는 메시지가 출력된다. 초과인원이 출입 시 동작하는 if문으로 간다. 초과 접속된 클라이언트에게 종료 메시지를 보내주고 클라이언트에서는 해당 메시지를 받으면 접속이 끊어지도록 코딩하자.

 

 

<server.c>

 

  

 

<client.c>

 

** 캡쳐된 코드 소속이 궁금할 때 구분법: iFd쓰면 client, icSock/iSock쓰면 server

 

 

ctrl + d 입력 시 정상종료

 

서버에서 Ctrl + D를 누르면 모든 클라이언트에게 종료 메시지를 출력하고 서버를 종료하도록 처리해주자.

 

 

 

<client.c>

 

 

 

포트 설정

 

PORT를 세련되게 고쳐 주자.

우선 실행파일이 인자를 받을 수 있도록 메인함수를 고쳐준다. 서버부터.

 

 

실행 시 포트번호를 인자로 받게 되고 이것이 유효한 숫자일 경우 포트번호를 변경해준다.

 

 

 

bind를 위해 접속정보를 세팅하는 구조체로 가서 PORT번호를 수정해준다.

 

 

클라이언트에서도 똑같이 작업해준다.

 

 

 

ctrl + c 정상종료

 

서버나 클라이언트에서 정상종료가 아닌 ctrl+c를 눌렀을 경우에도 클라이언트가 고통 받지 않고 정상종료 하도록 코딩해주자.

 

ctrl+c로 눌렀을 경우, 대화소켓으로 받은 read의 반환 값은 0이 된다. 이를 활용하여 read값이 0일 경우 정상종료 시켜주자.

 

<server.c>

 

 

 

<client.c>

 

 

채팅 서버, 클라이언트 만들기는 여기서 끝낸다. 지금까지 코딩한 채팅 프로그램이 성에 안차면 멀티룸 채팅에 도전해 보시씨요.

 

** 멀티룸 채팅 : 채팅 방을 여러 개 만들어서 유저가 선택적으로 접속


/*** 소스 ***/


#include "smartsock.h"

int main(int iRtn, char *cpCMD[])
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  char cBuf[BUF_SIZE];  
  fd_set fdRead;
  char cMSG[MSG_SIZE];
  char cNick[NIC_NAME_SIZE];
  unsigned short usPORT=PORT; //PORT == 7777

  if(iRtn == 2)
  {
    iFd  = atoi(cpCMD[1]);
    if(1024 < iFd)
    {
      if(65535 > iFd)
      {
        usPORT=iFd;        
        printf("PORT no. %d\n", usPORT);
      }
    }
  }


  /*** Nick Name in ***/
  while(1)
  {
    printf("Please Input Nick Name\n");
    fflush(stdout);
    iRtn = read(0, cNick, NIC_NAME_SIZE);
    if(iRtn < 2)//그냥 엔터키를 눌렀을 경우. **ctl + d 누르면 iRtn = 0
      continue;

    cNick[iRtn-1= 0;
    break;

  }
  /*** socket ***/

  iFd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(usPORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  write(iFd, cNick, NIC_NAME_SIZE);

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);      
    select(iFd+1,&fdRead, 000);

    if(0 != (FD_ISSET(0&fdRead) ) )
    {
      iRtn = read(0, cBuf, BUF_SIZE);      
      if(iRtn == 0)
      {
        write(iFd, MSG_END, sizeof(MSG_END));
        break;
      }
      cBuf[iRtn - 1= 0;
      sprintf(cMSG, "[%s]%s ", cNick, cBuf);
      write(iFd, cMSG, MSG_SIZE);

      printf("[Send MSG]: [%s]\n", cBuf);    
    }
    if(0 != (FD_ISSET(iFd, &fdRead) ))
    {
      iRtn = read(iFd, cMSG, sizeof(cMSG));      
      if(iRtn == 0)
      {
        printf("Server does not respond\n");
        break;
      }
      if0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) ))
      {
        break;

      }
      printf("[%s]\n", cMSG);    
    }
  }



  /*** read & write ***/
  //memset(cBuf, 0, BUF_SIZE);
  //iRtn = read(0, cBuf, BUF_SIZE);

  close(iFd);
  return 0;
}

<client.c>


#include "smartsock.h"
#include <unistd.h>

int main(int iRtn, char *cpCMD[])
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER+1];   //accept의 반환 값을 받는 변수
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuf[BUF_SIZE];
  const char * cP;
  fd_set fdRead;
  unsigned int uiUser;
  unsigned int uiCnt, uiCnt2;
  int iMSock;  //store greatest number in file descriptors
  char cNick[MAX_USER][NIC_NAME_SIZE];
  char cMSG[MSG_SIZE];
  unsigned short usPORT=PORT;  //PORT == 7777

  if(iRtn == 2)
  {
    iSock  = atoi(cpCMD[1]);
    if(1024 < iSock)
    {
      if(65535 > iSock)
      {
        usPORT = iSock;
        printf("PORT no. %d\n", usPORT);
      }
    }
  }

  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons(usPORT);

  iRtn = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRtn < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRtn = listen(iSock, 5);
  if(iRtn != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  uiUser = 0;
  while(1
  {
    // setting fd_set
    FD_ZERO(&fdRead);
    FD_SET(0&fdRead);
    FD_SET(iSock, &fdRead);
    iMSock = iSock;    

    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)  //사용자가 접속하면 해당 Fd를 set해주고 가장 높은 fd값을 저장
    {
      FD_SET(icSock[uiCnt], &fdRead);
      //FD_SET(iSock, &fdRead);
      if(iMSock < icSock[uiCnt])
      {
        iMSock = icSock[uiCnt];
      }      
    }
    select((iMSock+1), &fdRead, 000);//select 함수를 사용하여 감시해준다.(입력이 있을때까지 무한대기)
    if0 != FD_ISSET(iSock, &fdRead) ) //지정된 소켓 번호가 있으면 대화 소켓 번호를 받아저장하고 user+
    {
      icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
      if(icSock[uiUser] < 0)
      {
        perror("Accept : ");
        continue;
      }
      if(uiUser >= MAX_USER)
      {
        read(icSock[uiUser], cBuf, sizeof(cBuf));
        sprintf(cMSG, "Server is not vacant");
        write(icSock[uiUser], cMSG, sizeof(cMSG));
        write(icSock[uiUser], MSG_END, sizeof(MSG_END));
        close(icSock[uiUser]);

        printf("Server is not vacant [%s]\n", cBuf);
        printf("Client iP :%s\n", inet_ntoa(stAddr.sin_addr));
        continue;
      }
      read(icSock[uiUser], cNick[uiUser], NIC_NAME_SIZE);
      printf("Incoming Client :[%s] \n", cNick[uiUser]);
      printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
      write(icSock[uiUser], "Welcome :)"sizeof("Welcome :)"));
      sprintf(cMSG, "[%s]님이 입장하셨습니다.",cNick[uiUser] );
      for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
      {
        write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
      }
      ++uiUser;

    }
    if(0 != FD_ISSET(0&fdRead))    //서버에서 키보드 입력 받은 내용 클라이언트에게 보내기
    {
      iRtn = read(0, cBuf, BUF_SIZE);
      if(iRtn == 0)
      {
        for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
        {
          sprintf(cMSG, "Server is aborted");
          write(icSock[uiCnt], cMSG, sizeof(cMSG));
          write(icSock[uiCnt], MSG_END, sizeof(MSG_END));
        }
        break;
      }
      sprintf(cMSG, "[공지사항]:[%s]", cBuf);
      for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
      {
        write(icSock[uiCnt], cMSG, MSG_SIZE);//모든 사용자에게 보낸다.
      }
    }
    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
    {  
      if0 != FD_ISSET(icSock[uiCnt], &fdRead))
      {
        iRtn = read(icSock[uiCnt], cMSG, MSG_SIZE);
        
        if(
        ( 0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) )) 
        ||
        0 == iRtn)
        {
          sprintf(cMSG, "[%s]님이 퇴장하셨습니다.", cNick[uiCnt]);
          close(icSock[uiCnt]);
          --uiUser;
          icSock[uiCnt] = icSock[uiUser];          
          memcpy(cNick[uiCnt], cNick[uiUser], sizeof(NIC_NAME_SIZE));  
        }
        for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
        {
          write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
        }
      }
    }

  }
  for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
  {
    close(icSock[uiCnt]);  
  }
  close(iSock);
  return 0;
}


<server.c>


#ifndef __SMARTSOCK_H__
#include <sys/select.h>
#define __SMARTSOCK_H__

#include <stdio.h>
#include <string.h>
#include <strings.h>
// socket & bind & listen & accept & connect
#include <sys/types.h>
#include <sys/socket.h>

// sockaddr_in
#include <netinet/in.h>

// read & write
#include <unistd.h>

// htonl
#include <arpa/inet.h>

// errno, perror
#include <errno.h>

// open
#include <fcntl.h>
#include <sys/stat.h>

//select
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>

#define PORT      7777
#define IP        "192.168.0.173"

#define MAX_USER     3
#define NIC_NAME_SIZE   9
#define NIC_NAME_MSG   (9+2)

#define BUF_SIZE  255              //only message
#define MSG_SIZE  (BUF_SIZE+1+NIC_NAME_MSG)  //message + Nick Name
#define MSG_END    "\x01\x02\x03"        



#endif /* __SMARTSOCK_H__ */


<smartsock.h>


/*** 파일 ***/

client.c


server.c


smartsock.h







반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 26. 17:49

client2개 이상 서버에 접속하였을 경우, 한 쪽에서만 quit를 눌러도 접속한 클라이언트 모두가 서버에 접속이 끊기는 현상이 발생하였다. 이것을 막기 위해 ‘quit'가 키보드로부터 입력되었을 경우 이것을 종료시키는 명령을 키보드 입력을 감시하는 코드에 넣어주면 해결 된다.

 

 

현재 서버에 2개 이상의 클라이언트를 접속한 후에 강제 종료를 시키면 이전 메시지가 무한반복으로 경우가 발생한다. 이것을 해결해보자.

 

linux 압축

 

tar : 파일을 하나로 묶음

gzip : 용량을 압축

 

tar -xzvf : 압축 해제

 

 

클라이언트의 대화명을 설정할 수 있도록 해준 후 채팅을 할 수 있도록 만들어보자.

 

서버 - 클라이언트 관계에서 일반적으로 서버의 과부하를 줄이기 위해서 클라이언트에서 연산을 하도록 프로그램을 만들어 놓는다.

 

 

찾고자하는 단어 위에서 ‘*’을 누르면 해당 단어들이 노란색 배경으로 바뀐다.

 

 


/*** client.c ***/


#include "smartsock.h"

int main(void)
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  int iRtn;
  char cBuf[BUF_SIZE];  
  fd_set fdRead;
  char cMSG[MSG_SIZE];
  char cNick[NIC_NAME_SIZE];
  
  /*** Nick Name in ***/
  while(1)
  {
    printf("Please Input Nick Name");
    fflush(stdout);
    iRtn = read(0, cNick, NIC_NAME_SIZE);
    if(iRtn < 2)//그냥 엔터키를 눌렀을 경우. **ctl + d 누르면 iRtn = 0
      continue;

    cNick[iRtn-1= 0;
    break;

  }
  /*** socket ***/

  iFd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(PORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  write(iFd, cNick, NIC_NAME_SIZE);

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);      
    select(iFd+1,&fdRead, 000);

    if(0 != (FD_ISSET(0&fdRead) ) )
    {
      iRtn = read(0, cBuf, BUF_SIZE);      
      if(iRtn == 0)
      {
        break;
      }
      cBuf[iRtn - 1= 0;
      sprintf(cMSG, "[%s]%s ", cNick, cBuf);
      write(iFd, cMSG, MSG_SIZE);

      printf("[Send MSG]: [%s]\n", cBuf);    
    }
    if(0 != (FD_ISSET(iFd, &fdRead) ))
    {
      read(iFd, cMSG, MSG_SIZE);      
      printf("[%s]\n", cMSG);    
    }
  }



  /*** read & write ***/
  //memset(cBuf, 0, BUF_SIZE);
  //iRtn = read(0, cBuf, BUF_SIZE);

  write(iFd, MSG_END, sizeof(MSG_END));
  close(iFd);
  return 0;
}



/*** server.c ***/

#include "smartsock.h"
#include <unistd.h>

int main(void)
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER];   //accept의 반환 값을 받는 변수
  int iRtn;
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuf[BUF_SIZE];
  const char * cP;
  fd_set fdRead;
  unsigned int uiUser;
  unsigned int uiCnt, uiCnt2;
  int iMSock;  //store greatest number in file descriptors
  char cNick[MAX_USER][NIC_NAME_SIZE];
  char cMSG[MSG_SIZE];


  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons((PORT));

  iRtn = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRtn < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRtn = listen(iSock, 5);
  if(iRtn != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  uiUser = 0;
  while(1
  {
    // setting fd_set
    FD_ZERO(&fdRead);
    FD_SET(0&fdRead);
    FD_SET(iSock, &fdRead);
    iMSock = iSock;    

    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)  //사용자가 접속하면 해당 Fd를 set해주고 가장 높은 fd값을 저장
    {
      FD_SET(icSock[uiCnt], &fdRead);
      //FD_SET(iSock, &fdRead);
      if(iMSock < icSock[uiCnt])
      {
        iMSock = icSock[uiCnt];
      }      
    }
    select((iMSock+1), &fdRead, 000);//select 함수를 사용하여 감시해준다.(입력이 있을때까지 무한대기)
    if0 != FD_ISSET(iSock, &fdRead) ) //지정된 소켓 번호가 있으면 대화 소켓 번호를 받아저장하고 user+
    {
      icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
      if(icSock[uiUser] < 0)
      {
        perror("Accept : ");
        continue;
      }
      read(icSock[uiUser], cNick[uiUser], NIC_NAME_SIZE);
      printf("Incoming Client :[%s] \n", cNick[uiUser]);
      printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
      write(icSock[uiUser], "Welcome :)"sizeof("Welcome :)"));
      sprintf(cMSG, "[%s]님이 입장하셨습니다.",cNick[uiUser] );
      for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
      {
        write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
      }
      ++uiUser;

    }
    if(0 != FD_ISSET(0&fdRead))    //서버에서 키보드 입력 받은 내용 클라이언트에게 보내기
    {
      iRtn = read(0, cBuf, BUF_SIZE);
      cBuf[iRtn - 1= 0;

      sprintf(cMSG, "[공지사항]:[%s]", cBuf);
      for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
      {
        write(icSock[uiCnt], cMSG, MSG_SIZE);//모든 사용자에게 보낸다.
      }
    }
    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
    {  
      if0 != FD_ISSET(icSock[uiCnt], &fdRead))
      {
        read(icSock[uiCnt], cMSG, MSG_SIZE);
        if0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) )) 
        {
          sprintf(cMSG, "[%s]님이 퇴장하셨습니다.", cNick[uiCnt]);
          close(icSock[uiCnt]);
          --uiUser;
          icSock[uiCnt] = icSock[uiUser];          
          memcpy(cNick[uiCnt], cNick[uiUser], sizeof(NIC_NAME_SIZE));  
        }
        for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
        {
          write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
        }
      }
    }

  }
  for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
  {
    close(icSock[uiCnt]);  
  }
  close(iSock);
  return 0;
}


반응형
Posted by newind2000