Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

il mio primo Frequenzimetro

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

0
voti

[1] il mio primo Frequenzimetro

Messaggioda Foto Utentesobrano » 14 dic 2014, 19:54

Salve ho scritto il mio primo codice per un frequenzimetro fatto con ATmega32 (per ora l ho solo simulato e tutto sembra funzionare.) vi posto il codice che ho scritto, potete dirmi se c e da migliorare qualcosa?
sono alle prime armi e non sono ancora molto esperto...

Cio che mi disturba di piu e' che devo contare gli impulsi del segnale da misurare con il registro a 8bit perche la finestra temporale di 1s non potrei proprio farla con il registro a 8bit neanche con il prescaler massimo 1024.

prima di postarvi il codice vorrei farvi un paio di domande:
- quale' la frequenza massima che posso inviare dentro il microcontrollore?
- il pin T0 mi conta gli impulsi del segnale da misurare, ma che tensione deve avere il segnale di ingresso per poter essere contato?
- mi conviene usare un oscillatore al quarzo a 16Mhz? oppure uno piu lento magari da 4Mhz?


ecco il codice ben commentato:

Codice: Seleziona tutto
#undef F_CPU
#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd_stefano.h"

static volatile int signal_overflow = 0; //variabile da usare nell'ISR che rappresenta il numero di overflow del Timer/Counter0 (ovvero 256 impulsi del segnale da misurare)
static volatile int frequenza = 0;

int main()
{
   LCD8_Initialization();
   
   DDRB &= ~(1<<PINB1);
   TCCR0 |= 1<<CS00 | 1<<CS01 | 1<<CS02; //imposto la modalita "External clock source on T0 pin" il TCNT0(8 bits: 0-255) tiene conto degli impulsi del segnale da misurare
   TCCR1B |= 1<<CS10 | 1<<CS11; //imposto il prescaler del Timer/Counter1 a 64
   TCCR1B |= 1<<WGM12; //attivo il mode CTC ovvero "Clear to Compare". Questo azzera il contatore TCNT1 quando viene raggiunto l' OCR1A
   TIMSK |= 1<<TOIE0; //ablito l'interrupt per overflow del Timer/Counter0 perche contero gli impulsi della frequenza da misurare con il TCNT0 che arriva fino a 255 e contero il numero di overflow in 100ms per sapere la frequenza
   TIMSK |= 1<<OCIE1A; //abilito l'interrupt per compare match con l'OCR1A del Timer/Counter1. Quando il TCNT1 raggiunge l'OCR1 vuol dire che e' passata la finestra temporale scelta in cui contare gli impulsi del segnale e dare la frequenza.
   
   OCR1A = 25000; //Il TCNT1 arriva a 25000 dopo 100ms perche siamo a 16MHz con prescaler 64 quindi: 16.000.000/64 = 250.000 impulsi in 1 secondo => 25.000 ogni 100ms
   
   SendString("frequenza");
   SetCursorPosition(1,8); SendString("Hz");
   
   sei();
   
    while (1)
   {
     
   }
   return 0;
}

ISR(TIMER0_OVF_vect)//interrupt routine quando abbiamo un evento di overflow del TCNT0 (Timer/Counter0) ovvero quando sono stati contati 256 impulsi del segnale da misurare
{
    signal_overflow++;
}
ISR(TIMER1_COMPA_vect)//interrupt routine per compare match, quando il contatore TCNT1 diventa uguale all'OCR1A. (ovvero quando sono passati 100ms)
{
    frequenza = (signal_overflow*256+TCNT0)*10;
    TCNT0 = 0; //quindi azzero il contatore TCNT0 e la variabile che tiene conto degli overflow
    signal_overflow = 0; //azzero tutto cio che riguarda la vecchia misura di frequenza
    SetCursorPosition(1,0); //scrivo su LCD
    SendInteger(frequenza,6);
   
}
Avatar utente
Foto Utentesobrano
5 2
 
Messaggi: 26
Iscritto il: 11 nov 2014, 11:26

0
voti

[2] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesimo85 » 14 dic 2014, 23:52

sobrano ha scritto:- quale' la frequenza massima che posso inviare dentro il microcontrollore?
- il pin T0 mi conta gli impulsi del segnale da misurare, ma che tensione deve avere il segnale di ingresso per poter essere contato?
- mi conviene usare un oscillatore al quarzo a 16Mhz? oppure uno piu lento magari da 4Mhz?


La risposta alle domande 1 e 2 è nel datasheet. Cerca nella sezione 'Electrical Characteristics' dovrebbero essere elencati i valori minimi e massimi a seconda della tensione di alimentazione.

Per l'oscillatore ovviamente meglio da 16 MHz, anche se consuma di più.
Avatar utente
Foto Utentesimo85
30,9k 7 12 13
Disattivato su sua richiesta
 
Messaggi: 9927
Iscritto il: 30 ago 2010, 4:59

0
voti

[3] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesobrano » 15 dic 2014, 20:46

Salve sono di fronte a un bel problema e non so come risolverlo.

Sono passato al progetto reale e ho programmato l'ATmega32 ma purtroppo ho problemi con l'LCD che non ne vuole sapere di scrivere bene i caratteri che gli invio.

Premetto che con l'oscillatore interno settato a 1Mhz tutto funziona benissimo (misuro la frequenza molto bene e la vedo scritta bene sull'LCD) ma se scrivo i fuse per impostare l'oscillatore interno a 4MHz l'LCD non scrive piu bene i caratteri.
Eppure io ho inserito un led nel progetto per vedere se lampeggia bene ed in effetti con _delay_ms(1000) mi lampeggia perfettamente a 1 secondo (quindi i fuse sono impostati bene e il #define 4000000UL nel compilatore e nel makefile e' impostato bene credo)

la cosa bizzarra e' che una cosa simile mi era successa anche con il simulatore proteus8 in cui l'LCD scriveva degli strani caratteri tutti sconfusionati quando aumentavo la frequenza di clock. Nel caso del simulatore ho risolto cliccando con il pulsante destro sull'LCD e impostando clock frequency 4MHz.

Nella realta non posso ovviamente fare questa operazione e sul datasheet non mi sembra ci sia scritto nulla per impostare il clock.

Potete aiutarmi?

grazie
Avatar utente
Foto Utentesobrano
5 2
 
Messaggi: 26
Iscritto il: 11 nov 2014, 11:26

1
voti

[4] Re: il mio primo Frequenzimetro

Messaggioda Foto UtenteFedericoSibona » 15 dic 2014, 21:05

Scusa l'OT, ma il titolo mi ha fatto venire in mente Il mio primo frequenzimetro che è stato questo :mrgreen: :mrgreen:
frequencymeter_high_kit_uk_550_1082765.jpg
frequencymeter_high_kit_uk_550_1082765.jpg (28 KiB) Osservato 6489 volte
Avatar utente
Foto UtenteFedericoSibona
5.022 3 5 8
Master
Master
 
Messaggi: 3951
Iscritto il: 19 mar 2013, 11:43

0
voti

[5] Re: il mio primo Frequenzimetro

Messaggioda Foto Utenteedgar » 15 dic 2014, 21:48

sobrano ha scritto:Sono passato al progetto reale e ho programmato l'ATmega32 ma purtroppo ho problemi con l'LCD che non ne vuole sapere di scrivere bene i caratteri che gli invio.

Premetto che con l'oscillatore interno settato a 1Mhz tutto funziona benissimo (misuro la frequenza molto bene e la vedo scritta bene sull'LCD) ma se scrivo i fuse per impostare l'oscillatore interno a 4MHz l'LCD non scrive piu bene i caratteri.

Probabilmente c'e' un problema con le temporizzazioni del display.
Avatar utente
Foto Utenteedgar
10,0k 4 5 8
Master
Master
 
Messaggi: 5229
Iscritto il: 15 set 2012, 22:59

0
voti

[6] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentespud » 15 dic 2014, 22:00

Stai usando la libreria display di arduino? Probabilmente le tue impostazioni dei timer confliggono con quelle che si aspetta la libreria.
Atlant.

Behind every great man is a woman rolling her eyes.
Avatar utente
Foto Utentespud
3.767 3 10 12
free expert
 
Messaggi: 1601
Iscritto il: 1 feb 2012, 14:26
Località: Udine

0
voti

[7] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesobrano » 15 dic 2014, 22:22

sto usando una libreria scritta da me (in realta l'ho copiata da un video tutorial su newbiehack.com) e ha sempre funzionato bene.

Durante la fase di inizializzazione in effetti ci sono dei delay da impostare e che io ho impostato in base al datasheet del mio display LCD.

Sospettando appunto come dici un problema di delay ho provato a quadrupicarli tutti ( dato che a 1mhz funzionava) ma non e' cambiato nulla. Ho anche provato ad inserire qualche ritardo esagerato qua e la per essere sicuro che l'LCD non riceveva informazioni troppo rapidamente ma niente.
Avatar utente
Foto Utentesobrano
5 2
 
Messaggi: 26
Iscritto il: 11 nov 2014, 11:26

0
voti

[8] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesimo85 » 15 dic 2014, 22:34

Non sono molto pratico con gli LCD, ma il datasheet dell' LCD cosa dice riguardo ai tempi ?
Avatar utente
Foto Utentesimo85
30,9k 7 12 13
Disattivato su sua richiesta
 
Messaggi: 9927
Iscritto il: 30 ago 2010, 4:59

0
voti

[9] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesobrano » 15 dic 2014, 23:35

il datasheet non accenna nulla sullle frequenze, da ovviamente i ritardi in ms per la fase di inizializzazione che ho rispettato e che dicendo al compilatore F_CPU = 4000000UL dovrebbero rimanere validi :cry:

comunque l'LCD e quello dello starter kit di arduino uno per cui credo possa lavorare a 16mhz dato che arduino uno monta un quarzo a 16mhz

http://arduino.cc/documents/datasheets/ ... 2B-TMI.pdf



comunque ecco la libreria che ho scritto e tengo in un file separato .h che durante la compilazione si trova nella stessa cartella del main

Codice: Seleziona tutto
#ifndef lcd_stefano
#define lcd_stefano 


#define LCD_DataPort       PORTC
#define LCD_DataPortDDR      DDRC
#define LCD_ControlPort            PORTD
#define LCD_ControlPortDDR    DDRD
#define RS                         PIND2
#define EN                         PIND5
#define RW                 PIND7


#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>


//prototipi
void LCD8_Initialization(void); //inizializazione LCD per la modalita a 8Bit (uso tutti e 8 i pin dati D0...D7)
void Check_if_busy(void);
void LCD_Enable(void); //abilita l'LCD per una brevissima finestra temporale
void SendCharacter(unsigned char character);
void SendCommand(unsigned char command);
void SendString(char *string);
void SendInteger(int integer, int number_of_digits);
void ClearDisplay(void);
void SetCursorPosition(uint8_t row, uint8_t col);


void LCD8_Initialization(void)
{
    LCD_ControlPortDDR |= 1<<RS | 1<<RW | 1<<EN; //i pin di controllo saranno sempre in uscita
    _delay_ms(50); // primo lungo delay all'accensione
    SendCommand(0b00111100); //Data Length: 8bit,2lines,font5x11dots. Ultimi 2 bits non influenti
    _delay_us(40);
    SendCommand(0b00111100); //Ripetizione del Data Length come specificato nel datasheet
    _delay_us(38);
    SendCommand(0b00001110);
    _delay_us(40);
    SendCommand(0x01); //Display Clear
    _delay_ms(2);
    SendCommand(0b00000110); //Entry Mode: incremento posizione cursore, no shift dell'intero display
    _delay_us(40);
}

void Check_if_busy(void)
{
    LCD_DataPortDDR = 0; //devo impostare la porta dati in entrata per ricevere dall'LCD la flag di busy
    LCD_ControlPort |= 1<<RW; //RW=1, leggo dall'LCD
    LCD_ControlPort &= ~(1<<RS); //RS=0, trasferimento comando
    while (LCD_DataPort >= 0x80) //finche l'LCD e' occupato
    {
       LCD_Enable();
    }
    LCD_DataPortDDR = 0xFF; //rimetto la porta dati tutta in uscita pronta per inviare dati all'LCD
}

void LCD_Enable(void)
{
    LCD_ControlPort |= 1<<EN; //EN=1
    asm volatile ("nop");
   asm volatile ("nop");
   //_delay_ms(1);
    LCD_ControlPort &= ~(1<<EN); //EN=0
}

void SendCharacter(unsigned char character)
{
    Check_if_busy();
    LCD_ControlPort &= ~(1<<RW); //RW=OFF (write to LCD)
    LCD_ControlPort |= 1<<RS; //RS=ON (trasferimento dati)
    LCD_DataPort = character;
    LCD_Enable();
    LCD_DataPort = 0;
}

void SendCommand(unsigned char command)
{
   Check_if_busy();
   LCD_ControlPort &= ~(1<<RW); //RW=OFF (write to LCD)
   LCD_ControlPort &= ~(1<<RS); //RS=OFF (trasferimento comandi)
   LCD_DataPort = command;
   LCD_Enable(); //apri la finestrella di LCD abilitato
   LCD_DataPort = 0; //metto a 0 la porta dati credo per risparmiare energia, il dato e' stato letto durante la
                              //finestrella di LCD_Enable() ed ora che e' chiusa l'LCD non legge piu nulla dalla porta dati
}

void SendString(char *string)
{                           

    while(*string > 0) //finche' l'allocazione di memoria non e' vuota
    {
        SendCharacter(*string++);                                   
    }
}

void SendInteger(int integer,int number_of_digits)
{
   char string_of_integer[number_of_digits];
   itoa(integer,string_of_integer,10);
   SendString(string_of_integer);
}

void ClearDisplay(void)
{
    SendCommand(0x01); //Display Clear
    _delay_ms(2);
}

char FirstColumnAddress[2] = {0,64}; //array di caratteri che identificano gli indirizzi delle prime posizioni delle due righe questo array serve per la funzione SetCursorPosition()
                                   
void SetCursorPosition(uint8_t row, uint8_t col)
{
    SendCommand(0x80+FirstColumnAddress[row]+col); //parto dal primo indiritto 0x80 e aggiungo 0 nel caso della riga 0 e 64 nel caso della riga 1
                                               
}

#endif


È la seconda volta che ti inserisco il codice tra i tag code. La prossima volta usali grazie,
Avatar utente
Foto Utentesobrano
5 2
 
Messaggi: 26
Iscritto il: 11 nov 2014, 11:26

0
voti

[10] Re: il mio primo Frequenzimetro

Messaggioda Foto Utentesobrano » 15 dic 2014, 23:45

mi chiedo se sono le due istruzioni

asm volatile ("nop");
asm volatile ("nop");

che creano problemi..
Avatar utente
Foto Utentesobrano
5 2
 
Messaggi: 26
Iscritto il: 11 nov 2014, 11:26

Prossimo

Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 11 ospiti