• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Ziwdon

[Dúvidas] Cronómetro em Pascal

8 mensagens neste tópico

Boas.

Estou a iniciar-me em programação e ando a aprender Pascal, logo ainda estou muito "verde" e com muitas dúvidas pelo que precisava que alguém me ajudasse (estou a aprender por iniciativa propria, e nao tenho aulas).

Ando a tentar criar um programa que funcionará como um cronómetro e/ou como um cronómetro inverso.

O meu problema está mesmo nos cronómetros. Como não sabia como usar tempo (em segundos) no pascal, fiz uma pesquisa na net, e após algumas experiencias resolvi usar "Delay(1000)" que provoca um atraso de 1 segundo (1000 milisegundos).

Depois começei a criar o codigo para ambos os cronómetros, mas há sempre alguma coisa que não está bem.

Já reescrevi o código duas vezes. Na primeira estava bastante extenso e no cronometro normal o tempo nao parava e no inverso (que começa a contar de determinado tempo até aos 00:00:00) só parava as vezes, outras ia para números negativos.

Depois de reescrever o codigo, ficou muito mais simplificado. Porém os problemas continuam e ainda surgiram mais alguns.

CRONOMETRO NORMAL

procedure countup;
begin
sec:=0;
min:=0;
hour:=0;
secf:=0;
minf:=0;
hourf:=0;

clrscr;
writeln;
writeln('                                  CRONOMETRO');
writeln;
writeln('                                Tempo Inicial: ');
writeln('                              Introduza as horas');
     readln(hour);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(min);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(sec);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;
writeln('                                 Tempo Final: ');
writeln('                              Introduza as horas');
     readln(hourf);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(minf);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(secf);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;writeln;
     writeln ('                              Tempo Inicial: ',hour,':',min,':',sec);
     writeln;writeln;
     writeln ('                               Tempo Final: ',hourf,':',minf,':',secf);
     repeat
           writeln;
           writeln('                   Carregue no S(start) para iniciar a contagem');
           key := readkey;
     until key = 's';
clrscr;
writeln;writeln;writeln;writeln;writeln;
writeln('                               Contagem Iniciada');

{INICIO DO CRONOMETRO}

while (sec<secf) and (min<minf) and (hour<hourf) do
begin
      while sec<60 do
      begin
            writeln;
            delay(1000);
            sec := sec+1;
            clrscr;
            writeln;writeln;writeln;writeln;
            writeln ('                                   Tempo: ',hour,':',min,':',sec);
      end;
      if min < 59 then min:=min+1
      else begin min:=0; hour:=hour+1; end;
end;

{FIM DO CRONOMETRO}

writeln;
writeln('                               Contagem Terminada');
Writeln('                            Pressione ENTER para sair.');
end;

Bugs conhecidos:

- Assim que iniciamos a contagem, esta acaba logo.

- Se em vez de

"{INICIO DO CRONOMETRO}

while (sec<secf) and (min<minf) and (hour<hourf) do"

colocarmos

"{INICIO DO CRONOMETRO}

while (sec<secf) or (min<minf) or (hour<hourf) do"

a contagem já não termina assim que começa. Porém o cronometro não para no tempo final.

- Quando termina, supostamente quando carregassemos no enter deviamos sair do programa, mas simplesmente nao acontece nada (este bug nao existia no primeiro codigo).

CRONOMETRO INVERSO

procedure countdown;
begin
clrscr;
writeln;
writeln('                              CRONOMETRO INVERSO');
writeln;
writeln('                                Tempo Inicial: ');
writeln('                              Introduza as horas');
     readln(hour);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(min);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(sec);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;writeln;
     writeln ('                              Tempo Inicial: ',hour,':',min,':',sec);
     repeat
           writeln;
           writeln('                   Carregue no S(start) para iniciar a contagem');
           key := readkey;
     until key = 's';
clrscr;
writeln;writeln;writeln;writeln;writeln;
writeln('                               Contagem Iniciada');

{INICIO DO CRONOMETRO}

while (sec>0) or (min>0) or (hour>0) do
begin
      while sec>0 do
      begin
            writeln;
            delay(1000);
            sec := sec-1;
            clrscr;
            writeln;writeln;writeln;writeln;
            writeln ('                                   Tempo: ',hour,':',min,':',sec);
      end;
      if min > 0 then min:=min-1;
end;

{FIM DO CRONOMETRO}

writeln;
writeln('                               Contagem Terminada');
Writeln('                            Pressione ENTER para sair.');
end;

Bugs conhecidos:

- O cronometro não para nos 00:00:00 quando introduzimos minutos ou horas (ex. se iniciarmos o cronometro a partir dos 00:00:10 o cronometro para nos 00:00:00, mas se iniciarmos nos 00:01:10 o cronometro nao para nos 00:00:00). Este bug já ocorria no primeiro código mas apenas quando introduziamos as horas, agora acontece com horas e minutos.

- Falta introduzir a parte em que ele subtrai 1 às horas.

- Quando termina, supostamente quando carregassemos no enter deviamos sair do programa, mas simplesmente nao acontece nada (este bug nao existia no primeiro codigo).

CÓDIGO COMPLETO

Program Cronom;
Uses crt;
var hour, min, sec, hourf, minf, secf : integer;
    key : char;


procedure countup;
begin
sec:=0;
min:=0;
hour:=0;
secf:=0;
minf:=0;
hourf:=0;

clrscr;
writeln;
writeln('                                  CRONOMETRO');
writeln;
writeln('                                Tempo Inicial: ');
writeln('                              Introduza as horas');
     readln(hour);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(min);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(sec);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;
writeln('                                 Tempo Final: ');
writeln('                              Introduza as horas');
     readln(hourf);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(minf);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(secf);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;writeln;
     writeln ('                              Tempo Inicial: ',hour,':',min,':',sec);
     writeln;writeln;
     writeln ('                               Tempo Final: ',hourf,':',minf,':',secf);
     repeat
           writeln;
           writeln('                   Carregue no S(start) para iniciar a contagem');
           key := readkey;
     until key = 's';
clrscr;
writeln;writeln;writeln;writeln;writeln;
writeln('                               Contagem Iniciada');

{INICIO DO CRONOMETRO}

while (sec<>secf) or (min<>minf) or (hour<>hourf) do
begin
      while sec<60 do
      begin
            writeln;
            delay(1000);
            sec := sec+1;
            clrscr;
            writeln;writeln;writeln;writeln;
            writeln ('                                   Tempo: ',hour,':',min,':',sec);
      end;
      if min < 59 then min:=min+1
      else begin min:=0; hour:=hour+1; end;
end;

{FIM DO CRONOMETRO}

writeln;
writeln('                               Contagem Terminada');
Writeln('                            Pressione ENTER para sair.');
end;


procedure countdown;
begin
clrscr;
writeln;
writeln('                              CRONOMETRO INVERSO');
writeln;
writeln('                                Tempo Inicial: ');
writeln('                              Introduza as horas');
     readln(hour);
     repeat
           writeln;
           writeln('                         Introduza os minutos (0 a 59)');
           readln(min);
     until (min >= 0) and (min < 60);
     repeat
           writeln;
           writeln('                         Introduza os segundos (0 a 59)');
           readln(sec);
     until (sec >= 0) and (sec < 60);

     clrscr;
     writeln;writeln;
     writeln ('                              Tempo Inicial: ',hour,':',min,':',sec);
     repeat
           writeln;
           writeln('                   Carregue no S(start) para iniciar a contagem');
           key := readkey;
     until key = 's';
clrscr;
writeln;writeln;writeln;writeln;writeln;
writeln('                               Contagem Iniciada');

{INICIO DO CRONOMETRO}

while (sec>0) or (min>0) or (hour>0) do
begin
      while sec>0 do
      begin
            writeln;
            delay(1000);
            sec := sec-1;
            clrscr;
            writeln;writeln;writeln;writeln;
            writeln ('                                   Tempo: ',hour,':',min,':',sec);
      end;
      if min > 0 then min:=min-1;
end;

{FIM DO CRONOMETRO}

writeln;
writeln('                               Contagem Terminada');
Writeln('                            Pressione ENTER para sair.');
end;


procedure about;
begin
clrscr;
writeln('');
writeln('');
writeln('                         Nome: Cronom');
writeln('                         Versao: 1');
writeln('                         Criado por: Carlos Raposo');
writeln('                         Criado em: 2006');
writeln('                         Site: http://www.crspace.net');
writeln('                         Contacto: Buttpt@gmail.com');
writeln('                         Descricao: Programa que funciona');
writeln('                         como um cronometro normal e inverso.');
repeat
writeln;writeln;
     writeln('                         ******************************* ');
     writeln('                         *      Que deseja fazer?      * ');
     writeln('                         *                             * ');
     writeln('                         *    1 - Cronometro           * ');
     writeln('                         *    2 - Cronometro Inverso   * ');
     writeln('                         *    3 - About                * ');
     writeln('                         *    4 - Sair                 * ');
     writeln('                         ******************************* ');
     key := readkey;
until (key >= '1') or (key <= '4');
repeat
     Case key of
     '1' : countup;
     '2' : countdown;
     '3' : about;
     end;
until key = '4';
end;


Procedure menu;
begin
repeat
     writeln('Cronom v.1 por Carlos Raposo');
     writeln;writeln;writeln;writeln;writeln;
     writeln('                         ******************************* ');
     writeln('                         *      Que deseja fazer?      * ');
     writeln('                         *                             * ');
     writeln('                         *    1 - Cronometro           * ');
     writeln('                         *    2 - Cronometro Inverso   * ');
     writeln('                         *    3 - About                * ');
     writeln('                         *    4 - Sair                 * ');
     writeln('                         ******************************* ');
     key := readkey;
until (key >= '1') or (key <= '4');
repeat
     Case key of
     '1' : countup;
     '2' : countdown;
     '3' : about;
     end;
until key = '4';
end;


Begin
textbackground(Blue);
     textcolor(Yellow);
     clrscr;
menu;
end.

Peço desculpa se há alguns erros óbvios ou "estúpidos", mas como já disse estou agora a iniciar-me em programação.

Quanto ao algoritmo, foi das poucas maneiras que me ocorreram para fazê-lo...deve haver uma maneira mais simples.

Desde já agradeço a vossa ajuda.

Fiquem bem

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O problema é que estás a usar 2 whiles. Tens que verificar se o tempo já passou sempre que avances 1 segundo. Algo deste género (no que conta "para cima") :

{INICIO DO CRONOMETRO}

while (sec<>secf) or (min<>minf) or (hour<>hourf) do
begin
    writeln;
delay(1000);
sec := sec+1;
if sec = 60 then begin sec:=0; min := min+1; end;
if min = 60 then begin min:=0; hour:=hour+1; end;
clrscr;
writeln;writeln;writeln;writeln;
writeln ('                                   Tempo: ',hour,':',min,':',sec);
end;

{FIM DO CRONOMETRO}

o problema do enter é isto:

repeat
     writeln('Cronom v.1 por Carlos Raposo');
     writeln;writeln;writeln;writeln;writeln;
     writeln('                         ******************************* ');
     writeln('                         *      Que deseja fazer?      * ');
     writeln('                         *                             * ');
     writeln('                         *    1 - Cronometro           * ');
     writeln('                         *    2 - Cronometro Inverso   * ');
     writeln('                         *    3 - About                * ');
     writeln('                         *    4 - Sair                 * ');
     writeln('                         ******************************* ');
     key := readkey;
until (key >= '1') or (key <= '4');
repeat
     Case key of
     '1' : countup;
     '2' : countdown;
     '3' : about;
     end;
until key = '4';

se vires bem, o que estás a fazer é:

smiley11.gif 1. Escrever o menu

smiley11.gif 2. ler uma tecla

smiley11.gif 3. regressar a 1 se a tecla não estiver entre 1 e 4

smiley11.gif 4. verificar repetidamente se a tecla lida está entre 1 e 4.

Aquele 2º repeat é escusado, porque leste a tecla fora desse ciclo.

Por outro lado, leste de novo uma tecla para a variavel key, que ficou com 's' (quando inicia a contagem), ou seja, o ciclo repeat nao selecciona nenhuma das procedures porque key contem s, entao o programa fica ali preso para sempre. A solução é retirar o ciclo repeat, deixando só o case, e a mesma coisa na procedure about (que é código desnecessário). Devias fazer um readkey no final da about, remover o menu dessa procedure, e colocar um while true a envolver o código da procedure menu, com um break como opção 4... mas como já é tarde ::) vou só mostrar o código que alterei:

Procedure menu;
begin

while true do
begin
                clrscr;
	writeln('Cronom v.1 por Carlos Raposo');
	writeln;writeln;writeln;writeln;writeln;
	writeln('                         ******************************* ');
	writeln('                         *      Que deseja fazer?      * ');
	writeln('                         *                             * ');
	writeln('                         *    1 - Cronometro           * ');
	writeln('                         *    2 - Cronometro Inverso   * ');
	writeln('                         *    3 - About                * ');
	writeln('                         *    4 - Sair                 * ');
	writeln('                         ******************************* ');
	repeat		key := readkey;
	until (key >= '1') and (key <= '4');

	case key of
		'1' : countup;
		'2' : countdown;
		'3' : about;
		'4' : break;
	end;
end;

end;

Também alterei ali o until (key >= '1') and (key <= '4'); porque tinhas um or, e isso tornava a condição SEMPRE válida.

procedure about;
begin
clrscr;
writeln('');
writeln('');
writeln('                         Nome: Cronom');
writeln('                         Versao: 1');
writeln('                         Criado por: Carlos Raposo');
writeln('                         Criado em: 2006');
writeln('                         Site: http://www.crspace.net');
writeln('                         Contacto: Buttpt@gmail.com');
writeln('                         Descricao: Programa que funciona');
writeln('                         como um cronometro normal e inverso.');
readkey;
end;

...e um readkey por baixo das mensagens "Presisione Enter para sair" :) Penso que não fiz mais alteraações, por isso deve funcionar assm.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Primeiro que tudo muito obrigado por teres respondido :)

Funcionou tudo o que disseste mas só não percebi umas coisitas...

Podias me explicar o "while true do" e o "break"? Em que condições podemos usar o break (ja experimentei usar mas deu erro e disse que o break nao era permitido)? Não tinha conhecimento disso...

E também não percebi como fizeste para quando carregamos no enter voltarmos ao menu...é que dantes saía do programa.

Mais uma vez obrigado por teres respondido :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

o "while true do" é o chamado ciclo infinito. Ou seja, o programa repete o ciclo para sempre, a menos que encontre uma instrução break no código que está no seu interior; neste caso, quando pressionas a tecla 4 no menu, o programa vai para o case onde encontra um break, e sai do ciclo while.

É essa a função da instruçao break: quebrar um ciclo de repetição, seja ele for, while ou repeat. Assim sendo, a instrução break só pode ser utilizada dentro de um destes ciclos. Quando o programa encontra um break, salta para a instrução logo a seguir ao ciclo. Exemplo:

	while true do
	begin
		key := readkey;
		case key of
			'1' : opcao1;
			'2' : opcao2;
			'3' : opcao;
			'4' : break;
			else continue;
		end;
	end;
	uma_instrucao;

faz com que o programa fique à espera de uma tecla. Se a tecla for de 1 a 3, chama um procedimento correspondente; se a tecla for 4, quebra o ciclo while e vai executar a instrução uma_instrucao; se for outra tecla qualquer, volta ao inicio do ciclo while e fica à espera de uma nova tecla (é para isso que serve o continue, voltar ao inicio do ciclo numa nova iteração).

O meu Pascal está um bocado enferrujado, e não testei esse código, por isso não me cricifiquem se não funcionar ::)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ok agora ja percebi tudo e já consegui por a funcionar.

O teu pascal está optimo :)

Um muito obrigado pela ajuda. thx

Fica bem

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não li isto há bocado ::) Não sei se já entendeste, mas vou explicar na mesma, não se perde nada :)

E também não percebi como fizeste para quando carregamos no enter voltarmos ao menu...é que dantes saía do programa.

O programa volta sempre ao menu porque o procedimento menu contém um ciclo (o tal while infinito):

Procedure menu;
begin

while true do
begin
                clrscr;
	writeln('Cronom v.1 por Carlos Raposo');
	writeln;writeln;writeln;writeln;writeln;
	writeln('                         ******************************* ');
	writeln('                         *      Que deseja fazer?      * ');
	writeln('                         *                             * ');
	writeln('                         *    1 - Cronometro           * ');
	writeln('                         *    2 - Cronometro Inverso   * ');
	writeln('                         *    3 - About                * ');
	writeln('                         *    4 - Sair                 * ');
	writeln('                         ******************************* ');
	repeat		key := readkey;
	until (key >= '1') and (key <= '4');

	case key of
		'1' : countup;
		'2' : countdown;
		'3' : about;
		'4' : break;
	end;
end;

end;

O que é que acontece quando chamamos o menu?

smiley11.gif 1. Desenha o menu;

smiley11.gif 2. Fica à espera de uma tecla, até que essa tecla esteja entre 1 e 4;

smiley11.gif 3. Entra no case com a certeza que a tecla lida está entre 1 e 4 (caso contrário não tinha saído do repeat anterior);

smiley11.gif 4. conforme a tecla, entra no procedimento correcto;

smiley11.gif 5. quando retorna do procedimento, volta ao inicio do while infinito, desenha o menu, etc (a menos que tenha sido pressionada a tecla 4, que corresponde ao break, e nesse caso sai do while e do programa).

Mais alguma dúvida, é só perguntar que alguém há de responder :)

Ainda bem que pude ajudar :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ya eu calculei que voltassemos sempre ao menu porque era um ciclo infinito.

Mas obrigado na mesma...assim ficou mais esclarecido :)

Já agora deixo aqui o código do cronómetro inverso (código baseado no fornecido pelo TheDark) para o caso de haver alguem com a mesma dúvida:

{INICIO DO CRONOMETRO}

repeat
    writeln;
delay(1000);
sec := sec-1;
if sec = -1 then begin sec:=59; min := min-1; end;
if min = -1 then begin min:=59; hour:=hour-1; end;
clrscr;
writeln;writeln;writeln;writeln;
writeln ('                                   Tempo: ',hour,':',min,':',sec);
until (sec=0) and (min=0) and (hour=0);

{FIM DO CRONOMETRO}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

hello, I have translated this idea to BCB  :smoke:

you need, an TThread object in order to update a vcl component (regardless the state of other components), in this case the main form title.

public prototype of the thread object is:

__fastcall hebra_cronometro_inverso(bool CreateSuspended);

constructor:

__fastcall hebra_cronometro_inverso::hebra_cronometro_inverso(bool CreateSuspended)

        : TThread(CreateSuspended)

{

Priority        = tpHigher;

  FreeOnTerminate = true;

}

execute method:

while (!Terminated) {

      int  horas= frmMain->define_horas;

      int  minutos= frmMain->define_minutos;

      int    segundos= frmMain->define_segundos;

        AnsiString mititulo=  frmMain->Caption+"  ";

    while (horas >0 ||minutos >0|| segundos>0)

{

while(segundos>0){

//sleeps in thread avoid the freeze in main application

        Sleep(1000);

segundos=segundos-1;

frmMain->Caption=mititulo+IntToStr(horas)+":"+IntToStr(minutos)+":"+IntToStr(segundos);

}

if (minutos>0)

{

segundos=60;

minutos=minutos-1 ;

}  else if(horas>0){ minutos=60;horas=horas-1;}

}

}

you can now create a thread instance with the next code in any cpp file:

//create an object container in the stack

Objs = new hebra_cronometro_inverso*[0];

//initial state false refers to the createsuspend value that in false is run immediately the execute method

Objs[0] = new hebra_cronometro_inverso (false);

to pass the min, sec and hours values to the thread execute method you can transform the minutes value to the three values needed.

define_segundos=  timer_temporizador->Interval/1000;

if (define_segundos>60){

                  define_minutos=define_segundos/60;

                    define_segundos= define_segundos % 60;

                }

                  if(define_minutos>60){

                  define_horas=define_minutos/60;

                  define_minutos=define_minutos%60;

                  }

in order to delete the thread you can, of course:

  Objs[0]->Terminate();

  delete[] Objs;

regards

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora