/* * Usando o timer0 do 18F4550 * * Compilador : MPlabXC8. * Microcontrolador: 18F4550. * Autor: aguivone. * Versão: 1. * Data : 25 de janeiro de 2017. */ #include <xc.h> #define _XTAL_FREQ 20000000 // /* COMPILER DIRECTIVES FOR CHIP CONFIGURATION BITS*/ #include "Wiznet.h" // CONFIG1L #pragma config PLLDIV = 4 // depois testar se não vai dar problemas com o ADC e wiznet #pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2]) #pragma config USBDIV = 1 // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale) // CONFIG1H #pragma config FOSC = HS //HSPLL_HS //HS para cristal de 16 ou 20mhz(habilitei o pll interno mas para este exemplo nem precisava podia usar somete o HS) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) // CONFIG2L #pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOR = ON // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software) #pragma config BORV = 2 // Brown-out Reset Voltage bits (Setting 1 2.79V) #pragma config VREGEN = OFF // USB Voltage Regulator Enable bit (USB voltage regulator disabled) // CONFIG2H #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit)) #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) // CONFIG3H #pragma config CCP2MX = OFF // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3) #pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset) #pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation) #pragma config MCLRE = ON // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled) #pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled) #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) // CONFIG5L #pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected) #pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected) #pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected) #pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected) #pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected) #pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected) #pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected) #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. unsigned int guiPisca; unsigned char gucAlternaPino; //Defines #define LED_STATUS LATDbits.LATD0 //*********************************************************************************************************** // FUNÇÕES //*********************************************************************************************************** //=========================================================================================================== // Função: _inicializa_timer0 // Parâmetros: nenhum // Retorno: nenhum // Descrição: configura o timer0. //=========================================================================================================== void inicializa_timer0() // { TMR0IP = 1;//configura timer0 como alta prioridade //T0CON = 0X80;//habilita timer/modo 16bits/clock interno/prescaler dividido por 2 T0CON = 0XC5;//habilita timer/modo 8bits/clock interno/prescaler dividido por 64 TMR0IE = 1; // habilita interrupção de estouro do timer. TMR0 = 250;//zera registrador de contagem } //=========================================================================================================== // Checagem de Interrupção //=========================================================================================================== void interrupt interrupcao(void)//vetor de interrupção { if(TMR0IF)//interrupçao de timer0 { //interrupção do timer0 - estoura quando atinge 255(0XFF) - 8bits //interrupção do timer0 - estoura quando atinge 65536(0XFF) - 16bits //updateWizTimer(); TMR0 = 178;//reinicia timer com o valor calculado para 1ms TMR0IF = 0; if(guiPisca>0) {guiPisca--;} } } void main(void) { TRISB = 0X00; //Saida B1 e B0 TRISA = 0XFF; // TRISD = 0X00; //saidas TRISE = 0X00; //saidas TRISC = 0X10; //todas são entradas//somente C4 é entrada (SDI) ADCON0 = 0x00;//configura os pinos para portas digitais(ADC OFF) ADCON1 = 0x0F;//configura os pinos para portas digitais(ADC OFF) INTCON = 0XE0;//habilita interupção global , interrupção de periferico e inicializa_timer0(); for(;;) { if(guiPisca == 0) { if(gucAlternaPino == '0') { LED_STATUS=0; gucAlternaPino = '1'; } else { LED_STATUS=1; gucAlternaPino = '0'; } guiPisca = 250;//250ms } } }
Engenheiro eletricista - Desenvolvedor de hardware. Protótipos e projetos. Desenvolvimento de software de interface.(aguivone@gmail.com)
quarta-feira, 25 de janeiro de 2017
Usando o Timer0 do 18F4550 no XC8
Configurando fuses do oscilador do 18F4550 - avaliação de desempenho de clock
Olá, minha motivação para este exemplo se deve ao fato de ter, perdido muito tempo tentando descobri por que meu código não rodava no microcontrolador apesar de estar tudo correto com os registradores configurados,tanto que no simulador "proteus" tudo funcionava,mas na protoboard nada funcionava(era como se estivesse resetado).
Depois de vários testes descobri que meu erro foi habilitar o PLL(pois eu queria que ele rodasse mais rápido),O PLL é um recurso pra elevar a frequencia de trabalho do microcontrolador, mas se for configurado errado o microcontrolador nem funciona devido o clock exceder o potencial do hardware.
Vamos a um exemplo, que foi o que aconteceu comigo, coloquei um clock de 20Mhz dai configurei o PLL para não divir o clock vindo do prescaler logo isso excede a capacidade de clock e então o microcontrolador não funciona,observe que o simulador não alerta para este tipo de erro o que leva a algumas pessoas a se descabelar com sua aplicação(pois mesmo o código estando correto o microcontrolador não funciona),uma vez me lembro de um seguidor do blog ter um problema parecido e na época eu não soube explicar o por que, mas agora diante deste problema resolvi investigar pra trazer a vcs um "estudo de caso".
Para validar minhas suspeitas montei um código simples que apenas alterna um dos pinos do microcontrolador,pois segundo o datasheet essa operação gasta um ciclo de maquina(ou seja o sinal de saída terá a metade a frequência do clock interno),inicialmente eu mandei liga e desligar a porta do microcontrolador em C pra minha surpresa o sinal em nível alto era maior que o em nível baixo,então mandei que setasse apenas um pino e agora o sinal de saída foi simétrico(ou seja em C quando se seta a porta o compilador XC8 deve executar outras rotinas que o faz ter esse delay), Então para não ter essas influencia do compilador resolvi fazer o código em assembly(é então o sinal ficou fiel ao clock sem delay), mas como o laço for gasta alguns ciclo de maquina, resolvi executar o processo de alternar o led 3 vezes antes de retornar o laço "for".O resultado é visto nas figuras a seguir com um clock interno de 2,5Mhz.
Veja que o postcaler esta para 1 ou seja não irá dividir o clock de saída(assim teremos qual o clock máximo que vamos ter j[a descontados a divisão por 4 do PIC), com esse procedimento podemos esta realizando algo conhecido como "overclock" ou seja forçar o hardware a trabalhar no limite, dentre os possíveis consequências podemos ter imprecisões nos conversores ADC,ou erros nas comunicações serial rs232,SPI, e outros,Então minha sugestão é testar para saber se realmente essas frequências de trabalho mais elevadas não se torne um problema para sua aplicação.
Os resultados encontrados para as configurações foram:
Usando um cristal de 20MHZ sem o PLL ligado
#pragma config FOSC = HS // 2,5 MHZ
Usando um cristal de 20MHZ com o PLL ligado
#pragma config PLLDIV = 2 - para o valor 1 e 0 o microcontrolador atinge seu limete e não funciona mais
#pragma config FOSC = HSPLL_HS // 0MHZ - fica resetado.
#pragma config PLLDIV = 3
#pragma config FOSC = HSPLL_HS // 20MHZ -- > 8X mais rapido
#pragma config PLLDIV = 4
#pragma config FOSC = HSPLL_HS // 15MHZ -- > 6X mais rapido
#pragma config PLLDIV = 5
#pragma config FOSC = HSPLL_HS // 12MHZ -- > 4,8X mais rapido
O código fonte :
Depois de vários testes descobri que meu erro foi habilitar o PLL(pois eu queria que ele rodasse mais rápido),O PLL é um recurso pra elevar a frequencia de trabalho do microcontrolador, mas se for configurado errado o microcontrolador nem funciona devido o clock exceder o potencial do hardware.
Vamos a um exemplo, que foi o que aconteceu comigo, coloquei um clock de 20Mhz dai configurei o PLL para não divir o clock vindo do prescaler logo isso excede a capacidade de clock e então o microcontrolador não funciona,observe que o simulador não alerta para este tipo de erro o que leva a algumas pessoas a se descabelar com sua aplicação(pois mesmo o código estando correto o microcontrolador não funciona),uma vez me lembro de um seguidor do blog ter um problema parecido e na época eu não soube explicar o por que, mas agora diante deste problema resolvi investigar pra trazer a vcs um "estudo de caso".
Para validar minhas suspeitas montei um código simples que apenas alterna um dos pinos do microcontrolador,pois segundo o datasheet essa operação gasta um ciclo de maquina(ou seja o sinal de saída terá a metade a frequência do clock interno),inicialmente eu mandei liga e desligar a porta do microcontrolador em C pra minha surpresa o sinal em nível alto era maior que o em nível baixo,então mandei que setasse apenas um pino e agora o sinal de saída foi simétrico(ou seja em C quando se seta a porta o compilador XC8 deve executar outras rotinas que o faz ter esse delay), Então para não ter essas influencia do compilador resolvi fazer o código em assembly(é então o sinal ficou fiel ao clock sem delay), mas como o laço for gasta alguns ciclo de maquina, resolvi executar o processo de alternar o led 3 vezes antes de retornar o laço "for".O resultado é visto nas figuras a seguir com um clock interno de 2,5Mhz.
Figura 1 - sinal completo.
Figura 2 - detalhe dos sinais.
Veja que o postcaler esta para 1 ou seja não irá dividir o clock de saída(assim teremos qual o clock máximo que vamos ter j[a descontados a divisão por 4 do PIC), com esse procedimento podemos esta realizando algo conhecido como "overclock" ou seja forçar o hardware a trabalhar no limite, dentre os possíveis consequências podemos ter imprecisões nos conversores ADC,ou erros nas comunicações serial rs232,SPI, e outros,Então minha sugestão é testar para saber se realmente essas frequências de trabalho mais elevadas não se torne um problema para sua aplicação.
Os resultados encontrados para as configurações foram:
Usando um cristal de 20MHZ sem o PLL ligado
#pragma config FOSC = HS // 2,5 MHZ
Usando um cristal de 20MHZ com o PLL ligado
#pragma config PLLDIV = 2 - para o valor 1 e 0 o microcontrolador atinge seu limete e não funciona mais
#pragma config FOSC = HSPLL_HS // 0MHZ - fica resetado.
#pragma config PLLDIV = 3
#pragma config FOSC = HSPLL_HS // 20MHZ -- > 8X mais rapido
#pragma config PLLDIV = 4
#pragma config FOSC = HSPLL_HS // 15MHZ -- > 6X mais rapido
#pragma config PLLDIV = 5
#pragma config FOSC = HSPLL_HS // 12MHZ -- > 4,8X mais rapido
O código fonte :
/* * Avaliação de desempenho 18F4550 * * Compilador : MPlabXC8. * Microcontrolador: 18F4550. * Autor: Aguivone. * Versão: 1. * Data : 24 de janeiro de 2017. * * Neste exemplo vou demontrar como configurar o oscilador para usar o pll do pic(eleva seu clock e definir o quão mais rápido ele se tornara) */ #include <xc.h> #define _XTAL_FREQ 20000000 // // CONFIG1L #pragma config PLLDIV = 5 // 1X #pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2]) #pragma config USBDIV = 1 // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale) // CONFIG1H #pragma config FOSC = HSPLL_HS //HS para cristal de 16 ou 20mhz(habilitei o pll interno mas para este exemplo nem precisava podia usar somete o HS) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) // CONFIG2L #pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOR = ON // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software) #pragma config BORV = 2 // Brown-out Reset Voltage bits (Setting 1 2.79V) #pragma config VREGEN = OFF // USB Voltage Regulator Enable bit (USB voltage regulator disabled) // CONFIG2H #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit)) #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) // CONFIG3H #pragma config CCP2MX = OFF // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3) #pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset) #pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation) #pragma config MCLRE = ON // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled) #pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled) #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) // CONFIG5L #pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected) #pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected) #pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected) #pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected) #pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected) #pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected) #pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected) #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks) #pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks) void main(void) { TRISB = 0X00; //saída B1 e B0 TRISA = 0XFF; // TRISD = 0X00; //saídas TRISE = 0X00; //saídas TRISC = 0X10; //todas são entradas//somente C4 é entrada (SDI) ADCON0 = 0x00;//configura os pinos para portas digitais(ADC OFF) ADCON1 = 0x0F;//configura os pinos para portas digitais(ADC OFF) for(;;) { asm("BSF PORTD,0"); asm("BCF PORTD,0");//para garantir que cada instrução leve 1 ciclo de maquina asm("BSF PORTD,0");// ou seja a frequência interna é igual a metade da frequência do sinal asm("BCF PORTD,0"); asm("BSF PORTD,0"); asm("BCF PORTD,0"); } }
terça-feira, 6 de dezembro de 2016
Conversor de 12V para 24V com microcontrolador pic18F13K22
Olá, hoje o exemplo será de um conversor DC/DC (STEP UP) elevador de tensão, o projeto é dividido em 2 etapas;montagem do circuito de elevação DC e a implementação do firmware de controle.
O "coração do circuito" é basicamente oc componentes L1,C1 e D1 além do componente de chaveamento que pode ser transistor(aquece mais) ou mosfet. Veja a figura a seguir para melhor compreensão:
O circuito é bem simples de se implementar, provavelmente o mais trabalhoso será encontrar o indutor, dai se tem 3 escolhas : arrancar um indutor de uma fonte chaveada usada(sucata), este indutor pode ser feito com fios de cobre esmaltado, a bitola do fio vai depender da corrente a ser manuseada pelo circuito , e por ultimo ainda encontrar um indutor comercial que se aproxime do indutor desejado.Não vou entrar em muitos detalhes de dimensionamento do circuito pois isso foge da proposta do blog que é apenas montar o código-fonte.
No microcontrolador PIC18F13K22 o pinos usado foram pino 5 (usado para pwm), pino 8(ref_tensão), pino 15 (para led que indica falha) e pino16 (indica o status, fica piscando).Este código pode ser transferido para qualquer outro modelo de microcontrolador que tenha PWM.
Vamos então agora para o código fonte :
Código-fonte principal :
O circuito funcionou de forma satisfatória, conseguiu compensar a queda de tensão para uma carga de 300mA(com uma queda de tensão de saída de 0,3V), além de regular a tensão na saída mesmo que a entrada de tensão do circuito variasse. Como todos os outros exemplos postados aqui no blog este projeto é apenas didático podendo ser melhorado para uso comercial.
A tensão minima de trabalho ficou em 11V e a máxima é até 23V (geralmente até 1 ou 2 volta da tensão de saída), para mudar o valor da tensão de saída basta mudar o valor da variável "DDP_TRAB", não recomendo colocar um valor menor do que a entrada pois o circuito apenas eleva(conversor boost) a tensão.
Uma ultima dica é usar um dissipador de calor no mosfet de chaveamento.
Lembrando que para acompanhar as postagens basta entrar na página do facebook e curtir.
https://www.facebook.com/Microcontroladores-C-576463872371829 ou procurando por microcontroladores-c no face.
O "coração do circuito" é basicamente oc componentes L1,C1 e D1 além do componente de chaveamento que pode ser transistor(aquece mais) ou mosfet. Veja a figura a seguir para melhor compreensão:
O circuito é bem simples de se implementar, provavelmente o mais trabalhoso será encontrar o indutor, dai se tem 3 escolhas : arrancar um indutor de uma fonte chaveada usada(sucata), este indutor pode ser feito com fios de cobre esmaltado, a bitola do fio vai depender da corrente a ser manuseada pelo circuito , e por ultimo ainda encontrar um indutor comercial que se aproxime do indutor desejado.Não vou entrar em muitos detalhes de dimensionamento do circuito pois isso foge da proposta do blog que é apenas montar o código-fonte.
No microcontrolador PIC18F13K22 o pinos usado foram pino 5 (usado para pwm), pino 8(ref_tensão), pino 15 (para led que indica falha) e pino16 (indica o status, fica piscando).Este código pode ser transferido para qualquer outro modelo de microcontrolador que tenha PWM.
Vamos então agora para o código fonte :
Código-fonte principal :
/* * Conversor DC/DC * * Compilador : MPlabXC8 * Microcontrolador: 18F13K22 * Autor: Aguivone * Versão: 1 * Data de criação: 19/05/2015. * Retomada do projeto: 30/11/2016 * Primeira versão estavel: 06/11/2016 */ #include <stdio.h> #include <stdlib.h> #include <string.h> //para usar funçoes de string deve se adicionar este header #include <xc.h> #include "config_cpu.h" #include "conv_adc.h" // configuração de frequencia de PWM #define PWM_20KHZ_CLK16 inicializa_PWM1(1, 200, 1) #define _XTAL_FREQ 16000000//usado para rotinas de delays #define VAL_MAX_PWM 70 // valor max de pwm pra não sobreaquecer demais a bobina #define VAL_MIN_PWM 5 // valor minimo de pwm #define MAX_CORRENTE 1024//só pra ignorar por enquanto // em unidades do conversor //para calcular a tensão faça : (tensão desejada)/0,05371 ; // o valor deve ser inteiro(sem virgula) por exemplo; //para 12V temos : 12/0,05371 = 223,4 então será 223 ou 224. #define DDP_TRAB 450// para 24V (depende do divisor resistivo) #define LED_STATUS LATCbits.LATC0 #define LED_FALHA LATCbits.LATC1 //************************************************************************************/ //VARIAVEIS GLOBAIS //************************************************************************************/ //parametros de tensão/corrente long glTensao = 0;// em V long glCorrente = 0;// em A int uiStatus = 0; //indica o modo como está o estado das tensões //pwm long uiMax_passos = 0;//frequencia em khz int uiDuty_cycle = 1; //variaveis de uso geral long glTempo_led=0; int uiAlterna_leds=0; //=================================================================================== //Função: _interrupcoes //Parâmetro: não tem. //Retorno: não tem. //Descrição: usada para tratar as interrupções geradas pelo microcontrolador. //=================================================================================== void interrupt interrupcoes(void)//vetor de interrupção { if(ADIF) {//se interrupção do modulo analogico! ADIF = 0;//limpa flag } if(TMR2IF) {//interrupção do timer2 TMR2IF = 0;//não será usado } if(CCP1IF) {//interrupção do ccp1 CCP1IF = 0;//não será usado } } //=================================================================================== //Função: _delay_ms //Parâmetros: long delay, essa função cobre uma falha nas rotinas de tempo para o pic da serie 18F //Retorno: não tem retorno. //Descrição: faz microcontrolador perder tempo. //=================================================================================== void delay_ms(long delay) { while(delay > 0) { __delay_ms(1); delay--; } } //=================================================================================== //Função: _liga_leitura_0 //Parâmetro: não tem. //Retorno: não tem. //Descrição: liga entrada de sinal analogico na porta 0. //=================================================================================== void liga_leitura_0(void) { ADCON0 = 0X21; } //=================================================================================== //Função: _liga_leitura_1 //Parâmetro: não tem. //Retorno: não tem. //Descrição: liga entrada de sinal analogico na porta 1. //=================================================================================== void liga_leitura_1(void) { ADCON0 = 0X25; } void ler_ADC(int giMedia)//numero de amostras { int iMedia=0; glTensao = 0; glCorrente = 0; while(iMedia < giMedia) { glTensao = glTensao + ler_adc_un(); __delay_us(2);//tempo minino para aquisições iMedia++; } liga_leitura_1();//agora lê a corrente __delay_us(2);//tempo minino para aquisições iMedia=0; while(iMedia < giMedia) { glCorrente = glCorrente + ler_adc_un(); __delay_us(2);//tempo minino para aquisições iMedia++; } liga_leitura_0();//volta a ler tensão glTensao = glTensao/giMedia; glCorrente = glCorrente/giMedia; } void inicializa_PWM1(char prescaler,char pr2,char postcaler)//prescaler / PR2 / postcaler { uiMax_passos =(int) pr2; switch(prescaler) { case 1: { prescaler = 0; }break; case 4: { prescaler = 1; }break; case 16: { prescaler = 3; }break; } T2CON = (postcaler - 1)<<3; T2CON = T2CON + 4 + prescaler;//o 4 é para habilitar o timer PR2 = pr2; CCP1CON = 0X0F;//habilita pwm CCP1IE = 1;//desabilita interrupção pois não vamos precisar dela, modulo ccp1 TMR2IE = 0; //desabilita interrupção pois pode até travar processamento(não vamos usar tambem); timer 2 } void duty_cicle(long valor) { CCPR1 = valor; } //=================================================================================== //Função: _inicializa_cpu //Parâmetros: não tem //Retorno: não tem retorno. //Descrição: inicializa os registradores do microcontrolador. //=================================================================================== void inicializa_cpu(void) { TRISC = 0xC0;//habilita 6 e 7 com entrada analogica TRISA = 0XFF;//configura portA como entrada TRISB = 0X20;//configura portB B5 (pino RX) como entrada PORTB = 0; // limpar as portas que estão configuradas como saidas ADCON0 = 0X21;//liga modulo analogico digital e configura entrada de sinal para o pino RC6(AN8) ADCON1 = 0X00;// Vref- seta ao Vss e Vref+ ao Vdd ADCON2 = 0b10111110;// justificado a direita// tempo de aquisição 20TAD // clk Fosc/64 PEIE = 1;//habilita interrupção de perifericos do pic GIE = 1; //GIE: Global Interrupt Enable bit ANSEL = 0x00;//desabilita portas analogicas(para não atrapalhar recepção no pino) ANSELH = 0x03;//em alguns casos não funciona nem a interrupção de recepção. habilita somente os pinos que vão funcionar como AD PWM_20KHZ_CLK16;//100khz veja no comentario abaixo "SUGESTÃO DE DEFINES :" duty_cicle(1);//inicia com valor minimo uiDuty_cycle = 1; } // //*******************************Rotina principal*********************************************/ void main(void) { inicializa_cpu(); for(;;) { glTempo_led++; if(glTempo_led > 100) { if(uiAlterna_leds == 0) { LED_STATUS = 1; uiAlterna_leds=1; ;//pisca led } else { LED_STATUS = 0; uiAlterna_leds = 0; ;//pisca led } if(uiStatus > 0) { LED_FALHA = 1; } else { LED_FALHA = 0; } glTempo_led=0; } ///processamento das tensões ler_ADC(4);//pega pelo menos 5 amostras para tirar media /// /verifica tensão if(glTensao > DDP_TRAB )//flutuação máxima {//tensão superior a permitida if(uiDuty_cycle < VAL_MIN_PWM) { //não consegue mais compensar chegou ao limite uiStatus = 2;//sobretensão } else { //tenta compensar valor uiDuty_cycle--;//a duty_cicle(uiDuty_cycle); uiStatus = 0;//tudo ok } } else { if(glTensao < DDP_TRAB )//flutuação máxima { //tensão inferior a permitida if(uiDuty_cycle > VAL_MAX_PWM) { //não consegue mais compensar chegou ao limite uiStatus = 3;//subtensão } else { //tenta compensar valor uiDuty_cycle++;//lembre que a saida é invertida duty_cicle(uiDuty_cycle); uiStatus = 0;//tudo ok } }//fim de tensão fora do range } //////////////// }//loop infinito } /*calculos para pwm * * periodo do pwm * * Tpwm = [PR2+1]*4*Tosc*prescaler(do timer2) * * duty cycle * <bits 5e4> * D = (CCPR1L + CCP1CON) * Tosc * prescaler (do timer2) * * numero de passos do pwm * * N = (Fosc/(Fpwm * 4 * prescaler)) */ /* SUGESTÃO DE DEFINES : * use estes valores como referencia * Note que os valores do meio são o numero de passos do pwm(quanto mais passos mais preciso será) * //clock de 4mhz #define PWM_250HZ_CLK4 inicializa_PWM1(16, 250, 1) // #define PWM_500HZ_CLK4 inicializa_PWM1(16, 125, 1) // #define PWM_1KHZ_CLK4 inicializa_PWM1(4, 250, 1) // #define PWM_1K25HZ_CLK4 inicializa_PWM1(16, 50, 1) // #define PWM_2KHZ_CLK4 inicializa_PWM1(4, 125, 1) // #define PWM_2K5HZ_CLK4 inicializa_PWM1(4, 100, 1) // #define PWM_4KHZ_CLK4 inicializa_PWM1(1, 250, 1) // #define PWM_5KHZ_CLK4 inicializa_PWM1(1, 200, 1) // #define PWM_8KHZ_CLK4 inicializa_PWM1(1, 125, 1) // #define PWM_10KHZ_CLK4 inicializa_PWM1(1, 100, 1) // #define PWM_20KHZ_CLK4 inicializa_PWM1(1, 50, 1) // #define PWM_25KHZ_CLK4 inicializa_PWM1(1, 40, 1) // #define PWM_100KHZ_CLK4 inicializa_PWM1(1, 10, 1) // //clock de 8mhz #define PWM_500HZ_CLK8 inicializa_PWM1(16, 250, 1) // #define PWM_1KHZ_CLK8 inicializa_PWM1(16, 125, 1) // #define PWM_2KHZ_CLK8 inicializa_PWM1(4, 250, 1) // #define PWM_2K5HZ_CLK8 inicializa_PWM1(16, 50, 1) // #define PWM_4KHZ_CLK8 inicializa_PWM1(4, 125, 1) // #define PWM_5KHZ_CLK8 inicializa_PWM1(4, 100, 1) // #define PWM_8KHZ_CLK8 inicializa_PWM1(1, 250, 1) // #define PWM_10KHZ_CLK8 inicializa_PWM1(1, 200, 1) // #define PWM_16KHZ_CLK8 inicializa_PWM1(1, 125, 1) // #define PWM_20KHZ_CLK8 inicializa_PWM1(1, 100, 1) // #define PWM_40KHZ_CLK8 inicializa_PWM1(1, 50, 1) // #define PWM_50KHZ_CLK8 inicializa_PWM1(1, 40, 1) // #define PWM_200KHZ_CLK8 inicializa_PWM1(1, 10, 1) // //clock de 16mhz #define PWM_1KHZ_CLK16 inicializa_PWM1(16, 250, 1) // #define PWM_2KHZ_CLK16 inicializa_PWM1(16, 125, 1) // #define PWM_4KHZ_CLK16 inicializa_PWM1(4, 250, 1) // #define PWM_5KHZ_CLK16 inicializa_PWM1(16, 50, 1) // #define PWM_8KHZ_CLK16 inicializa_PWM1(4, 125, 1) // #define PWM_10KHZ_CLK16 inicializa_PWM1(4, 100, 1) // #define PWM_16KHZ_CLK16 inicializa_PWM1(1, 250, 1) // #define PWM_20KHZ_CLK16 inicializa_PWM1(1, 200, 1) // #define PWM_32KHZ_CLK16 inicializa_PWM1(1, 125, 1) // #define PWM_40KHZ_CLK16 inicializa_PWM1(1, 100, 1) // #define PWM_80KHZ_CLK16 inicializa_PWM1(1, 50, 1) // #define PWM_100KHZ_CLK16 inicializa_PWM1(1, 40, 1) // #define PWM_400KHZ_CLK16 inicializa_PWM1(1, 10, 1) //
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
*/
Código-fonte "config_cpu.h" :/* * File: config_cpu.h * Author: aguivone * * Created on 25 de Agosto de 2014, 16:24 */ #ifndef CONFIG_CPU_H #define CONFIG_CPU_H /*******************************configuraçôes do pic ****************************************************/ // CONFIG1H #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config PLLEN = OFF // 4 X PLL Enable bit (PLL is under software control) #pragma config PCLKEN = ON // Primary Clock Enable bit (Primary clock enabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) // CONFIG2L #pragma config PWRTEN = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software) #pragma config BORV = 19 // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal) // CONFIG2H #pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register) #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) // CONFIG3H #pragma config HFOFST = ON // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.) #pragma config MCLRE = OFF // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled) desliga programação em baixa voltage #pragma config BBSIZ = OFF // Boot Block Size Select bit (512W boot block size) #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) // CONFIG5L #pragma config CP0 = OFF // Code Protection bit (Block 0 not code-protected) #pragma config CP1 = OFF // Code Protection bit (Block 1 not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Write Protection bit (Block 0 not write-protected) #pragma config WRT1 = OFF // Write Protection bit (Block 1 not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers not write-protected) #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks) #endif /* CONFIG_CPU_H */
//////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
Código-fonte "conv_adc.h" :
/* * FUNÇOES USADAS NA CONVERSAO ANALOGICO/DIGITAL * * Compilador : MPlabXC8 * Microcontrolador: 18F13K22 * Autor: Aguivone * Versão: 1 * Data de criação: 21 de agosto de 2014. */ #include <xc.h> // =================================================================================== // Função: _ler_adc_un // Parâmetros: não tem. // Retorno : unsigned long ultensao. // Descrição : retorna o valor lido em unidades de medidas. // =================================================================================== unsigned long ler_adc_un(void) { unsigned long ultensao; ADCON0bits.GO = 1; //inicia conversão while (ADCON0bits.GO_DONE == 1); //espera finalizar leitura ultensao = (ADRESH << 8) | ADRESL; return(ultensao); } // =================================================================================== // Função: _ler_adc_mv // Parâmetros: não tem. // Retorno : unsigned long ultensao. // Descrição : retorna o valor lido em milivolts. // =================================================================================== unsigned long ler_adc_mv(void) { unsigned long ultensao; ultensao =((ler_adc_un() * 5000)/1023); //Vref está em milliVolts return(ultensao); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exemplo do protótipo funcionando :
Conclusões do projeto:
O circuito funcionou de forma satisfatória, conseguiu compensar a queda de tensão para uma carga de 300mA(com uma queda de tensão de saída de 0,3V), além de regular a tensão na saída mesmo que a entrada de tensão do circuito variasse. Como todos os outros exemplos postados aqui no blog este projeto é apenas didático podendo ser melhorado para uso comercial.
A tensão minima de trabalho ficou em 11V e a máxima é até 23V (geralmente até 1 ou 2 volta da tensão de saída), para mudar o valor da tensão de saída basta mudar o valor da variável "DDP_TRAB", não recomendo colocar um valor menor do que a entrada pois o circuito apenas eleva(conversor boost) a tensão.
Uma ultima dica é usar um dissipador de calor no mosfet de chaveamento.
Lembrando que para acompanhar as postagens basta entrar na página do facebook e curtir.
https://www.facebook.com/Microcontroladores-C-576463872371829 ou procurando por microcontroladores-c no face.
terça-feira, 9 de agosto de 2016
Gerando sinais analógicos com o PIC(onda triangular e dente de serra).
Olá,
As vezes precisamos converter dados digitais em sinais analógicos apesar de alguns microcontroladores terem esta opção já inclusa podemos também recorrer a chips dedicado para esta função como os chips da "analog devices" os AD5601/AD5611/AD5621 que são de 8,10 e 12 bits respectivamente.
O circuito montado no proteus foi este a seguir:
Observe que coloquei uma porta serial para saber o qual valor eu estava sendo enviado, o voltímetro 'lê' a tensão que estava saindo a cada incremento no chip.O código fonte ficou dividido em duas partes; uma gera onda dente de serra e o outro gera uma onda triangular, veja na imagem abaixo os prints da tela:
As formas de ondas em azul são os pacotes SPI que foram enviados ,em verde o clock gerado a cada transmissão de pacotes e em vermelho o momento em que o pino de "slave select " é ativado. Na figura a seguir é visto como é feito o cálculo para o chip AD5601, para calcular para os outros chips segue o mesmo raciocínio ou seja pega o valor de 5V e divide pelo números de resolução(incrementos) do chip ou seja 255 incrementos para o AD5601,1024 para o AD5611 e 4096 incrementos para o AD5621.
O código fonte fica :
As vezes precisamos converter dados digitais em sinais analógicos apesar de alguns microcontroladores terem esta opção já inclusa podemos também recorrer a chips dedicado para esta função como os chips da "analog devices" os AD5601/AD5611/AD5621 que são de 8,10 e 12 bits respectivamente.
O circuito montado no proteus foi este a seguir:
Observe que coloquei uma porta serial para saber o qual valor eu estava sendo enviado, o voltímetro 'lê' a tensão que estava saindo a cada incremento no chip.O código fonte ficou dividido em duas partes; uma gera onda dente de serra e o outro gera uma onda triangular, veja na imagem abaixo os prints da tela:
As formas de ondas em azul são os pacotes SPI que foram enviados ,em verde o clock gerado a cada transmissão de pacotes e em vermelho o momento em que o pino de "slave select " é ativado. Na figura a seguir é visto como é feito o cálculo para o chip AD5601, para calcular para os outros chips segue o mesmo raciocínio ou seja pega o valor de 5V e divide pelo números de resolução(incrementos) do chip ou seja 255 incrementos para o AD5601,1024 para o AD5611 e 4096 incrementos para o AD5621.
O código fonte fica :
/* * Usando comunicação SPI com ADS601/ADS611/ADS621 * * Compilador : MPlabXC8 * Microcontrolador: 16F1947 * Autor: aguivone * Versão: 1 * Data : 09/08/2016 */ #include <xc.h> #include <stdio.h> #include "serial16F1947.c" #include "SPI.c" #define _XTAL_FREQ 16000000 //usado para rotinas de delays #define LED LATAbits.LATA0 #define LER_LED PORTAbits.RA0 // ///////////configuração dos fuses bits///////////////////////////////////////////// // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable (VCAP pin functionality is disabled) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) ////////////////////////////////////////////////////////////////////////////////// //************************************************************************************/ //VARIAVEIS GLOBAIS //************************************************************************************/ bit flag_led=0; ////variaveis da porta serial char gcCaracter; //*******************************************************************************/ //=================================================================================== //Função: _interrupcoes //Descrição: usada para tratar as interrupções geradas pelo microcontrolador. //=================================================================================== void interrupt interrupcoes(void)//vetor de interrupção { if(RC1IF)//verifica interrupção da serial na COM1 {//interrupção da serial gcCaracter = RC1REG; escreve_RS232(gcCaracter,0);//finaliza string RC1IF = 0;// limpa flag de interrupção de recepção } /*if(RC2IF)//verifica interrupção da serial na COM2 {//interrupção da serial gcCaracter = RC2REG; escreve_RS232(gcCaracter,1);//finaliza string RC2IF = 0;// limpa flag de interrupção de recepção }*/ } //=================================================================================== //Função: _config_CPU //Parâmetros: não tem //Retorno: não tem retorno. //Descrição: inicializa os registradores do microcontrolador. //=================================================================================== void config_CPU() { //configura portas logicas TRISA = 0X00; TRISB = 0X00; TRISC = 0x80; TRISD = 0x00; TRISE = 0x00; TRISF = 0x00;//todos entrada e ainda são as entrasas analogicas TRISG = 0x04; // inicializa portas logicas configuradas como saida para 0 LATA = 0; LATB = 0; LATC = 0; LATD = 0; LATE = 0; LATF = 0; LATG = 0; inicializa_RS232(9600,1,0);//modo de alta velocidade inicializa COM1 //inicializa_RS232(9600,1,1);//modo de alta velocidade inicializa COM2 PEIE = 1;//habilita interrupção de perifericos do pic GIE = 1; //GIE: Global Interrupt Enable bit __delay_ms(100); } void Envia_pacote(unsigned long valor,int modo,int tipo)//valor,modo de operação,tipo do sensor { switch(tipo) { case 0: { valor = valor << 6; //8 bits - ADS601 }break; case 1: { valor = valor << 4;//10 bits - ADS611 }break; case 2: { valor = valor << 2;//12 bits - ADS621 }break; } valor = valor & 0B0011111111111111;//zera os 2 primeiros bits switch(modo) {//modos do power down case 1: { valor = valor + 0X4000;//1K ligado ao gnd }break; case 2: { valor = valor + 0X8000;//100K ligado ao gnd }break; case 3: { valor = valor + 0XC000; //three state }break; } escreve_SPI(((unsigned char)(valor>>8)),(unsigned char)valor ,1,0);//byte1 , byte2,numero de bytes a ser enviado(0 = 1 e 1 = 2),tipo de ligação ao terra } void main(void) { config_CPU(); imprime_RS232("Imprimindo: COM 1!\r\n",0); imprime_RS232("Digite um caracter:\r\n",0); inicializa_spi_mestre(0); long tensao,tempo=0; for(;;) { ///////////////simulação do trecho 1(onda dente de serra)////////////// imprime_RS232("Valor enviado = ",0); long_to_char_RS232(tempo,5,0,0); Envia_pacote(tempo,0,0); //8 bits - ADS601 o valor a ser colocado deve ser de 0 a 255. // Envia_pacote(tensao,0,1); //10 bits - ADS611 o valor a ser colocado deve ser de 0 a 1024. // Envia_pacote(tensao,0,2); //12 bits - ADS601 o valor a ser colocado deve ser de 0 a 4096. __delay_ms(200);//tempo de cada degrau imprime_RS232("\r\n",0); if(tempo > 245) { tempo = 0; } tempo = tempo + 10;
////////////////fim do trecho 1//////////////////////
///////////////simulação do trecho 2(onda triangular)//////////////
/* //descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado
if(tempo > 254)
{
tensao--;
if(tensao == 0)
{
tempo =0;
}
}
else
{
tensao++;
}
Envia_pacote(tensao,0,0);
__delay_ms(1);//tempo de cada degrau
*///descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado
////////////////fim do trecho 2//////////////////////
tempo++;
}
}
código dos includes externos
--------------------------------------------
"serial16F1947.c"
/* * FUNÇOES USADAS NA SERIAL * * Compilador : MPlabXC8 * Microcontrolador: 16F1947 * Autor: Aguivone * Versão: 1 * Data de criação: 21 de agosto de 2014. */ #include <xc.h> #include <stdio.h> #include <string.h> //para usar funçoes de string deve se adicionar este header #define _XTAL_FREQ 16000000//usado para rotinas de delays //=================================================================================== //Função: _inicializa_RS232 //Parâmetros: unsigned long ulVelocidade // : unsigned int uiModo // : porta serial(1 ou 0) //Retorno: não tem retorno. //Descrição: usada para iniciar a porta serial. //=================================================================================== void inicializa_RS232(unsigned long ulVelocidade,unsigned int uiModo,int porta) {//// por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada. // verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado. unsigned long valor; if(porta == 0) { RC1STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono. if(uiModo == 1) {//modo = 1 ,modo alta velocidade TX1STA = 0X24;//modo assincrono,trasmissao 8 bits. valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate } else {//modo = 0 ,modo baixa velocidade TX1STA = 0X20;//modo assincrono,trasmissao 8 bits. valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate } SP1BRG = valor; RC1IE = 1;//habilita interrupção de recepção TX1IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo) } else { RC2STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono. if(uiModo == 1) {//modo = 1 ,modo alta velocidade TX2STA = 0X24;//modo assincrono,trasmissao 8 bits. valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate } else {//modo = 0 ,modo baixa velocidade TX2STA = 0X20;//modo assincrono,trasmissao 8 bits. valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate } SP2BRGL = valor; SP2BRGH = valor<<8; RC2IE = 1;//habilita interrupção de recepção TX2IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo) } } //=================================================================================== //Função: _escreve1_RS232 //Parâmetros: char cValor, int porta //Retorno: não tem retorno. //Descrição: usada para escrever 1 caracter. //=================================================================================== void escreve_RS232(char cValor,int porta) { if(porta == 0) { TX1IF = 0;//limpa flag que sinaliza envio completo. TX1REG = cValor; while(TX1IF ==0);//espera enviar caracter } else { TX2IF = 0;//limpa flag que sinaliza envio completo. TX2REG = cValor; while(TX2IF ==0);//espera enviar caracter } __delay_us(50); } //=================================================================================== //Função: _imprime_RS232 //Parâmetros: const char ccFrase[], int porta //Retorno: não tem retorno. //Descrição: usada para escrever uma string(vetor de caracteres). //=================================================================================== void imprime_RS232(const char ccFrase[],int porta) { unsigned char indice = 0; unsigned char tamanho = strlen(ccFrase); while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas { escreve_RS232(ccFrase[indice],porta); indice++; } } //=================================================================================== //Função: _long_to_char_RS232 //Parâmetros: unsigned long ulQuant, -> valor a ser impresso na serial // int iTam,-> numero de caracter que deve ser impresso //Retorno: não tem retorno. //Descrição: converte um long ou int em uma sequencia de caracteres. //=================================================================================== void long_to_char_RS232(unsigned long ulQuant,int iTam,int virgula,int porta) { char cTexto[7]; int iValor = 0; if(virgula == 0) { virgula = 20;//dessa forma nunca será usado a virgula } while(iValor < 6 ) { cTexto[iValor]='0'; iValor++; } while(ulQuant>=10000) { ulQuant=ulQuant-10000; cTexto[5]++; } while(ulQuant>=1000) { ulQuant=ulQuant-1000; cTexto[4]++; } while(ulQuant>=100) { ulQuant=ulQuant-100; cTexto[3]++; } while(ulQuant>=10) { ulQuant=ulQuant-10; cTexto[2]++; } while(ulQuant>=1) { ulQuant=ulQuant-1; cTexto[1]++; } iValor = iTam ; while(iValor != 0 ) { escreve_RS232(cTexto[iValor],porta); iValor--; if(virgula == iValor){ escreve_RS232(',',porta);} } }------------------------------------------------------------------------------------
"SPI.c"
/* * File: SPI.c * Author: aguivone * * Created on 14 de Julho de 2016, 14:54 */ #include <xc.h> #define _XTAL_FREQ 16000000 //usado para rotinas de delays #define SPI1_SS LATCbits.LATC2 //configura pino de Slave selected #define SPI2_SS LATCbits.LATC0 //configura pino de Slave selected unsigned char ler_SPI( unsigned char dado,int porta_spi) {//le um byte unsigned char TempVar; unsigned char Retorno; if(porta_spi == 0) { SPI1_SS = 1; __delay_us(5); TempVar = SSP1BUF; // limpa BF SSP1BUF = dado; // escreve no buffer o codigo da solicitação while (!SSP1STATbits.BF);//espera terminar o envio TempVar = SSP1BUF; // limpa BF SSP1BUF = 0X00; // envia um dado qualquer somente para fazer a leitura while (!SSP1STATbits.BF); SPI1_SS = 0; Retorno = SSP1BUF; } else { SPI2_SS = 1; __delay_us(5); TempVar = SSP2BUF; // limpa BF SSP2BUF = dado; //escreve no buffer o codigo da solicitação while (!SSP2STATbits.BF);//espera terminar o envio TempVar = SSP1BUF; // limpa BF SSP2BUF = 0X00; // envia um dado qualquer somente para fazer a leitura while (!SSP2STATbits.BF); SPI2_SS = 0; Retorno = SSP2BUF; } return (Retorno); // byte lido } void escreve_SPI( unsigned char byte0,unsigned char byte1 ,int num_byte,int porta_spi) {//geralmente o primeiro byte tambem é chamado de opcode unsigned char TempVar; if(porta_spi == 0) {//usa a SPI 1 SPI1_SS = 0;//verifique se o hardware funciona deste modo ou é invertido __delay_us(5); TempVar = SSP1BUF; // limpa BF SSP1BUF = byte0; // escreve no buffer while ( !SSP1STATbits.BF ); //espera terminar o envio if(num_byte == 1) { TempVar = SSP1BUF; // limpa BF SSP1BUF = byte1; // escreve no buffer o byte 2 while (!SSP1STATbits.BF );//espera terminar o envio } SPI1_SS = 1; } else {//usa a SPI 2 SPI2_SS = 0;//verifique se o hardware funciona deste modo ou é invertido __delay_us(5); TempVar = SSP2BUF; // limpa BF SSP2BUF = byte0; // escreve no buffer while (!SSP2STATbits.BF); //espera terminar o envio if(num_byte == 1) { TempVar = SSP2BUF; // limpa BF SSP2BUF = byte1; // escreve no buffer while (!SSP2STATbits.BF); } __delay_us(5); SPI2_SS = 1; } } void inicializa_spi_mestre(int tipo)//inicialica modo mestre - 0-habilita somente spi1 , 1- habilita spi2 e 2- habilita os 2 spi { if((tipo == 0)||(tipo == 2)) { // SSP1CON1 = 0X20; //habilita pinos de spi // FOSC/4 //clock em nivel 0 // SSP1CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0 SSP1CON1 = 0X22; //habilita pinos de spi // FOSC/64 //clock em nivel 0 // SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de subida SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de descida SPI1_SS = 1;//inicia em nivel alto para AD5601/AD5611/AD5621 } if((tipo == 1)||(tipo == 2)) { SSP2CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0 SSP2STAT = 0XC0; //pega amostras no fim do byte e a trasmissão será na borda de subida SPI2_SS = 0; } }
Assinar:
Postagens
(
Atom
)