Ale musím říct, že zase taková prkotina, tím myslím, že stačilo změnit výpis na jiný datový typ a ejhle už to frčí.
Ale děkuji za vaše rady a postřehy. Teď už by to mohlo být OK. Zítra zkusím kouknout na tu komunikaci logickým analyzátorem.
Ale musím říct, že zase taková prkotina, tím myslím, že stačilo změnit výpis na jiný datový typ a ejhle už to frčí.
Ale děkuji za vaše rady a postřehy. Teď už by to mohlo být OK. Zítra zkusím kouknout na tu komunikaci logickým analyzátorem.
#15 Lotus
Ale pozor. Změnil jsem nastavení CPOL a CPHA. Obojí do 1.
A teď při měření 1,71V jsem dostal 5887H (v dec je to 22663) a podle výpočtu mám dostat 22413. A to už je asi nejblíž.
Při 2.31V 7710H (dec 30480) a výpočet říká 30277.
Nyná už to vypadá zajímavěji.
Tak jsem ten výpis hodil do HEXa.
A po nastavení 0V, jsem dostal na LCD hodnotu fffc
Při 4,97V LCD ukazuje 7fb1
No a ještě k tomu HW, jestli není chyba zde:
Zapojil jsem to takto: IN- jsem uzemnil, protože chci měřit v rozmezí 0-5V a na IN+ jsem připojil ono měřené napětí.
A ostatní jsem ošetřil z datasheetu.
Jinak zítra koupím ještě jeden obvod pro můj logický analyzátor a pokud se zadaří, tak průběhy s ním odměřím a dám je sem. Toto by mi určitě hodně pomohlo.
Tak to mám jeden malý problém. Nemám osciloskop.
CPHA & CPOL jsem prokombinoval mezi sebou. Pouze když byly oba v 1, tak se výsledek změnil. Ale změnil se k nepoznání (dostal jsem záporné číslo úplně mimo mísu).
A v ostatních kombinacích se číslo zobrazuje kladné, ale cca 2x menší.
Tak já jsem se silama už v koncích. Nikoho nic nenapadá?
Tak jsem nastavil ten CPHA do 1 a nic. Výsledek pořád stejný.
Nyní jsem ve fázi, že hodnota zobrazená na LCD je malá. cca 2x menší než má být. A CPOL a CPHA v datasheetu není uvedené jak nastavit, tak jsou v 0. Ale s nima jsem experimentoval, takže zde chybu nevidím. Neporadí někdo? Kód je zde:
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"
// Mega16 Pinout
#define MOSI 5
#define MISO 6
#define SCLK 7
#define SS 4
char buffer[20];
unsigned int get_adc(unsigned char adata)
{
static unsigned int temp=0;
_delay_ms(1);
PORTB &= ~(1<<SS); // SET CS to LOW (activate ADC)
_delay_us(2); // small dealy
SPDR = adata;
while(!(SPSR & (1<<SPIF))); //MSB
temp = SPDR;
temp <<=8; //shift to upper byte
SPDR = adata;
while(!(SPSR & (1<<SPIF))); //LSB
temp += SPDR; // add low byte
//temp <<=8; // why this??
PORTB |= (1<<SS); // SET CS ti HIGH (stop
return temp;
}
void spim_init(void)
{
// SET PORT B jako výstup
DDRB |= (1<<MOSI) | (1<<SCLK) | (1<<SS);
// SET MISO jako vstup
DDRB &= ~(1<<MISO);
// Povoleni SPI, SPI Master, LSB First, SPI CLK XTAL/16)
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);
// nastaveni funkcniho registra SPI (SPCR), CPHA a CPOL v log 0
SPCR &= ~ (1<<CPOL);
SPCR &= ~ (1<<CPHA);
// CS HIGH protože SPI ADS je aktivní v 0
PORTB |= (1<<SS);
}
int main(){
static unsigned int adc_value=0; // promenna AD prevodniku
spim_init();
lcd_init(LCD_DISP_ON); //inicializacia displeja
for(;;){
adc_value = get_adc(0xff); // získání hodnoty z AD prevodniku
lcd_gotoxy(0,1);
sprintf(buffer,"ADC: %05d",adc_value); //zobrazi na LCD hodnotu adc_value na 4 místa (0000)
lcd_puts(buffer);
}
return 0;
}
Tak jsem něco sesmolil, ale hodnoty mi trošku lítají od mínus do plus,... :-D
unsigned int get_adc(unsigned char adata)
{
static unsigned int temp=0;
PORTB &= ~(1<<SS); // aktivace ADC
_delay_us(2); // prodleva 1us
SPDR = adata;
while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx (příjem MSB)
temp = SPDR;
temp <<=8; // posune proměnnou TEMP o 8 vlevo
SPDR = adata;
while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx (příjem LSB)
temp += SPDR; // kombinace dat
temp <<=8;
PORTB |= (1<<SS); // nastavi CS do 1 a tim zakaze ADC
return temp; // navratí 16-bit hodnotu ADcka
_delay_us(4);
}
Dobrý večer pánové,
chtěl bych se zeptat, jestli jsem dobře pohopil komunikaci s AD7688 převodníkem.
Jako první jen uvedu zapojení (Mega16 = AD7688): MISO = SDO, SCK = SCK, SS = CNV
A vývod SDI spojen s VIO, takže chci komunikovat s "CS mode 3-wire, no busy indicator".
A teď ke komunikaci.
Jako první musím vytvořit impulz na pinu SS s délkou 10ns a poté následuje zvednutí SS po dobu 1us do jedničky. Po uplynutí této doby hodit SS do nuly a vyčítat 16bitů z MISO. Po přečtení 16 bitů SS do jedničky a vyčkat 2us (time between conversion". No potom už to volat pořád dokola jak chci. Je to tak správně? děkuji za odpověď.
Vyčítal jsem to z obrázku 35 (str. 17) a hodnoty časů (str. 5) z datasheetu
http://www.analog.com/static/imported-files/data_sheets/AD7688.pdf
Ahojte přátelé. :-)
Prosím mohl bych mít jednoduchý, dotaz?
Splašil jsem AD převodník TLC4541, ale nějak nemůžu přijít jak jej připojit k AVRku.
Vývody VDD, AIN, GND jsou mi jasné.
SDO = je výstup (přijímám 2 Byte)
SLCK = zdroj hodin
[b]
a teď: CS slouží k vybrání zařízení na sběrnici, ale zároveň, pokud jsem to dobře pochopil, mě informuje, jestli přijímám MSB nebo LSB z výstupu SDO.
Ale nač je tam FS? Nemohl bych ho jednoduše připojit na +5V?[/b]
Podotýkám, že zařízení je samo na sběrnici. Děkuji za radu
#1 Jirka
Takže jsem to opravil.
Nevím co se stalo ale byla tam někde chyba. :-D
Takže jsem provedl tyto změny.
Nástroje-Nastavení kompilátoru.
Záložka adresáře a tam jsem postupoval tak, že jsem smazal odkazy na adresáře DEV-C++ a nahradil jsem je odkazama na MinGW
Ahoj.
PLS ve škole programujeme v DEV-C++, a ten program chci mít i u sebe na notebooku, abych mohl dělat projekty.
No ale problém je ten, že se mi nedaří nic zkompilovat. A strejda google taky nepomohl.
Udělal jsem si jednoduchý program. Má pouze vypsat něco do konzole, ale ne a ne to rozjet. Poradí někdo?
Více info na obrázku.
#22 KIIV
Ano to s tím vymaskováním toho posledního bitu "7F" mě taky napadlo a tak jsem s tím začal operovat, ale zapomněl jsem změnit to rotování na 3. Tak proto mě to nějak něchtělo jet. Už to vypadá OK. Teď se už jenom poperu s tím zobrazením, ale to by už měla být "hračka".
Takže znova KIIVE Dík
tak jsem zase zpět.
Tady jsem si sesmolil kus kódu, ale mám problém. Přijímám hodnoty z AD od 2048 do 4095. A nemůžu to rozslousknout.
A zakopaný pes bude tady.
unsigned int get_adc(unsigned char adata)
{
static unsigned int temp=0;
PORTB &= ~(1<<SS); // SET CS do 0 (aktivovani ADC)
_delay_us(10); // zde by měla být krátká prodleva??
SPDR = adata; // vložit data do odesílací registru
while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx
temp = SPDR; // přijatá data nahraje do proměnné TEMP
temp <<= 8; // posune proměnnou TEMP o 8 vlevo
SPDR = adata; // vloží data do odesílacího registru
while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx
temp += SPDR; // combine data
temp >>=4; // posune proměnnou TEMP o 4 vpravo
PORTB |= (1<<SS); // nastavi CS do 1 a tim zakaze ADC
return temp; // navratí 12-bit hodnotu ADcka
}
Ono to vypadá, jak kdybych přijímal pouze část 12-bitů. Takže jsem si myslel, že je špatné rotování, ale to jsem nakonec vyloučil. Takže chyba asi bude ve slučování (temp += SPDR;) Ale prč takto nemůžu kombinovat čísla?
áááááááááááááááááááááá já z toho vyrostu. :-D
Tak stačilo změnit printf na sprintf a už to vypadá dobře. :-D :-D :-D :-D :-D :-D
Děkuji děkuji
PS: to by mě zajímalo, kolik takových chyb mě ještě čeká. :-D
Ano to jsem si vložil do cyklu for, kde to opakuju. Zdroj jsem připojil přímo k tomu AD převodníku a zkouším to. Ale bez odezvy.
A teď jsem si všiml, že ten modul AD převodníku je blbě. Ten trimr takto nemůže být připojený.
#12 hlucheucho
Ano tak s tím CPOL a CPHA jsi měl pravdu. To jsem měl nastavené blbě, nebo spíš vůbec. A na ty porty jsem se díval a vypadá, že je vše jak má, ale program furt nic.
Ale normálně na tvrdo jsem si vytiskl tu proměnnou lcd_puts(adc_value); a čekal jsem, že se ta hodnota bude měnit, že se displej zblázní, že bude ukazovat ptákoviny, ale místo toho tam pořád svítí 100. A nic se neděje.
No tady ty příspěvky jsem si přečetl pozdě. :-D Ale to ještě opravím. ;-)
Jinak jsem se pustil do programování, ale ono ejhle. Něco je blbě. Tady je kód, ale na displeji se mi nic nezobrazí. Asi něco dělám špatně. A to jsem zkoušel už mooc věcí.
SPI mám nastavenou na rychlost 1MHz. Takže by to mělo fungovat. Ale kde je chyba, to nevím.
#include <avr/io.h> #include <stdio.h> #include <util/delay.h> #include <avr/interrupt.h> #include "lcd.h" //knihovna pro komunikaci s LCD 2004 // Mega16 Pinout #define MOSI 4 #define MISO 6 #define SCLK 7 #define SS 4 char buffer[50]; unsigned int get_adc(unsigned char adata) { static unsigned int temp=0; PORTB &= ~(1<<SS); // SET CS do 0 (aktivovani ADC) // zde by měla být krátká prodleva?? SPDR = adata; // vložit data do odesílací registru while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx temp = SPDR; // přijatá data nahraje do proměnné TEMP temp = temp << 8; // posune proměnnou TEMP o 8 vlevo SPDR = adata; // vloží data do odesílacího registru while(!(SPSR & (1<<SPIF))); // Poslat 1 byte přes HW SPI a čeka na tx temp |= SPDR; // přijatá data nahraje do proměnné TEMP PORTB |= (1<<SS); // nastavi CS do 1 a tim zakaze ADC return temp; // navratí hodnotu ADcka } void spim_init(void) { // SET PORT B jako výstup DDRB |= (1<<MOSI) | (1<<SCLK) | (1<<SS); // SET MISO jako vstup DDRB &= ~(1<<MISO); // Povoleni SPI, SPI Master, SPI CLK XTAL/16, LSB First SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);
// CS HIGH protože SPI ADS je aktivní v
PORTB |= (1<<SS); } int main (void) { lcd_init(LCD_DISP_ON); //inicializace LCD static unsigned int adc_value=0; // promenna AD prevodniku spim_init(); // Inicializace SPI jako MASTER adc_value = get_adc(0xFF); // získání hodnoty z AD prevodniku lcd_gotoxy(0,1); printf(buffer,"%d",adc_value); lcd_puts(buffer); for(;;){} }
Ahojte.
Chci se naučit pracovat s AD převodníkem, ale nemůžu přijít na to jak jej připojit k MCU. Mohl by mi někdo poradit, jestli to mám dobře?
Jedná se o MAX187 a atmegu16.
MAX187 komunikuje po SPI sběrnici.
A jde mi o to, jestli ty MAX187 signály SCLK, CS, DOUT můžu takto napojit na MCU (SCK, SS, MOSI), nebo jsetli ty signály musím připojit na jiné piny.
Tady jsem si sesmolil takový vlastní modulek. Poradí někdo? Děkuji
A abych nezakládal nové téma, chci se zeptat.
Dejme tomu, že mám hodnotu hodiny, které chci aby se na displeji zobrazovaly jako 00:00:00. Ale problém je v tom, že mě se to zobrazí třeba takto: 12:2:24. Dá se to nějak odstranit, aby bylo zobrazeno 12:02:24??
sprintf (txstring,"%d:%d:%d",hod,min,sek);
lcd_puts(txstring);
No tak se nakonec podařilo. ;-)
if (DS18X20_read_decicelsius(&gSensorIDs[i-1][0],&decicelsius)==DS18X20_OK)
{
sprintf(txstring,"%d", decicelsius);
lcd_gotoxy(9,0);
lcd_puts(txstring);
}
A musím jen doplnit, že výsledek decicelsius je nutné vydělit 10 ;-)
Tak jsem si s tím trošku pohrál a vyplodil jsem toto, protože temp je unit_16
if ( DS18X20_read_celsius( &gSensorIDs[i-1][0],&temp)== DS18X20_OK ) {
a = temp/1000;
pom = temp % 1000;
b = pom/100;
pom = pom % 100;
c = pom / 10;
pom = pom % 10;
d = pom;
sprintf(txstring,"%d%d%d%d",a,b,c,d);
lcd_gotoxy(10,0);
lcd_puts(txstring);
}
A zjistil jsem, že ono to číslo zdaleka nepřipomíná teplotu a až příliš se mění s teplotou např: 13107 pak 00007,.....
Velice se omlouvám, ta knihovna je špatná. Tato je ta dobrá.
/*********************************************************************************
Title: DS18X20-Functions via One-Wire-Bus
Author: Martin Thomas <eversmith@heizung-thomas.de>
http://www.siwawi.arubi.uni-kl.de/avr-projects
Software: avr-gcc 4.3.3 / avr-libc 1.6.7 (WinAVR 3/2010)
Hardware: any AVR - tested with ATmega16/ATmega32/ATmega324P and 3 DS18B20
Partly based on code from Peter Dannegger and others.
changelog:
20041124 - Extended measurements for DS18(S)20 contributed by Carsten Foss (CFO)
200502xx - function DS18X20_read_meas_single
20050310 - DS18x20 EEPROM functions (can be disabled to save flash-memory)
(DS18X20_EEPROMSUPPORT in ds18x20.h)
20100625 - removed inner returns, added static function for read scratchpad
. replaced full-celcius and fractbit method with decicelsius
and maxres (degreeCelsius*10e-4) functions, renamed eeprom-functions,
delay in recall_e2 replaced by timeout-handling
20100714 - ow_command_skip_last_recovery used for parasite-powerd devices so the
strong pull-up can be enabled in time even with longer OW recovery times
20110209 - fix in DS18X20_format_from_maxres() by Marian Kulesza
**********************************************************************************/
#include <stdlib.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "ds18x20.h"
#include "onewire.h"
#include "crc8.h"
#if DS18X20_EEPROMSUPPORT
// for 10ms delay in copy scratchpad
#include <util/delay.h>
#endif /* DS18X20_EEPROMSUPPORT */
/*----------- start of "debug-functions" ---------------*/
/* functions for debugging-output - undef DS18X20_VERBOSE in .h
if you run out of program-memory */
#include <string.h>
static int16_t DS18X20_raw_to_decicelsius( uint8_t fc, uint8_t sp[] );
#if DS18X20_VERBOSE
#define uart_puts_P_verbose(s__) uart_puts_P(s__)
#else
#define uart_puts_P_verbose(s__)
#endif
/*----------- end of "debug-functions" ---------------*/
/* find DS18X20 Sensors on 1-Wire-Bus
input/ouput: diff is the result of the last rom-search
*diff = OW_SEARCH_FIRST for first call
output: id is the rom-code of the sensor found */
uint8_t DS18X20_find_sensor( uint8_t *diff, uint8_t id[] )
{
uint8_t go;
uint8_t ret;
ret = DS18X20_OK;
go = 1;
do {
*diff = ow_rom_search( *diff, &id[0] );
if ( *diff == OW_PRESENCE_ERR || *diff == OW_DATA_ERR ||
*diff == OW_LAST_DEVICE ) {
go = 0;
ret = DS18X20_ERROR;
} else {
if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS18S20_FAMILY_CODE ||
id[0] == DS1822_FAMILY_CODE ) {
go = 0;
}
}
} while (go);
return ret;
}
/* get power status of DS18x20
input: id = rom_code
returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE */
uint8_t DS18X20_get_power_status( uint8_t id[] )
{
uint8_t pstat;
ow_reset();
ow_command( DS18X20_READ_POWER_SUPPLY, id );
pstat = ow_bit_io( 1 );
ow_reset();
return ( pstat ) ? DS18X20_POWER_EXTERN : DS18X20_POWER_PARASITE;
}
/* start measurement (CONVERT_T) for all sensors if input id==NULL
or for single sensor where id is the rom-code */
uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[])
{
uint8_t ret;
ow_reset();
if( ow_input_pin_state() ) { // only send if bus is "idle" = high
if ( with_power_extern != DS18X20_POWER_EXTERN ) {
ow_command_with_parasite_enable( DS18X20_CONVERT_T, id );
/* not longer needed: ow_parasite_enable(); */
} else {
ow_command( DS18X20_CONVERT_T, id );
}
ret = DS18X20_OK;
}
else {
ret = DS18X20_START_FAIL;
}
return ret;
}
// returns 1 if conversion is in progress, 0 if finished
// not available when parasite powered.
uint8_t DS18X20_conversion_in_progress(void)
{
return ow_bit_io( 1 ) ? DS18X20_CONVERSION_DONE : DS18X20_CONVERTING;
}
static uint8_t read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n )
{
uint8_t i;
uint8_t ret;
ow_command( DS18X20_READ, id );
for ( i = 0; i < n; i++ ) {
sp[i] = ow_byte_rd();
}
if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) {
ret = DS18X20_ERROR_CRC;
} else {
ret = DS18X20_OK;
}
return ret;
}
#if DS18X20_DECICELSIUS
/* convert scratchpad data to physical value in unit decicelsius */
static int16_t DS18X20_raw_to_decicelsius( uint8_t familycode, uint8_t sp[] )
{
uint16_t measure;
uint8_t negative;
int16_t decicelsius;
uint16_t fract;
measure = sp[0] | (sp[1] << 8);
//measure = 0xFF5E; // test -10.125
//measure = 0xFE6F; // test -25.0625
if( familycode == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20
/* Extended measurements for DS18S20 contributed by Carsten Foss */
measure &= (uint16_t)0xfffe; // Discard LSB, needed for later extended precicion calc
measure <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units
measure += (16 - sp[6]) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16)
}
// check for negative
if ( measure & 0x8000 ) {
negative = 1; // mark negative
measure ^= 0xffff; // convert to positive => (twos complement)++
measure++;
}
else {
negative = 0;
}
// clear undefined bits for DS18B20 != 12bit resolution
if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) {
switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) {
case DS18B20_9_BIT:
measure &= ~(DS18B20_9_BIT_UNDF);
break;
case DS18B20_10_BIT:
measure &= ~(DS18B20_10_BIT_UNDF);
break;
case DS18B20_11_BIT:
measure &= ~(DS18B20_11_BIT_UNDF);
break;
default:
// 12 bit - all bits valid
break;
}
}
decicelsius = (measure >> 4);
decicelsius *= 10;
// decicelsius += ((measure & 0x000F) * 640 + 512) / 1024;
// 625/1000 = 640/1024
fract = ( measure & 0x000F ) * 640;
if ( !negative ) {
fract += 512;
}
fract /= 1024;
decicelsius += fract;
if ( negative ) {
decicelsius = -decicelsius;
}
if ( /* decicelsius == 850 || */ decicelsius < -550 || decicelsius > 1250 ) {
return DS18X20_INVALID_DECICELSIUS;
} else {
return decicelsius;
}
}
/* convert scratchpad data to physical value in unit celsius */
static double DS18X20_raw_to_celsius( uint8_t familycode, uint8_t sp[] )
{
uint16_t measure;
uint8_t negative;
int16_t decicelsius;
uint16_t fract;
double celsius;
measure = sp[0] | (sp[1] << 8);
//measure = 0xFF5E; // test -10.125
//measure = 0xFE6F; // test -25.0625
if( familycode == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20
/* Extended measurements for DS18S20 contributed by Carsten Foss */
measure &= (uint16_t)0xfffe; // Discard LSB, needed for later extended precicion calc
measure <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units
measure += (16 - sp[6]) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16)
}
// check for negative
if ( measure & 0x8000 ) {
negative = 1; // mark negative
measure ^= 0xffff; // convert to positive => (twos complement)++
measure++;
}
else {
negative = 0;
}
// clear undefined bits for DS18B20 != 12bit resolution
if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) {
switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) {
case DS18B20_9_BIT:
measure &= ~(DS18B20_9_BIT_UNDF);
break;
case DS18B20_10_BIT:
measure &= ~(DS18B20_10_BIT_UNDF);
break;
case DS18B20_11_BIT:
measure &= ~(DS18B20_11_BIT_UNDF);
break;
default:
// 12 bit - all bits valid
break;
}
}
decicelsius = (measure >> 4);
decicelsius *= 10;
// decicelsius += ((measure & 0x000F) * 640 + 512) / 1024;
// 625/1000 = 640/1024
fract = ( measure & 0x000F ) * 640;
if ( !negative ) {
fract += 512;
}
fract /= 1024;
decicelsius += fract;
if ( negative ) {
decicelsius = -decicelsius;
}
celsius = decicelsius;
celsius = celsius/10;
if ( /* decicelsius == 850 || */ decicelsius < -550 || decicelsius > 1250 ) {
return 0;
} else {
return celsius;
}
}
/* format decicelsius-value into string, itoa method inspired
by code from Chris Takahashi for the MSP430 libc, BSD-license
modifications mthomas: variable-types, fixed radix 10, use div(),
insert decimal-point */
uint8_t DS18X20_format_from_decicelsius( int16_t decicelsius, char str[], uint8_t n)
{
uint8_t sign = 0;
char temp[7];
int8_t temp_loc = 0;
uint8_t str_loc = 0;
div_t dt;
uint8_t ret;
// range from -550:-55.0°C to 1250:+125.0°C -> min. 6+1 chars
if ( n >= (6+1) && decicelsius > -1000 && decicelsius < 10000 ) {
if ( decicelsius < 0) {
sign = 1;
decicelsius = -decicelsius;
}
// construct a backward string of the number.
do {
dt = div(decicelsius,10);
temp[temp_loc++] = dt.rem + '0';
decicelsius = dt.quot;
} while ( decicelsius > 0 );
if ( sign ) {
temp[temp_loc] = '-';
} else {
///temp_loc--;
temp_loc--;
}
// reverse the string.into the output
while ( temp_loc >=0 ) {
str[str_loc++] = temp[(uint8_t)temp_loc--];
if ( temp_loc == 0 ) {
str[str_loc++] = DS18X20_DECIMAL_CHAR;
}
}
str[str_loc] = '\0';
ret = DS18X20_OK;
} else {
ret = DS18X20_ERROR;
}
return ret;
}
/* reads temperature (scratchpad) of sensor with rom-code id
output: decicelsius
returns DS18X20_OK on success */
uint8_t DS18X20_read_decicelsius( uint8_t id[], int16_t *decicelsius )
{
uint8_t sp[DS18X20_SP_SIZE];
uint8_t ret;
ow_reset();
ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
if ( ret == DS18X20_OK ) {
*decicelsius = DS18X20_raw_to_decicelsius( id[0], sp );
}
return ret;
}
/* reads temperature (scratchpad) of sensor with rom-code id
output: double
returns DS18X20_OK on success */
uint8_t DS18X20_read_celsius( uint8_t id[], double *celsius )
{
uint8_t sp[DS18X20_SP_SIZE];
uint8_t ret;
ow_reset();
ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
if ( ret == DS18X20_OK ) {
*celsius = DS18X20_raw_to_celsius( id[0], sp );
}
return ret;
}
/* reads temperature (scratchpad) of sensor without id (single sensor)
output: decicelsius
returns DS18X20_OK on success */
uint8_t DS18X20_read_decicelsius_single( uint8_t familycode, int16_t *decicelsius )
{
uint8_t sp[DS18X20_SP_SIZE];
uint8_t ret;
ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE );
if ( ret == DS18X20_OK ) {
*decicelsius = DS18X20_raw_to_decicelsius( familycode, sp );
}
return ret;
}
#endif /* DS18X20_DECICELSIUS */
#if DS18X20_MAX_RESOLUTION
static int32_t DS18X20_raw_to_maxres( uint8_t familycode, uint8_t sp[] )
{
uint16_t measure;
uint8_t negative;
int32_t temperaturevalue;
measure = sp[0] | (sp[1] << 8);
//measure = 0xFF5E; // test -10.125
//measure = 0xFE6F; // test -25.0625
if( familycode == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20
/* Extended measurements for DS18S20 contributed by Carsten Foss */
measure &= (uint16_t)0xfffe; // Discard LSB, needed for later extended precicion calc
measure <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units
measure += ( 16 - sp[6] ) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16)
}
// check for negative
if ( measure & 0x8000 ) {
negative = 1; // mark negative
measure ^= 0xffff; // convert to positive => (twos complement)++
measure++;
}
else {
negative = 0;
}
// clear undefined bits for DS18B20 != 12bit resolution
if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) {
switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) {
case DS18B20_9_BIT:
measure &= ~(DS18B20_9_BIT_UNDF);
break;
case DS18B20_10_BIT:
measure &= ~(DS18B20_10_BIT_UNDF);
break;
case DS18B20_11_BIT:
measure &= ~(DS18B20_11_BIT_UNDF);
break;
default:
// 12 bit - all bits valid
break;
}
}
temperaturevalue = (measure >> 4);
temperaturevalue *= 10000;
temperaturevalue +=( measure & 0x000F ) * DS18X20_FRACCONV;
if ( negative ) {
temperaturevalue = -temperaturevalue;
}
return temperaturevalue;
}
uint8_t DS18X20_read_maxres( uint8_t id[], int32_t *temperaturevalue )
{
uint8_t sp[DS18X20_SP_SIZE];
uint8_t ret;
ow_reset();
ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
if ( ret == DS18X20_OK ) {
*temperaturevalue = DS18X20_raw_to_maxres( id[0], sp );
}
return ret;
}
uint8_t DS18X20_read_maxres_single( uint8_t familycode, int32_t *temperaturevalue )
{
uint8_t sp[DS18X20_SP_SIZE];
uint8_t ret;
ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE );
if ( ret == DS18X20_OK ) {
*temperaturevalue = DS18X20_raw_to_maxres( familycode, sp );
}
return ret;
}
uint8_t DS18X20_format_from_maxres( int32_t temperaturevalue, char str[], uint8_t n)
{
uint8_t sign = 0;
char temp[10];
int8_t temp_loc = 0;
uint8_t str_loc = 0;
ldiv_t ldt;
uint8_t ret;
// range from -550000:-55.0000°C to 1250000:+125.0000°C -> min. 9+1 chars
if ( n >= (9+1) && temperaturevalue > -1000000L && temperaturevalue < 10000000L ) {
if ( temperaturevalue < 0) {
sign = 1;
temperaturevalue = -temperaturevalue;
}
do {
ldt = ldiv( temperaturevalue, 10 );
temp[temp_loc++] = ldt.rem + '0';
temperaturevalue = ldt.quot;
} while ( temperaturevalue > 0 );
// mk 20110209
if ((temp_loc < 4)&&(temp_loc > 1)) {
temp[temp_loc++] = '0';
} // mk end
if ( sign ) {
temp[temp_loc] = '-';
}
while ( temp_loc >= 0 ) {
str[str_loc++] = temp[(uint8_t)temp_loc--];
if ( temp_loc == 3 ) {
str[str_loc++] = DS18X20_DECIMAL_CHAR;
}
}
str[str_loc] = '\0';
ret = DS18X20_OK;
} else {
ret = DS18X20_ERROR;
}
return ret;
}
#endif /* DS18X20_MAX_RESOLUTION */
#if DS18X20_EEPROMSUPPORT
uint8_t DS18X20_write_scratchpad( uint8_t id[],
uint8_t th, uint8_t tl, uint8_t conf)
{
uint8_t ret;
ow_reset();
if( ow_input_pin_state() ) { // only send if bus is "idle" = high
ow_command( DS18X20_WRITE_SCRATCHPAD, id );
ow_byte_wr( th );
ow_byte_wr( tl );
if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS1822_FAMILY_CODE ) {
ow_byte_wr( conf ); // config only available on DS18B20 and DS1822
}
ret = DS18X20_OK;
}
else {
ret = DS18X20_ERROR;
}
return ret;
}
uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n )
{
uint8_t ret;
ow_reset();
if( ow_input_pin_state() ) { // only send if bus is "idle" = high
ret = read_scratchpad( id, sp, n );
}
else {
ret = DS18X20_ERROR;
}
return ret;
}
uint8_t DS18X20_scratchpad_to_eeprom( uint8_t with_power_extern,
uint8_t id[] )
{
uint8_t ret;
ow_reset();
if( ow_input_pin_state() ) { // only send if bus is "idle" = high
if ( with_power_extern != DS18X20_POWER_EXTERN ) {
ow_command_with_parasite_enable( DS18X20_COPY_SCRATCHPAD, id );
/* not longer needed: ow_parasite_enable(); */
} else {
ow_command( DS18X20_COPY_SCRATCHPAD, id );
}
_delay_ms(DS18X20_COPYSP_DELAY); // wait for 10 ms
if ( with_power_extern != DS18X20_POWER_EXTERN ) {
ow_parasite_disable();
}
ret = DS18X20_OK;
}
else {
ret = DS18X20_START_FAIL;
}
return ret;
}
uint8_t DS18X20_eeprom_to_scratchpad( uint8_t id[] )
{
uint8_t ret;
uint8_t retry_count=255;
ow_reset();
if( ow_input_pin_state() ) { // only send if bus is "idle" = high
ow_command( DS18X20_RECALL_E2, id );
while( retry_count-- && !( ow_bit_io( 1 ) ) ) {
;
}
if ( retry_count ) {
ret = DS18X20_OK;
} else {
ret = DS18X20_ERROR;
}
}
else {
ret = DS18X20_ERROR;
}
return ret;
}
#endif /* DS18X20_EEPROMSUPPORT */
Ahoj.
Našel jsem si knihovnu, pomocí které se snažím měřit teplotu. Nic těžkého, ale problém je, že se mi nedaří vyčíst teplotu z čidla. Zatím mám pouze jedno čidlo připojení k MCU atmega16, takt 16MHz.
Zde je knihovna DS18B20.c
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include "config.h"
#include "onewire.h"
#include "ds18x21.h"
#include "gps.h"
/****************************************************************************
* Start measurement
****************************************************************************/
void ds18x21_start_meas( unsigned int pin )
{
if( W1_IN & 1<< pin )
{
w1_byte_wr( 0xEE, pin );
}
}
/****************************************************************************
* Display measurement result
****************************************************************************/
double ds18x21_read_meas(unsigned int pin )
{
int t;
int r;
double c;
double temperature;
w1_reset(pin);
w1_byte_wr( 0xAA, pin ); // read temp
t = w1_byte_rd(pin); // low byte
w1_reset(pin);
w1_byte_wr( 0xA0, pin); // read remaining count
r = w1_read(9, pin);
w1_reset(pin);
w1_byte_wr( 0x41, pin); // load counter
w1_reset(pin);
w1_byte_wr( 0xA0, pin); // read slope counter
c = w1_read(9, pin);
if ( t > 0x80 )
{
t = t-256;
}
temperature = t - 0.5 + (( c - r ) / c);
return temperature;
}
double ds18x21_get_meas(unsigned int pin, double * temp)
{
int status;
w1_reset(pin); // Put error cheking in
ds18x21_start_meas(pin);
for ( int i=0; i < 250; i++)
{
_delay_us (10000);
w1_reset(pin);
w1_byte_wr( 0xAC, pin );
status = w1_byte_rd(pin);
// Temperature conversion finished ?
if ( status & 0x80)
{
break;
}
}
_delay_us (10000);
// read measurement value
*temp = ds18x21_read_meas(pin);
return 1;
}
Zde jsem si vytvořil cyklus pro ono měření:
for ( i = nSensors; i > 0; i-- ) {
if ( DS18X20_start_meas( DS18X20_POWER_PARASITE, &gSensorIDs[i-1][0] ) == DS18X20_OK ) {
_delay_ms( DS18B20_TCONV_12BIT );
sprintf (txstring,"T%d= ",(int) i);
lcd_gotoxy(5,0);
lcd_puts(txstring);
if ( DS18X20_read_celsius( &gSensorIDs[i-1][0],&temp)== DS18X20_OK ) {
sprintf(txstring,"%d",temp);
lcd_gotoxy(10,0);
lcd_puts(temp);
}
}
}
No a když program přeložím, tak displej se zblázní. Může někdo poradit, co dělám špatně? Dík moc
Zdravím všechny kdo čte tento příspěvek.
Mám malý problém. Mám za úkol simulovat teploměr na LCD pcd8544 (nokia 3310/5110). ;-)
Nic ohromnýho. Vše mi už funguje, ale nyní mám problém se zobrazení "grafiky".
Max teplota = 45°C což odpovídá Yaxis=6. Min teplota 0°C což zase odpovídá Yaxis=38.
A teĎ k problému. Když zadám aby vykreslil čáru o hodnotě teplota třeba = 20°C vše funguje. Ale když dám vykreslit 0°C, tak dojde k tomu, že vykreslím čáru kde nemám, protože nevím jak to přepočítat.
U mě to je takto: teplota = Yaxis. Jak to přepočítat, a ještě jeden problémek, nemůžu počítat s desetinnýma číslama, protože pracuju s Atmegou16.
Vím, napsal jsem to tak složitě, ale nevím jak nejlépe problém popsat. PLS poraďte.
No tak nakonec se přeci jen podařilo. ;-)
sprintf(buffer, "%i", teplota,teplota%10);
LcdStr(FONT_1X,(unsigned char*)buffer);
Ahojte. Dneska si jenom tak hraju s LCD od nokie 5110. Připojil jsem ji k MCU a něco si na něm nakreslil, napsal. Ale pak jsem si řekl, že bych se na něm mohl zobrazit teplotu. A zde je ten problém. Nějak nedokážu na tento displej zobrazi proměnnou. :-D
Tak dejme tomu, že mám proměnnou teplota, která je typu char. A teď jak pomocí těchto proměnných, které mám k dispozici, zobrazím onu teplotu v číslech na tom LCD? Stačí přesnost na celé číslo "00". Co myslíte, půjde to?
byte LcdChr ( LcdFontSize size, byte ch );
byte LcdStr ( LcdFontSize size, byte dataArray[] );
byte LcdFStr ( LcdFontSize size, const byte *dataPtr )
#1 Rotoped
a omlouvám se, kód jsem trošku špatně napsal.
//zde je nastaveni TIMERU0 z main
TCCR0 |= (1<<WGM01)|(1<<CS01)|(1<<CS00); //CTC mode, preddelicka 64 (4us)
OCR0=50;
TIMSK |= (1 << OCIE0);
//zde je interrupt smyčka
ISR(TIMER0_COMP_vect){ //přerušení od čítače časovače 0
}
Hojte. PLS mám malý problém. Nějak se nemůžu dopočítat.
Nastavil jsem si TIMER0 a modu CTC.
Krystal mám 16MHz.
Takže jsem nastavil děličku na 64 z toho vyplývá, že přetečení nastane vždy jednou za 4us, [1/(16/64)=4us] pokud to říkám dobře. A já teď nemůžu zjistit, na kolik musím nastavit OCR0, aby bylo 100us. Nebo jestli by to šlo, tak aby 1ms.
Tak se chci zeptat, nevíte nějaký vzorec, podle kterého to spočítám? Děkuji
ISR(TIMER0_COMP_vect){ //přerušení od čítače časovače 0
}
TCCR0 |= (1<<WGM01)|(1<<CS01)|(1<<CS00); //CTC mode, preddelicka 64 (4us)
OCR0=25;
TIMSK |= (1 << OCIE0);
Ahojte.Tak jsem to zkoumal a je to opravdu pravda. Jenom číňani to zkouší jako já. :-D Takže jsem to trošku ošetřil HW (kondík) a jinak jsem použil časovač a ejhle už to šlape jak hodinky. Pro jistotu jsem tlačítko ošetřil i SW.
unsigned char tlac_prodleva,tlac_present;
ISR (TIMER1_OVF_vect){ //tlacitko rotacniho enkoderu + osetreni zakmitu
TCNT1 = 64911; //preteceni
if((PIND & (1 << PD3))){
if(tlac_prodleva<20)
tlac_prodleva++;
if(tlac_prodleva==19)
tlac_present=1;
}
else{
if(tlac_prodleva==20){
flag++;
encoder=0;
}
tlac_prodleva=0;
}
}
Takže takto by to mohlo být?
ISR(INT1_vect) //tlačitko
{
cli();
_ms_delay(1);
pricti++;
sei();
}
neboli, pokaždé když stisknu tlačítko, tak se hodnota pricti strikně zvýší o 1.
Ahojte.
Myslíte, že by se našel někdo, kdo by mi pomohl? Stavím si časovač, a připojil jsem si tlačítko na přerušení INT1. A mě by zajímalo, jestli by zde šlo ošetřit to tlačítko proti zákmitům. A jestli jo, jak to provedu?? Klidně přidám svůj kód, ale myslím si, že to není potřeba. Děkuji za jakoukoli radu
Tak jsem se s tím popral po svém. :-D Pro ty, kdo by někdy řešil obdobný problém, tak tady je řešení. Sice nevím jestli je úplně OK, ale funguje.
//pole DAT
const char textdata[] PROGMEM=
{
0b11000000,//0
0b11111001,//1
0b10100100,//2
0b10110000,//3
0b10011001,//4
0b10010010,//5
0b10000010,//6
0b11111000,//7
0b10000000,//8
0b10010000,//9
0b10011100,//°
0b11000110,//C
};
//pomocí podmínky (potreba) je zobrazováno 'xx°C'
char potreba=0;
void zapis_na7segment() //zobrazovač na 4x7-segmentovce
{
if (potreba==0)
{
des_hodin=pgm_read_byte(&textdata[des_hodin]);
zapisBYTU74595(des_hodin);
jed_hodin=pgm_read_byte(&textdata[jed_hodin]);
zapisBYTU74595(jed_hodin);
des_minut=pgm_read_byte(&textdata[des_minut]);
zapisBYTU74595(des_minut);
jed_minut=pgm_read_byte(&textdata[jed_minut]);
zapisBYTU74595(jed_minut);
shift_register_hi;
_delay_ms(10);
shift_register_lo;
}
else
{
des_hodin=pgm_read_byte(&textdata[des_teplota]);
zapisBYTU74595(des_hodin);
jed_hodin=pgm_read_byte(&textdata[jed_teplota]);
zapisBYTU74595(jed_hodin);
des_minut=pgm_read_byte(&textdata[10]);
zapisBYTU74595(des_minut);
jed_minut=pgm_read_byte(&textdata[11]);
zapisBYTU74595(jed_minut);
shift_register_hi;
_delay_ms(10);
shift_register_lo;
}
}
Dobrý den,
řeším problém se 4 sedmisegmentovkama. Na internetu jsem našel program, který jsem si upravil ke své podobě a na kterém se učím.
A můj problém je takovýto:
chtěl bych, aby 7 segmentovka nezobrazovala pouze čísla, ale i jiné symboly.
Třeba '°C', nebo si zobrazit jen jeden segment. Myslíte, že to půjde? Tady přikládám můj program:
//#define F_CPU 8000000L
#include "util/delay.h"
#include "stdlib.h"
#include "avr/io.h"
#include "avr/pgmspace.h"
#include "avr/interrupt.h"
#define shift_register_hi PORTD|=(1<<3)
#define shift_register_lo PORTD&=~(1<<3)
#define clock_register_hi PORTD|=(1<<1)
#define clock_register_lo PORTD&=~(1<<1)
#define serial_register_hi PORTD|=(1<<0)
#define serial_register_lo PORTD&=~(1<<0)
const char textdata[] PROGMEM=
{
0b11000000,//0
0b11111001,//1
0b10100100,//2
0b10110000,//3
0b10011001,//4
0b10010010,//5
0b10000010,//6
0b11111000,//7
0b10000000,//8
0b10010000,//9
0b10011100,//°
0b11000110,//C
};
//====================================================================
unsigned char jed_hodin,des_hodin,jed_minut,des_minut,minuty,hodiny,sekundy; //jednotky hodin, desítky hodin, jednotky minut, desítky minut
//minuty, hodiny, druhý
//--------------------------INICIALIZACE---------------------------------------
void init_devices() //inicializace 74HC595
{
DDRD |= (1 << PD0); //nastaveni bitu PD0 jako vystupni
DDRD |= (1 << PD1); //nastaveni bitu PD1 jako vystupni
DDRD |= (1 << PD3); //nastaveni bitu PD3 jako vystupni
serial_register_lo;
shift_register_lo;
clock_register_lo;
}
//------------------------KONEC INICIALIZACE---------------------------------
void clock_74595() //hodinový pulz 74HC595
{
clock_register_hi;
clock_register_lo;
}
void kirimbyte74595(unsigned char data_led) //zápis BYTE
{
if(bit_is_set(data_led,7)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,6)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,5)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,4)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,3)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,2)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,1)) serial_register_hi;else serial_register_lo;
clock_74595();
if(bit_is_set(data_led,0)) serial_register_hi;else serial_register_lo;
clock_74595();
}
void zapis_na7segment() //zobrazovač na 4x7-segmentovce
{
des_hodin=pgm_read_byte(&textdata[des_hodin]);
kirimbyte74595(des_hodin);
jed_hodin=pgm_read_byte(&textdata[jed_hodin]);
kirimbyte74595(jed_hodin);
des_minut=pgm_read_byte(&textdata[des_minut]);
kirimbyte74595(des_minut);
jed_minut=pgm_read_byte(&textdata[jed_minut]);
kirimbyte74595(jed_minut);
shift_register_hi;
_delay_ms(10);
shift_register_lo;
}
void prevod() //prevod cisla
{
des_hodin=hodiny/10; //destíky hodiny
jed_hodin=hodiny%10; //jednotky hodiny
des_minut=minuty/10; //desítky minut
jed_minut=minuty%10; //jednotky minut
}
ISR (TIMER1_COMPA_vect)
{
TCNT1 = 0;
}
//------------------------------hlavni smycka------------------------------------
int main()
{
minuty=0;
hodiny=0;
sekundy=0;
init_devices();
TCCR1B |= (1<< CS12);
TIMSK |= (1<< OCIE1A);
OCR1A=31249;
sei();
for(;;)
{
prevod(); //fce prevod prevede cislo na jednotky a desitky
zapis_na7segment();
}
}
Budu rád za jakoukoli odpověď. Děkuji
Ahojte. Myslíte, že by se tu našla dobrá duše, která by mi poradila? Potřeboval bych zjistit, za jakou dobu nastane přerušení, když mám krystal 8MHz a nastavení takovéto:
TCCR1B |= (1<< CS12);
TIMSK |= (1<< OCIE1A);
OCR1A=65224;
podle mých výpočtů cca každých 10ms. Je to OK? Děkuji
Ahojte. prosím měl bych jeden dotaz. Snažím se udělat program, který by reagoval na stisk tlačítka. A to tak, že bych rozlišoval dlouhý a krátký stisk. Ale nějak nevím jak na to. Mohl by mi někdo poradit?
#1 jirkaj4
Tak jsem tady z5. Našel jsem na internetu zajímavý příklad programu, ale nějak nemůžu přijít, jak ty jednotlivé funkce použít. Může mi někdo poradit? Třeba jak na tu sběrnici (I2C) poslat nějaký bajt? Nebo jak jí říct, že čtu?
Ahojte. Našel jsem si zajímavé zapojení a to DS1307 a atmega8. Ale bohužel se mi stále nedaří změnit port, na kterém je připojené DS1307. Neví někdo jak na to?
odkaz na projekt: http://extremeelectronics.co.in/avr-tutorials/interfacing-ds1307-rtc-chip-with-avr-microcontroller/
zde: odkaz na projekt v raru (AVR Studio 4): http://www.extremeelectronics.co.in/avrprojects/Codes/RTC/RTC.zip
Budu rád za každou radu. Dík moc