Jump to content
snis

mikroC + 16f877a + LM35 + FAN por PWM

Recommended Posts

snis


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

?

Share this post


Link to post
Share on other sites
bsccara

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

Share this post


Link to post
Share on other sites
bsccara

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

Share this post


Link to post
Share on other sites
snis

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

Share this post


Link to post
Share on other sites
snis

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

Share this post


Link to post
Share on other sites
bsccara

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 ?

Share this post


Link to post
Share on other sites
snis

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

Share this post


Link to post
Share on other sites
bsccara

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.

Share this post


Link to post
Share on other sites
snis

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

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.