Miért nem működik az RTC-m?

Processing/Wiring (illetve C) nyelvű programozási fogások, tippek. (AVR-Duino, Arduino, EthDuino, Diecimila, Severino, Nano, LilyPad)
Válasz küldése
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Miért nem működik az RTC-m?

Hozzászólás Szerző: holex »

DS1307-ről vanszó, nullát ír ki másodpercre,percre, mindenre... Mi lehet a baja?

Kód: Egész kijelölése

#define F_CPU 16000000UL
#define SCL_CLOCK  100000L
#define DS1307_ADDR (0xD0) //device address

#include <avr/io.h>
#include <util/delay.h>
#include <lcd.c>
#include <stdlib.h>
#include <temp_sensor_util.h>
#include <avr/eeprom.h>
#include <compat/twi.h>
#include <i2cmaster.h>
#include <avr/pgmspace.h>


char buffer[20];


uint8_t negativ=0,egesz=0,tort=0,min_egesz=200,min_tort=0,max_egesz=0,max_tort=0;
uint8_t scratchpad[9];
uint8_t year, month, day, hour, minute, second;





/*************************************************************************
 Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
  
  TWSR = 0;                         /* no prescaler */
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */

}/* i2c_init */


/*************************************************************************	
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
    uint8_t   twst;

	// send START condition
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

	// send device address
	TWDR = address;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wail until transmission completed and ACK/NACK has been received
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

	return 0;

}/* i2c_start */


/*************************************************************************
 Issues a start condition and sends address and transfer direction.
 If device is busy, use ack polling to wait until device is ready
 
 Input:   address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
    uint8_t   twst;


    while ( 1 )
    {
	    // send START condition
	    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    
    	// wait until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
    
    	// send device address
    	TWDR = address;
    	TWCR = (1<<TWINT) | (1<<TWEN);
    
    	// wail until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
    	{    	    
    	    /* device busy, send stop condition to terminate write operation */
	        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
	        
	        // wait until stop condition is executed and bus released
	        while(TWCR & (1<<TWSTO));
	        
    	    continue;
    	}
    	//if( twst != TW_MT_SLA_ACK) return 1;
    	break;
     }

}/* i2c_start_wait */


/*************************************************************************
 Issues a repeated start condition and sends address and transfer direction 

 Input:   address and transfer direction of I2C device
 
 Return:  0 device accessible
          1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
    return i2c_start( address );

}/* i2c_rep_start */


/*************************************************************************
 Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
    /* send stop condition */
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
	
	// wait until stop condition is executed and bus released
	while(TWCR & (1<<TWSTO));

}/* i2c_stop */


/*************************************************************************
  Send one byte to I2C device
  
  Input:    byte to be transfered
  Return:   0 write successful 
            1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{	
    uint8_t   twst;
    
	// send data to the previously addressed device
	TWDR = data;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits
	twst = TW_STATUS & 0xF8;
	if( twst != TW_MT_DATA_ACK) return 1;
	return 0;

}/* i2c_write */


/*************************************************************************
 Read one byte from the I2C device, request more data from device 
 
 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
	while(!(TWCR & (1<<TWINT)));    

    return TWDR;

}/* i2c_readAck */


/*************************************************************************
 Read one byte from the I2C device, read is followed by a stop condition 
 
 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	
    return TWDR;

}/* i2c_readNak */


/*
 * days per month
 */
const uint8_t ds1307_daysinmonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };

/*
 * initialize the accellerometer
 */
void ds1307_init() {
	
	i2c_init();
	_delay_us(10);
}

/*
 * transform decimal value to bcd
 */
uint8_t ds1307_dec2bcd(uint8_t val) {
	return val + 6 * (val / 10);
}

/*
 * transform bcd value to deciaml
 */
static uint8_t ds1307_bcd2dec(uint8_t val) {
	return val - 6 * (val >> 4);
}

/*
 * get number of days since 2000/01/01 (valid for 2001..2099)
 */
static uint16_t ds1307_date2days(uint8_t y, uint8_t m, uint8_t d) {
	uint16_t days = d;
	for (uint8_t i = 1; i < m; ++i)
		days += pgm_read_byte(ds1307_daysinmonth + i - 1);
	if (m > 2 && y % 4 == 0)
		++days;
	return days + 365 * y + (y + 3) / 4 - 1;
}

/*
 * get day of a week
 */
uint8_t ds1307_getdayofweek(uint8_t y, uint8_t m, uint8_t d) {
	uint16_t day = ds1307_date2days(y, m, d);
	return (day + 6) % 7;
}

/*
 * set date
 */
uint8_t ds1307_setdate(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
	//sanitize data
	if (second < 0 || second > 59 ||
		minute < 0 || minute > 59 ||
		hour < 0 || hour > 23 ||
		day < 1 || day > 31 ||
		month < 1 || month > 12 ||
		year < 0 || year > 99)
		return 8;

	//sanitize day based on month
	if(day > pgm_read_byte(ds1307_daysinmonth + month - 1))
		return 0;

	//get day of week
	uint8_t dayofweek = ds1307_getdayofweek(year, month, day);

	//write date
	i2c_start_wait(DS1307_ADDR | I2C_WRITE);
	i2c_write(0x00);//stop oscillator
	i2c_write(ds1307_dec2bcd(second));
	i2c_write(ds1307_dec2bcd(minute));
	i2c_write(ds1307_dec2bcd(hour));
	i2c_write(ds1307_dec2bcd(dayofweek));
	i2c_write(ds1307_dec2bcd(day));
	i2c_write(ds1307_dec2bcd(month));
	i2c_write(ds1307_dec2bcd(year));
	i2c_write(0x00); //start oscillator
	i2c_stop();

	return 1;
}

/*
 * get date
 */
void ds1307_getdate() {
	i2c_start_wait(DS1307_ADDR | I2C_WRITE);
	i2c_write(0x00);//stop oscillator
	i2c_stop();

	i2c_rep_start(DS1307_ADDR | I2C_READ);
	second = ds1307_bcd2dec(i2c_readAck() & 0x7F);
	minute = ds1307_bcd2dec(i2c_readAck());
	hour = ds1307_bcd2dec(i2c_readAck());
	i2c_readAck();
	day = ds1307_bcd2dec(i2c_readAck());
	month = ds1307_bcd2dec(i2c_readAck());
	year = ds1307_bcd2dec(i2c_readNak());
	i2c_stop();
}


void writeTemp(){

	lcd_gotoxy(0,0);
	if (negativ) // If its negative
	{
		lcd_putc('-');
	}
	lcd_puts(itoa(egesz,buffer,10));
	lcd_putc('.');
	lcd_puts(itoa(tort,buffer,10)); //tortresz
	lcd_puts("    ");
		
}

void writeDate(){

	lcd_gotoxy(0,1);
	lcd_puts(itoa(year,buffer,10));
	lcd_putc('/');
	lcd_puts(itoa(month,buffer,10));
	lcd_putc('/');
	lcd_puts(itoa(day,buffer,10));
	
}

void writeTime(){

	lcd_gotoxy(0,2);
	lcd_puts(itoa(hour,buffer,10));
	lcd_putc(':');
	lcd_puts(itoa(minute,buffer,10));
	lcd_putc(':');
	lcd_puts(itoa(second,buffer,10));
	
}
static void master_reset(void)
{
	//Master Tx reset pulse
	//Pull bus low 480us minimum
	MASTER_TX();
	BUS_LOW();
	_delay_us(480);
	
	//Master Rx 480us minimum
	//Waiting for DS18B20 presence pulse
	MASTER_RX();
	_delay_us(480);
}

static void master_write_bit(uint8_t bit_value)
{
	//Initiate write time slot
	MASTER_TX();
	BUS_LOW();
	_delay_us(1);
	
	//Pull bus high to write "1" to DS18B20
	//or leave bus low to write "0" to DS18B20
	if(bit_value != 0)
	{
		BUS_HIGH();
	}
	
	_delay_us(59); //delay to meet write time slot req.
	
	//1us recovery time
	MASTER_RX();
	_delay_us(1);
}
static uint8_t master_read_bit(void)
{
	uint8_t bit_value;
	
	//Initiate write time slot
	MASTER_TX();
	BUS_LOW();
	_delay_us(1);
	
	//Master releasing bus
	MASTER_RX();
	_delay_us(10); //wait for DS18B20 output to stablize
	
	//Read in bit value
	if(BUS_LINE == 0)
	{
		bit_value = 0;
	}
	else
	{
		bit_value = 1;
	}
	
	//wait to meet minimum read time slot of 60us plus 1us recovery time
	_delay_us(50);
	
	return bit_value;
}
static void master_send_command(uint8_t command, commandType cmd_type)
{
	uint8_t bit_pos;
	
	//Need to reset for new round of access of DS18B20
	if(cmd_type == ROM_COMMAND_TYPE)
	{
		master_reset();
	}
	
	//Write each bit to DS18B20, LSB first
	for(bit_pos = 0; bit_pos != 8; ++bit_pos)
	{
		master_write_bit(command & (1<<bit_pos));
	}
}
static int16_t master_read_temp(void)
{
	uint8_t bit_pos;
	uint8_t i;
	
	//initialize, send rom command "skip rom" and function command "read scratchpad"
	master_send_command(ROM_COMMAND_SKIP_ROM, ROM_COMMAND_TYPE);
	master_send_command(FUNCTION_COMMAND_READ_SCRATCHPAD, FUNC_COMMAND_TYPE);
	
	//read scratchpad
	for(i=0;i<9;i++){
		scratchpad[i]=0;
		for(bit_pos=0;bit_pos<8;++bit_pos)
			scratchpad[i]|=master_read_bit()<<bit_pos;
	}
	return (scratchpad[1]<<8)|(scratchpad[0]);
}
void get_temp(void)
{
	int16_t TReading, Tc_100;
	
	
	TReading = master_read_temp();
	if (TReading & 0x8000) // negative
	{
		TReading = (TReading ^ 0xffff) + 1; // 2's comp
		negativ=1;
	}
	else negativ=0;
	Tc_100 = (int16_t)(6.25 * TReading);    // multiply by (100 * 0.0625) or 6.25
	egesz = (uint8_t)(Tc_100 / 100);  // egeszresz
	tort=(uint8_t)((Tc_100 % 100)/10); //tortresz


}
void start_conversion(void)
{
	//initialize, send rom command "skip rom" and function command "convert t"
	master_send_command(ROM_COMMAND_SKIP_ROM, ROM_COMMAND_TYPE);
	master_send_command(FUNCTION_COMMAND_CONVERT_T, FUNC_COMMAND_TYPE);
}
uint8_t crc8(const uint8_t *addr)
{
	uint8_t crc = 0;
	uint8_t len=8;
	while (len--) {
		uint8_t inbyte = *addr++;
		for (uint8_t i = 8; i; i--) {
			uint8_t mix = (crc ^ inbyte) & 0x01;
			crc >>= 1;
			if (mix) crc ^= 0x8C;
			inbyte >>= 1;
		}
	}
	return crc;
}


int main()
{
	
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();
    start_conversion();
	ds1307_init();
	
	
	
	
	
	while(1)
	{

		if (master_read_bit() == 1){		//konverzio kesz
			get_temp();
			start_conversion();
			if (crc8(scratchpad)==scratchpad[8]) writeTemp();
		}
		ds1307_getdate();
		writeDate();
		writeTime();

		
	}
	return 0;
}
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: Robert »

I2C címen bejelentkezik az eszköz?
- felhúzóellenállások OK?
- tápot kap?
- VBatt rendben vagy GNDre kötve (elem nélkül)?
- külső kvarc OK?
- cím OK?
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: holex »

Annyi volt a gond, hogy a seconds regiszter MSB-jét be kellett állítani.
nrobert
Újonc
Újonc
Hozzászólások: 5
Csatlakozott: 2015. június 10. szerda, 13:05

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: nrobert »

Sziasztok!

Van egy DS1307-es panelem DS18B20-as szenzorral. Az időt másodpercenként, a hőmérsékletet 5 másodpercenként kérdezem le és íratom ki egy LCD (Nokia 5110) kijelzőre. A hőmérséklet lekérdezésekor az idő kiírása megáll, majd 2 másodpercet ugrik. Van valakinek ötlete, hogy mi okozhatja ezt? A kód a következő:

Kód: Egész kijelölése

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Wire.h>
#include <OneWire.h>
#include "RTClib.h"
#include <DallasTemperature.h>

// LCD
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)

// RTC 
// A4 - SDA
// A5 - SCL
// D2 - DS

#define DS18B20_PIN 2

RTC_DS1307 RTC;
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
OneWire oneWire(DS18B20_PIN);       
DallasTemperature ds18(&oneWire);

void OraRajzol(byte h, byte m, byte s, byte y, byte n, byte d){
const float rad = 57.29577951;
float ang;
byte chw = 5; //kar. szélesség
byte chh = 7; //kar. magasság  
byte cx = display.height()/2;
byte cy = display.height()/2;
byte sx, sy;
String sIdo = "";
String sNap = "";
byte Hom;

display.clearDisplay();
display.fillCircle(cx, cy, 2, BLACK);

for( int i=0; i < 360; i += 90 ){
  ang = i / rad ;
  int sx0=cx+round(sin(ang)*cy);
  int sy0=cy-round(cos(ang)*cy);
  sx=cx+round(sin(ang)*(cy-5));
  sy=cy-round(cos(ang)*(cy-5));
  display.drawLine(sx0, sy0, sx, sy, BLACK);
}

ang = (s * 6) / rad;
sx = cx + round((sin(ang)*(cy-1)));
sy = cy - round((cos(ang)*(cy-1)));
display.drawLine(cx, cy, sx, sy, BLACK);

ang = (m * 6) / rad;
sx = cx + round((sin(ang)*(cy-5)));
sy = cy - round((cos(ang)*(cy-5)));
display.drawLine(cx, cy, sx, sy, BLACK);

ang = ((h * 30) + byte((m/12)*6))/rad;
sx = cx + round((sin(ang)*(cy-10)));
sy = cy - round((cos(ang)*(cy-10)));
display.drawLine(cx, cy, sx, sy, BLACK);

display.setCursor(display.width()-(8*(chw+1)),0);
sIdo += h; sIdo += ":";
if (m<10){
  sIdo += 0;
}
sIdo += m; sIdo += ":";
if (s<10){
  sIdo += 0;
}
sIdo += s;
display.print(sIdo);

display.setCursor(display.width()-(8*(chw+1)),display.height()-chh);
if (y<10){
  sNap += 0;
}
sNap += y; sNap += ".";
if (n<10){
  sNap += 0;
}
sNap += n; sNap += ".";
if (d<10){
  sNap += 0;
}
sNap += d;
display.print(sNap);

if(s % 5 ==0){
    ds18.requestTemperatures();
    Hom=round(ds18.getTempCByIndex(0));
  }

HomersekletKiiras(Hom);
display.display();
}

void HomersekletKiiras(byte h){
  String sHom = "";
  byte chw = 5; //kar. szélesség
  byte chh = 7; //kar. magasság
  display.setCursor(display.width()-(5*(chw+1)),chh+2);
  sHom += h;
  sHom += " ";
  sHom += char(247);
  sHom += "C";
  display.print(sHom);
}

void setup(){ 
  display.begin();
  display.setTextSize(1);
  display.setContrast(60);
  Wire.begin();
  RTC.begin();
  if (! RTC.isrunning()) {
    RTC.adjust(DateTime(__DATE__, __TIME__));
  } 
  ds18.begin();  
}

void loop(){
  byte hh;
  byte mm;
  byte ss;
  byte yy;
  byte nn;
  byte dd;

  DateTime now = RTC.now();
  hh = now.hour();
  mm = now.minute();
  ss = now.second();
  yy = now.year()%100;
  nn = now.month();
  dd = now.day();
  OraRajzol(hh, mm, ss, yy, nn, dd);
  delay(1000);
}
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: Robert »

A mögöttes libraryban van a várakozás.
Itt:
ds18.requestTemperatures();

Keress másik onewire lib-t, vagy szervezd át a programot :)
http://www.tavir.hu - a gazda :)
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: Robert »

Tipp:
a sorrendet cseréld meg:
1. Hőfokkiolvasás
2. Konverzió indítása
http://www.tavir.hu - a gazda :)
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: kapu48 »

Tipp 2:
Hagydki a :delay(1000); sort!
És a másodpercek változását figyeljed, csak akkor hivdmeg az LCD ki írást!
nrobert
Újonc
Újonc
Hozzászólások: 5
Csatlakozott: 2015. június 10. szerda, 13:05

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: nrobert »

Köszönöm a tippeket, ha jutottam valamire jelentkezem.
nrobert
Újonc
Újonc
Hozzászólások: 5
Csatlakozott: 2015. június 10. szerda, 13:05

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: nrobert »

Úgy tűnik sikerült megtalálnom a megoldást a problémámra:
A DS18B20-as szenzornak lehet módosítani a felbontását 9 és 12 bit között. Nagyobb felbontáshoz nagyobb pontosság és hosszabb konverziós idő társul. Pl: 9 bitnél 93,75 msec a konverziós idő, a pontosság 0,5 fok. 12 bitnél ez 750 msec és 0,0625 fok.

A felbontás beállítása:
  • ds18.getAddress(tempDeviceAddress, 0);
    ds18.setResolution(tempDeviceAddress, resolution);
    ds18.setWaitForConversion(false);
A setWaitForConversion-al beállítható, hogy várakozzon-e a processzor a hőmérséklet frissüléséig, vagy nem. A libraryban valóban ott a várakozás:
  • void DallasTemperature::requestTemperatures()
    {
    _wire->reset();
    _wire->skip();
    _wire->write(STARTCONVO, parasite);

    // ASYNC mode?
    if (!waitForConversion) return;
    blockTillConversionComplete(&bitResolution, 0);

    return;
    }
A felbontást 9 bitesre állítottam, ez nekem bőven elég, úgyis kerekítem a hőmérsékletet. Így a szenzor lekérdezése és a kijelző frissítése is belefér a másodperces gyakoriságba. Köszönöm a segítséget!
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: Robert »

Nem, vagyis nem teljesen.
A 93 vs 750 msec csak akkor, ha parazita módon használod. Ha 3 vezetékes, akkor ezek 1/5-e lehet a konverziós idő!
http://www.tavir.hu - a gazda :)
nrobert
Újonc
Újonc
Hozzászólások: 5
Csatlakozott: 2015. június 10. szerda, 13:05

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: nrobert »

Nekem egy gyárilag szerelt órapanelem van, amin már elő volt készítve a hely a szenzornak. Ezek szerint parazita módon volt a kapcsolás kialakítva. A setResolution-t gondolom nem kell minden bekapcsolás után lefuttatni, mert első alkalommal elmentődnek a beállítások az epromba?
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Miért nem működik az RTC-m?

Hozzászólás Szerző: Robert »

Goto adatlap:
1, nem égetődnek be
2, nincs eeprom

3, miért parazita lenne a bekötés? Simán lehet bármelyik...

Olvasni, nem feltételezni....
A műszaki tudomány egzakt....Nem feltételezés. Nem csillagállás, nem "véleményem szerint"... :P :oops: :evil:
http://www.tavir.hu - a gazda :)
Válasz küldése