quinta-feira, 3 de outubro de 2013

usando a interface USB HID do PIC18F4550 no MplabXC8

              Para quem leu o post sobre a criação de uma porta com virtual ( http://microcontroladores-c.blogspot.com.br/2013/10/exemplo-de-rs-232-via-usb-com-pic.html ) este exemplo segue o mesmo raciocínio embora seja mais simples que o da porta COM virtual(usa pouca biblioteca ) .Me basei em outro exemplo da microchip onde o microcontrolador vai indicar através de leds o estado da porta usb e também controlar esses leds, além de monitorar o estado de uma chave conectada ao pino RB5.
              Aqui está os arquivos para baixar: https://drive.google.com/folderview?id=0Bx9JeN0dmzXxV0h6LWMzVWVvLVE&usp=sharing  .dentro desta paste tem um aplicativo exemplo da microchip e que será utilizado para testar sua aplicação("HID.exe" veja figura abaixo) , a diferença deste programa em relação ao da porta COM virtual é que aqui é usado o modo de transferência em massa (em que é possível enviar grandes pacotes) .

             o hardware necessário para este exemplo e bem simples veja na figura a seguir:

Ao descompactar a pasta "exemplo usb_HID" e rodar a IDE Mplab XC8 procure na pasta firmware o arquivo do programa , pronto é rodar e gravar no microcontrolador a partir dai faça as alterações que você julgar necessário, finalizo aqui os exemplos usb com pic.  

quarta-feira, 2 de outubro de 2013

exemplo de RS-232 via USB com pic 18F4550 no Mplab XC8

    Olá a todos que seguem este blog pelo face e aos visitantes,hoje vou ensinar como fazer uma aplicação usando a USB no modo CDC(emula uma porta virtual RS232).Este exemplo foi baseado nos exemplos da microchip,todos os includes necessário para funcionar com o PIC18F4550 foram agrupados em uma pasta, procurei manter a estrutura da pasta da microchip pois a pilha usb  só funciona com a mesma estrutura da pasta de exemplo da microchip,assim para criar uma nova aplicação basta copiar esta pasta e alterar o nome da copia, e fazer algumas modificações que será explicado logo mais.
    Para fazer uma aplicação USB você vai precisar de instalar em seu PC os seguintes softwares que podem ser baixados no site da michochip:

    -> compilador C18 vá a este link e faça o dowload(pode ser versão acadêmica)
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010014   
    -> framework USB da microchip (drive da usb).
 http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en547784  
     Supondo que vc já tenha instalados os programas acima, verifique no XC8 se aparece o compilador C18(use como se fosse abrir um novo projeto),quando aparecer esta tela estará ok!



      Agora baixe a pasta "exemplo usb_cdc.rar" neste link : https://drive.google.com/folderview?id=0Bx9JeN0dmzXxV0h6LWMzVWVvLVE&usp=sharing,descompacte a pasta e renomeie(se quiser) e em seguida abrir com o XC8(abra pelo programa XC8),depois de aberto clique no arquivo "main.c" conforme a foto abaixo:

        

      veja que aparecerá algum "Warning" no compilador mas não se preocupe com isso pois isso é pelo fato de ter retirado algumas biblioteca que não são necessário para esta aplicação.
pronto! agora é só compilar e gravar o micro controlador.
      para criar seu programa basta alterar e verificar as seguinte bibliotecas:

"HardwareProfile.h", aqui está configurado o clock e os pinos do microcontrolador
"usb_descriptors"  , aqui é configurado o nome do dispositivo e a classe.
 
      Depois disto é só adicionar seu programa no local que está a rotina principal, para testar a microchip já deixou uma aplicativo de teste com o nome "Dynamic CDC Demo.exe" clique nele e digite algo para testar o programa(que apenas pega o que vem da serial virtual e retorna ao pc). o programa main deste exemplo tem a seguinte aparência:

 
O código fonte da rotina main():

//////////////////////includes necessários  /////////////////////////////////////////
// o resto das configurações então em hardware profile
#include "./USB/usb.h"//chama todas as lib necessarias
#include "/MPLAB.X/HardwareProfile.h" //aqui está configurado o clock e os pinos do microcontrolador
#include "GenericTypeDefs.h"//lib que define os tipos utilizados
#include "./USB/usb_function_cdc.h"//funçoes da serial
#include "Compiler.h"//aqui se define o compilador que está sendo utilizado
#include "usb_config.h"//configura a usb
#include "USB/usb_device.h"


//////////////config. dos fuses do microcontrolador///////////////////////////////
#pragma config PLLDIV   = 5         // (usei um cristal de 20 MHz )
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2         // o clock do pll será 96MHz PLL/2 = 48Mhz
#pragma config FOSC     = HSPLL_HS
#pragma config FCMEN    = OFF
#pragma config IESO     = OFF
#pragma config PWRT     = OFF
#pragma config BOR      = ON
#pragma config BORV     = 3
#pragma config VREGEN   = ON      //ativa o regulador de voltagem da USB
#pragma config WDT      = OFF
#pragma config WDTPS    = 32768
#pragma config MCLRE    = ON
#pragma config LPT1OSC  = OFF
#pragma config PBADEN   = OFF
//      #pragma config CCP2MX   = ON
#pragma config STVREN   = ON
#pragma config LVP      = OFF
//      #pragma config ICPRT    = OFF       // Dedicated In-Circuit Debug/Programming
#pragma config XINST    = OFF       // Extended Instruction Set
#pragma config CP0      = OFF
#pragma config CP1      = OFF
//      #pragma config CP2      = OFF
//      #pragma config CP3      = OFF
#pragma config CPB      = OFF
//      #pragma config CPD      = OFF
#pragma config WRT0     = OFF
#pragma config WRT1     = OFF
//      #pragma config WRT2     = OFF
//      #pragma config WRT3     = OFF
#pragma config WRTB     = OFF       // proteção de escrita da inicialização (Boot)
#pragma config WRTC     = OFF
//      #pragma config WRTD     = OFF
#pragma config EBTR0    = OFF
#pragma config EBTR1    = OFF
//      #pragma config EBTR2    = OFF
//      #pragma config EBTR3    = OFF
#pragma config EBTRB    = OFF

/////////////////////variaveis requerida pela USB /////////////////////////////////////////////////////

#pragma udata
char USB_Out_Buffer[CDC_DATA_OUT_EP_SIZE];
char RS232_Out_Data[CDC_DATA_IN_EP_SIZE];

unsigned char NextUSBOut;
unsigned char NextUSBOut;
//char RS232_In_Data;
unsigned char LastRS232Out; // Number of characters in the buffer
unsigned char RS232cp; // current position within the buffer
unsigned char RS232_Out_Data_Rdy = 0;
BOOL espera = 0;
USB_HANDLE lastTransmission;

//BOOL stringPrinted;


/**********prototipo das funções ***************************************/
void USBDeviceTasks(void);
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
void USBCBSendResume(void);
//void BlinkUSBStatus(void);
void UserInit(void);
void InitializeUSART(void);
unsigned char getcUSART();

/********** remapeando vetores ****************************/
#define REMAPPED_RESET_VECTOR_ADDRESS        0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS    0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS    0x1018
#define APP_VERSION_ADDRESS                     0x1016 //Fixed location, so the App FW image version can be read by the bootloader.
#define APP_SIGNATURE_ADDRESS                   0x1006 //Signature location that must be kept at blaknk value (0xFFFF) in this project (has special purpose for bootloader).

#define APP_FIRMWARE_VERSION_MAJOR  1   //valid values 0-255
#define APP_FIRMWARE_VERSION_MINOR  0   //valid values 0-99

/////////////////defines da porta serial /////////////////////////////

#define mDataRdyUSART() PIR1bits.RCIF
#define mTxRdyUSART()   TXSTAbits.TRMT
//--------------------------------------------------------------------------

#pragma romdata AppVersionAndSignatureSection = APP_VERSION_ADDRESS
ROM unsigned char AppVersion[2] = {APP_FIRMWARE_VERSION_MINOR, APP_FIRMWARE_VERSION_MAJOR};
#pragma romdata AppSignatureSection = APP_SIGNATURE_ADDRESS
ROM unsigned short int SignaturePlaceholder = 0xFFFF;

#pragma code HIGH_INTERRUPT_VECTOR = 0x08

void High_ISR(void) {
    _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18

void Low_ISR(void) {
    _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
extern void _startup(void); // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS

void _reset(void) {
    _asm goto _startup _endasm
}
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR(void) {
    _asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR(void) {
    _asm goto YourLowPriorityISRCode _endasm
}
#pragma code
#pragma interrupt YourHighPriorityISRCode

void YourHighPriorityISRCode() {

#if defined(USB_INTERRUPT)
    USBDeviceTasks();
#endif

} //This return will be a "retfie fast", since this is in a #pragma interrupt section
#pragma interruptlow YourLowPriorityISRCode

void YourLowPriorityISRCode() {

} //This return will be a "retfie", since this is in a #pragma interruptlow section

#pragma code
static void inicializa_cpu(void)
{
    ADCON1 |= 0x0F; // coloca todos os pinos como saida
    #if defined(USE_USB_BUS_SENSE_IO)
    tris_usb_bus_sense = INPUT_PIN; // veja HardwareProfile.h
    #endif
    #if defined(USE_SELF_POWER_SENSE_IO)
    tris_self_power = INPUT_PIN; // veja HardwareProfile.h
    #endif

    UserInit();
    USBDeviceInit(); //usb_device.c.  inicializa o modulo USB e os SFRs
    //variaveis para saber o status.
}//fim de inicializa_cpu

void UserInit(void) {
    unsigned char i;
    InitializeUSART();
    //     inicializa vetor
    for (i = 0; i<sizeof (USB_Out_Buffer); i++) {
        USB_Out_Buffer[i] = 0;
    }
    NextUSBOut = 0;
    LastRS232Out = 0;
    lastTransmission = 0;
}//end UserInit

void InitializeUSART(void) {
    unsigned char c;
    UART_TRISRx = 1; // RX
    UART_TRISTx = 0; // TX
    TXSTA = 0x24; // TX enable BRGH=1
    RCSTA = 0x90; // Single Character RX
    SPBRG = 0x71;
    SPBRGH = 0x02; // 0x0271 for 48MHz -> 19200 baud
    BAUDCON = 0x08; // BRG16 = 1
    c = RCREG; // read

}//end InitializeUSART

void putcUSART(char c) {//escreve na serial
    TXREG = c;
}

#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{    
    if (cdc_notice.GetLineCoding.dwDTERate.Val <= 115200)//velocidade maxima
     {
        //atualiza o baudrate no drive CDC
        CDCSetBaudRate(cdc_notice.GetLineCoding.dwDTERate.Val);
        //atualiza o baudrate da porta serial
#if defined(__18CXX) || defined(__XC8) // sem este "if" o programa não funciona(bug do compilador)
        {
            DWORD_VAL dwBaud;
            dwBaud.Val = (DWORD) (GetSystemClock() / 4) / line_coding.dwDTERate.Val - 1;
            SPBRG = dwBaud.v[0];
            SPBRGH = dwBaud.v[1];
        }
    }
}
#endif

unsigned char getcUSART() { //pega caracteres vindo da serial
    char c;
    if (RCSTAbits.OERR) // no caso de ocorrer um overrun
    {
        RCSTAbits.CREN = 0; // reseta porta
        c = RCREG;
        RCSTAbits.CREN = 1; // volta a funciona.
    } else {
        c = RCREG;
    }
    return c;
}



///funçoes prontas para os eventos da usb, caso queira usar alguma é só inserir os codigo-fonte nas chaves
//////////////////////////
void USBCBSuspend(void) {}
void USBCBWakeFromSuspend(void) {}
void USBCB_SOF_Handler(void) {}
void USBCBErrorHandler(void) {}
void USBCBCheckOtherReq(void)
{ 
    USBCheckCDCRequest();
}
void USBCBStdSetDscHandler(void) {}
void USBCBInitEP(void)
{    //habilita os enpoits do modo CDC
    CDCInitEP();
}

void USBCBSendResume(void) {
    static WORD delay_count;

    if (USBGetRemoteWakeupStatus() == TRUE) {
        //Verify that the USB bus is in fact suspended, before we send
        //remote wakeup signalling.
        if (USBIsBusSuspended() == TRUE) {
            USBMaskInterrupts();

            //Clock switch to settings consistent with normal USB operation.
            USBCBWakeFromSuspend();
            USBSuspendControl = 0;
            USBBusIsSuspended = FALSE;
            delay_count = 3600U;
            do {
                delay_count--;
            } while (delay_count);

            //Now drive the resume K-state signalling onto the USB bus.
            USBResumeControl = 1; // Start RESUME signaling
            delay_count = 1800U; // Set RESUME line for 1-13 ms
            do {
                delay_count--;
            } while (delay_count);
            USBResumeControl = 0; //Finished driving resume signalling

            USBUnmaskInterrupts();
        }
    }
}
////////////////////////////////////////////////////////////////////
#if defined(ENABLE_EP0_DATA_RECEIVED_CALLBACK)

void USBCBEP0DataReceived(void) {
}
#endif

BOOL USER_USB_CALLBACK_EVENT_HANDLER(int event, void *pdata, WORD size) {
    switch (event) {
        case EVENT_TRANSFER:
            //funçoes de retorno da porta usb
            break;
        case EVENT_SOF:
            USBCB_SOF_Handler();
            break;
        case EVENT_SUSPEND:
            USBCBSuspend();
            break;
        case EVENT_RESUME:
            USBCBWakeFromSuspend();
            break;
        case EVENT_CONFIGURED:
            USBCBInitEP();
            break;
        case EVENT_SET_DESCRIPTOR:
            USBCBStdSetDscHandler();
            break;
        case EVENT_EP0_REQUEST:
            USBCBCheckOtherReq();
            break;
        case EVENT_BUS_ERROR:
            USBCBErrorHandler();
            break;
        case EVENT_TRANSFER_TERMINATED:
            break;
        default:
            break;
    }
    return TRUE;
}

void rotina_principal(void)
{
   if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1))
         {
             //se a usb estiver em modo suspensonão faz nada
             return;
         }else{
            if(mUSBUSARTIsTxTrfReady())//não tem dados pendentes?
            {
                    if(espera == 0)
                    {
                     putrsUSBUSART(" \r\n escreva algo!");
                     espera = 1;//indica pra esperar uma resposta
                    }
                    else
                    {
                       char buffer[20];
                       char escrever[50] = "\r\n foi digitado:   ";
                      if((getsUSBUSART(buffer , sizeof(buffer))) != 0)//tem dados
                        {
                          int tamanho = 0;
                          while(tamanho <= sizeof(buffer))
                          {
                             escrever[tamanho+17] = buffer[tamanho];
                             //adiciona o que foi digitado ao que está escrito na variavel
                             tamanho++;
                          }
                          putUSBUSART(escrever ,sizeof(escrever));
                         // putUSBUSART(&escrever ,sizeof(escrever));
                          espera = 0;
                        }
                    }
            }
         CDCTxService();
         }

}//fim do programa principal

void main(void)
{
    inicializa_cpu();
  //  #if defined(USB_INTERRUPT)//se definido a usb vai usar as interrupções
    USBDeviceAttach();//para verifica o status e os eventos gerados
 //   #endif
    while (1)
    {
       #if defined(USB_POLLING)//se definido para verificar de tempo em tempo
        USBDeviceTasks();//executa as tarefas da usb(verifica o status e os eventos gerados)
        #endif
        //////////////coloque aqui seu programa///////////////////////////
        rotina_principal();
    ////////////////////////fim do programa /////////////////////////////////////////////
    }//fim do laço infinito
}//fim do main

aparência do programa "Dynamic CDC Demo" :




logo abaixo o hardware necessário: