Ir ao conteúdo

Posts recomendados

Postado

gostaria da ajuda de vocês para um medidor de duty cycle e frequencia com o pic 16f877a, preciso que tenha um range pequeno só de 0-1000Hz mas para DC de 0-30Volts.

desde já agradeço.

Postado

Se é só para ler a frequencia e o duty cicle é simples de fazer.

Só nao entedni a história dos 0 a 30V.

Esse seu sinal quadrado a ser medido tem amplitude de quantos Volts?

Falou

Postado

entam matheus é isso que estou falando eu quero medir a frequencia e o duty cycle pelo Rb0 int/ext e pelo que vi é necessário um circuito gerador de zeros ou então um circuito amplificador de sinal... eu pretendo estar medindo a frequencia e o duty cycle de uma maquina de tatuar ela trabalha entre 5-15vols

Postado

Ok....

Ela trabalha entre 5 e 15V... mas ela emite um sinal totalmente quadrado? Podemos usar um divisor resistivo para diminuir a amplitude do sinal.

Mas você precisa de certificar que o sinal é o mais quadrado possível. E seja assimétrico, ou seja, ele tenha a parte positiva e não tenha a perte negativa.

Falou

Postado

não ela não emite um sinal totalmente quadrado, mas como usa uma fonte DC, acho me corrija se eu estiver falando besteira que seu sinal é simetrico

Postado

Acabei de postar no outro tópico:

Pronto:

Circuito:

XwmQv.jpg

Código:


//ser utilizado de 8 bits também.
#FUSES NOWDT //Sem Watch dog, evitando reset
#FUSES HS //Crystal de oscilação igual a 4mhz
#FUSES PUT //Tempo de início do PIC
#FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=12000000) //Meu clock
#include <LCD_flex.C> //Rotina de LCD modo 4 vias. Obrigatório!

int1 nuevopulso=0;
int16 TFB=0,TFS=0,TF=0;
float32 AP=0.0,freq;
int1 cambio=0;

#int_ccp1
void ccp1_int()
{
if(cambio==0)
{
TFS=CCP_1;
setup_ccp1(CCP_CAPTURE_FE);
cambio=1;
}

else
{
TFB=CCP_1;
setup_ccp1(CCP_CAPTURE_RE);
cambio=0;

if(nuevopulso==0)
{
nuevopulso=1;
}
}
}

void main()
{
lcd_init();
setup_timer_1(T1_INTERNAL);
setup_ccp1(CCP_CAPTURE_RE);
cambio = 0;

enable_interrupts(int_ccp1);
enable_interrupts(global);

do
{
if(nuevopulso==1)
{
TF=(TFB-TFS);
AP = (TF*1.0)/3;
freq=(1/(AP*2)*1000000);
printf(lcd_putc,"\fFreq = %2.2fHz", freq);
delay_ms (200);
nuevopulso=0;
}
}
while (TRUE);
}
#include <16f628a.h>             //O PIC utilizado, obigatório!

LCD_flex que irá precisar. Só copiar colaremnovo documento do CCS, salvar ( não precisa compilar). Salva na pasta drivers:



// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver. Change these
// pins to fit your own board.

#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7

#define LCD_E PIN_B0
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

//#define USE_LCD_RW 1

//========================================

#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line


int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};


//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));

delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;

output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);

output_low(LCD_E);

return(retval);
}
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);

delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);

// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_LCD_RW
delay_ms(5);
#endif
}

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
address = lcd_line_two;
else
address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
delay_ms(2);
break;

case '\n':
lcd_gotoxy(1,2);
break;

case '\b':
lcd_send_byte(0,0x10);
break;

default:
lcd_send_byte(1,c);
break;
}
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}
#endif
// flex_lcd.c

Falou

Postado

Modificado:

Circuito:

624FG.png

Código:

#include <16f628a.h>             //O PIC utilizado, obigatório!
//ser utilizado de 8 bits também.
#FUSES NOWDT //Sem Watch dog, evitando reset
#FUSES HS //Crystal de oscilação igual a 4mhz
#FUSES PUT //Tempo de início do PIC
#FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=12000000) //Meu clock
#include <LCD_flex.C> //Rotina de LCD modo 4 vias. Obrigatório!


int1 nuevopulso=0;
int16 T_descida_1=0,T_subida_1=0,T_ON=0,T_total=0,T_subida_2=0;
float32 AP=0.0,freq, d;

int flag;


#int_ccp1
void ccp1_int(void)
{
if (flag == 3)
{
flag = 0;
}

if(flag==0)
{
T_subida_1=CCP_1;
setup_ccp1(CCP_CAPTURE_FE);
}

if (flag == 1)
{
T_descida_1=CCP_1;
setup_ccp1(CCP_CAPTURE_RE);
}

if(flag==2)
{
T_subida_2=CCP_1;
setup_ccp1(CCP_CAPTURE_RE);

if(nuevopulso==0)
{
nuevopulso=1;
}
}
flag++;
}

void main()
{
lcd_init();
setup_timer_1(T1_INTERNAL);
setup_ccp1(CCP_CAPTURE_RE);
flag = 0;

enable_interrupts(int_ccp1);
enable_interrupts(global);
nuevopulso=0;

do
{
if(nuevopulso==1)
{
T_ON=(T_descida_1-T_subida_1);
T_total = (T_subida_2-T_subida_1);

AP = (float)T_total/3.0;

freq=(float)1/(AP)*1000000;

d = (float)T_ON*100/T_total;

printf(lcd_putc,"\fFreq = %fHz\nDuty = %2.2f%%", freq,d);
delay_ms (200);
nuevopulso=0;
}
}
while (TRUE);
}

Não deixe de comentar se a dúvida foi resolvida!

Falou

Postado
só uma pergunta ligar o circuito assim diretamente não vai queimar o pic?

Depende do sinal a ser medido.

Se ele tiver uma amplitude de até 5V pode ligar direto. Mais q isso teremos q mudar o circuito....

Falou

Postado

sim mas como expliquei antes uma maquina de tatuar normalmente começa a trabalhar em torno de 5Volts ou seja dificilmente eu irei usar só 5 volts

você menciono em outra postagem usar um divisor resistivo acho que seria a maneira mais simples para solucionar isso, estou supondo se eu estiver falando bobeira me corrija

Postado

Então essa máquina de tatuar vai de 0 a 30V? Mas e o PWM vai onde?

De toda forma o divisor resistivo para essa configuração é formado por um resistor de 5K e um de 1K em série e você pega o sinal para o pic entre eles.

Pode simular aí.

Falou

Postado

Acho que a maquina de tatuar só recebe a tensão nas bobinas! Existe um contato NF que quando ela se movimenta para frente (momento em que o suporte das agulhas é atraido pela bobina) este contato é aberto e sem a atração magnética o suporte de agulhas volta a sua posição inicial (suporte de agulhas trabalha com deformação elástica) e novamente fecha o contato e inicia o processo!

Então eu acredito que a tensão é produzida pela fonte sem PWM, corrente continua!

A tensão vai influenciar no campo eletromagnético do eletroímã, gerando um campo maior e de mais força de atração!

Conclusão: A fonte não gera PWM!

Postado

não vou usar pwm apenas o duty cycle ele é usado para se fazer um ajuste correto da maquina para que ela possa trabalhar com a tensão mais baixa possivel diminuindo assim seu aquecimento e ate melhorando a aplicação da tinta pois não força a pele do tatuado

Postado

matheus gostaria de fazer 2 alterações, como faço para que no display apareça apenas os números antes do ponto sem o .00? e o que devo alterar para usa-lo em 4Mhz

Postado

Para usar os numeros antes do .(ponto) mude a seguinte linha:

printf(lcd_putc,"\fFreq = %fHz\nDuty = %2.2f%%", freq,d);

Para:

printf(lcd_putc,"\fFreq = %3.0fHz\nDuty = %3.0f%%", freq,d);

Para mudar o clock, mude essa linha:

#use delay(clock=12000000)        //Meu clock

Para:

#use delay(clock=4000000)        //Meu clock

Mas para medir frequencia é bom que o clock seja o mais alto possível!.

Para simular, altere o clock do PIC no proteus também.

Falou

  • Curtir 1
Postado

opa matheus ja fiz as alterações acho que você esqueceu de mencionar por isso vou postar aqui que ao se trabalhar com o clock de 4Mhz

nessa linha

AP = (float)T_total/3.0;

retirar a divisão

AP = (float)T_total;

  • 1 ano depois...
Postado
Acabei de postar no outro tópico:

Pronto:

Circuito:

XwmQv.jpg

Código:


//ser utilizado de 8 bits também.
#FUSES NOWDT //Sem Watch dog, evitando reset
#FUSES HS //Crystal de oscilação igual a 4mhz
#FUSES PUT //Tempo de início do PIC
#FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=12000000) //Meu clock
#include <LCD_flex.C> //Rotina de LCD modo 4 vias. Obrigatório!

int1 nuevopulso=0;
int16 TFB=0,TFS=0,TF=0;
float32 AP=0.0,freq;
int1 cambio=0;

#int_ccp1
void ccp1_int()
{
if(cambio==0)
{
TFS=CCP_1;
setup_ccp1(CCP_CAPTURE_FE);
cambio=1;
}

else
{
TFB=CCP_1;
setup_ccp1(CCP_CAPTURE_RE);
cambio=0;

if(nuevopulso==0)
{
nuevopulso=1;
}
}
}

void main()
{
lcd_init();
setup_timer_1(T1_INTERNAL);
setup_ccp1(CCP_CAPTURE_RE);
cambio = 0;

enable_interrupts(int_ccp1);
enable_interrupts(global);

do
{
if(nuevopulso==1)
{
TF=(TFB-TFS);
AP = (TF*1.0)/3;
freq=(1/(AP*2)*1000000);
printf(lcd_putc,"\fFreq = %2.2fHz", freq);
delay_ms (200);
nuevopulso=0;
}
}
while (TRUE);
}
#include <16f628a.h>             //O PIC utilizado, obigatório!

LCD_flex que irá precisar. Só copiar colaremnovo documento do CCS, salvar ( não precisa compilar). Salva na pasta drivers:



// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver. Change these
// pins to fit your own board.

#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7

#define LCD_E PIN_B0
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

//#define USE_LCD_RW 1

//========================================

#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line


int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};


//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));

delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;

output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);

output_low(LCD_E);

return(retval);
}
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);

delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);

// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_LCD_RW
delay_ms(5);
#endif
}

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
address = lcd_line_two;
else
address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
delay_ms(2);
break;

case '\n':
lcd_gotoxy(1,2);
break;

case '\b':
lcd_send_byte(0,0x10);
break;

default:
lcd_send_byte(1,c);
break;
}
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}
#endif
// flex_lcd.c

Falou

Eu não entend muito bem os cálculos de freq e duty.

Postado

Mais de 1 ano que fiz esse código.....

Mas já lembrei o raciocínio. Veja:

-----|____________|-----|____________|-----|____________|-----|  --> Sinal PWM
ON OFF ^ ON ^ OFF ^ ON OFF ON
| | |
| | |
| T_descida_1 |
T_subida_1 T_subida_2

Veja acima um esboço de um sinal PWM. Nele nos temos o tempo ON (tracejado) e o OFF (underline). Certo?

O período é a soma do tempo ON + tempo OFF.

Lá no meu programa, meu TIMER1 corre com o relógio interno (INTERNAL), dessa forma irá me retornar o tempo em uS (microsegundos).

Criei uma interrupção onde a mesma, logo no início, espera por uma subida de nível, ou seja, de 0V para 5V. Quando isso ocorre a seguinte linha é executada:

T_subida_1=CCP_1;

A variável acima pega o valor do CCP_1 que depende do TIMER1.

Logo em seguida o programa é reconfigurado para esperar uma descida de nível, ou seja, de 5V para 0V.

Nesse momento, o tempo é armazenado novamente pela linha:

T_descida_1=CCP_1;

Ora, se pegarmos o tempo de subida e o tempo de descida e subtraírmos os dois, teremos o tempo ON. O código faz isso no loop infinito, de acordo com a linha:

T_ON=(T_descida_1-T_subida_1);

Depois de pegar a borda de descida, o código espera novamente por uma borda de subida. O mesmo é pego com essa linha:

T_subida_2=CCP_1;

Dessa forma, olhando o desenho acima é possível verificar que pegamos:

Tempo de subida;

Tempo de descida;

Tempo de subida novamente.

Agora vem a matemática:

T_ON=(T_descida_1-T_subida_1); --> Calculamos o tempo ON.

T_total = (T_subida_2-T_subida_1); --> Calculamos o tempo Total ou chamado também de período.

AP = (float)T_total/3.0; --> Dividimos por 3 pois o PIC está com clock de 12Mhz e o clock "padrão" é 4Mhz. Digo padrão, pois em 4Mhz cada incremento do TIMER1 é de 1 uS.

freq=(float)1/(AP)*1000000; --> Ora, frequência é o inverso do tempo, certo? Então estou fazendo o inverso da variável AP para obter a frequência. MAS AP é em uS (micro segundos). Dessa forma, multiplico por 1000000 (1 milhao) para transformar os uS em segundos.

d = (float)T_ON*100/T_total; --> O que é o duty cicle? É a fração do T_ON por T_total.

No final multiplico por 100 para que tenho em porcentagem.

Veja que esse código trabalha com muitas variáveis do tipo float, faz muitas divisões e multiplicações. Isso deixa o código "lento".

Fiz dessa forma de propósito para ser um código didático. Numa aplicação real, você pode juntar todas as contas e ir simplificando para no final dar somente 1 multiplicação ou divisão. E pode também evitar os float, trabalhando somente com ints e deixando para dividir somente no final.

Isso deixará o código mais rápido.

Claro que se a função do PIC for somente calcular frequencia e duty cicle, ele fará isso com os pés e mãos nas costas.

Dúvidas? Pergunte.

Falou

  • mês depois...
Postado

Senhores,

Alguem poderia me ajudar em um programa, em que eu consiga controlar o duty cycle do pwm, atraves de dois botões.

Um botão incremeta o dyte cicly deixando ele quase em 100% e outro botão que decremente deixando no minimo.

Att,

Rafael

Postado

O que você já tem pronto?

Não deseja que eu faça tudo né.

O esquema dos botões é só você criar dois ifs e dentro de cada 1 incrementar ou decrementar a variável responsável pelo duty-cicle.

Falou

  • 3 anos depois...
Postado
Em 3/6/2011 às 20:25, MatheusLPS disse:

modificado:

circuito:

624FG.png

código:

 

 



















































































 

Asegúrese de comentar si se resolvió la cuestión!

rayo

Como hago para que el programa mida voltaje y cuando se corte los pulsos la medición vuelva a cero en espera de un nuevo pulso?

Postado

Estoy probando el código y no puedo modificar la muestra en el lcd para agregarle la toma del adc y tener voltimetro y amperimetro frecuencia y duty me dan una mano para modificar el código :)

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...