Ir ao conteúdo

Numeros randomicos mikroC


CIS

Posts recomendados

Postado

Pessoal, preciso fazer um programa para o PIC 16F628A, no compilador mikroC, que gere um numero aleatório de 1 a 16 para cada vez que um botão for pressionado. To pensando assim: para cada vez que o botão for pressionado, seto um flag e chamo a função randômica, salvo o numero aleatório numa variável e depois vou para o comando switch case testar a variavel. Para cada valor de 1 a 16 pretendo escrever duas frases num display 16x2. Minha duvida esta em como usar essa função randomica no compilador mikroC. Alguem pode me ajudar.

Obrigado desde já.

Postado

Ola CIS.

O mikroc possui uma biblioteca de C ANSI, vendo por este lado e possível usar o comando rand(). Tem umas desvantagens, e se não me engano só gera valores de 0 a 32767

http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/ansi_stdlib_library.htm#rand

O que você poderia fazer e usar uma regra de 3 para transformar o valor obtido pelo rand() em um valor proporcional de 1 a 16, posso te ajudar, mas e que agora estou na faculdade, então te ajudo com o algoritmo mais tarde, OK? Mas já fica a dica......... XD

Se tiver alguma duvida, basta perguntar.

Espero ter ajudado, grato Luiz Gustavo.

Postado

Mais ou menos eu entendi, so não consegui fazer... meu codigo esta assim.


sbit LCD_RS at RA0_bit;
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at Rb4_bit;
sbit LCD_D5 at Rb5_bit;
sbit LCD_D6 at Rb6_bit;
sbit LCD_D7 at Rb7_bit;

sbit LCD_RS_Direction at TRISA0_bit;
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISb4_bit;
sbit LCD_D5_Direction at TRISb5_bit;
sbit LCD_D6_Direction at TRISb6_bit;
sbit LCD_D7_Direction at TRISb7_bit;
// End LCD module connections

long a;
unsigned char flag = 0;


void main() {

CMCON = 7;
TRISB = 0B00000011;
PORTB = 0B00000000;

Lcd_Init(); // Inicialização do LCD
Lcd_Cmd(_LCD_CLEAR); // limpando o display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off desligado
while(1){

if(portb.f0) flag = 1;


//rand ()% ((( maior número - não mais baixo) + 1 ) + n º menor)
// ( 16 - 1 ) + 1 ) + 1
if(!portb.f0 && flag ){
a = rand();
a = (16*a)/32767;
flag = 0;
}

switch(a){
case 1:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao direita ");
Lcd_OUT(2,1," Azul ");
break;

case 2:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao direita ");
Lcd_OUT(2,1," Verde ");
break;

case 3:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao direita ");
Lcd_OUT(2,1," Amarelo ");
break;

case 4:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao direita ");
Lcd_OUT(2,1," Vermelho ");
break;

case 5:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao Esquerda ");
Lcd_OUT(2,1," Azul ");
break;

case 6:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao Esquerda ");
Lcd_OUT(2,1," Verde ");
break;

case 7:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao Esquerda ");
Lcd_OUT(2,1," Amarelo ");
break;

case 8:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Mao Esquerda ");
Lcd_OUT(2,1," Vermelho ");
break;

case 9:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Direito ");
Lcd_OUT(2,1," Azul ");
break;

case 10:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Direito ");
Lcd_OUT(2,1," Verde ");
break;

case 11:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Direito ");
Lcd_OUT(2,1," Amarelo ");
break;

case 12:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Direito ");
Lcd_OUT(2,1," Vermelho ");
break;

case 13:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Esquerdo ");
Lcd_OUT(2,1," Azul ");
break;

case 14:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Esquerdo ");
Lcd_OUT(2,1," Verde ");
break;

case 15:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1," Pe Esquerdo ");
Lcd_OUT(2,1," Amarelo ");
break;

case 16:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_OUT(1,1,"Pe Esquerdo ");
Lcd_OUT(2,1," Vermelho ");
break;

default:
break;

}



}

}

não esta nem compilando, mas da pra ter uma ideia do que eu quero.

Toda ajuda é bem vinda. Obrigado a todos.

Postado

Ola Cis.

Sua lógica não esta errada, eu copiei o programa e compilei aqui, então vi que estes erros, são problemas relacionados a "como a memoria RAM" esta sendo utilizada. Na verdade o que eu acontece é que você esta trabalhando com bibliotecas do MikroC, e não sabemos como essas bibliotecas foram feita, no seu caso a operação rand() esta "tentando" usar uma parte da memoria que estava sendo utilizada para suas mensagens do LCD (ou algo parecido.... XD) e no final de tanto escrever a mesma mensagem a memoria RAM ficou cheia. Esse erro é bem comum, pois este esquema que a biblioteca LCD usa para gerar as mensagem consome muita memoria RAM, a solução seria criar variáveis e salvar seus texto (que são sempre os mesmos) dentro delas, assim suas mensagem ficariam na parte da memoria RAM que o compilador separa para as variáveis e não interfere em outras bibliotecas, outra coisa, note que o comando switch ficou fora do laço IF que você usa para detectar o botão, isso fara com que o microcontrolador faça o teste TODA vez que executar o programa isso iria deixar seu programa extremamente lento. Então neste caso seu programa só precisar ser otimizado, cheguei da faculdade e estava sem nada para fazer, então eu fiz para você, espero que você leia linha por linha e perceba as modificações que fiz, pois minha intenção é lhe ensinar a como dominar o compilador e não fazer o seu trabalho, OK?


sbit LCD_RS at RA0_bit;
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at Rb4_bit;
sbit LCD_D5 at Rb5_bit;
sbit LCD_D6 at Rb6_bit;
sbit LCD_D7 at Rb7_bit;

sbit LCD_RS_Direction at TRISA0_bit;
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISb4_bit;
sbit LCD_D5_Direction at TRISb5_bit;
sbit LCD_D6_Direction at TRISb6_bit;
sbit LCD_D7_Direction at TRISb7_bit;
// End LCD module connections

int a;
unsigned char flag = 0;
char text1[]="Mão Direita";
char text2[]="Mão Esquerda";
char text3[]="Pé Direito";
char text4[]="Pé Esquerdo";
char text5[]="Azul";
char text6[]="Verde";
char text7[]="Amarelo";
char text8[]="Vermelho";

void escreve_lcd()
{switch(a)
{
case 1:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text1);
Lcd_OUT(2,1,text5);
break;

case 2:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text1);
Lcd_OUT(2,1,text6);
break;

case 3:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text1);
Lcd_OUT(2,1,text7);
break;

case 4:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text1);
Lcd_OUT(2,1,text8);
break;

case 5:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text2);
Lcd_OUT(2,1,text5);
break;

case 6:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text2);
Lcd_OUT(2,1,text6);
break;

case 7:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text2);
Lcd_OUT(2,1,text7);
break;

case 8:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text2);
Lcd_OUT(2,1,text8);
break;

case 9:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text3);
Lcd_OUT(2,1,text5);
break;

case 10:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text3);
Lcd_OUT(2,1,text6);
break;

case 11:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text3);
Lcd_OUT(2,1,text7);
break;

case 12:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text3);
Lcd_OUT(2,1,text8);
break;

case 13:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text4);
Lcd_OUT(2,1,text5);
break;

case 14:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text4);
Lcd_OUT(2,1,text6);
break;

case 15:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text4);
Lcd_OUT(2,1,text7);
break;

case 16:
Lcd_Cmd(_LCD_CLEAR);
Lcd_OUT(1,1,text4);
Lcd_OUT(2,1,text8);
break;

default:
break;

}
}

void main() {

CMCON = 7;
TRISB = 0B00000011;
PORTB = 0B00000000;

Lcd_Init(); // Inicialização do LCD
Lcd_Cmd(_LCD_CLEAR); // limpando o display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off desligado
while(1){

if(button(&portb,0,200,1))// verdadeiro= portb.f0=1 durante 200ms
{
a = rand();
a = (16*a)/32767;
escreve_lcd();
}

}

}

Não seis este programa vai funcionar como você quer, este compilou perfeitamente mas eu não simulei.... XD, mas acho que dá para entender a mensagem que quero passar.

No programa acima, salvei seus texto dentro de variáveis (também matrizes) CHAR, utilizei a biblioteca Button (que é MUITO EFICIENTE) para detectar quando o botão é pressionado, passei toda a parte de escrita do LCD para uma função, assim só sera executado quando o botão for pressionado, assim o microcontrolador dedicara toda sua atenção a analisar o botão, também repare que retirei os comando Lcd_Cmd(_LCD_CURSOR_OFF); pois uma vez que ele é executado o cursor é desabilitado completamente e não é necessário utiliza-lo de novo (aquilo esta só ocupando mais espaço). O programa final ficou com 1252 bytes de memoria de programa utilizada e 98 bytes de RAM (menos de 50%), enquanto seus antigo programa nem compilava por conta de exceder o limite de Memoria RAM do PIC..... hehe... É bom sempre tomar estes cuidados, pois estamos trabalhando com pequenos microcontroladores que tem recursos limitados, e o segredo de como aproveitar o máximo deles esta intimamente relacionado a capacidade de escrever um código eficiente, e isto você só adquire com o tempo.

Espero que tenha te ajudado, e não se esqueça de perguntar caso tenha alguma duvida.

Grato Luiz Gustavo.

Postado

Luiz Gustavo, muito obrigado pela aula. Tenha certeza que seguirei seus conselhos em ler linha a linha o código e estudar sobre essas condições de memoria dos microcontroladores. Vou fazer os testes em hardware e volto com os resultados.

Agora uma curiosidade: Faz faculdade de que ?

Muito obrigado pela ajuda.

Eu entendi as mudanças, fiz a leitura linha a linha, conferir com o hardware, esta tudo certo, mas não funcionou. Acho que é devido a logica da regra de três... não tem outra forma talvez?? Estou a entender o seguinte, supondo que a função rand() retorne o valor 25, então terei (16*25) / 32767 = 0.0122074 . Essa função funciona assim mesmo??

Fiz alterações no código do botão. Estou usando o kit de desenvolvimento ACEPIC18, e os botões estão conectados em RA2, RA3 e RA4.

Consegui escrever e tudo, mas agora me deparo com outro problema. O programa sempre inicia com a mesma escrita no lcd. Lendo um pouco vi que tenho que usar uma "semente" com a função srand(). Acho que da para implementar essa "semente" com a contagem de uma timer, mas como fazer... ou se tiver outra forma de fazer isso... Espero alguma ajuda.

Postado

Ola CIS.

Eu faço faculdade de Engenharia Elétrica com Enfase em Computação.

A logica da regra de trés esta correta, pense da seguinte maneira, você esta transformando um numero de 0 a 32767 em um numero de 1 a 16:

32767/15=2178,4 Como estamos trabalhando com valores inteiros (variável INT), desprezamos o que vem depois da virgula (no exemplo que você citou o 25 seria equivalente a zero), assim a cada 2178 números a mais contamos mais uma unidade, dessa forma 2178=1... 4356=2... e assim por diante (se quiser pode fazer os cálculos para comprovar a veracidade da regra.... hehe)

De fato esta é uma das desvantagens do RAND() no mikroC, os números aleatórios, são sempre os mesmos (meio contraditório isso, mas é verdade), o comando srand() usa um numero para dar inicio a uma nova sequencia de números aleatórios. A ideia que você deu é ótima, utilizar o contador para gerar um valor aleatório, neste caso é possível descartar totalmente o rand(), bastaria utilizar direto o valor retornado pelo contador. Neste caso a regra de 3 ainda é valida, mas seria necessário alterar os valore para 255 (caso o contador seja de 8 bits, tipo timer0) e se o contador for de 16 bits (timer 1) altere o valor máximo para 65536.

Inclusive esta técnica é muito utilizada para fazer tacômetros, medidores de distancia para carros e bicicletas, medidores de velocidade e até voltímetros... tudo com o contador do PIC.

Para isto basta configurar o contador do PIC para clock interno, ajuste o prescaler de maneira que a frequência de contagem fique confortável, pode ser mais lento para contadores de 8 bits e mais rápido para contador de 16 bits (pois neste caso o contador precisa percorrer uma faixa maior para variar cada unidade), deixe o contador contando e o configure para que a cada estouro de contagem ele recomece do zero, e quando o botão for pressionado, pare o contador leia o valor retornado por ele, aplique a regra de 3 e chame a rotina de escrita no LCD, seu programa esta praticamente pronto, basta apenas configurar o contador..... hehe.

Não conheço muito bem o PIC 16f628a então a parte de configuração do contador vai ficar para você, então divirta-se com o datasheet do PIC...... XD

Espero ter ajudado.

Grato Luiz Gustavo.

Postado

Muito obrigado Luiz Gustavo. Muito boa sua explicação.

E VTRX, outro grande mestre, eu consegui fazendo dessa forma mesmo. Parei com a ideia do "srand" . Assim que retomar o projeto vou tentar usando a contagem do timer0, e depois do timer1. Ao que me parece, para eu ter um numero aleatório eu não preciso exatamente da função rand(), da pra fazer com um algoritmo mais simples.

Para o que eu queria, ele ate ja está funcionando, mas faço questão de aprofundar mais nesse assunto, aprender outras técnicas e ver o que um microcontrolador pode me oferecer.

Obrigado a todos pela ajuda.

  • Coordenador
Postado

Caso o autor necessite, o mesmo será reaberto, para isso deverá entrar em contato com a moderação solicitando o desbloqueio.

Arquivado

Este tópico foi arquivado e está fechado para 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...