Busan IT/AVR 컨트롤러2015. 4. 28. 17:43

USART를 통한 데이터 전송, LCD에 사용자 지정 문자 출력

 

USART0_Init 함수의 설명(지난블로그에 소스로 올림)

 

 

USB to Serial에서 나온 신호를 그대로 ATmega에 연결하면 과전류가 흘러 MCU의 회로가 타버릴 수 있다. 시리얼 포트에는 7-12v의 전압을 신호로 보내주는데 MCU5v 신호에 맞게 설계되어 있기 때문이다.

 

RS 485Half-Duplex 통신 방식이고, RS 422Full-Duplex 통신 방식이다.

MAX 232 하나를 쓰면 반이중통신, 두 개를 쓰면 전이중통신이 가능하다.

 

//RS 422, 485에 대해 조사해 보자!

LCD에 사용자 지정 문자를 넣어 이름을 출력해보자!


 

못생겼지만 성공했다!

 

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

 

<main.c>

 

#include "SMART.h"
#include "USART.h"
#include "LCD.h"

int main(void)
{
  unsigned int uiNum;
  LCD_Init();
  LCD_INST(0x40); //CG ROM Address Set
  LCD_MYNAME();
  LCD_INST(0x80);
  LCD_Data(0x6f); //O
  LCD_INST(0x83); // 2칸 띄우기 
  LCD_Data(0x01); // ㅎ
  LCD_Data(0x02); // ㅣ 
  LCD_INST(0xC0); // 다음 줄로 이동 
  LCD_Data(0x03); // ㅠㄴ  
  LCD_Data(0xbd); //ㅈ
  LCD_Data(0x04); //ㅐ 
  LCD_Data(0x00); // ㅡ 
  LCD_Data(0x02); // ㅣ 

  
  
    
  while(1)
  {
  ;
    
  }

  
  return 0;

  
            

<SMART.h>

#ifndef __SMART_H__
#define __SMART_H__

/**** General Purpose Register A - L ****/

#define  PORTA (*((volatile unsigned char*)0x22))
#define   DDRA  (*((volatile unsigned char*)0x21))
#define   PINA  (*((volatile unsigned char*)0x20))

#define  PORTB (*((volatile unsigned char*)0x25))
#define   DDRB  (*((volatile unsigned char*)0x24))
#define   PINB  (*((volatile unsigned char*)0x23))

#define  PORTC (*((volatile unsigned char*)0x28))
#define   DDRC  (*((volatile unsigned char*)0x27))
#define   PINC  (*((volatile unsigned char*)0x26))

#define  PORTD (*((volatile unsigned char*)0x2B))
#define   DDRD  (*((volatile unsigned char*)0x2A))
#define   PIND  (*((volatile unsigned char*)0x29))

#define  PORTE (*((volatile unsigned char*)0x2E))
#define   DDRE  (*((volatile unsigned char*)0x2D))
#define   PINE  (*((volatile unsigned char*)0x2C))

#define  PORTF (*((volatile unsigned char*)0x31))
#define   DDRF  (*((volatile unsigned char*)0x30))
#define   PINF  (*((volatile unsigned char*)0x2F))

#define  PORTG (*((volatile unsigned char*)0x34))
#define   DDRG  (*((volatile unsigned char*)0x33))
#define   PING  (*((volatile unsigned char*)0x32))

#define  PORTH (*((volatile unsigned char*)0x102))
#define   DDRH  (*((volatile unsigned char*)0x101))
#define   PINH  (*((volatile unsigned char*)0x100))

#define  PORTJ (*((volatile unsigned char*)0x105))
#define   DDRJ  (*((volatile unsigned char*)0x104))
#define   PINJ  (*((volatile unsigned char*)0x103))

#define  PORTK (*((volatile unsigned char*)0x108))
#define   DDRK  (*((volatile unsigned char*)0x107))
#define   PINK  (*((volatile unsigned char*)0x106))

#define  PORTL (*((volatile unsigned char*)0x10B))
#define   DDRL  (*((volatile unsigned char*)0x10A))
#define   PINL  (*((volatile unsigned char*)0x109))


/* 인터럽트 사용을 위한 레지스터 */

#define EICRA (*((volatile unsigned char*)0x69))
#define EICRB (*((volatile unsigned char*)0x6A))
#define EIMSK (*((volatile unsigned char*)0x3D))
#define EIFR  (*((volatile unsigned char*)0x3C))
#define SREG (*((volatile unsigned char*)0x5F)) 

/* PCINT 사용을 위한 레지스터 */

#define PCICR (*((volatile unsigned char*)0x68))
#define PCIFR (*((volatile unsigned char*)0x3B))
#define PCMSK2 (*((volatile unsigned char*)0x6D))
#define PCMSK1 (*((volatile unsigned char*)0x6C))
#define PCMSK0 (*((volatile unsigned char*)0x6B))

/* 타이머 오버 플로우 */

// General Timer/counter Control Register
#define GTCCR (*((volatile unsigned char*)0x43)) 

// Register for Timer/Counter 0
#define OCR0A   (*((volatile unsigned char*)0x47)) // 타이머 카운터 비교 레지스터
#define OCR0B   (*((volatile unsigned char*)0x48))
#define TCCR0A   (*((volatile unsigned char*)0x44))
#define TCCR0B   (*((volatile unsigned char*)0x45))
#define TCNT0   (*((volatile unsigned char*)0x46))
#define TIFR0   (*((volatile unsigned char*)0x35))
#define TIMSK0   (*((volatile unsigned char*)0x6E))

/* USART */
#define   UCSR0A  (*((volatile unsigned char*)0xC0))
#define   UCSR0B  (*((volatile unsigned char*)0xC1))
#define   UCSR0C  (*((volatile unsigned char*)0xC2))
#define  UCSR1A  (*((volatile unsigned char*)0xC8))
#define  UCSR1B  (*((volatile unsigned char*)0xC9))
#define  UCSR1C  (*((volatile unsigned char*)0xCA))

#define   UBRR0H  (*((volatile unsigned char*)0xC5))
#define   UBRR0L  (*((volatile unsigned char*)0xC4))
#define  UBRR1H  (*((volatile unsigned char*)0xCD))
#define  UBRR1L  (*((volatile unsigned char*)0xCC))

#define   UDR0  (*((volatile unsigned char*)0xC6))
#define  UDR1  (*((volatile unsigned char*)0xCE))


// UCSR0A 레지스터
#define  RXC    7
#define  TXC    6
#define  UDRE  5
#define  FE    4
#define  DOR    3
#define  UPE    2
#define  U2X   1
#define  MPCM   0

// UCSR0B 레지스터
#define  RXCIE  7
#define  TXCIE  6
#define  UDRIE  5
#define  RXEN  4
#define  TXEN  3
#define  UCSZ2  2
#define  RXB8   1
#define  TXB8   0

// UCSR0C 레지스터
#define  UMSEL  6
#define  UPM1  5
#define  UPM0  4
#define  USBS  3
#define  UCSZ1  2
#define  UCSZ0   1
#define  UCPOL   0



/* CPU 동작시간을 맞춰주기 위한 Dealy문과 값 지정 */

#define  Delay(x)    for(uiCnt=0; uiCnt<(dNum1); ++uiCnt)

#define  dNum1 500
#define  dNum2 300000
#define  dNum3 10000000

/* 함수의 원형 */
unsigned char RX0_scan(void);
unsigned char RX0_char(void);
void TX0_char(unsigned char);
void TX0_string(unsigned char *);



#endif //__SMART_H__

 

<LCD.h>

 

#ifndef __LCD_H__
#define __LCD_H__

#include "SMART.H"

#define  LCD_BUS  PORTC
#define  LCD_CTL    PORTG

#define  LCD_BUS_DDR  DDRC
#define  LCD_CTL_DDR  DDRG

#define  LCD_PIN_RS  0 
#define  LCD_PIN_RW  1
#define  LCD_PIN_EN  2

#define  LCD_INST_CLR  0x01 //화면 지우기
#define  LCD_INST_HOME  0x02 //커서 홈
#define  LCD_INST_ENT  0x06 //Increase mode(I/D=1), 쉬프트 ON(S=0)
#define  LCD_INST_DSP  0x0//화면 보이게(1), 커서표시(1),  커서(깜빡 거림)
#define  LCD_INST_CUR  0x14 // 
#define  LCD_INST_FUNC  0x38 




void LCD_AVR_PIN_INIT(void);
void LCD_INST(unsigned char ucInst);
void LCD_Data(unsigned char ucData);
void LCD_Init(void);
void LCD_PRINT(const unsigned char * ucString);
void USART0_INIT(void);
void USART1_INIT(void);
void INIT(void);
void USART0_TX( unsigned char ucData );
void USART1_TX( unsigned char ucData );
void TEST_LCD(void);
void LCD_SetAddr(unsigned char);
void LCD_MYNAME(void);
void LCD_CGRom_Read(unsigned char);
void LCD_CGRom_Write(unsigned char);


#endif //__LCD_H__

<LCD.c>

#include "LCD.h"
#include "USART.h"
#include "SMART.h"

//Wide variable
static unsigned int uiCharCnt;



// LCD driver 프로그램 작성

void LCD_AVR_PIN_INIT(void)
{
  LCD_BUS_DDR = 0xFF;
  LCD_CTL_DDR = (1<<LCD_PIN_RS) |  (1<<LCD_PIN_RW) | (1<< LCD_PIN_EN); // == 0x07
  
  
  return;
}

void LCD_INST(unsigned char ucInst)

{
  volatile unsigned int uiCnt;
  
  LCD_BUS=ucInst;

  LCD_CTL = (0<<LCD_PIN_RS) | (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

  LCD_CTL = (0<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (1<< LCD_PIN_EN); // == 0x01

  
  Delay(500); //4//Tw(230)- Tsu2(80) = 150ns 지연 


  LCD_CTL = (0<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

}


void LCD_Data(unsigned char ucData)

{
  volatile unsigned int uiCnt;

  LCD_BUS=ucData;

  LCD_CTL = (1<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

  LCD_CTL = (1<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (1<< LCD_PIN_EN); // == 0x01

  
  Delay(500); //4//Tw(230)- Tsu2(80) = 150ns 지연 

  LCD_CTL = (1<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN);

  Delay(500); //4//10ns 지연

}

void LCD_Init(void)
  
{
  
  
  volatile unsigned int uiCnt;

  LCD_AVR_PIN_INIT();

  Delay(500); // ATmega가 LCD보다 구동이 먼저 되는 경우를 대비하여 넣어주는 딜레이 코드  

  LCD_INST(LCD_INST_FUNC);
  LCD_INST(LCD_INST_DSP);
  LCD_INST(LCD_INST_ENT);
  LCD_INST(LCD_INST_CUR);
  LCD_INST(LCD_INST_CLR);
  LCD_INST(LCD_INST_HOME);

  uiCharCnt = 0;
  

  return;
}

void LCD_PRINT(const unsigned char * ucString)
{
  for(;*ucString != 0; ++ucString)
  {
    LCD_Data(*ucString);
    
  }
  
  return
}

void LCD_SetAddr(unsigned char ucAddr)
{
  if(ucAddr>15)
  {
    if(ucAddr<40)
    {
      ucAddr = 40;
    }  
    else if(ucAddr>55)
    {
      ucAddr = 0;

    }
  }
  
  

  LCD_INST(0x80|ucAddr);
  
}

void LCD_CGRom_Write(unsigned char ucInst)

{
  volatile unsigned int uiCnt;
  
  LCD_BUS=ucInst;

  LCD_CTL = (0<<LCD_PIN_RS) | (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

  LCD_CTL = (1<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (1<< LCD_PIN_EN); // == 0x01

  
  Delay(500); //4//Tw(230)- Tsu2(80) = 150ns 지연 


  LCD_CTL = (0<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

}
void LCD_CGRom_Read(unsigned char ucInst)

{
  volatile unsigned int uiCnt;
  
  LCD_BUS=ucInst;

  LCD_CTL = (0<<LCD_PIN_RS) | (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연

  LCD_CTL = (1<<LCD_PIN_RS) |  (1<<LCD_PIN_RW) | (1<< LCD_PIN_EN); // == 0x01

  
  Delay(500); //4//Tw(230)- Tsu2(80) = 150ns 지연 


  LCD_CTL = (0<<LCD_PIN_RS) |  (0<<LCD_PIN_RW) | (0<< LCD_PIN_EN); // == 0x00 DC 영역

  Delay(500); //40ns 지연
}


void LCD_MYNAME(void)
{
  volatile unsigned int vuiCnt;
  unsigned char font[] =
  {
      0x0A, 0x040x000x000x000x000x1F, 0x00,  // 0.second char ㅡ  
      0x0E, 0x000x1f, 0x000x040x0a, 0x0a, 0x04,  // 1. forth char ㅎ 
      0x100x100x100x100x100x100x100x10,  // 2. fifth char ㅣ
      0x1F, 0x0A, 0x0A, 0x0A, 0x000x100x1F, 0x00,  // 3. sixth char ㅠㄴ 
      0x120x120x1E, 0x120x120x120x000x00,  // 4. eighth char ㅐ
      0x040x0A, 0x110x0A, 0x040x000x1F, 0x00,  // 5. nineth char ㅇ ㅡ
  
  };
  for(vuiCnt=0; vuiCnt<42; ++vuiCnt)
    LCD_Data(font[vuiCnt]);
    
}

 

 

 

 

 

 

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 4. 28. 09:01

함수 포인터 심화

 

test 함수는 smart 함수를 리턴하고 print 함수를 인자로 받는다.

 

int smart(printf);

 

int (* test(int (* T)(const char *,...))(char *)

{

return mart;

}

 

ptest함수를 가리킬 수 있는 함수 포인터

 

int (*(*p)(int(*)(const char *,...))(char *)

 

//포인터 모양이 이상하다 싶으면 함수 포인터가 아닌지 의심해 봐야 한다.

 

연습

 

1. 반환형 int 이름 smart 인자가 float *k인 함수를 선언한다.

2. 인자가 printf인 함수 testsmart를 반환하게 하게 선언한다.

3. test함수에서 printf를 사용하여 함수가 호출 됨을 선언한다.

4. main 함수에서 함수 포인터 p를 선언하고 ptest를 가리키게 한다.




#include <stdio.h>

int smart(float * k)
{
  
  return 0;
}



int (*  test(int (*T)(const char *, ...)  )  )(float * k)
{
  printf("test함수가 호출됨\n");
  return smart;

}





int main(void)
{

  int (*  (*p)(int (*T)(const char *,...)))(float *k);
  p = test;
  p(printf);


  return 0;

}





 

 

 

반응형
Posted by newind2000
Busan IT/AVR 컨트롤러2015. 4. 27. 15:25

USART - 스위치를 활용한 데이터 전송

 

=================================OUTLINE=================================

GPIOAFIO

USART의 정의

USB to Serial PORT 물리적인 연결 설정

통신규약과 결과 값

(실습)시리얼 통신을 활용한 글자 출력: 스위치를 활용하여 데이터 전송

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

LED를 켜기 위한 포트의 입출력은 GPIO를 통해 하였다.

 

GPIO(General Purpose Input/Output) <-> AFIO(Alternative Function Input/Output)

 

AFIO의 종류는,

 

ADC

DAC

USART

SPI

TWI

PWM

 

등이 있다. 그 중에는 가장 먼저 USART를 배워보자.

 

USART(UART),

 

Universal Synchronous/Asynchronous Receiver Transmitter의 약자로써, 범용 동기/비동기 송수신 방식이다.

 

 

USB to Serial PORT를 활용한 통신







데이터가 깨지는 것을 알 수 있으나 어떠한 방식으로 깨지는 지는 알 수 없다.

 

위의 설정 중 하나라도 통신 대상인 컴퓨터와 일치하지 않으면 데이터가 제대로 전달 되지 않음을 확인할 수 있다.

가장 흔히 쓰이는 통신규약은,

 

BAUD Rate: 9600bps

Parity: 없음

Stop Bit: 1

Hardware Control: None

 

9600-N-1-None

 

9600bps1bit를 전송하는데 걸리는 시간이,

104.17us에 한 bit이고 data1.04ms이다.

 

//milli - micro - nano



 

19200bps에서는,

 

1bit52.08us, 데이터당 520.8us이다. 속도가 빠를수록 안정성이 떨어진다는 단점이 있다.

 

Baud Rate를 산정하기 위해서,

우리는 주로 UBRR을 사용한다.

 

Atmega2560에서,

 

(16000000/16*9600) - 1 = 103


 

//비동기 2배속 모드는 비동기 일반모드보다 Baud Rate 선택 폭이 넓다.

 

지난 시간에 완성하지 못했던 스위치를 활용한 글자 전송을 해보자.

 



/*** 코드 ***/

<main.c>

#include "SMART.h"
#include "USART.h"
 
int main(void)
{
  /* 변수 설정 */
  unsigned char ucNum;

  /* PORT 설정 */
  DDRA = 0x00;
  DDRB = 0xFF;

  
  


  /* USART 레지스터 설정 */
  USART0_INIT();

  
  while(1)
  {
    while(1)
    {
      switch(ucNum = 0x0& PINA)
      {
        case 1 : 
          USART0_TX_string("  Mr. Sushi 문현점은   ");
          while(0x0& PINA == 0x01);
          break;

        case 2 :
          USART0_TX_string("  5월 1일에 ");
          while(0x0& PINA == 0x02);
          break;
        
        
        case 4 :
          USART0_TX_string("  반드시   ");
          while(0x0& PINA== 0x02);
          break;

  

        case 8 :
          USART0_TX_string("  쉬어야 한다!  ");
          while(0x0& PINA == 0x02);
          break;

        default :
          break;
      }
        
    }
  
            
    
  }
  return 0;
}

<USART.h> 

#ifndef __USART_H__
#define __USART_H__

#include "SMART.h"
#define  f_osc  ((unsigned long)(F_CPU)) //F_CPU는 makefile에 지정되어 있다.
#define  BAUD  115200 //BAUD(bps)
#define  UBRR_H  ((unsigned long)((f_osc/(16.0*BAUD))-0.5)>>8//연산자는 괄호로 감싸준다.
#define  UBRR_L  ((f_osc/(16.0*BAUD))-0.5)


void USART0_INIT(void);
void USART0_TX(unsigned char);
void USART0_TX_string(unsigned char *);


#endif //__USART_H__

 

<USART.c>

#include "USART.h"
#include "SMART.h"


void USART0_INIT(void)
{
  //UBRR 12 bit 특성에 따른 자리 값 설정
  UBRR0H=UBRR_H;
  UBRR0L=UBRR_L;


  //UCSRnA 레지스터의 세팅 
  UCSR0A=(0<<U2X) | (0<<MPCM);
  
  //UCSRnB 레지스터의 세팅
  UCSR0B=(1<<RXEN) | (1<<TXEN) | (0<<UCSZ2);

  //UCSRnC 레지스터의 세팅
  UCSR0C  =(0<<UMSEL)|(1<<UPM1)|(0<<UPM0)|(0<<USBS)|
        (1<<UCSZ1)|(1<<UCSZ0)|(0<<UCPOL);//Asynchronous mode, Even Parity, 1-stop bit, 8-bit size

  return;
}

void USART1_INIT(void)
{
  //UBRR 12 bit 특성에 따른 자리 값 설정
  UBRR1H=UBRR_H;
  UBRR1L=UBRR_L;


  //UCSRnA 레지스터의 세팅 
  UCSR1A=(0<<U2X) | (0<<MPCM);
  
  //UCSRnB 레지스터의 세팅
  UCSR1B=(1<<RXEN) | (1<<TXEN) | (0<<UCSZ2);

  //UCSRnC 레지스터의 세팅
  UCSR1C  =(0<<UMSEL)|(1<<UPM1)|(0<<UPM0)|(0<<USBS)|
        (1<<UCSZ1)|(1<<UCSZ0)|(0<<UCPOL);//Asynchronous mode, Even Parity, 1-stop bit, 8-bit size

  return;
}

void USART0_TX_string(unsigned char * ucString)
{
  while(*ucString != 0)
  {
    USART0_TX(* ucString);
    ++ucString;
  }
  return;
}


void USART0_TX(unsigned char ucData )
{
  // Wait for empty transmit buffer 
  while ( 0==( UCSR0A & (1<<UDRE)) );
  
  // Put data into buffer, sends the data
  UDR0= ucData;
  return;
}

void USART1_TX(unsigned char ucData )
{
  // Wait for empty transmit buffer 
  while ( 0==( UCSR1A & (1<<UDRE)) );
  
  // Put data into buffer, sends the data
  UDR1= ucData;
  return;
}

unsigned char USART0_RX( void)
{
  // Wait for data to be received
  while ( 0==(UCSR0A & (1<<RXC)) );  //datasheet p/184
  
  // Get and return received data from buffer 
  
  return UDR0;
}

unsigned char USART1_RX( void)
{
  // Wait for data to be received
  while ( 0==(UCSR1A & (1<<RXC)) );  //datasheet p/184, polling method
  
  // Get and return received data from buffer 
  
  return UDR1;
}



void USART_PRINT(const unsigned char * ucString)
{
  for(;*ucString != 0; ++ucString)
  {
    USART1_TX(*ucString);
    
  }
  
  return
}

 

 

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 4. 24. 17:13

함수 주소를 사용한 호출, 함수의 반환형

 

===========================outline===========================

- 함수 주소를 사용한 함수의 호출

- 함수가 return 값일 경우의 반환형

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

 

<함수의 주소를 사용한 함수의 호출>

 

메인함수의 주소를 출력해 보자.

계속 바뀐다....

 

visual studio에서 메모리 주소 보안 옵션을 끄고 메인 함수의 주소를 추출하자.


 

// 메모리 주소 보완 옵션 끄는 명령어 - cl a.c /link /DYNAMICBASE:NO

// smart의 주소: 0x00401000

<함수가 return 값일 경우의 반환형>

 

함수의 원형은,

 

반환형_함수의 이름(인자)의 형식을 띈다.

ex) int main(void)

 

만약 함수가 함수를 return 값으로 반환할 경우 함수의 인자를 어떻게 나타내 주어야 할까?

 

Q) return 값이 printf 함수인 smart함수를 만들어 보자.

 

? smart(void)

{

return printf;

}

 

에서,

 

우선 반환형 값에 int를 넣어 printf의 함수 원형이 뭔지 알아보자.

printf의 함수 원형은,

 

int (__cdecl *)(const char *,...)

 

임을 알 수 있다. __cdecl의 내용은 모르지만 우선 무시하고 삭제해주면,

 

int (*)(const char *,...)

 

이다.

 

이것을 넣고 다시 컴파일 해보면,

여전히 문법 에러가 뜬다.

 

아래에 답이 있으니 이해할 생각 하지 말고 외우자...

 

int (*)(const char *,...) smart(void)

해당 형태에서 smart(void)(*)*우측에 삽입한다.

 

int (* smart(void))(const char *,...)

 

저장하고 컴파일하면,

슬프도록 아름답게 잘된다.

 

 

 

 

 

 

 

 

반응형
Posted by newind2000
Busan IT/AVR 컨트롤러2015. 4. 24. 17:11

USART 통신의 기초와 기본 코딩

 

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

 <타이머/카운터>

- PWM 주파수 구하는 방법

 

<USART 통신>

- 직렬 통신이란

- 병렬 통신이란

- 직렬/병렬 통신 비교

- 직렬 통신 전송 방식에 따른 구분

- 직렬 통신 전송 방향에 따른 구분

- USART

- USART의 방식

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

 

Timer/Counter RegisterTCCRnA에서 TCNTOCCR 일반 모드/CTC모드/PC PWM로 구분할 수 있다.

 

<PWM 주파수 구하는 방법>

 

AVR 교재 p/185 - 186을 통해서 확인.

 

p/217. 2.3 USART 직렬통신 포트

 

직렬 통신이란,

 

하나의 데이터선을 통해 한 번에 한 비트를 전송하는 통신 방식이다.

한번에 한비트씩 통신함으로 속도가 느리지만 인프라 구축 시 비용이 적게 든다는 장점이 있다. 마이크로 프로세서와 컴퓨터 외부장치가 통신할 때 주로 사용한다.

양단 간 통신 거리가 먼 경우에 사용

ex) PCCOM Port, USB(Universal Serial Bus), IEEE1394, PCI Express

// IEEE1394: 영상 분야에서 많이 사용

 

병렬 통신이란,

 

한 번의 많은 정보를 전달하는 방식이다.

대량의 정보를 빠른 시간에 전송하다보니 속도가 빠르다는 장점이 있으나 인프라 구축 시 비용이 많이 든다는 단점이 있다.

마이크로 프로세서와 컴퓨터 내에 주변 장치간의 통신에 주로 사용된다.

ex) HDD

 

**직렬 통신과 병렬 통신 비교

 

직렬 통신의 전송 방식에 따른 구분,

 

동기식(Synchronous): 마스터(master)에서 슬레이브(slave)쪽으로 특정 신호를 이용하여 그 신호에 맞춰 데이터를 송수신하는 방식이다. 데이터 속도가 빠르나 clock 신호 선이 필요하다는 단점이 있다.

 

비동기식(Asyncronous): 데이터를 보낼 때 특정 약속에 따라 데이터를 송수신하는 방식이다.

 

 

전송 방향에 따른 구분,

 

- 단 방향 통신: 한 방향으로만 데이터를 전송하는 방식 ex)라디오, TV

- 반 이중 통신: 양방향 데이터 송수신이 가능하지만 한 쪽이 송신일 때 다른 방향은 반드시 수신인 형태를 취한다. ex) 무전기, 모뎀

- 전 이중 통신: 양쪽이 자유롭게 송수신이 가능하게 데이터를 전송하는 방식. ex) 전화기

 

USART(Universal Asyncronous Receiver and Transmitter)이란,

 

- 범용 비 동기식 Serial 통신 controller

- 비동기식 serial 통신에 필요한 제어 신호를 생성

// 한 때 유행했던 PC통신(모뎀)을 가능하게 한 장치

 

???

//CRC-8, CRC-16 통신 알고리즘?

오실레이터(oscillator) 값을 조정하면 baud rate가 바뀐다.

 

USART 방식은 크게 두 가지로 나뉜다.

 

1. Polling

- mainwhile(1)문 안에서 지속적으로 작동하며 송수신한다.

 

2. Interrupt

- UDR(수신 버퍼)에 데이터가 들어오면 인터럽트가 발생하여 데이터 전송.

- 특히 수신 부분에서 polling 방식을 취하면 데이터가 유실될 경우가 발생함으로 인터럽트를 권장한다.

/*** 실습 ***/

p/801에 있는 USART관련 코드를 쳐보자.

 

I. 서술

 

polling방식의 시리얼 통신 코드를 작성하는데 이에 필요한 레지스터 값을 넣어주자.

일단 코드를 작성하고 작성한 후 분석을 해보자.

 

II. 작업 나누기

1. 현재 헤더파일에 저장되어 있지 않은 register 값들을 define해준다.

2. 보고 친다=_=

 

III. 코딩

 

다음 시간에...

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 4. 23. 17:37

Void *, Hexaview 프로그램, vi 편집기의 기본 명령어

 

학습목표

 

- void *에 대하여 이해하고 void *의 캐스팅 문법에 대해 숙지한다.

- 헥사뷰 프로그램을 만들 수 있다.

- vi 편집기의 기본 명령어 기능을 익히고 간단한 프로그램을 작성하여 컴파일 할 수 있다.

 

void *는 포인터가 가리키는 형에 상관없이 대상을 지정할 수 있다. 다만 형을 맞춰주기 위해서 캐스팅을 사용해야 한다.

 

캐스팅 방법은 *((type *) X) 이다.

 

 

 

 

 

 

Hexaview를 만들어 보자!

 

주소 값 / 헥사 값 / 아스키 값이 나오도록 프로그램을 작성해야 한다.

골격은 이렇게,

완성된 놈의 코드는 요렇다.

 

/*** 코드 ***/

 

<main.c>

 #include <stdio.h>

#include "hexaview.h"

int main(void)
{
  int iNum=100;
  hexaview(&iNum, 160);
  


  return 0;
}

<hexaview.c>

#include <stdio.h>
#include "hexaview.h"

void hexaview(void * vP, unsigned int uiLen)
{
  unsigned int uiCnt;
  unsigned int uiLine;

  printf("===============================================================================\n");
  printf("  Address      Hexa           ASCII       \n"); 
  printf("-------------------------------------------------------------------------------\n");
  for (uiLine = 0; uiLine <=  uiLen; uiLine += 16)
  {
    printf(" %08X  ", vP);
  
    for(uiCnt=0; uiCnt<16; ++uiCnt)
    {
      printf("%02X ", *((unsigned char *)vP));
      vP = (char *)vP + 1;
    }
    vP = (char *)vP - 16;
    putchar(' ');

    for(uiCnt=0; uiCnt<16; ++uiCnt)
    {
      if (32 > *((unsigned char *)vP))
      {
        putchar('.');
      }    
      else if(127 < *((unsigned char *)vP))
      {
        putchar('.');
      }
      else
      {        
        printf("%1c", *((unsigned char *)vP));
      }

      vP = (char *)vP + 1;
    }
    putchar('\n');
  }
  return;

} 

<hexaview.h>

#ifndef __HEXAVIEW_H__
#define __HEXAVIEW_H__

/*** 함수 원형 선언 ***/

void hexaview(void *, unsigned int);


#endif //__HEXAVIEW_H__


산딸기 시간!

지난 시간에 vi 편집기로 작성하던 test.txt파일로 가보자.

 

<vi 편집기 명령어>

 

우선 20줄 정도의 무작위의 자료를 작성하고 나서 아래의 명령어들을 입력하여 학습해 보자.


<Command mode(esc키를 눌러 설정)>

dw = 한 단어 삭제

dd = 한 줄 삭제 

/dd삭제할 때 해당 줄이 복사된 상태이기 때문에 dd를 누른 후에 pu를 누르면 지웠던 줄이 다시 살아난다.

yy = 한 줄 복사    //y=yanked

yw = 한 단어 복사

p = 붙여넣기    //p=past

shift + p = 복사한 내용 위로 붙혀 넣기

//dy에서 숫자를 누르고 방향키를 누를 때 숫자는 현재 있는 라인에서 추가로 삭제하거나 복사한다.

v = visual  mode: 선택하는 구역을 보여준다.

ctrl + z = 다른 프로세서 실행

/ = 검색 모드

/로 검색한 문자가 1개 이상일 때,

- n = 다음 대상 선택    //n=next

- shift + n = 이전 대상 선택

shift + r or insert key = 겹쳐쓰기 

shift + j = 커서가 있는 줄과 다음줄을 가져다가 붙이기


<Expanded Command Mode(:키를 눌러 설정)>

w_파일명 = 파일명으로 저장


<Insert Mode(i를 눌러 설정)>


a: 현재 위치 다음에 문자 삽입

i: 현재 위치에 문자 삽입

 

//gcc 4.x 버전에서는 메모리 주소가 보안이 되어 바뀐다.

// 컴파일시 main.c -o main의 자리는 바꾸어도 컴파일에 지장이 없다.

컴파일 시 중간파일 생성을 위한 옵션 명령어,

 

gcc --save-temps -o * *.c

반응형
Posted by newind2000
Busan IT/AVR 컨트롤러2015. 4. 23. 12:07

PC PWM을 활용한 LED Dimming

 

학습목표

 

- PC PWM에 대하여 이해한다.

- PC PWM을 활용하여 LED dimming을 할 수 있다.

 

 

**다음 시간에는 16bit를 활용한 타이머를 사용하여 코딩을 해보자.

 

일반 모드와 CTC에 학습하였다.

 

오늘은 PC PWM의 대하여 공부하여 보자.

 

PWMPulse Width Modulation의 약자로 펄스폭 변조라는 의미이다. 클럭의 주기는 유지하나 highlow 구간을 조절하는 기능을 한다.

 

PCPhase Correct의 약자이다.

 

스위치를 이용한 dimming을 만들어 보자!

 

I. 서술

 

PORTA를 입력 PORT로 설정하고 0번 핀은 누를때마다 계속 올라가고 최대 밝기가 되어서는 꺼지게 만든다.

 

II. 작업 나누기

1. PORTA0번 핀을 입력 핀으로 설정한다.

2. 0번 핀을 입력 값으로 설정하고 누를 때마다 밝기가 세어지고 최대 값에서 핀을 한번 더 입력하면 꺼지게 한다.

 

III. 코딩

 

<main.c>

#include <atm2560.h>
#include "SMART.h"

int main(void)
{
  /*** 변수 선언 ***/
  unsigned char i=0, duty=0;
  volatile unsigned int uiCnt;
  char cNum;
  
  /*** 포트 설정 ***/
  DDRB = 0xFF;  //PORT B의 모든 핀 출력 설정
  DDRA = 0xFE;  //PORT A의 1번 핀 입력 설정
  
  
  /*** PC PWM  설정 ***/
  TCCR0A = 0x81;  //Phase Correct PWM
  TCCR0B = 0x02;  // 8분주


  while(1)
  {

    while(PINA==0x01)
    {
      if(PINA==0x00)
      {
          OCR0A = duty;
          duty +=51;          
          ++i;        
          
          if(i==6)
          {
            i=0;
            duty=0;
          }
            
        
      }

    }
        
        
      

    
          
  }
  
  return 0;
}

IV. 회로




 

 

 

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 4. 22. 17:44

함수 포인터, Linux vi 편집기의 설치와 사용

 

학습목표

- 함수 포인터의 문법을 이해하여 printf, scanf문을 사용자 생성 함수 포인터로 만들어 사용할 수 있다.

- 메모리 5대 영역을 이해하고 어떤 내용이 각 메모리에 저장되는지 알 수 있다.

- 리눅스 vi 편집기의 수정모드 명령모드 확장명령모드의 이동법을 익힌다.

- vi 편집기를 활용하여 간단한 코드를 작성하고 컴파일 할 수 있다.

- vi를 활용하여 간단한 편집을 할 수 있다.(삭제, 줄이동, 커서 이동)

 

 

// 초기화 되지 않은 전역변수는 변수 값에 0이 들어 있고 이것은 BSS영역에 저장된다.

 

메모리에 저장된 5가지 영역은 전부 포인터로 가리킬 수 있다.

 

지금까지 배운 바로는 Code 연역을 제외한 모든 메모리 영역을 가리킬 수 있었다.

 

오늘은 포인터로 Code영역을 가리키는 내용을 배워본다.

 

// 함수를 메인함수 밑에 선언한 경우 함수의 원형을 메인함수 위에 적어 주어야 한다.

// Code 영역은 RO로써 Read Only memory로써 오직 읽기만이 가능하다.

 

함수를 가리키는 포인터를 만들어 보자.

 

함수 포인터의 원형은 만들기 위해서,

 

1. 우선 기본적인 함수의 원형에서 이름을 제거한다.

ex) int main(void) -> int (void)

 

2. 함수의 이름을 넣었던 자리에 *을 넣는다.

ex) int (void) -> int *(void)

 

3. *만 넣기 어색하니까 *를 괄호로 싸준다.

ex) int *(void) -> int (*)(void)

 

4. * 옆에 변수명을 적어준다.

ex) int (*)(void) -> int (*smart)(void)

 

결과물은,

 

void (*smart)(void); //smart는 본인 지정 이름으로써 변경 가능

1. const char *A;

2. char const *A;

3. char * const A;

 

const를 선언하면 바로 우측에 있는 값이 상수가 된다. 때문에 1번과 2번의 경우에는 *가 상수(값을 수정할 수 없다)가 됨으로 A는 변수가 된다.

 

// 1번과 2번에서 const의 위치는 내용에 지장을 주지 않는다.

// 대입 연산자에서 왼쪽이 code 영역이 오면 에러가 난다. ex) 6 = 3;

//함수의 원형을 알고 싶을 때는 대입 연산자를 활용하여 일부러 에러를 내서 해당 함수의 원형을 알아 낸 후에 코딩을 한다.

 

예제 p/394

p/395 예제,

p/397 예제,

 

함수 포인터는 어떻게 응용할 수 있을까? To be continued(다음 시간에)

 

산딸기 시간,

 

ftp공유 폴더에 있는 RaspBerryPie관련 파일들을 모두 복사해서 내 컴퓨터에 저장해 놓는다.

vim 설치.txt 파일을 열어 설명에 따라 vim을 설치한다.

 

vi편집기에 대해서 배워보자.

 

vi편집기는 리눅스와 유닉스에서 visual editor로써 보급되어 왔다.

vi3가지 모드(mode)를 가지고 있다.

1. 명령모드 - 맨 처음 실행시키면 명령모드로 들어간다.

2. 수정모드

3. 확장 명령모드 - 커서가 제일 밑으로 가면 확장 명령 모드이다.

 

수정모드와 확장 명령 모드에서 ESC키를 누르면 명령 모드로 들어가진다. 현재 무슨 모드인지 모를 경우 ESC를 누르면 된다.

 

명령모드에서 수정모드로 이동하는 키(key)I(insert), a, o, r키이다.

 

명령모드에서 확장 명령 모드로 이동하는 키는 : 이다.

 

명령모드에서,

 

dd: 한줄 삭제

 

확장 명령모드에서 숫자를 치면 해당 줄로 이동한다. // 존재 줄보다 큰 값을 입력하면 마지막 줄로 이동

 

d + # + 방향키: #만큼의 줄을 방향키 방향으로 지움

 

확장wq를 누르면 vi 편집기를 빠져 나오게 된다.

 

vi 편집기에서,

 

I 수정모드로 간 후 위의 내용을 갖다 붙힌다.

 

확장 명령 모드에서 wq를 치고 빠져 나온다. //wq: write quit

 

vi. main.c를 입력한 후, 기본형을 쳐서 위의 입력한 값이 제대로 작동하는지 본다.

 

간단한 코드를 입력한 후 해당 코드를 컴파일 해보자.

 

컴파일 명령어,

 

gcc -o main main.c // gcc -o_만들 실행 파일명_소스파일

 

리눅스는 exe파일의 개념이 없다. 때문에 실행 파일명만 입력해주면 된다.





shift +D 는 현재 위치로부터 끝까지 삭제

u = 윈도우에서 Ctrl + z

o 키는 새 줄을 삽입하고 insert모드로 바뀐다.

shift o 는 위에 새 줄을 삽입하고 insert모드로 바뀐다.

//shift를 누른 상태에서의 명령어는 반대 기능을 가지는 확률이 높다.

 

//vi의 구현 목적은 마우스를 사용하지 않고 텍스트 편집을 할 수 있게 하는 것이다.

 

명령모드에서 h는 왼쪽으로 이동 l은 오른쪽으로 이동 j는 아래로 이동 k는 위로 이동이다.

 

vi test.txt파일을 만들면 linux에서 .test.txt.swp를 만든다.

wq로 해당 파일을 빠져 나오지 않으면 .test.txt.swp가 삭제되지 않고 백업파일 형식으로 남게 된다.

 

putty접속을 x를 눌러 종료하고 vi test.txt를 입력하면,

아래와 같이 뜨게 된다.

















 

 

 

 

반응형
Posted by newind2000
Busan IT/AVR 컨트롤러2015. 4. 22. 11:17

타이머(Timer)/카운터(Counter)CTC(Clear Timer of Compare Match Mode) 모드

 

학습목표 - CTC 모드를 활용한 인터럽트의 레지스터를 이해하고 설정할 수 있다.

 

타이머(Timer)/카운터(Counter)CTC(Clear Timer of Compare Match Mode) 모드

 

CTC모드의 차이점은 설정 값을 정해주어 0에서부터 지정된 설정 값까지 카운트를 하게 된다.

TCNTn의 값이 OCRnx의 값과 일치하면 그 다음 클록 사이클에서 0으로 클리어되고 인터럽트(Interrupt)가 요청되게 된다.

 

TCNTn의 값이 차례로 증가... 증가... 증가..

if(TCNTn==OCRnx)

인터럽트 발생;

 

/*** 포트 설정 ***/

 

OC0A가 토글되는 것을 표시하기 위해서 PORTB7번 핀을 열어준다.

 

DDRB = 0x80;

 

/*** 레지스터 설정 ***/

- TCCRnA에서 TCT모드를 설정하여 주어야 한다. OCnA OCnB를 다 차단하고 예제를 수행해 보자. COMA/B를 다 0으로 세팅하여 진행. 앞에 4는 카운터 값에 도달했을 때 비트를 반전시키겠다는 의미이다.

 

TCCR0A = 0x42;

- 분주비는 일반모드와 동일하게 1024. 앞에 8은 토글되는 값을 강제로 내보내겠다는 의미이다.

 

TCCR0B = 0x85;

 

- 타이머 마스트는 TIMSK0 = 0x02 compare match mode

TIMSK0 = 0x02;

 

- TCNT와 비교할 OCR0A의 값은 최대치인 0xFF

 

OCR0A = 0xFF;



 

/*** 코드 ***/

<main.c>


#include <atm2560.h>
#include "SMART.h"

unsigned char FND[10= {0x400x790x240x300x190x120x020x580x000x10};
volatile unsigned int uiCnt;
unsigned char ucCnt=0, ucCnt2=0;

int main(void)
{
  /*** 포트 설정 ***/

  DDRB = 0x80;
  DDRC = 0xFF;
  PORTC = 0xFF;

  /*** 타이머 카운터를 위한 설정 ***/

  SREG &= 0x7F;  //Global interrupt
  TIMSK0 = 0x02;  //Timer Compare Match
  TCCR0A = 0x42;  //Timer Mode : CTC모드
  TCCR0B = 0x85;  //분주비 1024
  TCNT0 = 0x00;  //Timer Counter 초기화
  OCR0A = 0xFF;  //
  SREG |= 0x80;  //Global Interrupt 
  
  while(1)
  {

    ;
          
  }
  
  return 0;
}

void __vector_21(void)
{    
    ++ucCnt;

    if(ucCnt==61)
    {
      PORTC=FND[ucCnt2%10];
      ++ucCnt2;
      ucCnt=0;
      if(ucCnt2==250)
        ucCnt2=0;
    }
}

 

 *** LED가 61번 깜빡이고 나서 숫자가 바뀐다. 육안으로는 확인가능했지만 촬영하니 깜빡임이 느껴지지 않았다.


반응형
Posted by newind2000
Busan IT/공장내 Network2015. 4. 21. 17:47

2차원 포인터와 배열, 라즈베리파이 권한 및 그룹 변경, 삼바 네트워크 설정

 

학습목표

 

- 2차원 포인터와 배열의 문법을 이해하고 활용할 수 있다.

- 라즈베리파이의 디렉토리의 권한과 그룹을 변경할 수 있다.

- 라즈베리파이에서 삼바를 사용하여 공유 네트워크를 설정 할 수 있다.

 

2차원 배열에서 배열을 가리키는 주소 값이 헷갈리는 경우에는 +1한 경우에 주소 값이 어떻게 되는지 생각해 보면 알 수 있다.

 

p/374 예제,

 

p/376 예제,

 

int (*ptr) [4]; 는 한 줄이 4개인 배열을 가리키는 포인터이다.

 

int (*p2)[4]: 배열 포인터 -> 배열을 가리키는 포인터

int *p2[4]: 포인터 배열 -> 포인터의 배열

 

p/384 예제,

 

산딸기 시간!

 

본인의 아이디로 접속해서 본인의 ID로 된 디렉토리의 소유와 권한을 root로 바꾸겠다.

 

명령어에 대한 사용법을 알기 위해서는,

 

명령어 --?를 치면 된다.

 

소유와 그룹을 바꾸기 위해서는,

 

소유 -> chown_-R_바꿀디렉토리_소유

ex)chown -R newind2000 newind2000

 

그룹 -> chgrp_권한_줄 대상

ex)chgrp_root_newind2000

 

// cd엔터 혹은 cd ~는 홈디렉토리로 이동하는 명령어

 

파일 앞에 점(.)이 붙어 있으면 숨김 파일의 속성을 띤다.

 

nano /bashrc 파일로 가서,

캡쳐의 화면처럼 alias 앞에 붙은 #를 없애주고, ll명령어에서 'ls -al'로 수정해준다.

저장하고 나온다.

 

명령어 ll을 쳐보면 ls -al 의 결과 값과 같이 나오는 것을 알 수 있다.7

//alias는 명칭을 의미한다.

 

삼바는 네트워크를 설정하는 프로그램이다.

맨 밑에 주소는 내 ip주소를 넣어야 한다.

 

 

 

 

 

 

 

 

반응형
Posted by newind2000