Ir para conteúdo


Revista PROGRAMAR - Edição 45 (Maio 2014): Download já disponível! Visita também o novo website da revista.

- - - - -

mikroC + 16f877a + LM35 + FAN por PWM


  • Por favor inicie sessão para responder
15 respostas a este tópico

#1 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 05 de Abril de 2012 - 17:21

Código (C):
// Lcd pinout settings
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

// Pin direction
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;

char *test = "Hello LCD";

unsigned int adc_rd;
unsigned long u;
unsigned char ch;

void main()
{
  ADCON1 = 0x009f;

 
trisa = 0XFF;      // portA input
trisd = 0;        // todas portas D output
trisb = 0;      // todas portas B output

Lcd_Init();
Lcd_Cmd(_Lcd_CLEAR);
Lcd_Cmd(_Lcd_CURSOR_OFF);
Lcd_Out(1, 1, "OLA");
Lcd_Out(2, 1, "Benvindo");
delay_ms(2000);


UART1_Init(9600);
UART1_Write_text("Ola\r");

while(1)
{

  adc_rd = adc_read(0);    // ler valor mv do lm35
  u = (long)adc_rd * 5000;  // converter mv
  u = u / 1023 - 40;            // 0..1023 -> 0-5000 mv
 
  ch = u/1000;              // tirar digitol em volt
                  // caracter ascii
 
  UART1_Write_text(48+u);
  UART1_Write_text("\r");
  Lcd_Out(2, 1, 48+u);
  delay_ms(500);
 


 

}
}
 


Imagem Colocada

estou com o problema que , apenas consigo ler caracteres , aumento a temp e muda de caracter..
alguma ajuda'
?

#2 bsccara

bsccara

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 482 mensagens

Publicado 05 de Abril de 2012 - 18:26

A linguagem C não converte directamente caracteres em strings. Uma string (em C) é um conjunto de caracteres com um zero no final.
Na tua chamada

Código (C):
UART1_Write_text(48+u);

estás a usar um 'unsigned long' (u+48) como sendo um ponteiro. O compilador deve-te dar um aviso por isso.
Tens de declarar um array de caracteres com tamanho suficiente. Se tens a garantia que 'u' só vai variar entre 0 e 5 (1 digito) podes fazer :

Código (C):
char valor[2];

valor[1] = 48 + u;
valor[2] = 0;
UART1_Write_text(valor);


#3 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 05 de Abril de 2012 - 19:13

mesmo que use apenas
Código :
UART1_Write_text(u);

deveria dar um valor lido em lm35 em RA0.

desta forma nem dá nada

sabes dizer me se adcon1 está bem configurado para ler do lm35?
datasheet: http://ww1.microchip.com/downloads/en/devicedoc/39582b.pdf

#4 bsccara

bsccara

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 482 mensagens

Publicado 05 de Abril de 2012 - 20:36

Ver Mensagemsnis, em 05 de Abril de 2012 - 19:13, disse:

mesmo que use apenas
Código :
UART1_Write_text(u);

deveria dar um valor lido em lm35 em RA0.

Não estás a perceber: se usas a função assim 'UART1_Write_text("Ola\r")' significa que a função estará declarada como 'UART1_Write_text(char *)', o que significa que está à espera dum ponteiro para uma string terminada a zero como argumento.
Quando lhe passas 'u' ou 'u + 48' estás a forçar o compilador a fazer uma conversão dum 'unsigned long' para um 'char *', ou seja a usar o valor da expressão como um ponteiro (endereço) para a string. Isso não funciona, pois o ponteiro passado assim provavelmente aponta para o início da memória do PIC.

Ver Mensagemsnis, em 05 de Abril de 2012 - 19:13, disse:

sabes dizer me se adcon1 está bem configurado para ler do lm35?
Não me parece: 0x9F no ADCON1 significa:

Bit 7 = 1 (ADFM Right justified)
            0 (ADCS2 off)
            0 (Não implementado)
            1 (Não implementado, bit inválido)
            1 | (Entrada analógica no AN0, todas outras AN como digitais,
            1 |  Vref+ no AN3 e Vref- no AN2)
            1 |
Bit 0 = 1 |

Como não tens nada ligado ao AN3 e AN2 não vais ter tensão de referência para o ADC. Para além disso não estás a inicializar o ADCON0, que fica com os valores de power-on, o que desliga o ADC. Acho que devias inicializar os dois assim:

Código (C):
ADCON0 = 0x81;
ADCON1 = 0xCE;
para um clock do ADC de Fosc / 64. Isso partindo do principio que o preprocessador transforma isto em instruções para configurar os registos (0x9F é o endereço do ADCON1 no PIC).

Para além disso o LM35 dá-te cerca de 250mV para uma temperatura de 25C, ou seja com os teus cálculos nunca vais passar de zero. Vê :

Escala máxima do ADC = Vcc=5V
ADC(5V) = 1023
ADC(250mv) = 51
(51 * 5000 / 1023 - 40) / 1000 = 0.21
ch = 0

A divisão por mil está a mais e o código para mostrar no LCD e enviar pela UART tem de lidar com números de mais dígitos. Também não percebo o -40.
No site existe um Zip com exemplos, incluindo com o LM35: http://www.mikroe.com/eng/downloads/get/1708/easypic_v7_examples_v100.zip

#5 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 05 de Abril de 2012 - 23:03

Antes de mais, um muito obrigado.
Neste momento nao posso testar. Assim que puder dou noticias

xxxxxxxxxxxxx   EDIT   xxxxxxxxxxxxxxxxxxxx

com a tua ajuda e dos exemplos que me deste, consegui chegar a qualquer coisa.



Código (C):
// Lcd pinout settings
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

// Pin direction
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;

char *test = "Hello LCD";

const unsigned short VREF = 5;

unsigned int adc_rd = 0;
float temp;
char txt[15];

void main()
{


  ADCON0 = 0x81;
  ADCON1 = 0xCE;
 
trisa = 0XFF;      // portA input
trisd = 0;        // todas portas D output
trisb = 0;      // todas portas B output

adc_init();

Lcd_Init();
Lcd_Cmd(_Lcd_CLEAR);
Lcd_Cmd(_Lcd_CURSOR_OFF);
Lcd_Out(1, 1, "Temperatura");
Lcd_Chr(2, 8, 223);
Lcd_Chr(2,9,'C');
delay_ms(2000);


UART1_Init(9600);
UART1_Write_text("Temperatura:\r");

adc_rd = 0;
while(1)
{

  adc_rd = ADC_Get_Sample(0);
  temp = (adc_rd * VREF)/10.240;
 
  floatToStr(temp, txt);
  txt[4] =0;

  UART1_Write_text(txt);
  UART1_Write_text("\r");
  Lcd_Out(2, 3, txt);
  delay_ms(500);
 
 

}
}
 


Imagem Colocada

#6 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 13 de Abril de 2012 - 11:33

boas,
estou com problemas em por uma fan funcionar conforme o valor de temperatura

Código (C):
// Lcd pinout definições
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

// Direcção Pin
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;

//char *test = "Hello LCD";

//Declaração de variaveis globais
const unsigned short VREF = 5;
unsigned int adc_rd = 0;
float temp;
char txt[15];
int i=0;

void main()
{
  //Declaração de variaveis
  adc_rd = 0;

  //Declaração de info das portas
  ADCON0 = 0x81;
  ADCON1 = 0xCE;
 
T2CON = 0x04;
  CCP1CON = 0x0F;
  PR2=0xFF;
 
  trisa = 0XFF;      // portA input
  trisc = 0;
  trisd = 0;        // todas portas D output
  trisb = 0;      // todas portas B output

  PORTC = 0;

  PWM1_Init(5000);
  pwm1_start();
  PWM1_Set_Duty(200); exemplo com 200




  //Iniciar adc
  adc_init();
 
  //Iniciar Lcd
  Lcd_Init();
 
  //Iniciar Uart1
  UART1_Init(9600);


   

  Lcd_Cmd(_Lcd_CLEAR);
  Lcd_Cmd(_Lcd_CURSOR_OFF);
  Lcd_Out(1, 1, "Aguarde");
  Lcd_Out(2, 2, "Teste aos Led's");
  UART1_Write_text("Aguarde:\r");
  UART1_Write_text("Teste aos Led's\r");
  delay_ms(1000);

//Testar se Led estão bons
do
{
  portd.f0=1;      //verde
  portd.f1=1;      //amarelo
  portd.f2=1;      //2x vermelho

  delay_ms(1000);

  portd.f0=0;
  portd.f1=0;
  portd.f2=0;

  delay_ms(1000);
  i++;
}while(i!=3);

Lcd_Cmd(_Lcd_CLEAR);
Lcd_Out(1, 1, "Aguarde");
Lcd_Out(2, 2, "Led's Bons");
UART1_Write_text("Led's em bom estado\r");  //mensagem não certa
delay_ms(2000);
Lcd_Cmd(_Lcd_CLEAR);

//Leitura do LM35
while(1)
{

  adc_rd = ADC_Get_Sample(0);
  temp = (adc_rd * VREF)/10.240;
 
  floatToStr(temp, txt);
  txt[4] =0;

  UART1_Write_text(txt);
  UART1_Write_text("\r");
 
  Lcd_Out(1, 1, "Temperatura:");
  Lcd_Chr(2, 8, 223);
  Lcd_Chr(2,9,'C');
  Lcd_Out(2, 3, txt);
 
  delay_ms(500);
 
  //indicação dos led's perante temp
  if (temp <30)
  {
      portd.f0=1;
      portd.f1=0;
  }
  if (temp >30)
  {
      portd.f0=1;
      portd.f1=1;
      portd.f2=0;
  }
  if (temp >90)
  {
      portd.f0=1;
      portd.f1=1;
      portd.f2=1;
  }
}
}
 


Imagem Colocada

#7 bsccara

bsccara

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 482 mensagens

Publicado 13 de Abril de 2012 - 15:59

Um concelho: evita cálculos em virgula flutuante em microcontroladores. Forças a inclusão de grande quantidade de código para suportar isso, o que não é aconselhável com as pequenas quantidades de memória nesses ICs. O teu cálculo deve ser refeito de:

Código (C):
temp = (adc_rd * VREF)/10.240;

para:

Código (C):
temp = ((unsigned long)adc_rd * VREF * 100)/1024;

ou

temp = ((unsigned long)adc_rd * VREF * 100) >> 10;

Obviamente a variável 'temp' deve passar a ser 'unsigned int'. Em vez da função 'FloatToStr' usa uma para converter inteiros em strings, que será muito mais pequena, também.

Quanto ao teu problema, terás de usar a função 'PWM1_Set_Duty' dentro do ciclo de leitura do LM35. Qual é o teu problema exactamente ?

#8 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 16 de Abril de 2012 - 14:24

Código (C):
// Lcd pinout definições
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

// Direcção Pin
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;

//char *test = "Hello LCD";

//Declaração de variaveis globais
//unsigned short current_duty;
const unsigned short VREF = 5;
unsigned int temp, adc_rd = 0;
//float temp;
char txt[15];
int i=0;

void main()
{
  //Declaração de variaveis
  //current_duty  = 16;
  adc_rd = 0;

  //Declaração de info das portas
  ADCON0 = 0x81;
  ADCON1 = 0xCE;


 
  trisa = 0XFF;      // portA input
  trisc = 0;
  trisd = 0;        // todas portas D output
  trisb = 0;      // todas portas B output
  PORTC = 0;

  T2CON = 0x04;
  CCP1CON = 0x0F;
  PR2=0xFF;
 
  PWM1_Init(5000);
 
  //Iniciar adc
  adc_init();
 
  //Iniciar Lcd
  Lcd_Init();
 
  //Iniciar Uart1
  UART1_Init(9600);

  Lcd_Cmd(_Lcd_CLEAR);
  Lcd_Cmd(_Lcd_CURSOR_OFF);
  Lcd_Out(1, 1, "Aguarde");
  Lcd_Out(2, 2, "Teste aos Led's");
  UART1_Write_text("Aguarde:\r");
  UART1_Write_text("Teste aos Led's\r");
  delay_ms(1000);


Lcd_Cmd(_Lcd_CLEAR);
Lcd_Out(1, 1, "Aguarde");
Lcd_Out(2, 2, "Led's Bons");
UART1_Write_text("Led's em bom estado\r");
delay_ms(2000);
Lcd_Cmd(_Lcd_CLEAR);

      pwm1_start();

//Leitura do LM35
while(1)
{
  adc_rd = ADC_Get_Sample(0);
  //temp = (adc_rd * VREF)/10.240;
  //temp = ((unsigned long)adc_rd * VREF * 100)/1024;
  temp = ((unsigned long)adc_rd * VREF * 100) >> 10;
 
  floatToStr(temp, txt);    //com intToStr não funciona
  txt[4] =0;

  UART1_Write_text(txt);
  UART1_Write_text("\r");
 
  Lcd_Out(1, 1, "Temp || Potencia");
  Lcd_Chr(2, 5, 223);
  Lcd_Chr(2,6,'C');
  Lcd_Out(2, 1, txt);
 
  delay_ms(500);

  PWM1_set_Duty(temp);

 
}
}

já estou usar PWM1_Set_duty , mas nao tenho qualquer sinal. mesmo com um osc na saida ccp1 não tenho nada

#9 bsccara

bsccara

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 482 mensagens

Publicado 16 de Abril de 2012 - 16:20

Vários pontos:

Ver Mensagemsnis, em 16 de Abril de 2012 - 14:24, disse:

Código :
temp = ((unsigned long)adc_rd * VREF * 100) >> 10;

O ADC do 877 é de 10 bits pelo que o resultado da função adc_rd irá variar entre 0 e 1023. Assim a variável 'temp' irá variar entre 0 e 499.512. A função 'PWM1_set_Duty' recebe um byte, que pode variar entre 0 e 255. Portanto se o valor de 'temp' exceder 255 vai provocar um 'wraparound' e subtrair 256 (256 será passado como 0). A escala do cálculo tem de ser reduzida.
   

Ver Mensagemsnis, em 16 de Abril de 2012 - 14:24, disse:

Código :
floatToStr(temp, txt);     //com intToStr não funciona

Se não funciona (não vejo porque) é preferível escrever uma rotina para converter a 'temp' numa string, pois a utilização de funções de virgula flutuante implicam o potencial acréscimo de vários KB de código na flash, que é limitada a 14KB.

Ver Mensagemsnis, em 16 de Abril de 2012 - 14:24, disse:

Código :
PWM1_set_Duty(temp);

Dependendo da aplicação, o controlo contínuo do 'duty cycle' pode não ser a melhor solução. É preciso estabelecer a relação temperatura / duty cycle do  PWM.

Tenta escrever um código mínimo, só para iniciar o PWM e depois vai juntando o resto aos poucos.

#10 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 17 de Abril de 2012 - 11:46

Código (C):
// Lcd pinout definições
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

// Direcção Pin
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;

unsigned int temp;

void main()
{
    trisc=0;
    portc=0;

    T2CON = 0x04;
    CCP1CON = 0x0F;
    PR2=0xFF;
   
    //Iniciar PWM
    PWM1_Init(5000);
    //Iniciar Lcd
    Lcd_Init();
   
    //PWM Start
    pwm1_start();
   
    while(1)
    {
      temp=254;
      PWM1_set_Duty(temp);

    }
}

tenho so um proj. novo com o 16f877a e a saida do ccp1.
como o codigo esta nao da sinal.

se trocar para portc.f2=1 a fan roda, logo o esquena deve estar bem feito.

#11 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 17 de Abril de 2012 - 17:15

https://docs.google.com/open?id=0BwoM1EQQ2ZAzRlZzb0N0Qm04X00

#12 albertoice

albertoice

    null

  • Novo Membro
  • Pip
  • 1 mensagens

Publicado 16 de Agosto de 2012 - 01:55

gostei amigo ta de paraben era o que eu procurava

#13 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 16 de Agosto de 2012 - 11:54

tenho aqui o projecto concluido se precisares de ajuda
abraço

#14 Guerra Lacerda

Guerra Lacerda

    null

  • Novo Membro
  • Pip
  • 2 mensagens

Publicado 20 de Fevereiro de 2014 - 01:41

Amigo poderia disponibilizar este projeto?

#15 snis

snis

    void

  • Membro
  • PipPip
  • 31 mensagens

Publicado 20 de Fevereiro de 2014 - 19:14

olas
tenho q ver onde tenho isso. sinceramente nao sei onde o guardei :(

#16 Guerra Lacerda

Guerra Lacerda

    null

  • Novo Membro
  • Pip
  • 2 mensagens

Publicado 23 de Fevereiro de 2014 - 22:26

ok, caso encontre ficarei muito agradecido.