Jump to content
Silva Manuel

Qual o tipo de variável a definir

Recommended Posts

Silva Manuel

Olá a todos!

Em primeiro lugar peço desculpa pela minha ignorância, mas estou a dar os primeiros passo em C e estou com uma dificuldade que não sei resolver.

Fiz uma pequena rotina para contar as rotações de um motor (hélice) usando "interrupts". Tenho também um contador de tempo com a resolução de 1ms usando um timer.  Acontece que se a variável usada para contar o tempo "time" não for do tipo "float" o resultado número de rotações é igual a "0xFFFF". Eu pretendia utilizar uma variável tipo "uint32_t", como contador de tempo para a usar  noutra função que poderá ultrapassar uma hora.

Antecipadamente agradeço a ajuda.

Cumprimentos,

Manuel Silva

Definição da variável:


volatile float time;

Coligo para contar as rotações:

 

ISR(INT0_vect)
{

   if(pulse_status==0)

		{time=0;
	pulse_count=0;
	pulse_status=1;}
else
pulse_count++;

	if (time>=500)
		{rpm=(30*(pulse_count))/(time/1000);
		 pulse_status=0;

		 while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm>>8);

		while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm);
			EIMSK = 0x00; // enable INT0
		 }	 

	else 
	{}

} 

Rotina de "interrupts" para contar (acumular) o tempo.

ISR(TIMER1_COMPA_vect)
{
time++;
}

O que eu pretendo fazer mas o resultado que obtenho é 0xFFFF.


volatile uint32_t  time;
volatile uint32_t temp_time;

Conta rotações:


ISR(INT0_vect)
{

   if(pulse_status==0)

		{time_temp=time;
	pulse_count=0;
	pulse_status=1;}
else
pulse_count++;
time_temp=time-time_temp;

	if (time_temp>=500)
		{rpm=(30*(pulse_count))/(time_temp/1000);
		 pulse_status=0;

		 while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm>>8);

		while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm);
			EIMSK = 0x00; // enable INT0
		 }	 

	else 
	{}

}

Share this post


Link to post
Share on other sites
bubulindo

Antes de mais, acho que terias mais sorte se postasses na área de electrónica. Até porque o problema do teu programa está na plataforma e configuração usada e não necessariamente no código.

Depois, acho que não perdes nada em dar uma vista de olhos nas bibliotecas do Fleury:

http://www.jump.to/fleury

Não é C básico, mas serve perfeitamente para comunicações série e não deves ter grandes problemas em compilar, a não ser que uses algum dos AVR mais exóticos.

Eu vejo vários erros no teu código e algumas coisas que podem estar erradas na configuração.

Primeiro, tens dois pedaços de código para contar rotações, qual deles não funciona?

Segundo, a variável time pode fazer overflow.

Terceiro, como já sugeri, a maneira como envias os dados não é a mais simples... por vezes usar um ASCII é melhor, mas dá um pouco mais de trabalho.

Quarto, a comunicação série pára o programa durante o tempo necessário para enviar o número de rotações. Isto pode ser problemático se o motor andar a alta velocidade uma vez que ou perdes pulsos, ou acabas por levar o microcontrolador a baralhar-se todo.

Suponho que a variável rpm seja um int:

rpm=(int)(30*(pulse_count))/(time/1000);

Isto é capaz de dar outro sentido ao código. O problema é que estás a dividir o pulse count por um número que ou pode ser um infinitesimal... logo, o resultado vai ser grande. Porque é que divides o time por 1000?

De resto, não percebo muito bem a lógica usada para calculares as RPM, mas se fizesses algo assim não era mais simples?

#define TIMER_SETTING      0.1 //digamos que o timer funciona com 100 milisegundos. 

voltile long rpm; 
volatile long time; 



ISR(TIM1_OVF_vect) //queres testar o overflow
{
//se quiseres
//if (motor == running)
time++; 
//else
//time = 0; 
}

ISR(INT0_vect)
{

rpm = (time * 65535) + TCNT1; //assim sabes o número de vezes que o relógio pulsou de pulso para pulso do encoder (ou sensor)
    
time = 0; //prepare for the next
TCNT1 = 0;   
} 


int main ()
{
volatile int i; 
char result[5];
itoa(rpm, result, 10); 
//configurar portas de entrada
//configurar UART
//configurar interrupções

sei(); 

for (i = 0; i <60000; i++)
  {
   //rotina de envio de dados convém ser relativamente lento de forma a não dar cabo do buffer no computador... 
   // Enviar os dados aqui tem também a vantagem da rotina de envio poder ser interrompida para contar pulsos 
   //e do envio dos dados não estar dependente das rotações. No teu código, quanto mais depressa o motor andasse, mais medidas ias ter. 
   rpm = rpm * TIMER_setting; //tempo que demorou a dar uma volta (assumindo que só tens um sensor)
   rpm = (long) 60/rpm; //quantas voltas por minuto? 

   printf("voltas %L \n", rpm);  
  }


return 0; 
}


Este código serve apenas para dar uma ideia de como resolver o problema. Tens de ter em atenção qual a precisão que queres atingir e qual a melhor estratégia para o conseguir.


include <ai se te avio>

Mãe () {

}

Share this post


Link to post
Share on other sites
Silva Manuel

Bubulindo, obrigado pela sua ajuda e comentários.

O último código era o que pretendia usar, isto é,  eu pretendia usar uma variável tipo "uint32_t" para "time", pois quero usar este contador de milisegundos para outra função em que não pode existir overflow.  Quando uso "time" com 32 bits que é usado no segundo código, obtenho o resultado "0xFFFF" . Se resolver este problema fico com o problema resolvido.

A variável time quando o motor está em funcionamento  é inicializada na primeira passagem da hélice e é usada até >= 500ms.  O método de enviar os dados que estou a usar é apenas para debug. O valor de RPM assim como outros vão ser colocados num vector. Os valores a enviar serão todos em bytes para reduzir o número de tráfego. O processador que receber esta informação fará todas as conversões.  Eu tenho um problema, que é só poder enviar cerca de 64 bytes/segundo.

O primeiro programa está a funcionar e já o testei até ao limite de 60000 rotações sem problemas.  Eu faço a divisão  por mil para converter para segundos uma vez que estou a contar o tempo em milisegundos.

rpm = (time * 65535) + TCNT1; //assim sabes o número de vezes que o relógio pulsou de pulso para pulso do encoder (ou sensor)

Peço desculpa mas não compreendo a expressão anterior.

Vou analisar com cuidado as suas sugestões e ver a melhor maneira de reescrever o programa.

Obrigado.

Manuel Silva

Share this post


Link to post
Share on other sites
bubulindo

Essa expressão dá-te o número de pulsos que o temporizador teve mesmo que faca overflow do temporizador. Assim sabes exactamente quantos pulsos passaram desde a última vez que mediste o tempo que demorou a fazer uma rotacão, para agora e podes calcular ao contrário.

Ou seja, se uma rotacão demora X segundos, em 60 segundos consigo fazer 60/X.

Tens um encoder ou um sensor de posicão que pulsa em cada volta?

60000 RPM são 1000 rotacões por segundo. Onde arranjaste um motor destes?

A minha resposta foi um pouco... à pressa porque tinha de tomar o pequeno almoco antes de ir para o trabalho. Mais logo tento fazer algo mais completo.


include <ai se te avio>

Mãe () {

}

Share this post


Link to post
Share on other sites
Silva Manuel

Mais uma vez obrigado Bubulindo.

É verdade, em vez de contar o número de vezes que a hélice passa à frente do sensor posso medir o tempo que o motor demora a dar uma volta. Não me tinha lembrado dessa opção.  Vou analisar esta opção para ver qual a è a que sobrecarrega menos o controlador.

O sensor é um fototransistor com um amplificador operacional, para melhorar a resposta do mesmo e não ser influênciado pela luz ambiente.

Para conseguir simular estas rotações fiz um disco com várias ranhuras ligado a um motor CC e comparei o resultado que obtinha com um contarotações  normal.

Eu neste momento com um Atmega644P estou a ler os dados de um GPS a um baudrate de 115200, ler a pressão atmosférica com um sensor SCP1000, medir a voltagem de duas baterias (ADC), velocidade do avião relativamente ao vento e a enviar estes dados a um baudrate de 9600 através de um link de telemetria de um rádiocontrol. Ainda queria medir a corrente de descarga da bateria, para calcular a descarga em mAh. Os dados são enviados em bruto isto é, o valor lido pelo ADC (2 bytes), pressão atmosférica 6 bytes, GPS 32 bytes, etc.  O controlador no solo como só tem a tarefa de ler a UART e fazer display, faz os restantes cálculos.

Vou analisar e ver qual a opção que ocupa mesmo o controlador e mais fiável. Quero salientar que praticamente não sei C, vou lendo uns livros e tentanto até consiguir.

Obrigado.

Cumprimentos,

Manuel Silva

Share this post


Link to post
Share on other sites
bubulindo

Hmmm...

Não vejo como é que um amplificador operacional faz com que a luz ambiente não influencie a leitura. Terás de estar a fazer uma espécie de comparador, mas muito provavelmente haverá uma condição que baralhará o motor. Para esta aplicação, o ideal é mesmo algo que não pare o processador muito tempo.

Um encoder por exemplo, vai ter tempos de interrupção muito curtos para poderes fazer algo com ele sem dar cabo do resto do programa. Logo fazer algo menos "cansativo" para o processador vai beneficiar-te em termos de carga, mas pode dificultar as coisas se utilizares essas rotações no controlo do avião.

Esta não é uma questão de C... é mesmo desenho de sistemas.


include <ai se te avio>

Mãe () {

}

Share this post


Link to post
Share on other sites
Silva Manuel

Olá Bubulindo!

  Se o acoplamento entre o fototransistor for feito com um condensador a componente DC não vai ser amplificada. Só variações rápidas de sinal são amplificadas, desta forma podemos aumentar bastante o ganho do amplificador sem problemas.

Voltando à questão do problema que tenho em C.

A razão de usar esta formula de cálculo das rotações é para evitar o erro possível a baixas rotações. Em baixas rotações o tempo entre duas passagens da hélice é bastante maior e se amostragem for fixa a probabilidade e erro é maior. O que faço é iniciar a contagem a partir da 1ª passagem da hélice depois de enable do Int0 e comparo o tempo com 500ms se for maior conto o tempo até à próxima passagem da hélice, obtendo o tempo total de n voltas com uma resolução de 1ms.

Gostaria de entender o porquê de não poder definir a variável "time" como "uint32_t" e ter de ser "float". Será porque tenho a operação "(time/1000)"?


ISR(INT0_vect)
{


   if(pulse_status==0)

		{time=0;
	pulse_count=0;
	pulse_status=1;}
else

pulse_count++;

	if (time>=500)
		{rpm=(int)(30*(pulse_count))/(time/1000);
		 pulse_status=0;

		 while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm>>8);

		while (!(UCSR1A & (1<<UDRE1)));           					
			UDR1=(uint8_t)(rpm);
			EIMSK = 0x00; // enable INT0
		 }	 

	else 
	{}

}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.