반응형
이전에 프로젝트 했던걸 정리하는 차원에서 포스팅...
펌웨어 시리얼 통신
쉬운 예제가 이해하기 제일좋다.
통신초기화 관련 예제코드
void uart0_init(u32 baud)
{
/*================================
BAUD = F_CPU / (16 * (UBRR + 1) )
UBRR = (F_CPU / (16L*baud)) - 1
==================================*/
baud = (F_CPU / (16L*baud)) - 1;
// buad 로 인자로 받아온 buad로 초기화..
//uart1 register baud setting
UBRR0H = (u08)(baud>>8); // 클경우 상위 8bit만 잘리기에..
UBRR0L = (u08)(baud);
DDRE=0xFE; // PE1(TXD) 출력(1), PE0(RXD) 입력(0)
UCSR0A=0x00;
// UCSR0B=0x18; // Receive enable, Transmitte enable
// UCSR0C=0x06; // 비동기 방식, No parity bit, 1 stop bit
// UBRR0H=0x00;
// UBRR0L=0x67; // 16MHz에서 9600 bps (10진수 103)
// UCSR0B 설정
// bit7:수신완료 인터럽허용 ,
// bit6:송신완료 인터럽허용,
// bit4:uart rx enable,
// bit3: uart tx enable
// bit2 : sendding size setting UCSR0C 같이 설정 => 0 : 8bit
// 11011000
UCSR0B = (1<<7) | (1<<6) | (1<<4) | (1<<3) | (0<<2) ; // 00011000
// UCSR0C 설정
// bit6 : synchro setting => 0: dissynchro mode
// bit5,bit4 : parity bit setting => 00 : not used
// bit3 : stop bit setting => 0 : stop bit 2 use
// bit2,bit1 : data sendding size => 11 : 8bit
// 00001010
UCSR0C = (0<<3) | (1<<2) | (1<<1) | (0<<5) | (0<<4);
}
- iar 컴파일러 기준이다.
- 해당 시리얼을 위와 같이 코딩하면 될듯하다.
- 자세힌 모르겠는데.. 보우레이트 계산에서 틀리게 들어갈수도있으니.. 안되면 직접 공학용계산기 뚜드려서 상수로 넣을것! 한번 위의 수식이 안되서... 직접때러넣으니 통신 성공한적도있음
간단한 printf 대용으로 구현
int getchar(void)
{
// UCSRnA
// bit7 : 버퍼에 수신문자 있으면 1
while (!(UCSR0A & 0x80)) //
; //wait for character
return ((int) UDR0 & 0xFF); //grab character
}
int putchar(int ch)
{
// UCSRnA
// bit5 : 송신 버퍼가 비어서 데이터를 받을 준비되면 1
while (!(UCSR0A & 0x20))
; //wait xmit ready
UDR0 = (unsigned char) ch;
return (ch); //send the character
}
void SendString(char *buf)
{
int i;
for(i=0; i<strlen(buf); i++)
{
if(buf[i]==0)
break;
putchar(buf[i]);
}
}
- iar 기준이다.
- printf 를 사용하기전에 간단히 위와같이 해서 사용하면 될듯
avr에서 쉘만들기
#pragma vector = USART0_RXC_vect
// 비동기 uart 통신위해서 송신측 인터럽 사용
__interrupt void usart0_rxc(void)
{
__disable_interrupt();
u16 i;
u08 dummy;
// UCSR1A &= ~(1<<7); // 인터럽트 플래그 해제
//while(!(UCSR1A&(1<<7))); // 데이터 기다린다.
dummy = UDR0; // 인터럽트 발생시에 일단 i/o 레지스터의 값을 읽어온다.
// usart0 !!!!
buf_rx0[rx0_head] = dummy;
// 그리고 버퍼에 저장시키고
rx0_head = (rx0_head+1)%BUF_SZ;
// 다음 저장을 위해.. 하개 증가시킨다. 단 버퍼의 최대 사이즈는 판별할것
// 엔터를 쳤을때 커맨드로 인식, cmd1 측으로 명령어 string 보낸다.
// 0x0d : carriage return , 0x0a = newline
if(dummy==0x0d || dummy==0x0a)
{
for(i=0; i<CMD0_SZ && rx0_tail!=rx0_head; rx0_tail=(rx0_tail+1)%BUF_SZ, i++)
cmd0[i] = buf_rx0[rx0_tail];
// 차례대로 다시 커맨드배열로 정렬
cmd0[i-1] = 0; // 마지막에 리턴 문자 제거후 완전한 str만듬
cmd0len = i-1;
//for(; i<CMD0_SZ; i++)
// cmd0[i] = 0;
if(i>0)
cmd0f = 1; // 여기서만 set
// setting cmd string input flag --> ParseCmd check
}
// putchar(dummy); // receive echo
__enable_interrupt();
}
- iar 기준이다.
- uart 인터럽 핸들러를 이용한다.
- isr에서 전역으로 선언된 배열에 하나의 캐릭터가 들어올때마다 때려넣는다..
- 엔터 / 탭 등이 들어오면.. 하나의 명령어로 인식을 한다. => 플래그 세팅
- 명령어로 인식하자마자.. 커멘드를 새로 정렬해서 strcmp 하기 쉽게 한다. (전역으로 선언된 배열에 캐릭터를 하나씩 때려넣을때 반대로 들어가있기때문..ㅋㅋ)
- main 코드에서는 명령어들어왔을때의 플래그를 매번 검사
- 플래그 세팅시에 커맨드가 저장된 배열을 비교하면서 해당루틴으로 분기
참고. 고급 printf 구현..
출처 : http://kldp.org/node/23207
임베디드 환경에서의 printf 구현이 쉽지는 않다. 아래와 같은 코딩으로 불편하나마 printf()를 대체하여 쓸수가 있다.
C 함수의 호출 원리를 이용한 sprintf() 의 약식 구현 이다. va_start() 나 va_end() 함수를 사용하여 구현할 수도 있지만, 이것도 stack의 동작을 숨기고 있어서 좀더 low level 로 구현하고자 한다.
스텍이나 메모리 상황이 안좋거나.. 타겟쪽에 라이브러리를 올리지 못하는 상황이라면 아래와같이 코딩하여 사용할수있을것이다.(컴파일이 된다면..) 소스원작자는 32bit ARM에서 target에 printf()관련 라이브러리를 통째로 올릴수없어서 코딩하였다고 한다.
/*+-------------------------------------------------------------------------+
| FILE: sprintf.c |
| Version: 0.1 |
| |
| Copyright (c) 2003 Chun Joon Sung |
| Email: chunjoonsung@hanmail.net /
+-------------------------------------------------------------------------+*/
char *itoa( char *a, int i)
{
int sign=0;
int temp=0;
char buf[16];
char *ptr;
ptr = buf;
/* zero then return */
if( i )
{
/* make string in reverse form */
if( i < 0 ){
i = ~i + 1;
sign++; }
while( i ){
*ptr++ = (i % 10) + '0';
i = i / 10; }
if(sign)
*ptr++ = '-';
*ptr = '';
/* copy reverse order */
for( i=0; i < strlen(buf); i++ )
*a++ = buf[strlen(buf)-i-1];
}
else
*a++ = '0';
return a;
}
char *xtoa( char *a, unsigned int x, int opt)
{
int i;
int sign=0;
int temp=0;
char buf[16];
char *ptr;
ptr = buf;
/* zero then return */
if( x )
{
/* make string in reverse form */
while( x )
{ *ptr++ = (x&0x0f)<10 ? (x&0x0f)+'0' : (x&0x0f)-10+opt; x>>= 4; }
*ptr = '';
/* copy reverse order */
for( i=0; i < strlen(buf); i++ )
*a++ = buf[strlen(buf)-i-1];
}
else
*a++ = '0';
return a;
}
long _sprintf(buf, format, arg)
char *buf;
char *format;
long arg;
{
int cont_flag;
int value;
int quit;
char *start=buf;
long *argp=(long *)&arg;
char *p;
while( *format )
{
if( *format != '%' ) /* 일반적인문자*/
{
*buf++ = *format++;
continue;
}
format++; /* skip '%' */
if( *format == '%' ) /* '%' 문자가연속두번있는경우*/
{
*buf++ = *format++;
continue;
}
switch( *format )
{
case 'c' :
*buf++ = *(char *)argp++;
break;
case 'd' :
buf = itoa(buf,*(int *)argp++);
break;
case 'x' :
buf = xtoa(buf,*(unsigned int *)argp++,'a');
break;
case 'X' :
buf = xtoa(buf,*(unsigned int *)argp++,'A');
break;
case 's' :
p=*(char **)argp++;
while(*p)
*buf++ = *p++;
break;
default :
*buf++ = *format; /* % 뒤에엉뚱한문자인경우*/
break;
}
format++;
}
*buf = '';
return(buf-start);
}
main()
{
char buf[80];
_sprintf( buf, "%d, %x, %X, %sn", 1234, 0xabcd, 0xabcd, "abcd");
puts(buf);
}
반응형