TUTORIAL: Módulo CCP
Modo de Captura
O módulo CCP( Capture / Compare / PWM ) é um periférico que permite, ao programador, controlar e medir diversos eventos.
Modo de Captura:
Permite medir a duração de tempo durante um evento. Este circuito monitora o estado do TIMER1, que constantemente muda de valor.
Este modo possui dois registros, CCPR1H e CCPR1L, que copia os valores do TIMER1 ( registros TMR1H e TMR1L), nas seguintes situação:
- Cada flanco descendente no pino CCP1;
- Cada flanco ascendente no pino CCP1;
- Cada 4 flancos ascendente no pino CCP1;
- Cada 16 flancos ascendente no pino CCP1;
Modo de Comparação:
Neste modo o valor de CCP1 (registros CCPR1H e CCPR1L) é constantemente comparado com o valor do TIMER1( registros TMR1H e TMR1L). quando os valores coincidem, o estado lógico do pino CCP1 é alterado, a flag CCP1IF é setada e/não é gerada uma interrupção. Veja a configuração dos modos logo abaixo, para uma melhor compreensão.
Modo PWM:
DCxB1 e DCxB0: É usado somente no modo PWM;
CCPxM3:CCPxM0: Modos:
0000 - Módulo desabilitado;
0001 - Não usado;
0010 - Modo Comparação: Alterna saída quando ocorre a comparação, e o bit CCPxIF é setado;
0011 - Não usado;
0100 - modo Captura: flanco ascendente no pino CCPx;
0101 - modo Captura: flanco descendente no pino CCPx;
0110 - modo Captura: 4 flancos ascendente no pino CCPx;
0111 - modo Captura: 16 flancos ascendente no pino CCPx;
1000 - modo Comparação: Inicializa pino CCPx=0, quando ocorre a comparação, pino CCPx=1 e CCPxIF = 1;
1001 - modo Comparação: Inicializa pino CCPx=1, quando ocorre a comparação, pino CCPx=0 e CCPxIF=1;
1010 - modo Comparação: Gera uma interrupção quando ocorre a comparação;
1011 - modo Comparação: EVENTO ESPECIAL, Timer resetado, e inicia uma conversão AD quando ocorre a comparação, CCPxIF=1;
11xx - modo PWM;
EXEMPLO: Captura o tempo de nivel alto de um pulso
EXEMPLO: Captura o tempo de nivel alto de um pulso
char Flags = 0; unsigned int tempo2, tempo1; char resultado[16]; #define bordaDescida Flags.F0 #define capturaOK Flags.F1 void interrupt() { if(CCP1IF_bit) { if(bordaDescida == 0)//se for borda de subida(indo para o nível alto) { tempo1 = (CCPR1H << 8) + CCPR1L;//captura o 1º valor bordaDescida = 1; } else //se for borda de descida { tempo2 = (CCPR1H << 8) + CCPR1L;//enquanto esteve no nível alto, captura o 2º valor bordaDescida = 0; capturaOK = 1; } CCP1CON.F0 = ~CCP1CON.F0; //inverte o modo( borda de subida <-> borda de descida) CCP1IF_bit = 0; } } void main() { //Clock = 8Mhz, prescaller 1:2, t = (4/8) * 2 * 1 = 1[us] T1CON = 0B00010001; //cada unidade do valor de timer1 corresponde a 1[us] CCP1CON = 0B00000101; //borda de subida TRISC.F2 = 1; INTCON.GIE = 1; INTCON.PEIE = 1; PIE1.CCP1IE = 1; //habilita interrupção do modulo CCP uart1_init(9600); delay_ms(10); while(1) { if(capturaOK) { tempo2 = tempo2 - tempo1; //resultado em [us] inttostr(tempo2, resultado); uart1_write_text(resultado); capturaOK = 0; } } } ->
Utilizando o modo de captura, você consegue medir tempos com uma alta precisão, de frequências baixas até frequências altas.
Para enviar a saída por LCD, além das configurações iniciais do LCD, só mudaria a penultima linha "uart1_write_text(resultado);"
ResponderExcluirpor :
Lcd_Init();
Lcd_Cmd(_Lcd_clear);
Lcd_Cmd(_Lcd_cursor_off);
Lcd_out(1,1,resultado);
?
isso, so que voce deve colocar antes do while(1):
ExcluirLcd_Init();
Lcd_Cmd(_Lcd_clear);
Lcd_Cmd(_Lcd_cursor_off);
e substituir uart1_write_text por:
Lcd_out(1,1, resultado);
Olá, aproveitando essa pergunta, eu também estou enviando dados adquiridos do CCP para o LCD. No entanto, tento realizar operações com tempo2. Assim:
Excluirtempo2 = tempo2 - tempo1; //resultado em [us]
Ang = (tempo2*360)/16666.666;
lcd_out(2,1,Ang);
Por exemplo, se eu substituir tempo2 por 1390, então Ang = 30.0240. Mas isso só funciona se eu substituir direto o número 1390 em Ang. Agora se eu deixar Ang em função de tempo2 não dá certo. Eu queria lhe pedir uma ajuda pra descobrir porq.
Evitar fazer calculos com float do jeito que voce, tudo numa so linha. É muita coisa pro microcontrolador calcular e ira causar um estouro na memoria. por isso aparece um valor errado.
ExcluirVc falou que substituir tempo2 por 1390 da certo. Como nao possui variavel, o compilador ja calcula o resultado.
Faça dessa maneira, quando utilizar float:
Ang = tempo2;
Ang *= 360;
Ang /= 16666.666;
Modulo Ccp - Microcontrolandos >>>>> Download Now
Excluir>>>>> Download Full
Modulo Ccp - Microcontrolandos >>>>> Download LINK
>>>>> Download Now
Modulo Ccp - Microcontrolandos >>>>> Download Full
>>>>> Download LINK MV
Para um clock de 4MHz, como ficariam as alterações?
ResponderExcluirse for utilizar um clock de 4mhz, voce deve alterar o prescaler para 1:1, ou seja, T1CON = 0B00000001;
ExcluirOlá Tiago, primeiramente gostaria de parabenizar-lhe pelo blog. Estou aprendendo muito sobre MCUs aqui.
ResponderExcluirEstou com um pequeno problema, estou tentando escrever no LCD o resultado igual explicado nos post acima, porém não to conseguindo, o lcd não mostra nada (com outros programas que já uso o LCD Escreve normal).
Será que CCP está usando algum pino que eu configurei para o LCD?
Segue o código (18F4520) Compilador MickoC:
// configuração dos pinos do LCD
sbit LCD_RS at RE2_bit;
sbit LCD_EN at RE1_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D4 at RD4_bit;
// direção dos pinos do pic
sbit LCD_RS_Direction at TRISE2_bit;
sbit LCD_EN_Direction at TRISE1_bit;
sbit LCD_D7_Direction at TRISD7_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D4_Direction at TRISD4_bit;
char Flags = 0;
unsigned int tempo2, tempo1;
char resultado[16];
#define bordaDescida Flags.F0
#define capturaOK Flags.F1
void interrupt()
{
if(CCP1IF_bit)
{
if(bordaDescida == 0)//se for borda de subida(indo para o nível alto)
{
tempo1 = (CCPR1H << 8) + CCPR1L;//captura o 1º valor
bordaDescida = 1;
}
else //se for borda de descida
{
tempo2 = (CCPR1H << 8) + CCPR1L;//enquanto esteve no nível alto, captura o 2º valor
bordaDescida = 0;
capturaOK = 1;
}
CCP1CON.F0 = ~CCP1CON.F0; //inverte o modo( borda de subida <-> borda de descida)
CCP1IF_bit = 0;
}
}
void main()
{
Lcd_Init();
Lcd_Cmd(_Lcd_cursor_off);
//Clock = 8Mhz, prescaller 1:2, t = (4/8) * 2 * 1 = 1[us]
T1CON = 0B00001001; //cada unidade do valor de timer1 corresponde a 1[us]
CCP1CON = 0B00000101; //borda de subida
TRISC.F2 = 1;
INTCON.GIE = 1;
INTCON.PEIE = 1;
PIE1.CCP1IE = 1; //habilita interrupção do modulo CCP
delay_ms(10);
while(1)
{
if(capturaOK)
{
tempo2 = tempo2 - tempo1; //resultado em [us]
IntToStr(tempo2, resultado);
Lcd_out(1,4, "frequencia");
Lcd_out(2,2, resultado);
capturaOK = 0;
}
}
}
Vc usou os pinos RE1, RE2. Estes pinos tbm sao analogicos. entao vc deve desativar. Nao tenho certeza, mas acho q vc deve configurar o registro ADCON1=0X0F.
ExcluirFala Tiago,
ExcluirEstou usando o Pic16f628A, ele só tem um modulo CCP.
Tem como usar mais de uma porta com o CCP para capturar tempo?
Abraços
Andersosn
Cara onde vc pega essa imagem do PIC
ResponderExcluirObrigado
eu pego essas imagens da apostila.
ExcluirProcure aqui no blog por Apostilas sobre Microcontroladores. É uma apostila com a capa verde.
Abraços,
Tiago.
Boa noite meu caro, primeiramente queria lhe parabenizar pelo trabalho. Coloquei o teu código pra rodar aqui e compilou de boa, quando fui simular usando o proteus fiz um pequena modificação com a finalidade de mostrar no lcd16x2 os valores de referentes aos períodos de uma função senoidal, gerada a partir do próprio proteus com a finalidade obter a frequência da mesma, porém o erro gerado é enorme,pensei que talvez pelo fato do código está dimensionado pra um pulso, mas quando coloquei um onda quadrada o resultado também não foi satisfatório, por ex uma onda senoidal de 440 hz e v =5v , está imprimindo na variável resultado 172, você poderia me indicar alguma correção?
ResponderExcluiragradeço desde já.
Fala pessoal!
ResponderExcluirEstou com um projeto já a 4 anos.
Estou usando o PIC 16f628A para ler sinal PPM que vaira de 800ms a 2200 ms.
Acabei utilizando a interrupção do PORTB em conjunto com o Timer1.
Eu estava com problemas para ler mais de 2 canais simultaneos.
Por fim, depois de 4 anos, consegui resolver o problema.
Eu não conhecia essa opção do CCP.
Por Exemplo, neste modelo de pic que estou utilizando, só tem um modulo CCP, e creio eu que deve
ser utilizado na Porta RB3 (PWM).
Pergunta, tem como utilizar essa função CCP para capturar tempo em outras portas do PORTB?
Abraços
Anderson
Não, o PIC16F628A só tem apenas um modulo CCP e somente o pino RB3 é usado como entrada para a captura.
ExcluirAbraços.
Fala Tiago,
ExcluirEntão, não tem como eu ler mais de um tipo de Entrada usando apenas um CCP?
eu já ví alguns códigos por aí, onde o pessoal faz um for para Ler os Canais usando o CCP.
Como eu eu não entendia muito o bem o CCP, acabei deixando de lado.
Vc acha possível trabalhar a interrupção em conjunto com o CCP?
exemplo: A cada interrupção, copio o estado da porta em questão para a porta do CCP e depois capturo o tempo?
Só que com isso, irei perder a minha saída PWM, correto?
Tiago, parabéns pelo blog, sempre busco ajuda aqui!
ResponderExcluirEstou precisando medir duas frequência diferentes usando o modo capture (CCP1 e CCP2 - PIC16F876A). Pelo que entendi os dois usam o TIMER1 como base de tempo e assim não estou sabendo como fazer para zerar o flag capturando os tempos simultaneamente. Tenho que fazer tudo dentro de uma mesma rotina de interrupção? Estou usando como base um projeto seu com 18F628 postado qui no site. Tem como ajudar aí? Desde já agradeço.
Att,
Boa tarde Tiago,
ResponderExcluirFiz a gravação do programa no PIC , verifiquei que em baixas frequências(da ordem de 6hz pra baixo ) o programa começa a enviar valores com sinal negativo ou seja ele passa pelo zero e envia os valores em negativo,tem algo que possa ser modificado para ler o tempo em nivel alto de 0hz até o máximo da amostragem?
Att,
Edson
Fala Edson.
ExcluirNa verdade eu tb estou com algumas dúvidas a respeito do ccp.
Fiz um post com uma dúvida é até agora ninguém me respondeu.
Mas vamos lá, como eu resolvi o meu problema.
Configurei o port b para interrupção externa na borda de subida.
Configurei o preescaler para 1/2 se não me engano, mas aí vc vai ter que ver na sua APLICAÇÃO qual é a melhor configuração, creio que no seu caso 1/8
Estou usando o timer1 .
Quando tenho a interrupção zero o meu time e configuro para borda de descida.
Quando houver a interrupção na borda de descida capturo o tempo do timer 1 e configuro novamente para borda de subida.
Espero ter ajudado
Boa tarde Anderson !
ResponderExcluirMuito obrigado por sua ajuda fico muito grato.
Vou verificar as observações que você fez, daí passo um retorno aqui.
Att,
Edson
Fala Edson
ResponderExcluirImagina, espero ter ajudado.
Bom dia !
ResponderExcluirSó pelo fato de ter dado atenção já ajuda muito Anderson!
Grande abraço
Att
Edson