Teploměr s DS18B20 měří na 4 des. místa - změna na 1 des. m.

Zdravím, potřeboval bych pomoci s úpravou mého kódu. Našel jsem rutinu na DS18B20 která funguje výborně, můj problém je, že to měří na 4 desetinná místa. Já bych ale potřeboval aby to měřilo jen na jedno desetnné místo. Mohl by mi někdo poradit jak na to? Moooc děkuji :slight_smile:

Code:

#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include “lcd_h.h”

char buffer[12];

#define F_CPU 1000000UL
#define THERM_CMD_CONVERTTEMP 0x44
#define THERM_CMD_RSCRATCHPAD 0xbe
#define THERM_CMD_WSCRATCHPAD 0x4e
#define THERM_CMD_CPYSCRATCHPAD 0x48
#define THERM_CMD_RECEEPROM 0xb8
#define THERM_CMD_RPWRSUPPLY 0xb4
#define THERM_CMD_SEARCHROM 0xf0
#define THERM_CMD_READROM 0x33
#define THERM_CMD_MATCHROM 0x55
#define THERM_CMD_SKIPROM 0xcc
#define THERM_CMD_ALARMSEARCH 0xec

/* Thermometer Connections /
#define THERM_PORT PORTA
#define THERM_DDR DDRA
#define THERM_PIN PINA
#define THERM_DQ PA0
/
Utils */
#define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
#define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)

#define THERM_DECIMAL_STEPS_12BIT 625 //.0625

uint8_t therm_reset(){
uint8_t i;

//Pull line low and wait for 480uS
THERM_LOW();
THERM_OUTPUT_MODE();
_delay_us(480);
//Release line and wait for 60uS
THERM_INPUT_MODE();
_delay_us(60);
//Store line value and wait until the completion of 480uS period
i=(THERM_PIN & (1<<THERM_DQ));
_delay_us(420);
//Return the value read from the presence pulse (0=OK, 1=WRONG)
return i;
}

void therm_write_bit(uint8_t bit){
//Pull line low for 1uS
THERM_LOW();
THERM_OUTPUT_MODE();
_delay_us(1);
//If we want to write 1, release the line (if not will keep low)
if(bit) THERM_INPUT_MODE();
//Wait for 60uS and release the line
_delay_us(60);
THERM_INPUT_MODE();
}

uint8_t therm_read_bit(void){
uint8_t bit=0;
//Pull line low for 1uS
THERM_LOW();
THERM_OUTPUT_MODE();
_delay_us(1);
//Release line and wait for 14uS
THERM_INPUT_MODE();
_delay_us(14);
//Read line value
if(THERM_PIN&(1<<THERM_DQ)) bit=1;
//Wait for 45uS to end and return read value
_delay_us(45);
return bit;
}

uint8_t therm_read_byte(void){
uint8_t i=8, n=0;
while(i–){

//Shift one position right and store read value
n>>=1;
n|=(therm_read_bit()<<7);
}
return n;
}
void therm_write_byte(uint8_t byte){
uint8_t i=8;
while(i–){
//Write actual bit and shift one position right to make the next bit ready
therm_write_bit(byte&1);
byte>>=1;
}
}

int main( void )
{

lcd_init();
lcd_clrscr();

while(1){

lcd_gotoxy(0,0);	

lcd_puts(“Teplota”);
therm_read_temperature(buffer2) ;

}
}

void therm_read_temperature(char *buffer){
// Buffer length must be at least 12bytes long! “+XXX.XXXX C”]
uint8_t temperature[2];
int8_t digit;
uint16_t decimal;
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete

while(!therm_read_bit());


	//Reset, skip ROM and send command to read Scratchpad
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_RSCRATCHPAD);
	//Read Scratchpad (only 2 first bytes)
	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();
	//Store temperature integer digits and decimal digits
	digit=temperature[0]>>4;
	digit|=(temperature[1]&0x7)<<4;
	//Store decimal digits
	decimal=temperature[0]&0xf;
	decimal*=THERM_DECIMAL_STEPS_12BIT;
	//Format temperature into a string +XXX.XXXX C]
	sprintf(buffer, "%+d.%04u C", digit, decimal);

lcd_clrscr();
lcd_gotoxy(0,1);

sprintf(buffer, “%+d.%04u”, digit, decimal);
lcd_puts(buffer);
lcd_putc(‘C’);
}

:arrow_right: administrator: přejmenováno z "Teplomer s DS18B20 - pomoc s upravou kodu"

V řádku “sprintf(buffer, “%+d.%04u”, digit, decimal);” uprav formátovací řetězec (znaky za druhým procentem). Jak konkrétně si budeš muset najít. Pro začátek bych tam zkusil “%01u”. Uvidíš, co o udělá.

Myslím že to tak nepůjde.

Jdou ořezat desetinné místa u float.
Ale u celého čísla by to bylo nelogické.
Třeba z čísel 50, 500, 5000 by bylo vždy 5. A to nemá s původním číslem žádnou souvislost.

Zkusil bych

sprintf(buffer, "%+d.", digit); lcd_puts(buffer); sprintf(buffer, "%u", decimal); lcd_putc(buffer[1]);

Nebylo by to spíš buffer[0] v druhém lcd_puts()?

To formátování v hlavě nenosím, byl to jen tip :slight_smile: Na mcu takové funkce nepoužívám, píši si vlastní na míru. Když to nepůjde, může 4 místné číslo vydělit 1000 a zobrazovat tam ten výsledek.
To by bylo něco jako:
decimal /= 1000;
sprintf(buffer, “%+d.%u”, digit, decimal);
Pak nám třeba řekne, co je rychlejší :slight_smile:

Další otázka je, zda sprintf nezakončuje řetězec “\0”. Řekl bych, že ano. Jak jinak by lcd_puts() poznala, co má vypsat. Potom by nebylo možno “lcd_puts(buffer[0]);” použít. Musel by o řádek výše ještě dopsat “buffer[1] = ‘\0’;” a opět nechat jen “lcd_puts(buffer);”

zkoušel jsem “%01u” ale pořád jen 4 desetinné místo, zkoušel jsem (snad dobře) tipy zkombinovat, ale výsledek pořád stejný :frowning: 4 desetinné místa. zkoušel jsem tam toto

int main( void )
{
lcd_init();
lcd_clrscr();

while(1){

lcd_gotoxy(0,0);	

lcd_puts(“Teplota”);
therm_read_temperature(buffer2) ;

}
}

void therm_read_temperature(char *buffer){
// Buffer length must be at least 12bytes long! “+XXX.XXXX C”]
uint8_t temperature[2];
int8_t digit;
uint16_t decimal;
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete

while(!therm_read_bit());

	//Reset, skip ROM and send command to read Scratchpad
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_RSCRATCHPAD);
	//Read Scratchpad (only 2 first bytes)
	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();
	//Store temperature integer digits and decimal digits
	digit=temperature[0]>>4;
	digit|=(temperature[1]&0x7)<<4;
	//Store decimal digits
	decimal=temperature[0]&0xf;
	decimal*=THERM_DECIMAL_STEPS_12BIT;
	decimal/=1000;
	//Format temperature into a string +XXX.XXXX C]
	//sprintf(buffer, "%+d.%04u C", digit, decimal);

lcd_clrscr();
lcd_gotoxy(0,1);

//sprintf(buffer, “%+d.%01u”, digit, decimal);
sprintf(buffer, “%+d.”, digit);
lcd_puts(buffer);
sprintf(buffer, “%d”, decimal);
buffer[1] = ‘\0’;
lcd_putc(buffer[1]);

//lcd_puts(buffer);
lcd_putc(‘C’);
}

[code]void therm_read_temperature(char *buffer)
{
// Buffer length must be at least 12bytes long! “+XXX.XXXX C”]
uint8_t temperature[2];
int8_t digit;
uint16_t decimal;
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete

while(!therm_read_bit()); 

//Reset, skip ROM and send command to read Scratchpad 
therm_reset(); 
therm_write_byte(THERM_CMD_SKIPROM); 
therm_write_byte(THERM_CMD_RSCRATCHPAD); 
//Read Scratchpad (only 2 first bytes) 
temperature[0]=therm_read_byte(); 
temperature[1]=therm_read_byte(); 
therm_reset(); 
//Store temperature integer digits and decimal digits 
digit=temperature[0]>>4; 
digit|=(temperature[1]&0x7)<<4; 
//Store decimal digits 
decimal=temperature[0]&0xf; 
decimal*=THERM_DECIMAL_STEPS_12BIT; 

//Format temperature into a string +XXX.XXXX C] 
//sprintf(buffer, "%+d.%04u C", digit, decimal); 
decimal /= 1000;
sprintf(buffer, "%+d.%u", digit, decimal); 
lcd_puts(buffer); 
lcd_putc('C'); 

}[/code]
Tohle by mělo desetinnou část minimálně vydělit 1000. Měla by tam tedy alespoň zůstat maximálně 1 číslice jinak samé nuly. Ikdyž mi není jasné, proč by to tam ty nuly dopisovalo. Když tak sem dej i obsah souboru “lcd_h.c”. Jo a do “code” pls :wink:.

Omlouvám se, můj příklad měl být takto

sprintf(buffer, "%+d.", digit); lcd_puts(buffer); sprintf(buffer, "%u", decimal); lcd_putc(buffer[0]);
aby se z “decimal” zobrazila jen první číslice.

To je pravda.
Jenom bych zdůraznil, že lcd_puts(buffer[0]) nejde vůbec použít.
lcd_puts() potřebuje argument typu pointer na char, ale “buffer[0]” je typu char.
Já jsem použil lcd_putc(), která vytiskne jeden znak a bývá deklarovaná jako “void lcd_putc(char c)”.

Tak v zobrazení to není zkusil jsem zapoznámkovat:

//sprintf(buffer, "%0u", decimal); //buffer = '\0'; //lcd_putc(buffer[1])

takže tisknu jen to digit a stejně se tam 4 desetiny ukazují :frowning:

tudíž mám tam jen

sprintf(buffer, "%+d.", digit);
lcd_puts(buffer);

a ukazuje to +27.1250

EDIT: Omlouvám se nahrál jsem blbej .hex tak proto to dělalo, ale zkouším dál, tak přinesu poznatky

tak dostal jsem s vaší pomocí jedno desetinné číslo ALE

sprintf(buffer, "%+d.", digit); lcd_puts(buffer); sprintf(buffer, "%u", decimal); lcd_putc(buffer[0]);

při tomto to jede ale teplota ukazuje 25.0 25.1 25.8 25.9 (prostě 25.3-25.7) tam nedostanu (zkusil jsem změnit hodnutu v decimal)

digit=temperature[0]>>4; digit|=(temperature[1]&0x7)<<4; decimal=temperature[0]&0x9; //decimal*=THERM_DECIMAL_STEPS_12BIT;
místo decimal=temperature[0]&0x9; bylo decimal=temperature[0]&0xf;

0xf zase mělo za následek že teplota jela dobře ale byly to hodnoty 25.1-25.9 25.1 26.0 jako by to jelo (a myslím že jsem to tam už měl 25.9 25.10 25.11 25.13 26.0

a když jsem zrušil poznámku decimal*=THERM_DECIMAL_STEPS_12BIT; tak to měří 25.0 25.6 25.5 26.0 26.6 26.5[/code]

A je to původní kód, jenom se změnou zobrazení?
Zkus teda na zkoušku zobrazit celou proměnnou “decimal”.

sprintf(buffer, "%+d.", digit); lcd_puts(buffer); sprintf(buffer, "%u", decimal); lcd_puts(buffer);
AB

Pokud původní kód fungoval (co nedefinovaná proměnná buffer2 ??)
tak je třeba ho nechat, nezasahovat do výpočtů, jak to děláš výše.
Je třeba jenom změnit zobrazení.

AB

tááák konečně to funguje!!! super moooc díky za pomoc :slight_smile:

jinak pro dobré měření a zobrazení funguje toto:

[code] decimal=temperature[0]&0xf;
decimal*=THERM_DECIMAL_STEPS_12BIT;
decimal/=1000;

lcd_clrscr();
lcd_gotoxy(0,1);
sprintf(buffer, “%+d.”, digit);
lcd_puts(buffer);
sprintf(buffer, “%u”, decimal);
lcd_puts(buffer);[/code]

ještě jednou díky :slight_smile: