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

snis

mikroC + 16f877a + LM35 + FAN por PWM

16 posts in this topic


// 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);





}
}

proteus.jpg

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

alguma ajuda'

?

0

Share this post


Link to post
Share on other sites

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

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 :

char valor[2];

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

0

Share this post


Link to post
Share on other sites

mesmo que use apenas

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.

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:

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

0

Share this post


Link to post
Share on other sites

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.


// 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);



}
}

lm35.jpg

0

Share this post


Link to post
Share on other sites

boas,

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


// 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;
 }
}
}

img.jpg

0

Share this post


Link to post
Share on other sites

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:

temp = (adc_rd * VREF)/10.240;

para:

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 ?

0

Share this post


Link to post
Share on other sites

// 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

0

Share this post


Link to post
Share on other sites

Vários pontos:

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.

 

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.

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.

0

Share this post


Link to post
Share on other sites

// 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.

0

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