Sari la conținut
ELFORUM - Forumul electronistilor

Contorizare secunde cat mai precis


Vlad Mihai

Postări Recomandate

Buna ziua,

 

Lucrez la o aplicatie cu FPGA (Xilinx) care imi trimite niste   date pe serial in LabVIEW. Datele  respective  vreau sa le plotez in timp real atunci cand  porneste placa cu FPGA. M-am gandit la  un montaj mic cu  arduino si DS1307 si care sa  transform cumva sa imi dea  numarul de secunde in loc de timp in ore minute si secunde. Intrebarea mea, se poate face asa ceva cu acest DS1307? Ma intereseaza sa  fie   cat mai precis    datele  privind informatia de timp.

Multumesc de raspuns! 

 

Ps: sunt deschis si la alte solutii.

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

Top autori în acest subiect

  • mars01

    8

  • Mircea

    3

  • Vlad Mihai

    3

  • digix

    2

Top autori în acest subiect

Zic si eu, cu toate ca nu cred ca am inteles 100% problema ta. De ce? Pai pui o intrebare si ai raspunsul in textul intrebarii.1. Fpga trimite un semnal la Arduino cand a pornit.2. Arduino incepe sa puna secunde (stii cum transformi ore/minute in secunde) intr-un contor.3. Transferi contorul in Fpga cat de des ai nevoie.4. Fpga decide sa se opreasca. Arduino goleste contorul si asteapta un alt semnal de pornire de la Fpga.PS: nu poti lega DS direct la Fpga? DS va fi mereu ON sau il resetezi la fiecare pornire Fpga, nu conteaza.

Link spre comentariu

Salut,

 

Daca ai nevoie de o acuratete mare atunci nu folosi DS1307. 

Decat sa utilizezi DS1307, poti folosi un Arduino care are cuartz (nu rezonator ceramic) cu functia millis().

Eventual foloseste DS3231 care este mult mai precis decat DS1307.

 

Un exemplu pentru Arduino folosind functia millis():

/*  Whenever NSTROBE signal becomes LOW, Arduino will start counting seconds in variable 'sec_count'	When NSTROBE signal becomes HIGH, Arduino will send the value of the variable 'sec_count' via UART	(but only if NSTROBE was previously at least once LOW)	and then will clear the counting variable.*/#define NSTROBE 7                       // define the NSTROBE signal on pin 7 of the Arduinounsigned long sec_count = 0;		// variable to count the secondsunsigned long now;			// variable to store the current timeuint8_t flag = 0;			// variable used to assure that we have values sent to PC only after at least one NSTROBE active casevoid setup(){	pinMode(NSTROBE, INPUT_PULLUP); // declare NSTROBE as INPUT and it activates the input pullup for noise imumnity on the NSTROBE line	Serial.begin(115200);		// init of the UART library	}void loop(){	now = millis();			// store the current time	while (1)	{		if (!digitalRead(NSTROBE))		{			if ((millis() - now) >= 1000)			{				sec_count++;		// increment the seconds counter variable						// cli();		// disable interrupts				now = millis();		// store the current time as a value to be used in the next loop				// sei();		// enable interrupts				flag = 1;			}		}		else		{			if ((Serial.available() == 1) && (flag == 1))			{				flag = 0;						Serial.println(sec_count);	// send the values to PC				sec_count = 0;			}		}	}}
Editat de mars01
Link spre comentariu

Un alt exemplu pentru Arduino (AVR) folosing intreruperi, port manipulation si fara functiile clasice setup() si loop().

Am introdus si un blink cu LED-ul de pe pinul 13. Perioada este de 2sec, 1sec ON, 1sec OFF.

Acest semnal se poate folosi pentru a spune FPGA-ului cand s-a terminat o secunda. Poate sa apara o eroare de - 1secunda functie de cand semnalul de control NSTROBE de pe pinul 7 Arduino devine HIGH (inactiv).

/*  Whenever NSTROBE signal (pin 7 on Arduino) becomes LOW, Arduino will start counting seconds in variable 'sec_count'When NSTROBE signal becomes HIGH, Arduino will send the value of the variable 'sec_count' via UART(but only if NSTROBE was previously at least once LOW)and then will clear the counting variable.*//* The ENABLED and DISABLED states are used to make sure that we enable/disable the TIMER1 only there was a change in the TIMER1 state.*/#define DISABLED 0#define ENABLED  1#include <utildelay.h>#include <HardwareSerial.h>volatile unsigned long sec_count = 0;		// variable to count the secondsuint8_t flag = 0;				// variable used to assure that we have values sent to PC only after at least one NSTROBE active caseboolean last_state = false;boolean toggle = 1;char buf[10];					// buffer to store the seconds as stringvoid init(){	cli();					// disable interrupts	PORTD |= (1 << PD7);			// activates the input pullup for noise imunity on the NSTROBE line (pin 7 on Arduino)	DDRD &= ~(1 << PD7);			// declare NSTROBE as INPUT	//set-up the built in LED to change state on every 1" - this means 1" is ON, 1" is OFF	DDRB |= (1 << PB5);			// AVR pin PB5 (pin 13 Arduino, the one with the built in LED) set as OUTPUT	PORTB &= ~(1 << PB5);			// LED OFF	Serial.begin(115200);			// init of the UART library		//timer 1 setup CTC  interrupt every 1"	TCCR1A = 0;	TCCR1B = 0;	TCNT1 = 0;	OCR1A = 15624;				// ((16*10^16) / 1024) - 1 = 15624 // 1024 is the used prescaler}ISR(TIMER1_COMPA_vect){	sec_count++;	if (toggle == 1)	{		PORTB |= (1 << PB5);		// LED ON		toggle = 0;	}	else	{		PORTB &= ~(1 << PB5);		// LED OFF		toggle = 1;	}}int main(){	init();	while (1)	{		if (!(PIND & (1 << PD7)))	// read the NSTROBE pin		{			_delay_ms(10);		// a little debouncing for noise immunity			if (!(PIND & (1 << PD7)))			{				if (last_state == DISABLED)				{					toggle = 1;		// ensure that at every TIMER1 start the LED will start as ON					TCCR1B |= (1 << WGM12);					TCCR1B |= (1 << CS12) | (1 << CS10);	// set CTC mode and set PRESCALER to 1024					TIMSK1 |= (1 << OCIE1A);		// enable TIMER1 in CTC mode					sei();					last_state = ENABLED;				}				flag = 1;			}		}		else		{			_delay_ms(10);					// a little debouncing for noise immunity			if ((PIND & (1 << PD7)))			// read the NSTROBE pin			{				if (last_state == ENABLED)				{					TCCR1B = 0;			// disable TIMER1 while NSTROBE is inactive					last_state = DISABLED;				}				PORTB &= ~(1 << PB5);			// the LED stays OFF while TIMER1 is disabled				if (flag == 1)				// this flag assure that there will be data transmission only when we have what to transmit				{										itoa(sec_count, buf,10);	// more RAM used - 10 bytes, less FLASH than using directly Serial.print(sec_count)					Serial.println(buf);		// send the values to PC					sec_count = 0;			// clear second counter				}				flag = 0;			}		}	}	return 0;}
Editat de mars01
Link spre comentariu

Si ca sa ma joc, un exemplu in care nu se mai foloseste nici-o functie buit-in a Arduino ceea ce face programul sa fie mult mai rapid. Nu am implementat toata comunicatia UART, doar partea de transmisie.

Memoria FLASH ocupata s-a redus la mai mult de jumatate (960bytes) fata de variantele anterioare iar cea SRAM este ocupata (36 bytes) de cca 6 ori mai putin.

/* NOTE: the UART TX as implemented here works only for ATMEGA328P and the like   (Arduino Uno, Arduino Mini Pro etc).*//*  Whenever NSTROBE signal (pin 7 on Arduino) becomes LOW, Arduino will start counting seconds in variable 'sec_count'When NSTROBE signal becomes HIGH, Arduino will send the value of the variable 'sec_count' via UART(but only if NSTROBE was previously at least once LOW)and then will clear the counting variable.*//* The ENABLED and DISABLED states are used to make sure that we enable/disable the TIMER1 only there was a change in the TIMER1 state.*/#include <utildelay.h>#include <avrinterrupt.h>#define DISABLED 0#define ENABLED  1// defines for UART TX communication#define UART0_STATUS   UCSR0A#define UART0_CONTROL  UCSR0B#define UART0_DATA     UDR0#define UART0_UDRIE    UDRIE0#define UART0_TX_BUFFER_SIZE 16#define UART0_TX_BUFFER_MASK ( UART0_TX_BUFFER_SIZE - 1)#define UART_BAUD_SELECT(baudrate) (((F_CPU)/(baudrate*16L))-1)// end// variable declaration for UART TX communicationstatic volatile unsigned char UART_TxBuf[UART0_TX_BUFFER_SIZE];static volatile unsigned char UART_TxHead;static volatile unsigned char UART_TxTail;// end // UART interrupt functionISR(USART_UDRE_vect){	unsigned char tmptail;	if (UART_TxHead != UART_TxTail) {		/* calculate and store new buffer index */		tmptail = (UART_TxTail + 1) & UART0_TX_BUFFER_MASK;		UART_TxTail = tmptail;		/* get one byte from buffer and write it to UART */		UART0_DATA = UART_TxBuf[tmptail];  /* start transmission */	}	else{		/* tx buffer empty, disable UDRE interrupt */		UART0_CONTROL &= ~(1 << UART0_UDRIE);	}}// end// UART TX communication init functionvoid Serial_init(unsigned long baudrate){	UART_TxHead = 0;	UART_TxTail = 0;	UBRR0H = (unsigned char)((UART_BAUD_SELECT(baudrate)) >> 8);	UBRR0L = (unsigned char)UART_BAUD_SELECT(baudrate);	UART0_CONTROL = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);	UCSR0C = (1 << USBS0) | (3 << UCSZ00);}// end// UART TX communication function for one char write to UARTvoid Serial_write(unsigned char data){	unsigned char tmphead;	tmphead = (UART_TxHead + 1) & UART0_TX_BUFFER_MASK;	while (tmphead == UART_TxTail){		;/* wait for free space in buffer */	}	UART_TxBuf[tmphead] = data;	UART_TxHead = tmphead;	/* enable UDRE interrupt */	UART0_CONTROL |= (1 << UART0_UDRIE);}// end// UART TX communication function for writing strings followed by New line to UARTvoid Serial_println(char *string){	while (*string != '0')	Serial_write(*string++);   // write char's to UART parsing the string until find the 'end of string' char	Serial_write(13);      // write a 'CR' char to UART	Serial_write(10);      // write a 'new line' char to UART}// endvolatile unsigned long sec_count = 0;	// variable to count the secondsuint8_t flag = 0;			// variable used to assure that we have values sent to PC only after at least one NSTROBE active caseboolean last_state = false;boolean toggle = 1;char buf[10];				// buffer to store the seconds as stringvoid init(){	cli();				// disable interrupts	PORTD |= (1 << PD7);		// activates the input pullup for noise imunity on the NSTROBE line (pin 7 on Arduino)	DDRD &= ~(1 << PD7);		// declare NSTROBE as INPUT	//set-up the built in LED to change state on every 1" - this means 1" is ON, 1" is OFF	DDRB |= (1 << PB5);		// AVR pin PB5 (pin 13 Arduino, the one with the built in LED) set as OUTPUT	PORTB &= ~(1 << PB5);		// LED OFF	Serial_init(115200);		// init of the UART library		//timer 1 setup CTC  interrupt every 1"	TCCR1A = 0;	TCCR1B = 0;	TCNT1 = 0;	OCR1A = 15624;			// ((16*10^16) / 1024) - 1 = 15624 // 1024 is the used prescaler}ISR(TIMER1_COMPA_vect){	sec_count++;	if (toggle == 1)	{		PORTB |= (1 << PB5);		// LED ON		toggle = 0;	}	else	{		PORTB &= ~(1 << PB5);		// LED OFF		toggle = 1;	}}int main(){	init();	while (1)	{		if (!(PIND & (1 << PD7)))					// read the NSTROBE pin		{			_delay_ms(20);						// a little debouncing for noise immunity			if (!(PIND & (1 << PD7)))			{				if (last_state == DISABLED)				{					toggle = 1;	// ensure that at every TIMER1 start the LED will start as ON					TCCR1B |= (1 << WGM12);					TCCR1B |= (1 << CS12) | (1 << CS10);	// set CTC mode and set PRESCALER to 1024					TIMSK1 |= (1 << OCIE1A);		// enable TIMER1 in CTC mode					sei();					last_state = ENABLED;				}				flag = 1;			}		}		else		{			_delay_ms(20);		// a little debouncing for noise immunity			if ((PIND & (1 << PD7)))	// read the NSTROBE pin			{				if (last_state == ENABLED)				{					TCCR1B = 0;	// disable TIMER1 while NSTROBE is inactive					last_state = DISABLED;				}				PORTB &= ~(1 << PB5);	// the LED stays OFF while TIMER1 is disabled				if (flag == 1)		// this flag assure that there will be data transmission only when we have something to transmit				{										ltoa(sec_count, buf,10);	// convert the number in long type into a string 					Serial_println(buf);		// send the values to PC					sec_count = 0;			// clear 'seconds' counter				}				flag = 0;			}		}	}	return 0;}
Editat de mars01
Link spre comentariu

Si daca vrei sa salvezi pe PC secundele in format CSV (comma separated values) tot ce trebuie sa faci este sa modifici functia:

// UART TX communication function for writing strings followed by New line void Serial_println(char *string){	while (*string != '0')	Serial_write(*string++);	Serial_write(13);	Serial_write(10);}// end

in acest fel:

// UART TX communication function for writing strings followed by ','void Serial_println(char *string){	while (*string != '0')	Serial_write(*string++);	Serial_write(',');}// end
Editat de mars01
Link spre comentariu

Salut si multumesc de raspunsuri,

 

@thunderer, sa conectez   DS-ul la fpga e complicat din punct de vedere al programarii, de  asta am ales sa il conectez la arduino. In principiu am nevoie   de un counter care sa imi numere secundele  foarte  precis atunci cand primeste un semnal pe un pin si sa transmita la fiecare secunda daca se poate informatia  de timp in pc, fie direct pe serial sau   fie  prin FPGA si apoi  pe serial in pc.

@mars01  multumesc mult de   coduri si  propuneri, o sa le studiez atent si o sa revin cu detalii,

 

Toate cele bune,

Vlad

Link spre comentariu

O baza de timp pe 1 secunda ar ajuta? FPGA-ul va face contorizarea in functie de cand vrea el sa citeasca. Sau ar fi declansatorul pentru baza de timp, daca nu vrei ruleze mereu (ar fi bine sa ruleze mereu pentru stabilitate).

Link spre comentariu

Vlad, daca vrei sa trimiti datele de la Arduino la FPGA, in principiu le poti trimite si paralel. Arduino are 20 de GPIO din care scazi unul pentru semnalul de STROBE si ramai cu 19 pini pe care poti trimite paralel informatia cu numarul de secunde. Dar acest lucru te limiteaza la un numar maxim de 2^19 secunde. Adica 524288 secunde (~ 8738 minute, ~145 ore).

 

Sau trimiti pe bucati informatia (folosesti de ex 8 GPIO si trimiti intai primii 8 biti, apoi urmatorii 8 biti si tot asa). Dar din putinul care il stiu despre FPGA (e in plan o familiarizare cat de curand) serializarea pe FPGA este mai complicata.

 

 

Solutia oferita de @thunderer este mult mai fezabila daca intentionezi sa pui FPGA-ul sa numere. Nu stiu in ce masura se poate, dar teoretic cu divizari multiple ai putea ca din clock-ul FPGA-ului sa scoti un semnal de 1Hz cu care sa incrementezi un numarator construit tot in FPGA. In felul acesta ramai cu totul la nivelul FPGA-ului, te bazazi pe caracteristica sa principala: paralelismul.

Editat de mars01
Link spre comentariu

Nu exclud optiunea bazei de timp externe, la asta m-am gandit initial. Asta ar permite Fpga sa faca si alte operatii, inclusiv un "sleep".

Link spre comentariu

Pai in cazul acesta 15 bistabili D din FPGA cascadati ii pot scoate o frecventa de 1Hz dintr-un oscilator TXCO de 32768 Hz. Iesirea din astia 15 bistabili, adica semnalul de 1Hz poate sa intre intr-un numarator 24bit (adica alti 24 bistabili D), numarator care poate numara pana la 16.777.216, echivalent la ~194zile, care ar trebuie sa fie suficient pentru aplicatii de-ale fizicienilor.

 

Mai complicat o sa fie realizarea modulului UART in FPGA. Desi la o simpla cautare pe GOOGLE, a aparut asta: https://github.com/pabennett/uart

Si daca imparti cei 24biti in 3 grupe (shift la dreapta si AND cu o masca 0x0FF) pe care le trimiti succesiv va trebui sa faci decodarea dupa receptia la PC.

Un link interesant este aici: http://www.edaboard.com/thread167139.html

 

BTW, ai vazut placuta asta, Papilio Duo? Are un FPGA cu un Arduino pe bottom layer (un ATMEGA32).

 

Dar sa termin cu offtopic-ul (topic Arduino si nu FPGA).

Editat de mars01
Link spre comentariu

Salut, tocmai de asta nu am vrut sa  fac acest counter in FPGA, e complicat la programat. Prefer totusi sa incerc ceva cu arduino......FPGA-ul deja are   multicele pe el (o comunicatie  diferentiala bidirectionala, un serial mai  complex, un counter local, niste  buffere  etc....)...

 

Multumesc pentru timp si raspunsuri!

Se pare ca  sunt si fani  FPGA pe acest  forum, pe mine m-au cucerit de cand am inceput  sa implementez  hardware pentru servici o placa cu Kintex 7, iar acum am o placa de dezvoltare cu SPARTAN 6, NEXYS 3,Momentan astept sa prind o scoala de  vara pe FPGA preferabil in  afara ca  sa  invat cate ceva.

Link spre comentariu

DS3231 pe pinul INT/SQW, poate genera, dupa cum este programat, o intrerupere la intervale exacte de timp incepand de la 1secunda pana la o data din viitor. Detalii in datasheet, tabelul din pagina 11.

 

L-am folosit cu succes pentru generarea unei intreruperi care scoate din sleep mode un arduino folosit ca data logger, alimentat pe baterii, la fiecare 15minute. In plus, tot din DS3231 imi iau data si temperatura pentru esantion.    

Link spre comentariu

Sigur, dar in mod default genereaza 8192Hz (cei doi biti de configurare sunt 1 la power-up) pe acel pin. Lucru care necesita o configurare la power-up pentru a scoate acel 1Hz, deci un controller pentru ca ar fi mai complicat sa pui sa faca FPGA-ul acest lucru (ar mai trebui creat un IP cu functia de I2C cu tot bla bla-ul). Si ne intoarcem la Arduino in acest fel.

Care Arduino s-ar putea sa ofere de unul singur acel 1Hz cu precizia necesara.

 

In varianta utilizarii FPGA ar putea fi folosita iesirea care genereaza cei 32768Hz (default la power-up) avand in vedere ca DS3231 contine un TXCO foarte precis, care are si compensare functie de temperatura.

Editat de mars01
Link spre comentariu

Este clar ca DS3231 trebuie setat ca data, tip alarma ...cu un arduino o singura data la prima pornire. 

Apoi poate functiona independent, in modul setat, pe o baterie CR2032 mult si bine. 

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