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:
Te mandei um e-mail, por favor dá uma olhada.
ResponderExcluirTenho interesse em um desenvolver um bootloader.
Abraço.