Sari la conținut
ELFORUM - Forumul electronistilor

Afisare float pe lcd pic16f877 hi tech-c


Vizitator fod

Postări Recomandate

Salut,

Vreau sa fac o placa de achizitie de date si nu stiu cum pot afisa pe un LCD un float(de ex o temperatura cu o zecimala dupa virgula)? Ma poate ajuta cineva cu o portiune de cod functionala?

Folosesc pic16f877, MPLAB cu HI TECH-C si libraria pentru LCD este urmatoarea :

 

 

#define _LCD_C

 

#include

#include

#include

#include

#include "lcd.h"

//#include "HardwareProfile.h"

 

// Delays (in uS) (big delay is *2)

#define SMALL_DELAY 40

 

// write a nybble to the port

void lcdWriteNybble(unsigned char nybble)

{

// This routine is required because the LCD data bus

// is not connected on a continuous sequence of port pins

// so we have to break it up and write to the pins

// individually.

 

// Write the nybble to the LCD databus pins

if (nybble & 0b00000001) LCD_DB4 = 1; else LCD_DB4 = 0;

if (nybble & 0b00000010) LCD_DB5 = 1; else LCD_DB5 = 0;

if (nybble & 0b00000100) LCD_DB6 = 1; else LCD_DB6 = 0;

if (nybble & 0b00001000) LCD_DB7 = 1; else LCD_DB7 = 0;

}

 

// write a byte to the LCD in 4 bit mode

void lcdWrite(unsigned char address, unsigned char c)

{

LCD_RS = address;

__delay_us(SMALL_DELAY);

 

// Write the 4 bits non-distructively to the port

lcdWriteNybble((c >> 4) & 0x0F);

 

// Toggle the clock bit

LCD_EN = 1;

__delay_us(SMALL_DELAY);

LCD_EN = 0;

__delay_us(SMALL_DELAY);

 

// Write the 4 bits non-distructively to the port

lcdWriteNybble(c & 0x0F);

 

// Toggle the clock bit

LCD_EN = 1;

__delay_us(SMALL_DELAY);

LCD_EN = 0;

__delay_us(SMALL_DELAY);

}

 

// write one character to the LCD

void lcdPutch(char c)

{

// This routine needs updating so it monitors the cursor posiiton

LCD_RS = 1; // write characters

lcdWrite(DATA_REG, c);

}

 

void lcdClearDisplay(void)

{

lcdWrite(CMD_REG, LCD_CLR);

 

// Reset our internal cursor position

lcdX = 0;

lcdY = 0;

 

// Delay

for (int counter = 0; counter < 200; counter++) __delay_us(100);

}

 

// Initialise the LCD

void lcdInit(void)

{

int counter;

 

// Power up delay

for (counter = 0; counter < 1500; counter++) __delay_us(100);

 

LCD_EN = 0; // Set clock low

LCD_RS = CMD_REG; // Set RS to command register

 

// Set up the interface

lcdWriteNybble(LCD_WAKE);

 

LCD_EN = 1;

LCD_EN = 0;

for (counter = 0; counter < 500; counter++) __delay_us(100);

LCD_EN = 1;

LCD_EN = 0;

__delay_us(200);

LCD_EN = 1;

LCD_EN = 0;

__delay_us(200);

 

// Set the interfact to 4 bits

lcdWriteNybble(LCD_4BIT);

__delay_us(SMALL_DELAY);

LCD_EN = 1;

__delay_us(SMALL_DELAY);

LCD_EN = 0;

 

// Don't know what this does...

lcdWrite(CMD_REG, 0x28);

 

// Enable display / hide cursor

lcdWrite(CMD_REG, LCD_ENDISP);

 

// Clear the display and home the cursor

lcdClearDisplay();

 

// Set the cursor movement direction to right

lcdWrite(CMD_REG, LCD_CURRIGHT);

 

// Turn on display

lcdWrite(CMD_REG, LCD_DISPON);

 

// Reset our internal cursor position

lcdX = 0;

lcdY = 0;

}

 

void lcdDisplayState(int state)

{

if (state == 1) lcdWrite(CMD_REG, LCD_DISPON);

else lcdWrite(CMD_REG, LCD_DISPOFF);

}

 

// Move the cursor to the specified X,Y

void lcdGoto(int x, int y)

{

int offset;

 

// Select the correct line of the display

switch (y)

{

case 0: offset = 0x00;

break;

case 1: offset = 0x40;

break;

case 2: offset = 0x14;

break;

case 3: offset = 0x54;

break;

}

 

// Select the correct character of the line

offset += x;

 

// Send the command to the LCD

lcdWrite(CMD_REG, LCD_DDSET | offset);

 

// Reset our internal cursor position

lcdX = x;

lcdY = y;

}

 

// Output a string of characters to the display

void lcdPuts(const char *string)

{

// Since the 4 line display is in the order line 1, line 3, line 2, line 4

// we need to read the current cursor position and control how the text is

// output, adjusting the cursor position as we go

int loop;

 

for (loop = 0; loop < strlen(string); loop++)

{

// Write the character to the LCD

lcdWrite(DATA_REG, string[loop]);

lcdX++;

 

// Have we reached the end of the line?

if (lcdX == 20)

{

// Move to the start of the next line

lcdX = 0;

lcdY++;

 

// If we are off the bottom of the screen

// go back to the top line

if (lcdY == 4) lcdY = 0;

 

// Adjust the cursor position on the LCD

lcdGoto(lcdX, lcdY);

}

}

 

 

Multumesc!

Link spre comentariu
  • Răspunsuri 13
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • Liviu M

    4

  • nooob64

    2

  • MatyC

    1

Top autori în acest subiect

Imagini postate

Salut , cel mai simplu mod de a afisa un float este cu sprintf insa costul memoriei este mare (unele compilatoare ajung si la 4KB pt primul apel al functiei sprintf) ex : sprintf(lcd_buffer,"numar float = %.2f",nr_float);

Eu asi alege metoda cu sprintf pentru controlere cu multa memorie (mai mare de 16KB flash).

Pentru pic16f877 incearca varianta in care "spargi" numarul int si afisezi virgula cind trebuie.

unsigned char ch;unsigned int adc_rd;char *text;long tlong;void main() {.............  LCD_Cmd(LCD_CURSOR_OFF);                 // send command to LCD (cursor off)  LCD_Cmd(LCD_CLEAR);                      // send command  to LCD (clear LCD)  text = "LCD example";                    // assign text to string  LCD_Out(2,1,text);                       // print string a on LCD, 2nd row, 1st column  ADCON1     = 0x82;                       // configure VDD as Vref, and analog channels  TRISA      = 0xFF;                       // designate PORTA as input  Delay_ms(2000);  text  = "voltage:";                      // assign text to string  while (1) {    adc_rd  = ADC_read(2);                 // get ADC value from 2nd channel    LCD_Out(2,1,text);                     // print string a on LCD, 2nd row, 1st column    tlong = (long)adc_rd * 5000;           // covert adc reading to milivolts    tlong = tlong / 1023;                  // 0..1023 -> 0-5000mV    ch     = tlong / 1000;                 // extract volts digit    LCD_Chr(2,9,48+ch);                    // write ASCII digit at 2nd row, 9th column    LCD_Chr_CP('.');    ch    = (tlong / 100) % 10;            // extract 0.1 volts digit    LCD_Chr_CP(48+ch);                     // write ASCII digit at cursor point    ch    = (tlong / 10) % 10;             // extract 0.01 volts digit    LCD_Chr_CP(48+ch);                     // write ASCII digit at cursor point    ch    = tlong % 10;                    // extract 0.001 volts digit    LCD_Chr_CP(48+ch);                     // write ASCII digit at cursor point    LCD_Chr_CP('V');    Delay_ms(1);  }}//~!
Link spre comentariu

Exemplul pe care ti l-am dat este din MikroC

O librarie pt LCD proprie , insa pentru avr-uri:

int s_contor=0;int s_end = 0;unsigned char s_count=0;#ifndef LCD_DRIVER_H_#define LCD_DRIVER_H_#define RS   AVR32_PIN_PB12#define RW   AVR32_PIN_PB13#define E    AVR32_PIN_PB14#define DB4  AVR32_PIN_PB15#define DB5  AVR32_PIN_PB16#define DB6  AVR32_PIN_PB17#define DB7  AVR32_PIN_PB18#define LCD_BCKL AVR32_PIN_PB19#endif /* LCD_DRIVER_H_ */char lcd_buffer[21];void lcd_putchar(char c,unsigned char x,unsigned char y);//pune caracter la x,yvoid transferthedata (unsigned char data);//transfera datelevoid writecommand(unsigned char data);//scrie comanda la lcdvoid writedata(unsigned char data);//trimite comanda la lcdvoid init_lcd();//initializare lcdvoid write_char(char chr);//trimite caracter la lcd (fara pozitionare, se incrementeaza cursorul)void lcd_setup(unsigned char lcd , unsigned char bkl);//setare lcd on/off , bkl on/offvoid lcd_clear();//clear lcdvoid lcd_gotoxy(unsigned char x ,unsigned char y);//pozitionare cursor la x(coloana), y(linie)void lcd_puts(char *c,unsigned char x,unsigned char y);//pune string la x,yvoid lcd_delay();void scrolling_text(char *text,unsigned char x,unsigned char y,int delay); //afiseaza scrolling textunsigned char vector_init[]={12,0x03,0x03,0x03,0x02,0x02,0x0C,0x00,0x08,0x00,0x01,0x00,0x06};void transferthedata (unsigned char data){   if (data & 0x01)      setbit(DB4);   else if ( ! (data & 0x01) )      clrbit(DB4);   if ( ( data >> 1 ) & 0x01 )      setbit(DB5);   else if ( !(( data >> 1 ) & 0x01) )       clrbit(DB5);   if ( ( data >> 2 ) & 0x01 )      setbit(DB6);   else if ( !(( data >> 2 ) & 0x01) )       clrbit(DB6);   if ( ( data >> 3 ) & 0x01 )      setbit(DB7);   else if ( !(( data >> 3 ) & 0x01) )       clrbit(DB7);}void lcd_delay(){	cpu_delay_us(850,FOSC0_redef);// delay_ms(1) ....}void writecommand(unsigned char data)   {      clrbit(E);      clrbit(RS);      clrbit(RW);      transferthedata(data);      setbit(E);      lcd_delay();      clrbit(E);      lcd_delay();//10ms   }void writedata(unsigned char data)   {      clrbit(E);      setbit(RS);      clrbit(RW);      transferthedata(data);      setbit(E);      lcd_delay();      clrbit(E);      lcd_delay();   }void init_lcd(){	unsigned char i=0;	delay_ms(30);	for(i=1;i<=vector_init[0];i++)	{		writecommand(vector_init[i]);		delay_ms(5);	}}void write_char(char chr){   writedata(chr >> 4);   writedata(chr);}void lcd_setup(unsigned char lcd , unsigned char bkl){	if(lcd == 1)	{		writecommand(0x00);		writecommand(0x0C); //display on  ; cursor , blink off	}	else	{		writecommand(0x00);		writecommand(0x00);	}	if(bkl == 1)		setbit(LCD_BCKL);	else		clrbit(LCD_BCKL);}void lcd_clear(){	writecommand(0x00);	writecommand(0x01);}void lcd_gotoxy(unsigned char x ,unsigned char y){if(y==2){	writecommand(0x0C); //muta cursorul	writecommand(0x00); //pe linia 2}if(y==1){	writecommand(0x00); //muta cursorul	writecommand(0x02); //pe linia 1}while(x!=0){	writecommand(0x01); //muta cursorul	writecommand(0x04); //in dreapta cu 1x--;}}void lcd_putchar(char c,unsigned char x,unsigned char y){	lcd_gotoxy(x,y);	write_char(c);}void lcd_puts(char *c,unsigned char x,unsigned char y){	unsigned char i;	lcd_gotoxy(x,y);	for(i=0;i<strlen(c);i++)		write_char(c[i]);}void long2lcd(unsigned long x,unsigned char z,unsigned char y){        unsigned long limita;        unsigned char nrz;        unsigned char fost;        unsigned char r=0;        limita=10000000;        fost=0;        while (limita>=10){                nrz=48;                while (x>=limita){                        x-=limita;                        nrz++;                        fost=1;                }                if (fost) {                	lcd_putchar(nrz,z+r,y);                	r++;                }                limita/=10;        }        lcd_putchar(x+48,z+r,y);}void nr2lcd(unsigned char c,unsigned char x,unsigned char y){        lcd_putchar(48+c/10,x,y);        lcd_putchar(48+c%10,x+1,y);}
Link spre comentariu

Dupa parerea mea, daca urmezi sfatul lui nooob64, acela de a afisa numarul pe bucati, atunci poti folosi biblioteca ta. Scris asa, la repezeala si fara sa testez, codul ar arata cam asa:

 

volatile bit bNumarNegativ;void main(void){   unsigned char ucIntregi = 0;   unsigned char ucZecimale = 0;      float fNumarDeTest=123.95; //un numat cu partea intreaga < 255 si partea zecimala < 255 (2 zecimale)   bNumarNegativ = 0;   if(fNumarDeTest<0)   {       bNumarNegativ = 1;       ucIntregi = (unsigned char) -fNumarDeTest; //asta ar trebui sa "arunce" partea zecimala       ucZecimale = (unsigned char) (-(fNumarDeTest + ucIntregi) * 100); //asta ar trebui sa pastreze numai partea zecimala      }   else   {       bNumarNegativ = 0;       ucIntregi = (unsigned char) fNumarDeTest; //asta ar trebui sa "arunce" partea zecimala       ucZecimale = (unsigned char) ((fNumarDeTest - ucIntregi + 1) * 100); //asta ar trebui sa pastreze numai partea zecimala      }   if(bNumarNegativ ) //pentru numere negative afisam semnul    {       lcdGoto(2, 4); //linia 2, coloana 4       lcdWrite(CMD_REG, '-'); //afiseaza punctul zecimal   }   else   {       lcdGoto(2, 5); //linia 2, coloana 5   }       lcdWrite(CMD_REG, (ucIntregi /100) + '0'); //afiseaza sutele    lcdWrite(CMD_REG, ((ucIntregi /10)%10) + '0'); //afiseaza zecile    lcdWrite(CMD_REG, (ucIntregi %10) + '0'); //afiseaza unitatile    lcdWrite(CMD_REG, '.'); //afiseaza punctul zecimal   lcdWrite(CMD_REG, ((ucZecimale /10)%10) + '0'); //afiseaza zecimile   lcdWrite(CMD_REG, (ucZecimale %10) + '0'); //afiseaza sutimile}
Bineinteles, am presupus ca biblioteca ta functioneaza (ca ai afisat deja alte caractere cu functiile alea) si ca pui bucatica de cod de mai sus la locul ei in program.

 

PS Daca ajungi la concluzia ca e ce-ti trebuie, poti "extinde" biblioteca definind o functie care sa contina codul de mai sus.

 

LE In urma unor teste am corectat codul. Observatii:

- e "urias" (compilat cu picc - lite mode (adica fara optimizari) - numai conversia ocupa 15% din memoria unui 16F877)

- la "generarea" zecimalelor are probleme cu "rezolutia" - uneori ucZecimale e cu o unitate pe langa ce ar trebui sa fie.

Link spre comentariu

Am atasat un fisier cu librariile pt lcd (.c si .h) si o imagine cu ce imi afiseaza daca folosesc codul urmator :

 

lcdClearDisplay();lcdGoto(0,0);lcdPuts("    TEMPERATURA     ");lcdGoto(0,1);lcdPuts("20*C-");ucIntregi = (unsigned char) temp; //asta ar trebui sa "arunce" partea zecimalaucZecimale = (unsigned char) ((temp - ucIntregi + 1) * 100); //asta ar trebui sa pastreze numai partea zecimala   lcdGoto(5,1);    lcdWrite(CMD_REG, (ucIntregi /100) + 48); //afiseaza sutele lcdWrite(CMD_REG, ((ucIntregi /10)%10) + 48); //afiseaza zecile lcdWrite(CMD_REG, (ucIntregi %10) + 48); //afiseaza unitatile lcdWrite(CMD_REG, '.'); //afiseaza punctul zecimallcdWrite(CMD_REG, ((ucZecimale /10)%10) + 48); //afiseaza zecimilelcdWrite(CMD_REG, (ucZecimale %10) + 48); //afiseaza sutimilelcdGoto(13,1);lcdPuts("*C-25*C");lcdGoto(0,2);lcdPuts("     UMIDITATE      ");lcdGoto(0,3);lcdPuts("  15% - xx.x% - 35%");	

Fac ceva gresit?

post-51482-139829388686_thumb.jpg

Link spre comentariu

Da, am folosit functia lcdinit();.Asta nu inteleg nici eu, dar sa verific am pus un delay de o sec intre fiecare instructiune de afisare si am observat ca prima data afiseaza "temperatura" si "20*C" dar apoi cand face acea conversie imi afiseaza acele caractere. Fara acel delay nu ai timp sa vezi ce se intampla si vezi numai acele carractere...

Link spre comentariu

Cand apelezi lcdWrite() ca sa scrii pe LCD (in codul de la mine), schimba CMD_REG cu DATA_REG.

 

LE Cu ce frecventa a oscilatorului simulezi? Se potriveste cu cea din lcd.h (5 MHz)?

 

#define _XTAL_FREQ 5000000

LLE Ar fi bine daca ne-ai povesti si cum ai configurat portul B (banui ca e tot setat ca iesire); in simulator cred ca n-are importanta daca e activat LVP (si cum e conectat PGM).

Link spre comentariu

Cu placere, desi am senzatia ca metoda (cam mura-n gura) n-a fost prea "didactica" (proiectul asta cam miroase a tema de la scoala). Sper totusi ca ai ramas cu ceva din el. Felicitari! :101

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări