Kilometre sayacı ve hız göstergesi

semih_s

Kıdemli Üye
Katılım
16 Aralık 2020
Mesajlar
1,455
96 model bir iveco 35-9'un muayeneden geçmesi için kilometre saatinin "de" çalışıyor olması gerekiyor. Malesef kilometre teli binlerce kilometrre önce yerinden çıkmış ve şanzımana bağlı naylon dişliler tozdan bozulmuş, metal dişli paslanmış ve yüzeyi bozulmuş.

IMG20220626143241.jpg
IMG20220621205123.jpg

Bu parçaların yenisini bulamadı usta. Çıkmaları da şanzımanla beraber vermek istiyorlar ya da fiyat çok yüksek oluyor. Ben de hız göstergesini stepper, kilometre sayacını 7 segmentle yapmaya karar verdim. Bunu bu model araçla yapmak mümkün, çünkü sürücü kartı ve takometre kullanım zorunluluğunun altında kalıyor araç sınıfı. Aslında harcayacağım zamanı düşününce bu hiç ekonomik değil. Amaç da tamamen ekonomi değil.

Gösterge yeterince büyük ve derin.
IMG20220621205053.jpg
IMG20220622171219.jpg




Kilometre sayacı için uygun 7 segmenti Aliexpres'te buldum ama beklemek istemiyorum ve biraz daha büyük de olsa özdisanda buldum. 4 basamak iki displayi kullanıp göstergedeki kesiği biraz büyüteceğim ve sadece 6 basamak gösterceğim orjinalindeki gibi.



IMG20220626150216.jpg

Kırmızı işaretlediğim yere küçük bir opto-interrupter koyup her kontak açılışında referansa çekeceğim stepperi. Bunun için parçaladığım eski printerlardan kalan ufak bir tane buldum çıkmaların arasında.

Displaylerin bacakları normalde aşağıya bakıyor, fakat motordan dolayı pcbye ve göstergeye tars bağlanmak zorundalar. Göstergede noktaları kullanmayacağımdan bunun önemiyok, gerekli düzenlemeyi kodlamada yapacağım.
 
Tabii göstergenin ne okuyacağı belli olduktan sonra bu işe girişmeye kara verdim.

kardan cıvata.jpg


Kardan kavramayı şanzımana bağlayan 4 cıvata eşit boyuttda ve sabit mesafede dönüyor şansımana göre. Bu cıvataları hall sensorle okuyabilmeyi umuyorum. Bunun için daha önce benze şekilde kullandığım bir UGN3503 lineer hal sensör çıkışını comparatörle Açık Kollektör çıkışla göstergeye göndereceğim.

Cıvata sensörü için devreyi daha hazırlıyorum. bugün ilk prototipi bastırıp en geç yarın sabah yerinde çalışıp çalışmadığını deneyeceğim.
 
Yanlış bilmiyorsam endüktif sensörler bu iş için halihazırda kullanılıyor. Aşağıya bir resim ekliyorum. Montajı kolay olur. Su toz çamur gibi dertleri az olur.


1656247511223.png
 
Yanlış bilmiyorsam endüktif sensörler bu iş için halihazırda kullanılıyor. Aşağıya bir resim ekliyorum. Montajı kolay olur. Su toz çamur gibi dertleri az olur.


18037 eklentisine bak
Elimde hall sensör vardı. Ama bu daha kararlı çalışır eminim. Bundan da spiariş vereyim, zırt pırt bozulacak bir şeyle uğraşmamalı.
 
Bu arada 4 ciavata yerine tek civata okumak daha mantıklı. Frekans daha düşük olacağından gürültü az olur. Bunun için Bir şekilde civatanın birinin diğerlerinden uzun olmasını sağlamalısın.
 
Elimde hall sensör vardı. Ama bu daha kararlı çalışır eminim. Bundan da spiariş vereyim, zırt pırt bozulacak bir şeyle uğraşmamalı.
Kaliteli markaların datasheetlerinde response zamanları vardır. Devir frekans hesaplayıp uygunluğuna bak istersen. Bir makine de aynen böyle bir kullanım vardı. Sensör bozulunca çin malı taktılar belli bir devrin üzerinde kaçırmaya başladı... Sonra kaliteli marka ile sorun çözüldü.
 
Diferansiyelin oranı kabaca 5/1 gibi, gösterge limiti 140 km/h, saniyede 38metre yapıyor, teker çevresi 241cm ve bu da 140km/h için saniyede yaklaşık olarak 16 devir yapıyor. şaft 5*16= 80 tur döner saniyede.

4 cıvatayla sensörün algılayacağı frekans 320Hz makimum. 500hz'lik bir mesafe sensörünün işimi göreceğini tahmin ediyorum.


Bunun için dc freauency response 0,5KHZ verilmiş. bunu alacağım. Eğer sıkıntı olursa cıvatalardan iki tanesini uzun takar frekansı yarıya düşürürüm, Bunun için yarın sipariş vereceğim. Hall sensor ile ne yapabileceğimi bir görmek istiyorum.
 
UGN3503 hall sensörden nasıl bir sinyal alacağımı ve bu sinyali kullanmak için neyabileceğimi araştırmak için breadboarda bağladım sensörü.
Sensör manyetik akıyı ölçüyor ve çıkışı besleme geriliminin orta değerine göre veriyor.

5 voltla beslerken manyetik alan yoksa 2,5V çıkış alınıyor. Manyetik alanın yönü ve gücüne göre çıkış 0-5 volt arasında değişiyor. İnce detaylar farklılıklar var tabii ama çalışması kabaca böyle.

Sensörün arkasına biraz boşluk bırakarak mercimek kadar bir mıknatıs yerleştirmek için çift taraflı köpük bant kullanarak teste başlıyorum. Boşluk bırakmaktaki amaç sensörü doygunluğa getirmemek. Böylece Cıvata sensöre yaklaştığında manyetik akı artacak ve çıkışta oransal bir oynama olacak.

IMG20220626180017.jpg
IMG20220626181547.jpg
IMG20220626181617.jpg
IMG20220626181534.jpg


Cıvata yokken, 2,5mm mesafede ve yaklaşık 5mm mesafedeki değerleri böyle oluyor.

Mıknatısla sensör arasına daha fazla mesafe koyarak sinyalin genliği üzerindeki etkisini incelemek için mesafe iki katındayken sonuçlar da böyle oluyor: mesafeler sırasıyla aynı.

IMG20220626180858.jpg
IMG20220626181148.jpg
IMG20220626181106.jpg


Bu sonuçlara göre mıknatıs ve sensör arasındaki mesafeyi daha yüksek tutup sinyali opamp ile yükseltmeye karar verdim. 4mm mesafede algılama yapabilmeyi bu uygulama için güvenli ve yeterli buluyorum.
 

Ekler

  • IMG20220626180610.jpg
    IMG20220626180610.jpg
    178.4 KB · Görüntüleme: 81
Bende de benzer bir hall sensör vardı. N kutbunda 0v, S kutbunda 5v ortada 2.5v veriyordu. Analog çıkışlıydı. Sendekide benzer sanırım. Böyle olunca döndükçe alan azalıp artacak yani çıkış sinüs gibi olabilir. 4 küsür bir seri zener ile tepeleri filtreleyebilirsin.
 
Senin konu ile alakası yok ama bu hall sesnor ile akım ölçmek ne kadar başarılır acaba...aşağıdaki çizim aklıma yatıyor. Histeresiz ve endüktans etkisi sorun çıkarmaz ise pratik kullanımı olabilir.

1656272837550.png
 
Senin konu ile alakası yok ama bu hall sesnor ile akım ölçmek ne kadar başarılır acaba...aşağıdaki çizim aklıma yatıyor. Histeresiz ve endüktans etkisi sorun çıkarmaz ise pratik kullanımı olabilir.

18049 eklentisine bak
Sanırım bu şekilde çalışan hazır moduller satılıyordu.

Yukarıdaki bu mantıkla çalışıyor. Ama bu şekilde yapınca daha küçük akımlar ölçülebilir heralde. Hall sensörün 0A akım referansı sabit kalıyor mu bakmak lazım, sıcaklık ve besleme gerilimi falan etkiliyor bir kaç grafik vardı datasheette. Bu iş için daha uygun hall sensörler de vardır mutlaka.
 
Hall devresini Bir opamp ve bir transistörle NPN açık kollektör şeklinde tasarladım. Sinyal 40 milivolt tepeden tepeye, tahminen çarpık bir sinüs dalga olacak ama simulasyonda sinüsle denedim. İlk opampla, sinyali kendi low-pass sinyaliyle karşılaştırıp farkı yükselterek 10mV tepeden tepeye sinyal için 1V tepeden tepeye çıkış olacak şekilde şartlandırdım. Bu son sinyali de diğer opampla yine kendi lowpasiyle karşılaştırıp NPN transistörden kare dalga çıkış aldım.

Sinyal tepeden tepeye 5-200 milivolt arasında iken 1 ila 300 HZ arasında iken çıkışın %50'ye yakın duty cycle ile kare dalga olduğunu simulasyonda denedim.

hall şema.jpg
Hall devresi yerleşim.jpg



Ekran Görüntüsü (57).png
Ekran Görüntüsü (58).png

PCB de makul ölçülerde oldu. Çift katman basıp yerine eğreti şekilde oturtarak deneyeceğim. Eğer temiz sonuç görürsem. Bu devreyle devam edeceğim. Bakalım şanzımanın titreşimi ne yapacak, evdeki hesap çarşıya uyacak mı...
 
Son düzenleme:
Gösterge devresini de çizdim ve PCB'ye uyguladım. İlla ki bir sürücü kullanmak gerektiğinden 7 segmentleri HC595'lerle sürüyorum, daha süremiyorum da devreye öyle bağladım. Mcu wskiden kalma bir Atmega8. Devrede yanlışlıklar yapmışım, devreyi kurduktan sonra farkedip jumperlarla düzelttim.


gösterge şema.jpg
IMG20220629202255.jpg

Hall sensörlü dedektör gerektiği gibi çalışıyor ama hava koşullarından koruyup, yerine monte etmek çok zahmetli olacağı için endüktif sensör sipariş ettim.

Sıra kod yazmaya geldi. ve kanser yapıcı stres başladı, yarım saat atmega8'in kristalle çalışacak şekilde ayarlandığını anlamak sürdü, 15 dakka da hc595'lerin enable pinlerini yanlış bağladığımı farketmem.

Bir LDR'ekledim, farlar yanınca displayleri kısabilmek için.
Kilometreyi eeproma yazacağım. Yazma sınırını korumak için kontak kapandığında yazacağım. Devre gücünü kontaktan aldığından kontak kapandığında epproma yazabilmek için optoyla kontak durumunu okuyup kapandığında kondansatörde kalan son enerjiyle eeproma kayıt yapmayı deneyeceğim. Buna pek de gerek yok aslında. şimdi düşününce araç hareketsiz kaldığında da yazsam olurmuş.

Mantıklı bir iş değil, eskiler hurdaya çıkmaya mahkum sonunda.
 

Ekler

  • hall sensör.mp4
    1.6 MB
Gösterge devresini de çizdim ve PCB'ye uyguladım. İlla ki bir sürücü kullanmak gerektiğinden 7 segmentleri HC595'lerle sürüyorum, daha süremiyorum da devreye öyle bağladım. Mcu wskiden kalma bir Atmega8. Devrede yanlışlıklar yapmışım, devreyi kurduktan sonra farkedip jumperlarla düzelttim.


18135 eklentisine bak 18133 eklentisine bak
Hall sensörlü dedektör gerektiği gibi çalışıyor ama hava koşullarından koruyup, yerine monte etmek çok zahmetli olacağı için endüktif sensör sipariş ettim.

Sıra kod yazmaya geldi. ve kanser yapıcı stres başladı, yarım saat atmega8'in kristalle çalışacak şekilde ayarlandığını anlamak sürdü, 15 dakka da hc595'lerin enable pinlerini yanlış bağladığımı farketmem.

Bir LDR'ekledim, farlar yanınca displayleri kısabilmek için.
Kilometreyi eeproma yazacağım. Yazma sınırını korumak için kontak kapandığında yazacağım. Devre gücünü kontaktan aldığından kontak kapandığında epproma yazabilmek için optoyla kontak durumunu okuyup kapandığında kondansatörde kalan son enerjiyle eeproma kayıt yapmayı deneyeceğim. Buna pek de gerek yok aslında. şimdi düşününce araç hareketsiz kaldığında da yazsam olurmuş.

Mantıklı bir iş değil, eskiler hurdaya çıkmaya mahkum sonunda.
Abi displayi değiştirdin mi? İlk fotoğrafdaki displayde noktalar mevcutken burda onlar kaybolmuş.

Bence ne varsa eskiler de var bu 0 teknoloji araca bakar kötü davranmazssan full teknolojik diye satılanlardan uzun süre gider.

Yenilerin içinden çıkılamaz bir elektronik arızaları oluyor.
 
Son düzenleme:
Abi displayi değiştirdin mi? İlk fotoğrafdaki displayde noktalar mevcutken burda onlar kaybolmuş.

Bence ne varsa eskiler de var bu 0 teknoloji araca bakar kötü davranmazssan full teknolojik diye satılanlardan uzun süre gider.

Yenilerin içinden çıkılamaz bir elektronik arızaları oluyor.
Displayde noktaları devre kalemiyle kapattım. Zaten ters bağlandığından daha da garip duruyordu.

Yeni araçlarının ömürlerinin daha kısa olacağını ben de düşünüyorum. Ama bu eskiyen araçların da yıpranan ve tamirle iflah olmayacak parçaları var üretimi devam etmeyen. Mesela bu 35-9'un kabin yayları burulma çubuklarıyla yapılmış ve birisi kırık. Kırılma sebebi malzeme yorgunluğudur. Yenisiyle değişmesi lazım ama yok, çıkması da zaten aynı yorgunlukta. Sonunda parçalanıp çıkma parça olacak.
 
Kodlamayı tamamladım. Parlaklık ayarı dışında planladığım diğer işlevleri çalışıyor. Demosunu ekleyeyim.
Kodlarken bir adc input kullanarak bir trimpotla değişken bir frekans uyguladım tako sinyaline. bu frekansı da bir ledle gözlemledim. Gösterge belli bir hızdan sonrasını göstermeyek şekilde ayarlı, demodaki km sayacının artışı Formula1 hızlarında bir sinyalle sağlanıyor. Gücü kestiğimde stepper akımını kesip kalan enerjiyle eeproma kayıt yapıyorum. Bu da 100.000 kontak aç-kapa döngüsünden daha fazla bir eeprom ömrünü sağlıyor.

Kodlama için harcadığım zaman bu işten göreceğim faydadan çok daha fazla. Bu nedenle kodu olabildiğince parametrik hazırladım. Başka herhangi bir araca uygulamak için sadece kodda belirlenmiş parametreleri tespit edip ilgili sabitleri girmek yeterli olacak. Kodda biraz çöp değişken var, hatta bir kaç da çöp satır. Yine de 2500 KB civarı derleniyor ve başka projeler için smd kılıfta bir atmega48'i yeterli kılıyor.


gösterge:
/*
 * IVECO_TAKO.c
 *
 * Created: 21.06.2022 22:02:08
 * Author : brehk
 *
 * Sinyal/km sabitini kullanarak sinyal girdisinden hızı hesaplar
 * Hızı stepper konumuna çevirip analog göstergeye yansıtır
 * Her kontak açılışında stepperi referansa çeker
 * her 100 metrede km sayacını artırı artışında uygun birimde artırır.
 * girişler
 * - tako dijital input
 * - referans dijital input
 * - LDR için ADC input
 * - debugging için ADC input
 * - kontak dijital inputu
 * çıkışlar
 * - stepper fazları 4 tane
 * - SPI master pinleri
 * - hc595 latch pini
 * - debugging led
 *
 */

/*
    Hız hesaplaması tako sinyali periyodunun hareketli ortalamasıyla yapılacak
    Hesaplamayı basitleştirmek için önceden hesaplanmış bir sabitin, sinyal periyoduna bölünmesiyle heaplanacak.
    Her sinyal geldiğinde sinyal periyodu bir değişkene yazılıp hız hesaplanacak.
    Bir sinyal sayacı da artırılarak gidilen yolu hesaplamakta kullanılacak
    SABİT, kilometre başına sinyal sayısı, timer1 tik süresi(sn), stepper adım açısı( derece) ve
    gösterge adım açısı parametrelerini kullanarak bir kez hesaplanacak. Bu sayede bu bu kod bu parametreleri bilinen her göstergede çlışacaktır
    
    teker turu başına şaft devri= 4,625
    teker turu başına pulse 4*4,625=18,5
    km başına teker turu 100.000/241,5 =414
    km başına pulse    414*18,5=7.659 pulse
    saatte 100km için saniyede 100*7.659/3600=212,75 pulse
    pulse periyotu 1 kmh için 1/(212,75/100)=0,47 saniye
    hız 0,47/pulse periyodu(saniye) olarak kmh cinsinden hesaplanmış olur.
    Timer tik periyodunu da saniye cinsinden tespit ettikten sonra
    1 kmh için temel timer tik sayısı 0,47 / (timer tik periyodu) olur
    hız= temel timer tik sayısı / pulse timer tik sayısı olur.
    sonraki adımda hızı step cinsinden çevirmek olacak
    1kmh için adım sayısının tespiti için
    
    SABİT=(3600/tik_KM)*(FCPU/prscl)*(ADIM/KM)*(örnek_sayısı)
    
    örnek sayısı: hareketli ortalama için toplanacak örnek sayısı.
    
    dışarıda hesaplanıp const long SABIT değişkenine atanır.
    Mcu, hız hesabı için SABIT/Tik_periyodu formulünü kullanır.
    
    
    
    
*/

#define F_CPU        8000000

#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include "avr/iom8a.h"

#define SABIT 323465l

#define KM_TIK    7659            // kilometredeki tik sayısı
#define TIMER_PRSCL 256

// kadran parametreleri
#define STEP_TUR        4096l
#define KM_180            93l        // 180 derece ibrehareketinin kaç kmh süpürdüğü
#define REF_OFFSET        50l        // referans sensörünün 0 kmh'den kaç step adimi geride olduğu
#define OLCEK_KM        10l            // ibre ölçeğinin farklı olduğu kmh genelde 10 ya da 20 olur
// OLCEK_KM ile 0 kmh arası süpürülen kadranın normale oranı.
// meseala normalde: 1km/derece iken 0-10 arası 2km/derece ise oran 2 olur
#define OLCEK_ORAN        2l       
        

#define LATCH_DDR        DDRB
#define LATCH_PORT        PORTB
#define LATCH_PIN        PINB
#define LATCH_PIN_NO    1
#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_L

#define DATA_DDR        DDRB
#define DATA_PORT        PORTB
#define DATA_PIN        PINB
#define DATA_PIN_NO        3
#define DATA_H            (DATA_PORT|=1<<DATA_PIN_NO)
#define DATA_L            (DATA_PORT&=~(1<<DATA_PIN_NO))   

#define CLOCK_DDR        DDRB
#define CLOCK_PORT        PORTB
#define CLOCK_PIN        PINB
#define clock_PIN_NO    5
#define CLOCK_H            (CLOCK_PORT|=1<<clock_PIN_NO)
#define CLOCK_L            (CLOCK_PORT&=~(1<<clock_PIN_NO))
#define CLOCK_L_H_L        CLOCK_L;CLOCK_H;CLOCK_L;

#define SHIFT1        DATA_H;_delay_us(100);CLOCK_L;_delay_us(100);CLOCK_H;_delay_us(100);CLOCK_L;_delay_us(100)
#define SHIFT0        DATA_L;_delay_us(100);CLOCK_L;_delay_us(100);CLOCK_H;_delay_us(100);CLOCK_L;_delay_us(100)

#define LED_DDR        DDRC
#define LED_PIN        PINC2
#define LED_PORT    PORTC
#define LED_ON        (LED_PORT|=1<<LED_PIN)
#define LED_OFF        (LED_PORT&=~(1<<LED_PIN))
#define LED_TOGGLE    LED_PORT^=1<<LED_PIN

#define LDR_DDR        DDRC
#define LDR_PORT    PORTC
#define LDR_PIN        PINC
#define LDR_PIN_NO    1

#define KONTAK_DDR        DDRD
#define KONTAK_PORT        PORTD
#define KONTAK_PIN        PIND
#define KONTAK_PIN_NO    4
#define KONTAK_OKU        ((KONTAK_PIN>>KONTAK_PIN_NO)&1)


// anot veya katod display seçimi
//#define ANOT
#define KATOT

// Segment ve basamakların hc595 bağlantıları
// 0: ikinci(taşma registeri) H biti, 15: birinci(taşan register) A biti
// bit shift operatörünün sağı değiştirilecek
#define A    1<<9
#define B    1<<13
#define C    1<<4
#define D    1<<1
#define E    1<<8
#define F    1<<11
#define G    1<<3
// basamaklar için sadece pin konumu

#define D0        1<<2        //en yüksek basamak
#define D1        1<<5
#define D2        1<<6
#define D3        1<<10
#define D4        1<<12
#define D5        1<<14        //en düşük basamak

// stepper ayarları
#define S1A_DDR        DDRD
#define S1A_PORT    PORTD
#define S1A_PIN_NO    0
#define S1A_H        (S1A_PORT|=1<<S1A_PIN_NO)
#define S1A_L        (S1A_PORT&=~(1<<S1A_PIN_NO))

#define S1B_DDR        DDRD
#define S1B_PORT    PORTD
#define S1B_PIN_NO    1
#define S1B_H        (S1B_PORT|=1<<S1B_PIN_NO)
#define S1B_L        (S1B_PORT&=~(1<<S1B_PIN_NO))

#define S2A_DDR        DDRD
#define S2A_PORT    PORTD
#define S2A_PIN_NO    2
#define S2A_H        (S2A_PORT|=1<<S2A_PIN_NO)
#define S2A_L        (S2A_PORT&=~(1<<S2A_PIN_NO))

#define S2B_DDR        DDRD
#define S2B_PORT    PORTD
#define S2B_PIN_NO    3
#define S2B_H        (S2B_PORT|=1<<S2B_PIN_NO)
#define S2B_L        (S2B_PORT&=~(1<<S2B_PIN_NO))

// stepper farklı sürüş modları

//#define TEKFAZ
//#define CIFTFAZ
#define YARIMADIM

// tek faz sürme modu
#ifdef TEKFAZ
#define DURUM_0        S1A_L;S1B_L;S2A_L;S2B_L; //tümü kapalı
#define DURUM_1        S1A_H;S1B_L;S2A_L;S2B_L;
#define DURUM_2        S1A_L;S1B_H;S2A_L;S2B_L;
#define DURUM_3        S1A_L;S1B_L;S2A_H;S2B_L;
#define DURUM_4        S1A_L;S1B_L;S2A_L;S2B_H;
#endif

// çift faz sürme modu
#ifdef CIFTFAZ
#define DURUM_0        S1A_L;S1B_L;S2A_L;S2B_L; //tümü kapalı
#define DURUM_1        S1A_H;S1B_H;S2A_L;S2B_L;
#define DURUM_2        S1A_L;S1B_H;S2A_H;S2B_L;
#define DURUM_3        S1A_L;S1B_L;S2A_H;S2B_H;
#define DURUM_4        S1A_H;S1B_L;S2A_L;S2B_H;
#endif

// yarım adım sürme modu
#ifdef YARIMADIM
#define DURUM_0        S1A_L;S1B_L;S2A_L;S2B_L; //tümü kapalı
#define DURUM_1        S1A_H;S1B_L;S2A_L;S2B_L;
#define DURUM_15    S1A_H;S1B_H;S2A_L;S2B_L;
#define DURUM_2        S1A_L;S1B_H;S2A_L;S2B_L;
#define DURUM_25    S1A_L;S1B_H;S2A_H;S2B_L;
#define DURUM_3        S1A_L;S1B_L;S2A_H;S2B_L;
#define DURUM_35    S1A_L;S1B_L;S2A_H;S2B_H;
#define DURUM_4        S1A_L;S1B_L;S2A_L;S2B_H;
#define DURUM_45    S1A_H;S1B_L;S2A_L;S2B_H;
#endif

#define REF_DDR        DDRC
#define REF_PORT    PORTC
#define REF_PIN        PINC
#define REF_PIN_NO    3
#define REF_OKU        ((REF_PIN>>REF_PIN_NO)&1)

#define TAKO_DDR    DDRB
#define TAKO_PORT    PORTB
#define TAKO_PIN    PINB
#define TAKO_PIN_NO    0
#define TAKO_OKU    ((TAKO_PIN>>TAKO_PIN_NO)&1)
#define TAKO_TOGGLE    TAKO_PORT^=1<<TAKO_PIN_NO;


/*
#define R_0        (A|B|C|D|E|F);
#define R_1        (B|C);
#define R_2        (A|B|G|E|D);
#define R_3        (A|B|G|C|D);
#define R_4        (B|C|G|F);
#define R_5        (A|F|G|C|D);
#define R_6        (A|F|G|C|D|E);
#define R_7        (A|B|C);
#define R_8        (A|B|C|G|E|D|F);
#define R_9        (A|B|C|D|F|G);
uint16_t seg[10]={R_0,R_1,R_2,R_3,R_4,R_5,R_6,R_7,R_8,R_9};
*/

uint16_t seg[12]={(A|B|C|D|E|F),(B|C),(A|B|G|E|D),(A|B|G|C|D),(B|C|G|F),(A|F|G|C|D),
                    (A|F|G|C|D|E),(A|B|C),(A|B|C|G|E|D|F),(A|B|C|D|F|G),0,0};
// basamak maske değişkeni
// her bir basamak ayrı ayrı binary olarak ve tüm basamaklar binary olarak
//uint16_t bas_maske[7]={~(D0) , ~(D1) , ~(D2) , ~(D3) , ~(D4) , ~(D5) , D0|D1|D2|D3|D4|D5 };
uint16_t bas_maske[7]={~(D5) , ~(D4) , ~(D3) , ~(D2) , ~(D1) , ~(D0) , D0|D1|D2|D3|D4|D5 };
//const uint16_t                     

            const uint16_t kalibre;
            uint16_t disp[6]={1,2,3,4,5,6};
            uint8_t EEMEM eeprom_basamak[7]={0,1,2,3,4,5,6};
            uint8_t b_degeri[6];//= {1,2,3,4,5,6};



// rakam segment değişkenleri, 10 rakam ve bir karanlık
// seg[i]: binary olarak "i" rakamının gösterimi için
// açılacak segmentlerin hc595'in bacaklarında isabet ettiği yerler
//uint16_t seg[11];
volatile uint32_t perT;
int32_t gost[8],sabit,hedef,konum;

uint16_t sinyal,bufUint,bufUint1,s0,s1,tov0,okunanADC,ovf10,per[8],tiksay,kirim;
int16_t hiz,ovf1,ovf2,adim_per;
uint8_t asama,j,k,l,step_s;
uint8_t buffbyte,buffbyte1,p_i,p_b,per_up;

void km_up(void);
void disp_sur (void);
void disp_set (void);
void stepper_adim(int8_t yon);
void eeprom_put(void);
void eeprom_get (void);
void ibre_init(void);
void hiz_hesap(void);

ISR(TIMER0_OVF_vect)
{
    tov0++;
    ovf1++;
    ovf2++;
}
ISR(ADC_vect)
{
    okunanADC=ADCH;
    
}

ISR(TIMER1_OVF_vect)
{
    b_degeri[0]=1;
}

ISR(TIMER1_COMPA_vect)
{
    TCNT1=0;
    hedef=0;
    p_i=0;
    per_up=0;
    
}
ISR(TIMER1_CAPT_vect)
{
    per[p_i]=ICR1;
    TCNT1=0;
    tiksay++;
    
    p_i++;
    
    if(p_i>7){per_up=1;p_i=0;}// ilk 8 sinyal toplandıktan sonra hesap yap
    if(per_up)// hareketli ortalama her sinyal gelişinde son 8 sinyali toplar.
    {
        perT=0;
        for(uint8_t i=0;i<8;i++)
        {
            perT+=per[i];
        }
        perT/=8;
        hiz_hesap();
        if(hedef>3500)hedef=3500;
        
    }
    
    LED_TOGGLE;
    if(tiksay>KM_TIK)
    {
        
        km_up();
        tiksay=0;
    }
}

int main(void)
{
    LED_DDR|=1<<LED_PIN;
    LATCH_DDR|=1<<LATCH_PIN_NO;
    // SPI pinlerini output ayarla
    DDRB|=1<<PINB3 | 1<<PINB5 | 1<<PINB2;
    LATCH_L;
    // SPI ayarı
    // en düşük değerli bit önce transfer edilir.
    // spi hızı maksimumda
    SPCR |= (1<<SPE)|(1<<MSTR)|(1<<DORD);
    SPSR |= 1<<SPI2X;
    // timer0 ekranı zaman takibi için kullanılacak, makul bir taşma kesme süresiyle bir
    TCCR0|= 0b10; //prscl 1024
    TIMSK|=1<<TOIE0;
    sei();
    
    //Stepper ayarları çıkışları
    S1A_DDR |= 1<<S1A_PIN_NO;
    S1B_DDR |= 1<<S1B_PIN_NO;
    S2A_DDR |= 1<<S2A_PIN_NO;
    S2B_DDR |= 1<<S2B_PIN_NO;
    
    //referans girişi pullup açık
    REF_DDR&=~(1<<REF_PIN_NO);
    REF_PORT|=1<<REF_PIN_NO;
    
    //LDR
    LDR_DDR&=~(1<<LDR_PIN_NO);
    LDR_PORT|=1<<LDR_PIN_NO;
    
    //kontak sense setup
    KONTAK_DDR&=~(1<<KONTAK_PIN_NO);
    KONTAK_PORT|=1<<KONTAK_PIN_NO; // pullup açık
    
    
    //ADC setup
    DDRC&=~(1<<PINC5);
    PORTC&=~(1<<PINC5);
    
    ADMUX|=  1<<REFS1 | 1<<ADLAR| 1<<REFS0;// | 1<<2 ;//  adc5 pin28
    ADCSRA|= 1<<ADEN |  1<<ADIE | 1<<ADFR | 0b101;
    ADCSRA|= 1<<ADSC;
    
    //TAKO sinyal girişi
    TAKO_DDR|=(1<<TAKO_PIN_NO);
    
    //Timer 1 input capture CTC
    //TCCR1B|=1<<WGM13 | 1<<WGM12;
    TCCR1B|=0b100; // prscl 0b1:1 0b10:8 0b11:64 0b100:256 0b101:1024
    OCR1A=20000;
    TIMSK|=1<<TICIE1;// | 1<<OCIE1A | 1<<TOIE1 ;
    /*
    eeprom_put();
    while(1);
    */
    eeprom_get();
    
    ibre_init();
    
    _delay_ms(300);
    
    while(REF_OKU<1){stepper_adim(1);_delay_ms(1);}
    konum=-REF_OFFSET;
        
    
    disp_set();
    while (1)
    {
        if(KONTAK_OKU)
        {
            DURUM_0;//stepper gücünü keser
            eeprom_put();
            _delay_ms(500);
        }
        
        
        if(tov0>4)
        {
            tov0=0;
            disp_sur();
        }
        
        if(ovf1>adim_per)// 4050 için ölçülmüş 1 saniye periyot
        {
            ovf1=0;
            if(hedef>konum)
            {
                stepper_adim(-1);
                konum++;
            }
            else if(hedef<konum)
            {
                stepper_adim(1);
                konum--;
            }
            
            // kaba bir pid daha doğrusu p
            adim_per=75-abs(hedef-konum);
            if(adim_per<5)adim_per=5;
        }
        
        if(ovf2>okunanADC)
        {
            TAKO_TOGGLE;
            ovf2=0;
        }
    }
}

void disp_sur (void)
{
    switch(asama)
    {
        case 0:
            LATCH_L_H_L;// 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:
            SPDR=disp[j]>>8;
            asama=0;
            j++;//basamak takip değişkeni
            if(j>5)//altıncı basamaktan sonra başa döner
            {
                j=0;
            }
            break;
        default: asama=0;j=0;
    }
    
}

void disp_set (void)
{
    uint8_t i=0;;
    
    for(i=0;i<5;i++)
    {
        if(b_degeri[i]==0)b_degeri[i]=11;// b_degeri[i]=11'in segment gösterim karşılığı hepsi kapalıdır >> seg[11]=0;
        else break;
    }
    
    for(i=0;i<6;i++)
    {
        // gösterilecek segmentleri aç | bütün basamakları kapat & gösterilecek basamağı aç
        // i=0: 100 binler basamağı, i=5: 1'ler basamağı
        #ifdef KATOT
            disp[i]= ( seg[b_degeri[i]] | bas_maske[6] ) & bas_maske[i];
        #endif
        #ifdef ANOT
            disp[i]= ~(( seg[b_degeri[i]] | bas_maske[6] ) & bas_maske[i]);
            
        #endif
        
        
    }

}

void stepper_adim(int8_t yon)
{
     //gösterge konumunu referansa göre adım cinsinden takip eder.
    step_s+=yon;// step_s stepperin 4 farklı konumu temsil eder 1 ila 4 değerlerini alabilir
    
    #ifdef YARIMADIM
        if(step_s>8)step_s=1; // stepper durumu 4'ü aşarsa 1'den devam et
        if(step_s==0)step_s=8;    // stepper durumu 0 olursa 4'ten devam et
        switch (step_s)
        {
            case 1:DURUM_1;break;
            case 2:DURUM_15;break;
            case 3:DURUM_2;break;
            case 4:DURUM_25;break;
            case 5:DURUM_3;break;
            case 6:DURUM_35;break;
            case 7:DURUM_4;break;
            case 8:DURUM_45;break;
            default: DURUM_0;break;
        }
    #else
        if(step_s>4)step_s=1; // stepper durumu 4'ü aşarsa 1'den devam et
        if(step_s==0)step_s=4;    // stepper durumu 0 olursa 4'ten devam et
        switch (step_s)
        {
            case 1:DURUM_1;break;
            case 2:DURUM_2;break;
            case 3:DURUM_3;break;
            case 4:DURUM_4;break;
            default: DURUM_0;break;
        }
    #endif
}

void eeprom_put (void)
{
    for(uint8_t i=0;i<6;i++)
    {
        eeprom_update_byte((uint8_t*) &eeprom_basamak[i],b_degeri[i]);
        while (!eeprom_is_ready());
    }   
    eeprom_update_word((uint16_t*) 10,tiksay);
    while (!eeprom_is_ready());
}

void eeprom_get (void)
{
    for(uint8_t i=0;i<6;i++)
    {
        b_degeri[i]=eeprom_read_byte(& eeprom_basamak[i]);
        while (!eeprom_is_ready());
    }
    tiksay=eeprom_read_word((uint16_t*)10);
    while (!eeprom_is_ready());
}

void km_up(void)// her 100 metrede bir çalışır.
{
    int8_t i=0;
    b_degeri[5]++;
    
    for(i=5;i>0;i--)
    {
        // basamak değeri 9'u geçen basamak sıfırlanır
        // bir sonraki basamak değeri 1 artırılır
        if(b_degeri[i]==10)
        {
            b_degeri[i]=0;
            b_degeri[i-1]++;
            if(b_degeri[i-1]>10)b_degeri[i-1]=1;
        }   
    }
    // sayıdan önceki  basamakları kapat
    for(i=0;i<5;i++)
    {
        if(b_degeri[i]==0)b_degeri[i]=11;// b_degeri[i]=11'in segment gösterim karşılığı hepsi kapalıdır >> seg[11]=0;
        else break;
    }
    
    disp_set();
}

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<9;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=8;
        }
        for(i=0;i<6;i++)// 10^i basamağının değerlerini hesaplar
        {
            b_degeri[i] = gost[i]-gost[i+1]*10;
        }
        
        
        
    }
}

void shift_16(uint16_t val)
{
    for(char i=0;i<16;i++)
    {
        if(1&(val>>i)){DATA_PORT |=(1<<DATA_PORT);}
        else {DATA_PORT &= ~(1<<DATA_PIN_NO);}
        CLOCK_L_H_L;
        if (i==15){LATCH_L_H_L;}
    }
}


void hiz_hesap (void)
{
    hedef=SABIT/perT;
    if(hedef<kirim) hedef/=2;
    else hedef-=kirim;
    
    hedef+=REF_OFFSET;
}
void ibre_init (void/*parametreler*/)
{
    kirim= OLCEK_KM*STEP_TUR/KM_180/2;
    kirim/= OLCEK_ORAN;   
}

Bu proje sırasında bilgisayarımın SSD'si nalları dikti. Bereket çalışma dosyalarımı ayrı bir diskte tutuyordum. Şimdı sıra montajda,
 

Ekler

  • göst_demo.mp4
    6.9 MB
Dönüş hızını daha da arttırman lazım bence. Ani fren yapan bir arabanın hızı çok çabuk aşağı iner.

Hatta motor devir sayacı için de aynı uygulamayı yapacaksan daha da çabuk dönmesi lazım, motor devri çok ani değişebilir.
 
Dönüş hızını daha da arttırman lazım bence. Ani fren yapan bir arabanın hızı çok çabuk aşağı iner.

Hatta motor devir sayacı için de aynı uygulamayı yapacaksan daha da çabuk dönmesi lazım, motor devri çok ani değişebilir.
Evet, stepper biraz yavaş kalıyor, maksimum hızını biraz artırabilirim. Kaba bir pid kodu yazıştım stepper pozisyonu için, tako sinyalini simule ettiğim adc gürültülü olduğundan hız çok değişken gibi algılanıyordu, ibre fazla titremesin diye biraz yavaş bıraktım. Yerinde test ettikten sonra bunu düzeltebilirim.
 
Geri giderken ne olacak :D

Kartal ile geri giderken gösterge sıfırın altına iniyordu. Muhtemelende sayısı ters çalışıyordu. Şu an kullandığım araba 2016 model geri giderkende iler gidiyormuş gibi davranıyor...
 

Forum istatistikleri

Konular
5,656
Mesajlar
97,289
Üyeler
2,438
Son üye
İbrahimSönmez

Son kaynaklar

Son profil mesajları

cemalettin keçeci wrote on HaydarBaris's profile.
barış kardeşim bende bu sene akıllı denizaltı projesine girdim ve sensörleri arastırıyorum tam olarak hangi sensör ve markaları kullandınız yardımcı olabilir misin?
m.white wrote on Altair's profile.
İyi akşamlar.Arabanız ne marka ve sorunu nedir.Ben araba tamircisi değilim ama tamirden anlarım.
* En mühim ve feyizli vazifelerimiz millî eğitim işleridir. Millî eğitim işlerinde mutlaka muzaffer olmak lâzımdır. Bir milletin hakikî kurtuluşu ancak bu suretle olur. (1922)
Kesici/Spindle hızı hesaplamak için SpreadSheet UDF'leri kullanın, hesap makinesi çok eski kalan bir yöntem :)
Dr. Bülent Başaran,
Elektrik ve Elektronik Mühendisi
Yonga Tasarım Özdevinimcisi
Üç güzel "çocuk" babası
Ortahisar/Ürgüp/Konya/Ankara/Pittsburgh/San Francisco/Atlanta/Alaçatı/Taşucu...

Back
Top