embeded/AVR (ATmega,ATtiny)2011. 7. 25. 11:10
2.31E 버전의 경우
Options - Settings - Make Control 에
Message Filtering Level 이라는 설정을 All로 바꾸어 주면된다. (기본은 Messages 였던듯)
물론, 빌드이기 때문에 수정사항이 있거나 Build All을 해주어야 원하는 코드 사이즈가 나온다.


Rebuilding target Debug...
filename.c
ICCAVR: --cpu=m64 -ms -o D:\prj\Debug\Obj\ -I C:\Program Files\IAR Systems\Ew23 Evaluation version\avr\SRC\CLIB\INC\ -e -y --initializers_in_flash -z9 --no_clustering --cross_call_passes=2 --debug -DENABLE_BIT_D

   IAR Atmel AVR C/EC++ Compiler V2.28A/WIN, Evaluation Version
   Copyright 1996-2002 IAR Systems. All rights reserved.

  14983 bytes of CODE memory (+ 12 bytes shared)
    599 bytes of DATA memory (+ 40 bytes shared)

Errors: none
Warnings: none
Linking...
XLINK: D:\prj\Debug\Obj\filename.r90 C:\Program Files\IAR Systems\Ew23 Evaluation version\avr\lib\cl3s-ec-sf.r90 -o D:\prj\Debug\Exe\filename.hex -Fintel-standard -
 17 213 bytes of CODE memory (8 range fill)
    801 bytes of DATA memory
Errors: none
Warnings: none
 
Total number of errors: 0
Total number of warnings: 0 

[링크 : http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=35464]
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2011. 3. 31. 17:58
PINA_Bit0 이런 녀석이 winavr 쪽의 PINA0 이런것과 1:1 매칭이 되는지
PINA0 PORTA0 이런것이 정말 비트 단위로 읽어올수 있고 조작이 가능한지도 모호한 상황인데..
아무튼 아래의 링크는 iar 용 매크로 라던가 변수선언들을 변환하여
일반적인 avr용 컴파일러에서 컴파일이 가능하도록 해주는 래핑소스이다.

#define GPIO_BITREG(port,bitnum) \
        ((volatile BitRegisterType*)_SFR_MEM_ADDR(port) \
        )->bit ## bitnum

#define PINA_Bit0  GPIO_BITREG(PINA,0)
#define PINA_Bit1  GPIO_BITREG(PINA,1)
#define PINA_Bit2  GPIO_BITREG(PINA,2)
#define PINA_Bit3  GPIO_BITREG(PINA,3)
#define PINA_Bit4  GPIO_BITREG(PINA,4)
#define PINA_Bit5  GPIO_BITREG(PINA,5)
#define PINA_Bit6  GPIO_BITREG(PINA,6)
#define PINA_Bit7  GPIO_BITREG(PINA,7)

[링크 : http://www.koders.com/c/fid4B73863201A18CBCB1076C1A7430B0EBF15B6E9F.aspx?s=crc
 


아무튼 자세한건 집에가서 AVR에다가 올려봐야 하려나 -_-
/* Input Pins, Port A */
#define PINA      _SFR_IO8(0x19)
/* Data Direction Register, Port A */
#define DDRA      _SFR_IO8(0x1A)
/* Data Register, Port A */
#define PORTA     _SFR_IO8(0x1B)

/* Port A Data Register - PORTA */
#define    PA7       7
#define    PA6       6
#define    PA5       5
#define    PA4       4
#define    PA3       3
#define    PA2       2
#define    PA1       1
#define    PA0       0

/* Port A Data Direction Register - DDRA */
#define    DDA7         7
#define    DDA6         6
#define    DDA5         5
#define    DDA4         4
#define    DDA3         3
#define    DDA2         2
#define    DDA1         1
#define    DDA0         0

/* Port A Input Pins - PINA */
#define    PINA7        7
#define    PINA6        6
#define    PINA5        5
#define    PINA4        4
#define    PINA3        3
#define    PINA2        2 
#define    PINA1        1
#define    PINA0        0

[출처: C:\WinAVR-20100110\avr\include\avr\iom128.h] 
 
-- 퇴근후 추가
대충해보니 머.. 정의문이라서 정수로 들어가다 보니 아무런 의미도 없는듯 -_-
아무튼, PINA.0 이런식으로 구성이 가능한것은  code vision 쪽 확장인것으로 추측되고
winavr에서는 표준적으로 비트 마스킹을 통해서만 가능한 것으로 추측된다.

[링크 : http://down.file.naver.com/howpc/kin.nhn?m=read&section=read&docid=117760743&page=362]
[링크 : http://cafe359.daum.net/_c21_/bbs_search_read?grpid=1DDsW&fldid=9E8k
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2011. 3. 31. 09:37
아래는 winavr의 iom64.h의 내용중 일부이다
/* Input Pins, Port A */
#define PINA      _SFR_IO8(0x19)

/* Data Direction Register, Port A */
#define DDRA      _SFR_IO8(0x1A)

/* Data Register, Port A */
#define PORTA     _SFR_IO8(0x1B)

정리하자면
PINA는 입력된 값을 읽고
PORTA는 출력할 값을 읽고
DDRA는 그 포트의 방향을 정해준다.

예를들어, UART 같은 경우
TX 값은 PORTA에 쓰고, RX값은 PINA에서 읽는 식이라고 하면 되려나?
Pin* is for read, Port* is for write and DDR* is for direction... 
* = Register ( A, D,C...) 

PIN* is the register you use to read the value on a port if it is an input (so if the corresponding bit in DDR* is '0'). PORT* is used to output values, or to read earlier outputted values back.
 
[링크 : http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=197070]
 


Posted by 구차니
embeded/AVR (ATmega,ATtiny)2011. 3. 12. 22:13
WINAVR로 프로그램을 하긴 했지만, sizeof로 일일이 확인해본게 아니라 긴가민가 했는데
일단 ATMEGA128은 8bit 프로세서이고, int 형은 2byte이다.


ATmega128   8-bit AVR Microcontroller, 128KB Flash, 64-pin
                   View Parameters



[링크 : http://blog.daum.net/lucifer_blog/38]

 The concept is quite simple. The file types.h includes the ANSI-required file limits.h. It then explicitly tests each of the predefined data types for the smallest type that matches signed and unsigned 1-, 8-, 16-, and 32-bit variables. The result is that my data type UCHAR is guaranteed to be an 8-bit unsigned variable, INT is guaranteed to be a 16-bit signed variable, and so forth. In this manner, the following data types are defined: BOOLEAN, CHAR, UCHAR, INT, UINT, LONG, and ULONG.

Posted by 구차니
원래 목적은, 임의의 인터럽트를 소프트웨어적으로 발생시키는 건데
딱히 그에 맞는 문서를 발견하지 못했다.

그와 유사한 것은
외부 인터럽트의 경우 입력으로 설정되어 있더라도, 핀값을 설정해서 임의로 인터럽트를 발동시킬수 있다고 한다.

[링크 : http://gnc.chungbuk.ac.kr/?module=file&act=procFileDownload&file_srl=38154&sid=bdc58bb2e09e0bbfb91e3d176e68a1cf]
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2010. 2. 16. 22:46
별건 아니지만, 예전 프로그램을 조합+개조하여 만들어 본 녀석인데..
흐음.. 엔터를 두번이나 눌러야 하다니 이걸 어떻게 개선을 해야 하려나..

아무튼 이녀석의 목적은
- 서보모터를 시리얼 포트를 통해 값을 입력받아 제어한다.

일단 약간의 버그로 인해
- 숫자 입력후 엔터를 두번 눌러야 각도가 변경되고
- 엔터만 눌러대거나, 이상한 각도를 입력하면 서보가 길길댄다.

입력가능한 숫자 범위는 서보마다 다르겠지만
ES-311 엘레파츠의 저렴한 모터로는
32~112 값으로 0도에서 180도까지 이동이 가능하다(정확하게는 한 160도 정도 되는듯?)

Posted by 구차니
embeded/AVR (ATmega,ATtiny)2010. 1. 14. 16:00


일단은 보면 두개의 파형이 다르다.
하나는 45Hz 이고 다른 하나는 48Hz 이다...

위의 사진(45Hz)은 180도로 설정하기 위한 2000us 이고
아래 사진(48Hz)은    0도로 설정하기 위한 600us 이다. (grid 하나당 10ms)

아무튼, 20ms 간격은 맞지만, 문제는 20ms 로 반복되는 것이 아니라
20ms 이후에 신호가 나옴으로 인해서 점점 주기에서 벗어나는 문제가 발생했다.
이래저래 PWM 신호 발생 루틴을 수정해야할듯 하다.



ES-311은 원래 HS-311의 클론이고,
HS-311은 1500usec neutral에 +- 900 usec으로 제어신호를 보내면 된다.(머리 데굴데굴 0ㅁ0)

[링크 : http://www.servocity.com/html/hs-311_standard.html]

2010.02.03 추가
HS-311 은 90도 버전과 180도 버전 두가지가 존재하나 보다.

2010/01/11 - [AVR / 8051] - Atmega128에서 아날로그 서보모터 작동시키기(Atmega128 analog servo tutorial)

Posted by 구차니
embeded/AVR (ATmega,ATtiny)2010. 1. 11. 23:55
How to control analog servo using Atmega128 timer0 (8bit timer)

서보모터는, 재미난 녀석이다. 근데 다루기 쉽지는 않다 ㅠ.ㅠ
예전에 구매한 녀석으로 이렇게 생겨먹었다.

특이하게도 색이 흰색/빨강/검정이 아니라 주황/빨강/갈색이다.
빨강은 Vcc
갈색은 GND
주황은 Signal 이다.


서보 스펙
아날로그 신호를 받아들이며(아날로그 서보)
4.8V에 0.19sec/60' 대략 180도 전체 이동에 0.6sec 정도 걸린다.(생각보다 빠른거 같은데 막상보면 느리다.)

AVR 스펙
us-technology 사의 제품으로 16Mhz로 작동하며
PORTC 는 디버깅용 LED
PORTF 는 PWM 출력용으로 사용하였다.

Timer0(8bit timer)를 이용하여, PWM 신호를 만들어낸다.(Timer만으로 제어함)
[링크 : http://www.us-technology.co.kr/product/product_main.asp?mode=101&smode=2]

소스코드는 AVR BIBLE (배성중/북두출판사) 를 참고하였으며
winavr 요즘 버전에 맞추고(ISR, outp 매크로, include 경로), 클럭이 맞지않아 변수들을 수정하여 타이밍을 조절하였다.

지루한 계산
16Mhz = 16,000,000 hz 이고
서보 모터는 20ms = 0.02sec 단위로 신호를 넣어준다.
그리고 PWM 신호는 0.5ms ~ 2ms 사이의 길이를 넣어주면 0 ~ 180도의 각도로 이동한다.
(책에는 1.5ms 에서 길거나 짧거나 라고 하는데 서보마다 다른듯.. 데이터 시트에도 없다 ㄱ-)

일단 8bit timer를 사용함으로 256 clock 마다 overflow를 발생시키며
    16,000,000(clock/sec) / 256 = 62,500 times
1초에 62,500 번의 overflow가 발생하게 된다.
    1/62500 = 0.000016 sec 이며
    62500/50 = 1250 이다.(20ms 는 1초에 50회)
즉, 256번씩의 overflow를 1250번 반복하게 되면 0.02sec = 20msec 간격을 잡을수 있다.
그리고 1msec는 62.5 인터럽트가 모이면 되고,
실험적으로 서보에서 사용하는 PWM의 width를 얻어내면 된다.

엘레파츠 ES-311 서보에서
     0도는 0.512ms = 32 overflows
    90도는 1.216ms = 76 overflows
    180도 1.792ms = 112 overflows

아무튼 위의 값은 정확한건 아니지만.. (ㄱ-) 대략적으로 맞아들어가며
0도와 180도의 하한/상한을 찾은뒤 평균내면 90도가 잡아진다.(레드썬!)
(위의 값으로는 180도 쪽이 약간 5도 정도 부족해 보이나,
끽끽대며 더이상 가지 못하는 문제가 있어 실질적으로 90도를 약간 좌측으로 수정해야 하지 않을까 싶다.)

대충의 계산방식이 들어있는 스프레드시트 파일.
클럭과 timer overflow 에 필요한 clock을 입력하면 된다.



Posted by 구차니
타이머는 처음인데.. 머가 먼지 모르겠다 ㅠ.ㅠ
#include "stdio.h"
#include "avr/io.h"
#include "avr/interrupt.h"
#include "util/delay.h"

static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

static int uart_putchar(char c, FILE *stream)
{
  if (c == '\n') uart_putchar('\r', stream);
  loop_until_bit_is_set(UCSR0A, UDRE);
  UDR0 = c;

  return 0;
}

#define OVERFLOW 256
#define TICKS_PER_SEC 1000
#define Prescaler 64

volatile unsigned int tic_time;

ISR(TIMER0_OVF_vect)
{
	tic_time++;
	TCNT0 = OVERFLOW - (F_CPU / TICKS_PER_SEC / Prescaler);
}

int main(void)
{
	/* for USART */
	UBRR0H = 0;
	UBRR0L = 8; // 115k with U2X = 0
	UCSR0A = 0x00; // U2X = 0;
	UCSR0B = 0xD8;
	UCSR0C = 0x06; //Asyncronous - no parity - 1bits(stop) - 8bits(data)

	DDRD = 0x00;

	stdout = &mystdout;

	TCCR0 = 0x04;     // Prescaler 설정
	TCNT0 = OVERFLOW - (F_CPU / TICKS_PER_SEC / Prescaler);// 오버플로우에 사용될 초기값
	TIMSK = 0x01;     // 오버플로우 인터럽트 허용
	sei();

	int count = 0;
	for(;;)
	{
		if(tic_time == 1000)
		{
			tic_time = 0;
			printf("c %d\n",count++);
		}
	}
    return 0;
}
일단 사용법을 몰라서. 구글 검색하다 나온 rcan 님의 블로그 내용을 일단 복사해서 붙여넣었다.
[링크 : http://rcan.net/560]


기본적인 내용은 printf() 사용하는 것들이고, F_CPU는 cpu 클럭에 관한 선언문으로
AVRStudio wizard 사용시 클럭을 넣어주면 생성되는 변수이다.

타이머 관련 내용은 다음과 같다.

ISR(TIMER0_OVF_vect) // 8bit Timer0 에 대한 인터럽트 루틴
TCCR0;             // 타이머 프리스케일러
TCNT0;             // 타이머/타운터용 초기값
TIMSK;              // 타이머 오버플로우시 인터럽트 발생

일단 TCCR0를 보자면


타이머/카운터 제어용 레지스터로서,

Bit 7 – FOC0: Force Output Compare
Bit 6, 3 – WGM01:0: Waveform Generation Mode
Bit 5:4 – COM01:0: Compare Match Output Mode
Bit 2:0 – CS02:0: Clock Select

에 대한 설정을 하게 된다.

TCCR0 = 0x04 에서 0은 WGM01:0=0 으로 아래의 테이블을 보면(엄밀하게는 0x48 값의 위치이다)
Timer/Counter Mode of OperationNormal로 되어있다.

이 모드에서는 0에서 부터 255까지(8bit 타이머) 증가하며,
별도의 카운터 값 리셋은 하지 않으나 오버플로우 된상태로 계속 더하므로,
실질적으로 255다음에 0부터 계속 증가하게 된다. (TCNT0는 수정하는 즉시 그 값부터 증가하게 됨)


TCCR0 = 0x04 에서 4는 CS02=1로 아래의 테이블을 보면
clkT0S/64 (From prescaler) 라고 되어있다. 즉, 입력 클럭을 64로 나누어서 느긋하게 증가시킨다.




그리고 TCNT0
카운트를 위한 변수이고, 8bit timer/counter 이므로 0x00 에서 0xFF 즉, 0 에서 255 값을 가지며
255가 되면 overflow interrupt를 발생시킨후 0부터 다시 숫자를 증가시킨다. (normal mode)

그런데 이 변수에 복잡한 수식으로 값을 넣는 이유는 정확한 시간을 발생하기 위해서이다.
클럭마다 다르겠지만, 일단 클럭을 위에서 1/64로 주므로 64 clock 마다 1씩 증가된다.
16Mhz 에서 64clock 마다 인터럽트를 생성하면(F_CPU / Prescaler) 1초에 250,000 번 발생하게 되고
이 오버플로우 갯수를 세어 1000번을 묶으면 (tic_time == 1000 그리고 F_CPU / TICKS_PER_SEC / Prescaler)
1초에 250번의 오버플로우가 발생하게 된다.
그런데 오버플로우 값은 255 까지(총 256) 이므로, 0부터 증가해서 255까지 timer를 증가시키면
1초가 맞지 않게 되므로, TCNT0의 값을 OVERFLOW - 250 으로 하여 초기값을 맞춰주게 된다.
결과적으로 TCNT0의 값은 6이 된다.
(음.. OVERFLOW가 255여야 하지 않을려나..)



그리고 TIMSK는 이름대로 타이머 인터럽트 마스크 레지스터로,

Bit 1 – OCIE0: Timer/Counter0 Output Compare Match Interrupt Enable
Bit 0 – TOIE0: Timer/Counter0 Overflow Interrupt Enable

오버플로우시에 인터럽트를 발생시키거나
OCR0(Output Compare Register) 값과 TCNT0의 값이 동일할때 인터럽트를 발생시키도록 설정한다.

TIMSK = 0x01; 이므로 TOIE0가 설정되었고, 이 값은 overflow 시에만 인터럽트를 발생시키도록 한다.


Posted by 구차니

서보에 주어야 하는 데이터는 20ms 간격, 개당 2.5ms 씩
그런 이유로 1개의 타이머로 제어시 최대 8개 까지 가능
Posted by 구차니