Fork me on GitHub

17/07/13

Controlando PIC18F4550 via USB

PIC: Controlando PIC18F4550 via USB





Projeto de um sistema de comunicação via USB, entre o PIC18F4550 e o programa feito em C#.
 

Este programa monitoras 8 entradas digitais e 8 entradas analógicas e controla 8 saídas digitais e 2 saídas PWM.

O Firmware foi feito no MikroC PRO PIC. O código é simples, mas para realizar a comunicação USB, você deve configurar os seguintes bits de configuração: Selecione o menu Project > Edit Project


PLL Prescaler Selection: Caso você queira utilizar um outro valor de cristal, altere este campo

No download, estou incluindo o firmware, e o software junto com o seu código-fonte.

DOWNLOAD:
Projeto: ControladorUSB.rar





#include "built_in.h"
#define STX 0x0F

unsigned char HidReadBuff[64]  absolute 0x500;
unsigned char HidWriteBuff[64] absolute 0x540;
unsigned char Reserve4thBankForUSB[256] absolute 0x400;

enum Comandos {None=0, Analog, DigitalIn, DigitalOut, PWM};

char cmd = None;

void interrupt()
{
 Usb_Interrupt_Proc();
}

void CheckCommand()
{
   if(cmd == None)
   {
     if(HidReadBuff[0] != STX) return;
     cmd = HIDReadBuff[1];
   }
}

void EntradaAnalogica()
{
unsigned analogVal;
  HIDWriteBuff[1] =  Analog;
analogVal = ADC_get_sample(0);
  HIDWriteBuff[2] =  Hi(analogVal);
  HIDWriteBuff[3] =  Lo(analogVal);
analogVal = ADC_get_sample(1);
  HIDWriteBuff[4] =  Hi(analogVal);
  HIDWriteBuff[5] =  Lo(analogVal);
analogVal = ADC_get_sample(2);
  HIDWriteBuff[6] =  Hi(analogVal);
  HIDWriteBuff[7] =  Lo(analogVal);
analogVal = ADC_get_sample(3);
  HIDWriteBuff[8] =  Hi(analogVal);
  HIDWriteBuff[9] =  Lo(analogVal);
analogVal = ADC_get_sample(4);
  HIDWriteBuff[10] =  Hi(analogVal);
  HIDWriteBuff[11] =  Lo(analogVal);
analogVal = ADC_get_sample(5);
  HIDWriteBuff[12] =  Hi(analogVal);
  HIDWriteBuff[13] =  Lo(analogVal);
analogVal = ADC_get_sample(6);
  HIDWriteBuff[14] =  Hi(analogVal);
  HIDWriteBuff[15] =  Lo(analogVal);
analogVal = ADC_get_sample(7);
  HIDWriteBuff[16] =  Hi(analogVal);
  HIDWriteBuff[17] =  Lo(analogVal);

  while(!HID_Write(&HIDWriteBuff, 64));
}

void EntradaDigital()
{
   HidWriteBuff[1] = DigitalIn;
   HidWriteBuff[2] = PORTD;

   while(!Hid_Write(&HidWriteBuff, 64));
}

void SaidaDigital()
{
   HidWriteBuff[1] = DigitalOut;
   HidWriteBuff[2] = PORTB;

   while(!Hid_write(&HidWriteBuff, 64));
}

void USB_Recv()
{
 char dataRx = 0;

   while(1)
   {
      HidWriteBuff[0] = STX;
      EntradaAnalogica();
      EntradaDigital();
      SaidaDigital();

      dataRx = HID_Read();

      if(dataRx)
      {
        dataRx = 0;
        CheckCommand();

        if(cmd == DigitalOut) //Saídas Digitais
        {
          PORTB = PORTB ^ (1 << HidReadBuff[2]);
          cmd = None;
        }

        else if(cmd == PWM)
        {
         PWM1_Set_Duty(HidReadBuff[2]);
         PWM2_Set_Duty(HidReadBuff[3]);
         cmd = None;
        }
     }
   delay_ms(100);
   }
}

void main()
{
    TRISD = 255;
    TRISB = 0;
    TRISA = 255;
    TRISC = 0;
    PORTB = 0xAA;
    
    ADC_Init();
    PWM1_Init(4000);
    PWM2_Init(3000);
    PWM1_Set_Duty(127);
    PWM2_Set_Duty(127);
    PWM1_Start();
    PWM2_Start();
    HID_Enable(&HidReadBuff, &HidWriteBuff);
    
    Usb_Recv();
}

35 comentários:

  1. Parabens pelo seu trabalho ,Preciso de uma ajuda na montagem de um projeto ,Me manda um email helbertparanhos_50@hotmail.com sobre um medidor de tensão

    ResponderExcluir
  2. Parabéns pelo Blog, ele é muito bom e bem didático!!
    Por favor gostaria de sua ajuda!
    O meu projeto é bem parecido com este, a diferença é que digito uma tecla pelo teclado e o PIC trata esta função executando algo.No proteus está funcionando perfeitamente.
    O meu problema é que quando gravo no PIC e conecto no PC o PC não reconhece a USB do PIC, não carrega nada. Sabe me disser o que está faltando ou o que é?

    ResponderExcluir
    Respostas
    1. Boa noite... realmente parabens msm pelo blog!!!
      Por gentileza gostaria de uma informação, quando simulo no proteus roda perfeitamente, mas quando gravo no pic ele tbm nao reconhece o dispositivo usb, é como se faltasse um driver de instalação... desde ja obrigado

      Excluir
    2. Provavelmente deve ter algo errado com o circuito, talvez o capacitor de regulação de tensão da usb, ou alguma configuração de clock do pic, ou até mesmo problemas com o cristal. Teste algum outro projeto antes, que não envolva a usb, pra verificar que o hardware funciona.

      Excluir
  3. Ola, estou com um problemam, quando eu simulo no proteus seu .hex ele funciona, o windows reconhce, quando recompilo os arquivos que estao na pasta do firmware, ele não funciona mais, pode me dizer por que isso ocorre? eu recompilo sem modificar nada, porem mesmo assim o windows sequer reconhece que o dipositivo esta conectado, quando retorno ao .hex que vem no .rar ele reconhece.

    ResponderExcluir
    Respostas
    1. Nao sei o q pode estar acontecendo!
      Tem como ver se o .hex da pasta é exatamente igual ao .hex depois de recompilado?

      Excluir
    2. Como faço para ver isso? Estou construindo um inversor de tensao, e gostaria que o computador enviasse alguns valores para o pic, e o pic enviasse algumas variaveis para o pc, voce pode me ajudar com esse projeto? Eu tenho o codigo pra ele funciona com botoes, entao eu gostaria que ele funcionasse a partir do botoes, mas se estivesse conectado ao pc ele apenas recebece do pc.

      Excluir
    3. O problema é o caminho do projeto que foi criado originalmente no computador de quem postou, você deve alterar o path do projeto para sua pasta atual ou vc. copia o código e cria um novo projeto e salva em qualquer pasta, depois basta colar o código e compilar que irá funcionar.

      Excluir
  4. O cara ignora o que eu disse ae em cima, o problema estava no crack que eu havia usado para o mikroC, agora compila certinho. Sera que tem como voce me dizer como funciona o envio e recebimento de dados via usb?
    por exemplo:
    HidWriteBuff[1] = DigitalOut;
    HidWriteBuff[2] = PORTB;

    while(!Hid_write(&HidWriteBuff, 64));

    esse buff[1] é o que identifica o dado? e o [2] é oque?

    ResponderExcluir
    Respostas
    1. o byte 1 informa ao PC que "tipo" de dado será enviado.
      o byte 2 é o valor do dado a ser enviado.
      No caso do exemplo citado por você, o byte 1 informa que o dado representa uma saida digital da PORTB, e o byte 2 é o valor da saída da PORTB.

      Excluir
  5. Cara, entendi essa parte, agora estou com outro problema, eu tenho meu codigo escrito no compilador ccs, e eu nao consegui de jeito nenhum fazer a comunicação usb por la, agora eu tenho dois codigos em dois compiladores diferentes, e eu nao sei migrar o codigo do ccs pro mikroC, principalmente por causa das interrupções que no mikroC é diferente. É muito dificil fazer essa adaptaçao entre os compiladores? Voce poderia me ajudar com isso?

    http://pastebin.com/0c1DP2ya
    http://pastebin.com/BWSxvjLm

    ResponderExcluir
    Respostas
    1. Ou entao, voce poderia me dizer como eu uso as interrupções da porta B, timer0 e timer2?
      estou tentando implementar aqui, inclusive vi o tutorial no seu site, mas parece que a interrupção não esta sendo acionada =[

      http://pastebin.com/5RmRp9Ey <= void main
      http://pastebin.com/y07SpU7M <= void interrupt ()

      Excluir
    2. //Achei este erro!!! Tambem é o mesmo erro do TIMER2!!!

      void TIMER0_isr(void)
      {
      //Tem q ser colocado aqui
      INTCON.TMR0IF=0; //SEMPRE q houver a interrupção, vc deve limpar a flag, caso
      // contrario nao ocorrera a proxima interrupção

      cont3++;
      if(cont3==5);//SET_ADC_CHANNEL(0);
      if(cont3==10)
      {
      valor = ADC_Read(7);
      comando=1;
      cont3=0;
      // INTCON.TMR0IF=0; //Nao pode ser colocado aqui
      }
      }

      Excluir
  6. 1- Hmm, interessante, segui oque voce disse, e para fazer um teste, habilitei a interrupçao dos pinos B, e escrevi o seguinte cógigo

    {
    if (INTCON.RBIF == 1){
    INTCON.RBIF = 0;
    if (MODULO == 'B'){
    PORTa=255;
    MODULO = 'A';
    }
    else {
    PORTa = 0;
    MODULO = 'B';
    }
    }

    o problema é que quando eu aperto o botão, ele fica "piscando" as portas A.

    2- qual é o comando pra mim setar uma saida do microcontrolador como alta, no ccs eu uso outpu_high(pin_a1), mas no mikroc eu uso oq?

    cara, vlw mesmo, voce ta me ajudando pra caramba =D

    ResponderExcluir
    Respostas
    1. Pra não ficar postando muita duvida nos comentario desse post, é possivel eu me comunicar com vc de outra forma? talvez email?

      Excluir
  7. Olá, conseguimos funcionar as entradas e saídas digitais e a saída PWM. Porém as entradas analógicas não funcionaram. Vocês têm alguma ideia do que pode ser? Consultei o datasheet do 18F4550 e não encontrei nenhum registrador que possa estar incorretamente configurado. Obrigado

    ResponderExcluir
    Respostas
    1. Pelos nossos testes, o PIC está adquirindo o valor do conversor A/D dentro da rotina EntradaAnalogica() . Porém o programa em C# não atualiza os ProgressBar que apresentam os valores do AD.

      Excluir
  8. Não tem como simular o funcionamento do programa com o Proteus no Windows 8 de 64bits?

    ResponderExcluir
  9. Boa tarde, no meu projeto eu preciso apenas enviar uma string simples para o pic, como eu poderia modificar o programa para fazer isso?

    Obrigado.

    ResponderExcluir
  10. Não tem como simular o funcionamento do programa com o Proteus no Windows 8 de 64bits?

    ResponderExcluir
  11. Thiago... acho que deve ter algum problema na configuração dos Fuses Bits, pois o computador reconhece a HID mas não comunica.. diz que aconteceu algum erro e que a comunicação não foi possível ser feita. Eu sempre tenho esse problema quando o MCU não entra em 48MHZ no barramento. Qual o Oscilador você usa neste código?
    Eu alterei seu programa para trabalhar com o Oscilador de 8MHZ e o programa funcionou perfeitamente.
    Outro ponto é no cruzamento de Thready... Sempre que dou play, ele me dá erro de cruzamento de Thready já no método de Analógico... Precisa fazer um tratamento de INVOKE nele eu acredito.

    ResponderExcluir
  12. Júnior,

    O que você deve fazer é simplesmente adicionar o código abaixo no evento load do seu form.

    #Código

    CheckForIllegalCrossThreadCalls = false;

    Fiz aqui e funcionou.

    Abs!

    ResponderExcluir
  13. urgente alguem me ajuda , mesmo q amigo ali em cima eu compilo mesmo projeto e não funciona com hex compilado .. meu mikroc é versão mikroc for pic 5.61. alguem ai sabe versão q funciona?

    ResponderExcluir
  14. Quando eu envio o dado do firmware para o software funciona mas quando envio o dado do software para o firmware nao funciona ou seja o firmware não recebe nada tem ideia do que pode ser.

    ResponderExcluir
  15. Olá Tiago, tudo bem? Primeiramente obrigado por compartilhar o seu conhecimento!

    Eu abri o source no mikroC, porém ele gera um .hex diferente do que já vem compilado. Eu não alterei nenhuma configuração na IDE, simplesmente abri e mandei compilar. Como sou iniciante com microcontroladores, não estou conseguindo entender o porquê disso. O .hex já gerado rodou direitinho no Proteus, reconheceu o dispositivo e tudo mais! Porém com o que eu gerei por aqui, logicamente deu erro.

    Você saberia por que isso está ocorrendo? Será que é alguma configuração específica de compilação? Segue abaixo o link de ambos os arquivos .hex:

    https://drive.google.com/file/d/0B7031uB8x8LmTmJNcGxraDN5cW8/view?usp=sharing
    https://drive.google.com/file/d/0B7031uB8x8LmY1hoQUk1VGU5NUE/view?usp=sharing

    Obrigado e abraços!

    ResponderExcluir
    Respostas
    1. Olá, tudo bem!
      Também não entendo...fiz o mesmo, baixei o arquivo, abri e mandei compilar e o .hex gerado ta normal...olhando o arquivo que vc gerou, a diferença do tamanho é gigantesca...veja se ha alguma mensagem de erro na hora de compilar, tipo "demo limit".
      Abraços.

      Excluir
    2. Não sei se ainda é útil, porém esse erro me aconteceu constantemente e eu demorei a achá-lo, tomem cuidado com os cracks do MikroC, muitos não funcionam, fazem com que seu programa seja compilado de forma errada. Peguem o PicKit e abram o .hex que vocês verão como as posições de mémoria estão vazias...

      Excluir
  16. Boa Noite, Estou gostando muito do seu Blog, esta sendo muito Útil para mim, e gostaria de saber se teria como utilizar o PI16F877 neste projeto e o que deveria ser mudado?

    ResponderExcluir
    Respostas
    1. Olá, não tem como, pois o PIC16F877A não possui USB. O que você poderia fazer é utilizar um PIC com usb ou utilizar a porta serial. Caso utilize a porta serial voce pode conectar através da porta USB utilizando um conversor FTDI.

      Excluir
  17. Parabéns pelo projeto. Ficou bem simples e fácil de entender. Você poderia me dizer qual biblioteca é essa UsbLibrary.dll que você usou no programa em C#? Estou tentando encontrar alguma documentação sobre ela na internet, mas não consegui. Existe alguma biblioteca nativa no Visual Studio que faça a comunicação USB HID, assim como existe para comunicação serial?

    ResponderExcluir
  18. Qual é o codigo que grava no pic?

    ResponderExcluir

Postagens Relacionadas!!