semih_s
Hobici
- Katılım
- 16 Aralık 2020
- Mesajlar
- 1,965
Bir süredir boş vaktimde uğraştığım proje. Devreyi tamamladım ve dizgisini yaptım. Birazdan da kartı basacağım.
Edit: Aşağıdaki şema ve fotoğraflar projenin güncel durumudur. birkaç ufak değişiklik ve geliştirme oldu.
TL431 ile bir transistörü sabit akım kaynağı olarak düzenledim. Bu sabit akımı değiştirerek kademeler arasında geçiş yapılabiliyor. Ekran seçmedim. Şimdilik tek bir 4 basamaklı 7 segment led display kullanmayı düşünüyorum.
Cihazın beyni Atmega88-168 veya 328 olabilecek. 8 mhz dahili osilatörle çalışacak ve arduino olacak. Ekran için ayrıca spi ve i2c çıkışları da yerleştirdim. UART çıkışı da ekledim. Cihazda tuş yok, kalibrasyon için arduino serial monitor ile çalışacak bir arayüz koymayı düşünüyorum. Ölçümü high-side sensing ile INA180B1 akım monitörü ile yapıyorum.
Cihazda kalibrasyon sonrası %1'den daha iyi bir isabetlilik bekliyorum. Hem INA180'in çıkışının gnd'yi tam olarak giremeyecek olmasından, hem de ADC'nin olası kusurlarından tahminimce 10-15mOhm altını düzgün ölçemeyecek. Zaten 10mOhm ölçecek olsa da bu pek işe yarar bir ölçüm olmaz, çünkü en düşük kademede 1-2 mOhm gibi bir çözünürlükle olduğundan %10'dan an daha kötü bir isabetlilik olur.
Relatif ölçüm için tuş gerekli ama bunun yerine cihazı inputlar kısa devre iken açarak kullanmayı düşündüm, Olmadı kullanılmayan uart-spi-i2c headerların birine tuş iliştiririm.
Uğraşmak isteyenler için simulasyonun çalıştığı proje dosyasını da ekleyeyim.
Edit:
Alete yazıcıdan kutu basmak veya hazır kutu kesip delip yerleştirmek zor geldi. Eski bir telefonun piline silikon bantla yapıştırdım. Durum aşağıda görünüyor. Tırnak parlatıcısıyla yolları izole ettim. Bir pakete iliştirip bıraksam panik yaratacak bir görüntüsü oldu. Bununla yakın zamanda daha fazla uğraşacağımı sanmıyorum...
Ekrandaki çizgiler pil durumunu gösteriyor, pil durumunu ölçüm dışı direnç takıldığında yada ölçüm yapılmadığında gösteriyor. Fotoğraftaki durum pilin %50 civarı olduğu hal.
Aşağıda 7 segment ekranın 74HC595 ile çalışan devresi de var. Pdf olarak toner transfere hazır dosya da ekte. Tam ödevlik yani . Proje dosyası da ekte. Segmentlerin bacaklara göre dağılımı farklı displayler için kodda konfigürasyon kısmı var.
Kod aşağıdaki gibi. Biraz frankeştayn gibi (frankeştayn doktor ama yaratığın adı yokmuş yapacak bir şey yok)
Edit: Aşağıdaki şema ve fotoğraflar projenin güncel durumudur. birkaç ufak değişiklik ve geliştirme oldu.
TL431 ile bir transistörü sabit akım kaynağı olarak düzenledim. Bu sabit akımı değiştirerek kademeler arasında geçiş yapılabiliyor. Ekran seçmedim. Şimdilik tek bir 4 basamaklı 7 segment led display kullanmayı düşünüyorum.
Cihazın beyni Atmega88-168 veya 328 olabilecek. 8 mhz dahili osilatörle çalışacak ve arduino olacak. Ekran için ayrıca spi ve i2c çıkışları da yerleştirdim. UART çıkışı da ekledim. Cihazda tuş yok, kalibrasyon için arduino serial monitor ile çalışacak bir arayüz koymayı düşünüyorum. Ölçümü high-side sensing ile INA180B1 akım monitörü ile yapıyorum.
Cihazda kalibrasyon sonrası %1'den daha iyi bir isabetlilik bekliyorum. Hem INA180'in çıkışının gnd'yi tam olarak giremeyecek olmasından, hem de ADC'nin olası kusurlarından tahminimce 10-15mOhm altını düzgün ölçemeyecek. Zaten 10mOhm ölçecek olsa da bu pek işe yarar bir ölçüm olmaz, çünkü en düşük kademede 1-2 mOhm gibi bir çözünürlükle olduğundan %10'dan an daha kötü bir isabetlilik olur.
Relatif ölçüm için tuş gerekli ama bunun yerine cihazı inputlar kısa devre iken açarak kullanmayı düşündüm, Olmadı kullanılmayan uart-spi-i2c headerların birine tuş iliştiririm.
Uğraşmak isteyenler için simulasyonun çalıştığı proje dosyasını da ekleyeyim.
Edit:
Alete yazıcıdan kutu basmak veya hazır kutu kesip delip yerleştirmek zor geldi. Eski bir telefonun piline silikon bantla yapıştırdım. Durum aşağıda görünüyor. Tırnak parlatıcısıyla yolları izole ettim. Bir pakete iliştirip bıraksam panik yaratacak bir görüntüsü oldu. Bununla yakın zamanda daha fazla uğraşacağımı sanmıyorum...
Ekrandaki çizgiler pil durumunu gösteriyor, pil durumunu ölçüm dışı direnç takıldığında yada ölçüm yapılmadığında gösteriyor. Fotoğraftaki durum pilin %50 civarı olduğu hal.
Aşağıda 7 segment ekranın 74HC595 ile çalışan devresi de var. Pdf olarak toner transfere hazır dosya da ekte. Tam ödevlik yani . Proje dosyası da ekte. Segmentlerin bacaklara göre dağılımı farklı displayler için kodda konfigürasyon kısmı var.
Kod aşağıdaki gibi. Biraz frankeştayn gibi (frankeştayn doktor ama yaratığın adı yokmuş yapacak bir şey yok)
Ohmmetre INA180:
/*Ohmmetre_ina180B1_V2 için firmware
Atmega88-168-328 ile çalışır
*/
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>
// SPI ile 7segment sürmek için tamımlamalar
#define DDR_SPI DDRB //
#define PORT_SPI PORTB //
#define SPI_SCK PINB5 //
#define SPI_MOSI PINB3 //
#define SPI_SS PINB2 //
#define LATCH_DDR DDRD
#define LATCH_PORT PORTD
#define LATCH_PIN PIND
#define LATCH_PIN_NO 3
#define LATCH_H (LATCH_PORT|=1<<LATCH_PIN_NO)
#define LATCH_L (LATCH_PORT&=~(1<<LATCH_PIN_NO))
#define LATCH_L_H_L LATCH_L;LATCH_H;LATCH_H;LATCH_L;LATCH_L
// anot veya katod display seçimi (KATOT İÇİN DENENMEDİ ve düzenlenmedi -Work In Progress)
#define ANOT
/**
7SEGMENTS
A
F B
G
E C
D DP
**/
// hangi segmentin hangi "595" bacağına bağlandığı
/*
14-|"U" |- 74HC595
13-| |-15
12-| |-
11-| |-
10-| |-
9-| |-
8-| |-
GND -|.......|-Q'------|
|
6-|''U''|- |
5-| |-7 |
4-| |-D_in----|
3-| |-
2-| |-
1-| |-
0-| |-
GND-|.......|-
*/
// Segment ve basamakların hc595 bağlantıları yukarıdaki şemaya göre
// bit shift operatörünün sağı değiştirilecek, hangi segmentin
// hangi bacağa bağlı olduğuna göre
#define A 1<<12
#define B 1<<0
#define C 1<<6
#define D 1<<4
#define E 1<<2
#define FS 1<<14
#define G 1<<3
#define DP 1<<5
// basamaklar için sadece pin konumu
#define D0 1<<13//en yüksek basamak
#define D1 1<<11
#define D2 1<<15
#define D3 1<<1 //en düşük basamak
#define R0 (A|B|C|D|E|FS)
#define R1 (B|C)
#define R2 (A|B|G|E|D)
#define R3 (A|B|G|C|D)
#define R4 (B|C|G|FS)
#define R5 (A|FS|G|C|D)
#define R6 (A|FS|G|C|D|E)
#define R7 (A|B|C)
#define R8 (A|B|C|G|E|D|FS)
#define R9 (A|B|C|D|FS|G)
// seg[i]: binary olarak "i" rakamının gösterimi için
// açılacak segmentlerin hc595'in bacaklarında isabet ettiği yerler
// seg[10] ve seg[11] pil seviye gösterimi için
int16_t seg[12]={~R0,~R1,~R2,~R3,~R4,~R5,~R6,~R7,~R8,~R9,~(G),~(D)};
// basamak maske değişkeni
int bas_maske[5]={(D3)|~(D0|D1|D2|D3) , (D2)|~(D0|D1|D2|D3) , (D1)|~(D0|D1|D2|D3) , (D0)|~(D0|D1|D2|D3) , ~(D0|D1|D2|D3) };
// gösterilecek sayının basamak değerleri için ve nokta pozisyonu için
byte b_degeri[12],nokta;
#define KADEME100 5
#define KADEME10 6
#define KADEME1 7
#define PIL A6
#define DIRENC A0
int disp[8];
byte asama,j,kademe,ADC_reset;
unsigned long t0,t1,t2;
int gost[8];
int adc_seri[128],a_i,ADC_bayrak,pil_seviyesi;
int pil_full=618;
int pil_bos=480;
int buff;
float top,ort;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Kalibrasyon katsayıları>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Bu katsayılar her kademe için ilgili değerde (1-10-100 Ohm) direnç ile ölçüm yaparak belirlenir
// kalibrasyon için %1'lik bir grup direnç içinden ölçülerek seçilmiş ortalama değerde bir
// direnç ile kalibrasyon yapmak %1'den iyi bir doğruluk yakalanmasını sağlar.
float kal_kademe1=1.051;
float kal_kademe10=1.051;
float kal_kademe100=1.075;
void timer2_init(void);
void getADC(byte kanal);
void kademe_sec(byte k);
void SPI_MasterInit(void);
void disp_sur (void);
void dumpADC (void);
void basamak(int16_t sayi);
void disp_set (void);
void dac_yaz (uint16_t deger);
ISR(TIMER2_COMPA_vect)
{
disp_sur();
}
/*
ISR(ADC_vect) // hareketli ortalama
{
ADC_bayrak++;
top+=ADC;
if(a_i>126)
{
a_i=0;
}
}
*/
void setup()
{
analogReference(INTERNAL);
pinMode(KADEME100,OUTPUT);
pinMode(KADEME10,OUTPUT);
pinMode(KADEME1,OUTPUT);
LATCH_DDR|=1<<LATCH_PIN_NO;
SPI_MasterInit();
kademe_sec(KADEME100);
timer2_init();
sei();
}
void loop()
{
if(kademe==0) // başlangıç
{
}
if(kademe==KADEME1)
{
if(millis()>(t0+500))
{
t0=millis();
getADC(DIRENC);
buff=round(ort*kal_kademe1);
if(ort>=1021)kademe_sec(KADEME10);
else
{
basamak(buff);
disp_set();
}
}
}
if(kademe==KADEME10)
{
if(millis()>(t0+500))
{
t0=millis();
getADC(DIRENC);
buff=round(ort*kal_kademe10);
if(ort<=103)kademe_sec(KADEME1);
else if(ort>=1020)kademe_sec(KADEME100);
else
{
basamak(buff);
disp_set();
}
}
}
if(kademe==KADEME100)
{
if(millis()>(t0+500))
{
t0=millis();
getADC(DIRENC);
buff=round(ort*kal_kademe100);
if(ort>=1020)// ölçüm dışı yüksek direnç
{
// pil ölç ve oranla 4 basamakta seviyeyi göster
// Pil seviyesi full:"----" %75:"---_" %50:"--__" %25: "-___" düşük: "_____"
if(millis()>=t1+100)
{
t1=millis();
analogRead(PIL);
pil_seviyesi=(analogRead(PIL)-pil_bos)/24;
if(pil_seviyesi>3)
{
for(byte i=0;i<4;i++)
{
disp[i]=(seg[10]&bas_maske[i]);
}
}
else if(pil_seviyesi>2)
{
for(byte i=1;i<4;i++)
{
disp[i]=(seg[10]&bas_maske[i]);
}
disp[0]=(seg[11]&bas_maske[0]);
}
else if(pil_seviyesi>1)
{
for(byte i=2;i<4;i++)
{
disp[i]=(seg[10]&bas_maske[i]);
}
for(byte i=0;i<2;i++)
{
disp[i]=(seg[11]&bas_maske[i]);
}
}
else if(pil_seviyesi>0)
{
for(byte i=3;i<4;i++)
{
disp[i]=(seg[10]&bas_maske[i]);
}
for(byte i=0;i<3;i++)
{
disp[i]=(seg[11]&bas_maske[i]);
}
}
else
{
for(byte i=0;i<4;i++)
{
disp[i]=(seg[11]&bas_maske[i]);
}
}
}
}
else
{
basamak(buff);
disp_set();
}
}
if(ort<100)kademe_sec(KADEME10);
}
}
void kademe_sec(byte s)
{
kademe=s;
switch (s)
{
case KADEME100:
digitalWrite(KADEME100,HIGH);
digitalWrite(KADEME10,LOW);
digitalWrite(KADEME1,LOW);
nokta=1;
break;
case KADEME10:
digitalWrite(KADEME10,HIGH);
digitalWrite(KADEME1,LOW);
digitalWrite(KADEME100,LOW);
nokta=2;
break;
case KADEME1:
digitalWrite(KADEME1,HIGH);
digitalWrite(KADEME10,LOW);
digitalWrite(KADEME100,LOW);
nokta=3;
break;
default:
digitalWrite(KADEME100,HIGH);
digitalWrite(KADEME10,LOW);
digitalWrite(KADEME1,LOW);
break;
}
delay(1000);
}
void getADC(byte kanal)
{
top=0;
analogRead(kanal);
analogRead(kanal);
analogRead(kanal);
for(byte i=0;i<33;i++)
{
adc_seri[i]=analogRead(kanal);
top+=adc_seri[i];
ort=top/33;
}
}
void dumpADC (void)
{
Serial.println(F("ADC okumaları"));
for(byte i=0;i<128;i++)
{
Serial.print(i);
Serial.print(". ");
Serial.println(adc_seri[i]);
}
}
void disp_set (void)
{
uint8_t i=0;;
for(i=0;i<4;i++)
{
// gösterilecek segmentleri aç | bütün basamakları kapat & gösterilecek basamağı aç
// i=0: 100 binler basamağı, i=5: 1'ler basamağı
disp[i]=0;
disp[i]= ( seg[b_degeri[i]] & bas_maske[i]);
}
disp[nokta]&=~(DP);//dot_maske;
}
void basamak(int16_t sayi)//basamakları hesaplar basamak değerlerini b[i] array değişkene atar ve 7segment display için binary registerlarını tayin eder
{
uint8_t i;
{
gost[0]=sayi;
for(i=0;i<5;i++)//bas:basamak sayısını mod için yardımcı değerleri hesaplar
{
gost[i+1] = gost[i]/10;
//if(gost[i+1]==0)i=4;
}
for(i=0;i<6;i++)// 10^i basamağının değerlerini hesaplar
{
b_degeri[i] = gost[i]-gost[i+1]*10;
}
}
}
void disp_sur (void)
{
switch(asama)
{
case 0:
LATCH_H;// en son gönderilen disp değerini shift reg çıkışlarına yansıtma
// en düşük bitten başlanıyor, gönderime alt 8 biti gönderme
SPDR = 0xff&disp[j];
asama++;
break;
case 1:
LATCH_L;
SPDR=disp[j]>>8;
asama=0;
j++;//basamak takip değişkeni
if(j>3)//altıncı basamaktan sonra başa döner
{
j=0;
}
break;
default: asama=0;j=0;
}
}
void SPI_MasterInit(void)
{
// Set MOSI and SCK output, all others input
DDR_SPI = (1<<SPI_SCK)|(1<<SPI_MOSI)|(1<<SPI_SS);
SPCR = (1<<SPE)|(1<<MSTR)|(1<<DORD);
//SPSR|=1<<SPI2X;
}
void dac_yaz (uint16_t deger)
{
//Bu fonksiyon çağrıldığında spi birimi 16bitin tamamını gönderene kadar mcu meşgul olur.
//Bunun yerine >> while (!(SPSR & (1<<SPIF))); << kodları kaldırılıp loop içinde belli bir periyotta sürekli
//transfer tamamlanma kontrolü yapıp, tamamlandıysa SPI registerine gönderilecek veri yazılabilir.
// 8 bitte bu çok kolay olsa da 16 bit için hc595 latch pini de toggle edileceğinden sekansı dikkatli ayarlamak gerekir.
// en düşük bitten başlanıyor, gönderime alt 8 biti gönderme
SPDR = 0xff°er;
while (!(SPSR & (1<<SPIF)));
SPDR=deger>>8;
while (!(SPSR & (1<<SPIF)));
LATCH_L_H_L;// en son gönderilen disp değerini shift reg çıkışlarına yansıtma
}
void timer2_init(void)
{
TCCR2A=0;
TCCR2B=0;
TCCR2A|=1<<WGM21; // CTC mod
TCCR2B|=0b111; // prescaler 1024
TIMSK2|= 1<<OCIE2A; // Compare interrupt 2A CTC için
OCR2A=20;
}
void ADC_init(void)
{
ADMUX=0;
ADMUX|= 1<<REFS1|1<<REFS0;
ADCSRA=0;
ADCSRA|=1<<ADEN | 1<<ADATE | 0b110 ;
}
void ADC_kanal_sec(byte kanal)
{
ADC_reset=1; // adc buffer array değişkenini sıfırlamak için bayrak
if(kanal<8)
{
ADMUX=~(0b1111); //
ADMUX|=kanal;
}
}
Ekler
Son düzenleme: