SangQ

PIC18F 사용하기!! (컴파일러는 C18 C) 본문

프로젝트

PIC18F 사용하기!! (컴파일러는 C18 C)

SangQ 2010. 10. 19. 12:04
PIC16F를 사용하여 3개의 제품도 만들어봤겟다. 좀 더 고 스펙인 18F 시리즈를 사용해서 
ANSI C compiler 인 C18 C를 써보기로 했다.

사용한 칩은 18F6520이다. 사무실에 킷트가 있길래 사용하였다. 대부분 18F452를 쓴 소스들이 돌아닌다.



1. FUSE 설정

#pragma config OSC = HS, OSCS = OFF                                                    // CONFIG1H   
#pragma config PWRT = OFF, BOR = OFF  //, BORV = 27                     // CONFIG2L   
#pragma config WDT = OFF, WDTPS = 128                              // CONFIG2H
#pragma config CCP2MUX = OFF      // CONFIG3H    
#pragma config STVR = OFF, LVP = OFF ,DEBUG = OFF      // CONFIG4L  
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF                // CONFIG5L
#pragma config CPB = OFF, CPD = OFF                                                                     // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF                           // CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF                                            // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF      // CONFIG7L
#pragma config EBTRB = OFF          
요렇게 일일이 설정하는 방법도 있고

#pragma romdata CONFIG
_CONFIG_DECL(_CONFIG1H_DEFAULT & _OSC_HS_1H,\
             _CONFIG2L_DEFAULT & _BOR_OFF_2L,\
             _CONFIG2H_DEFAULT & _WDT_OFF_2H,\
             _CONFIG3H_DEFAULT,\
             _CONFIG4L_DEFAULT & _LVP_OFF_4L,\
             _CONFIG5L_DEFAULT,\
             _CONFIG5H_DEFAULT,\
             _CONFIG6L_DEFAULT,\
             _CONFIG6H_DEFAULT,\
             _CONFIG7L_DEFAULT,\
             _CONFIG7H_DEFAULT);
#pragma romdata
요런것도 있고,

#pragma config OSC = HS
#pragma config WDTEN = OFF, LVP = OFF
기본적으로 반드시 설정해줘하는것들이 있는데
18F6520을 기준으로 기본적으로 해야 될것은 오실레이터 속도 설정, 와칭독 사용 유무 설정 정도 ??
오실레이터 속도는 당연히 해주는것이고, 와칭독 설정 안했더니 MCU 맘대로 reset이 되어버렸다. ㄷㄷ

여기서 pragma 란보통 C 컴파일러는 컴파일러-specific 부분의 처리를 위하여 #pragma 라는 선행처리기를 사용하곤 합니다. 따라서, #pragma 구문을 사용할 경우 타 C 컴파일러와는 호환이 되지 않기 때문에 보통 C 언어 배울 때 #pragma 키워드를 설명하지 않는 경우가 많습니다. 하지만, 임베디드 컨틀로러의 경우 타사 디바이스와는 근본적으로 호환되지 않는 경우가 대부분이기 때문에 업체마다 #prgam 구문을 이용하여 자사의 디바이스에 맞춰 C 컴파일러의 사용 성능을 최고로 끌어올리고 있습니다.

#pragma 지시어 [옵션...]  <<--이렇게 선언하면 된다. 자세한건 데이터 시트에 있다. ㅎㅎ;

2. 실전 예제 

2-1. 예제의 처음은 LED 깜박이기 이다. ㅎㅎ

#include <p18f6520.h>
#include "delays.h"

void main(void)
{
TRISF = 0x00;  // I/O setting
while(1)
{
LATFbits.LATF0 = ~LATFbits.LATF0;  
Delay10KTCYx(50); // Delay 50 x 10000 = 50,0000   //500000의 명령어를 수행할수 있는시간의 딜레이
}
}

2-2. ADC 사용하기

#include <p18f6520.h>
#include <adc.h>
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>

void  INTCHK(void);
unsigned int ad_read(int channel);
unsigned int result1,result2,result3;
void main( void )
{
INTCON=0Xc0;
PIE1=0B00100000;
TRISC=0b10000000;
TRISF=0b00000100; //F0 : ADC AN5,AN6,AN7
TXSTA=0b00100100;
RCSTA=0b10010000;
SPBRG=64;  // 19200bps

ADCON1 = 0b00000111;  // bit7~6:Read as '0', bit5~4: ( VREF+=AVdd, VREF-=AVss ) bit3~0 : analog AN0~AN7
ADCON2 = 0b10000110;  // bit7: 오른쪽 정렬 , bit6~3: Read as '0' , 
                                          //bit2~0 :110:Fosc/64(000:Fosc/2,001:Fosc/8,100:Fosc/4,101:Fosc/16)

while(1)
{
result1 = ad_read(0);
result2 = ad_read(1);
result3 = ad_read(2);
printf("ADC_Value1 : %d, ADC_Value2 : %d, ADC_Value3 : %d\n\r",result1,result2,result3);
}
}

unsigned int ad_read(int channel)
{ // start an ADC conversion and return the 8 most-significant bits of the result
switch(channel)
{
case 0:
ADCON0 = 0b00010101;                 //AN5
     ADCON0bits.GO_DONE = 1;                  // start conversion
     while (ADCON0bits.GO_DONE == 1);      // wait for it to complete
//     Delay10TCYx( 5 );
     return ADRES;                                     // return high byte of result

     case 1:
     ADCON0 = 0b00011001;                        //AN6
     ADCON0bits.GO_DONE = 1;                 // start conversion
     while (ADCON0bits.GO_DONE == 1);    // wait for it to complete
//     Delay10TCYx( 5 );
     return ADRES;                                   // return high byte of result

     case 2:
     ADCON0 = 0b00011101;                        //AN7
     ADCON0bits.GO_DONE = 1;                 // start conversion
     while (ADCON0bits.GO_DONE == 1);    // wait for it to complete
//     Delay10TCYx( 5 );
     return ADRES;                                   // return high byte of result

     default:
     break;
}  
}

여러개의 ADC를 써보니 한쪽 값이 변할때 다른 한쪽 값이 변해버리는 상황 때문에 뭐가 문제일까?? 하고 계속 찾아봤는데
결론은 키트의 ADC 부분에 다른것이 물려있어서라고 단정 지었다. ^^;;

코드 내용중에 USART1 쓰는 방법도 있다.

#define BAUD   19200      //desired baud rate
#define FOSC   20000000   //oscillator frequency
#define DIVIDER ((unsigned int)(FOSC/(16 * BAUD) -1))
라고 디파인 시켜 놓고

SPBRG = DIVIDER;
요로코롬 쓰면 통신 속도 조절하는데 간편하다.

2-3 SPI 사용하기.

SPI 통신 해봐라고 사장님이 MCP3202를 주셨다. (12bit짜리 ADC : 0~4096)

요거 대로 코드를 구현 하였다.

약간 틀린점은 Start Bit 시작하는 타임이 다르다.

#include <p18f6520.h>
#include <spi.h>
#include <delays.h>

#define SPI_CS LATFbits.LATF7

unsigned int data,data1,data2;
unsigned char var,var1;

void main( void )
{
INTCON=0Xc0;

TXSTA=0b00100100;
RCSTA=0b10010000;
SPBRG=64;  // 19200bps

TRISC = 0b00010000; //// SDI : in
TRISF = 0x00;

// SSPSTAT = 0x40;//01000000                      //레지스트리로 설정하였으나 실패 ㅠ.ㅜ
// SSPCON1 = 0b00100010; //0b00100010        

OpenSPI(SPI_FOSC_64 , MODE_00, SMPMID); // C18 C에서 제공하는 라이브러리에 있는 함수를 사용하였다. 

SPI_CS = 1; 
while(1)
{
SPI_CS = 0;
Delay100TCYx(10);
WriteSPI(0x1E);

if(SSPSTATbits.BF)
{
var = ReadSPI();
var1 = ReadSPI();
}
SPI_CS = 1;
data = var;
data1 = data<<4 ;
data2 = data1 | (var1 & 0xf0) ;
printf("12bit_ADC_Value : %d\n\r" , data2);
// var = 0; var1 = 0;  data =0;  data =0; data2 = 0;
}
}

지금은 랜으로 통신좀 해보겠다고 Wiznet의 W5100과 씨름 중인데 PIC쪽 소스가 거의 안보인다. ㅠ.ㅠ
bootcamp라는 잡지에서 PIC를 쓴 소스가 있긴하나 HI-Tech C고 UDP에 클라이언트 ;;
내가 원하는건 18C C에 TCP에 Server 인데  
소켓만드는 함수부터 내가 다 만들어야되나 avr로 된 헤더 파일을 약간씩 수정하면 될거 같은데 ㅠㅠ 에효~ 그냥 징징