ADC przykład pomiaru do 20V


Może się komuś przyda taki gotowiec do pomiaru wyższych napięć. Do samochodu, albo czegokolwiek bo wartość zmierzona nie musi być wyświetlana a np. użyta do porównania z założoną. Będę upraszczał jak tylko się da :D
Na początku..jak wiadomo mikrokontroler może mieć w sobie ADC (zamienia wartośc analogową na cyfrową wartość). ADC może mierzyć do wartości zasilania mikrokontrolera czyli max. 5V
Żeby wiedzieć jak sie odnieść do przyłożonego napięcia potrzebuje wzorca - punktu odniesienia (tak jak waga odważnika na szali). Tym punktem jest AREF - jego nóżka jest wyprowadzona na zewnątrz mikrokontrolera. Są różne metody ustalenia punktu odniesienia, ale w przykładzie wybrałem porównanie do napięcia zasilania. Wybiera sie je konfigurujac ADC w programie. Jeśli tak wybierzemy to napięcie już na tej nóżce tam jest i nie trzeba go podłączać do zasilania a jedynie kondensatorem "pomóc" w lepszym ustabilizowaniu.
Teraz pomiar do 20V :D Sprawa jest nieskomplikowana. Jeśli mikrokontroler może mierzyć do 5V to jeśli weźmiemy cztery TAKIE SAME rezystory to na pierwszym z odczepów patrząc od strony masy będziemy mieli 1 /4 przyłożonego napięcia. Czyli mozemy mierzyć do 20V i napięcie będzie się tam proporcjonalnie zmieniać od 5V do 0V.
"Sposób z jednakowymi rezystorami" jest szerzej stosowany i jak się przyjrzycie niektórym schematom to zobaczycie ;) i może być narysowany tak jak przykład na schemacie w ramce.
Każdy kolejny TAKI SAM rezystor to wielokrotność 5V.
PROSZĘ JEDNAK ZAWSZE UWAŻAĆ BY NIE PRZEKROCZYĆ 5V PRZYKŁADANYCH DO MIKROKONTROLERA!
Teraz już z górki
V=odczyt*(napięcie_odniesienia/1024)
To co w nawiasie to nasze AREF czyli 5V / preskaler i daje 0,0048828125 (to widać w programie jako 0,0049)
Jako że mamy podzielone napięcie przez 4 to teraz mnożymy wynik razy 4. Dla innej konfiguracji trzeba działać analogicznie :D
Tu mamy gotową wartośc napięcia która możemy użyć. Żeby ją tylko wyświetlić w przykładzie przekształciłem ją na tekst przy użyciu polecenia Fusing. Zachęcam do lektury polskiego Helpa do Bascom.
Jeszcze kilka słów o programie.
Najpierw konfiguruje porty. Dla odczytu z ADC ważne jest by ustawić dany pin jako wejśćie. Tu ważne jest PINC.0 o który będzie pytał program. ADC(0) jest na tym pinie np. w ATmega8. Dla Twojego procesora sprawdź w nocie katalogowej. Timer0 jest tak ustawiony że po odliczeniu do 124 sam sie zeruje i liczy od nowa . Zajmuje mu to 4ms i co te 4ms skacze do podprogramu Int_4ms. Tam program już dodaje te 4ms oraz dokonuje pomiaru z ADC. Pomiarów jest więcej by je uśrednić. Wyjasnia to prosty przykład.
Pierwszy odczyt 14,2 a drugi 14,8 bo napięcie delikatnie "pływa" w zalezności od tego jak je filtrujemy. Jesli dodamy wyniki do siebie i podzielimy przez ich ilośc to wyjdzie 29/2=14,5
W przykładzie pomiarów jest 16. Program z poniższego listingu przetestowałem przed chwilą osobiście więc działa :P. Skróciłem go na potrzeby prezentacji tak by wynik był odświeżany co sekunde.

$crystal = 8000000
Config Portb = &B11111111 : Portb = &B11111111
Config Portc = &B11111110 : Portc = &B00000000              'PINC.0 ustawiony jako wejście
Config Portd = &B11000011 : Portd = &B01111111
 
Config Lcd = 16 * 2
Cursor Off Noblink
Cls
 
Config Adc = Single , Prescaler = Auto , Reference = Avcc   'Zrodlem odniesienia bedzie napiecie zasilania
Start Adc                                                   ' dla urzadzen bateryjnych mozna ADC wlaczyc na czas pomiaru,
                                                             ' tu wlaczamy odrazu
 
Config Timer0 = Timer , Prescale = 256 , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 1
Enable Compare0a : On Compare0a Int_4ms : Compare0a = 124   'mina akurat 4ms gdy zliczy 124
 
Dim 4ms As Byte                                             'licznik dla 4ms i przy 250 x 4ms bedzie sekunda
 
Dim P As Byte                                               'licznik dla ilosci pomiarow
Dim Probka As Word                                          'wartosc odczytana z przylozonego do ADC
Dim Napiecie As Word                                        'dodaje do siebie kolejne odczyty
Dim Napiecie_u As Single                                    'napiecie usrednione single bo z przecinkiem
Dim Hsingle As Single                                       'pomocnicza zmienna
Dim Volt As String * 5                                      'zmienna "tekstowa" 5 znakow ksztaltowana przez "fusing"
 
Const P_max = 16                                            'ilosc pomiarow do usredniania
 
Lcd "Zasilanie:"                                            'wyswietlamy tylko raz na potrzeby testu
'*************
'*** START ***
'*************
Do
'---------------------co 1s--------
 If 4ms >= 250 Then                                         'po odliczeniu 250 bedzie sekunda
     4ms = 0                                                'zerowanie licznika dla nastepnej sekundy
 
  Hsingle = Napiecie_u * 0.0049
  Hsingle = Hsingle * 4
  Volt = Fusing(hsingle , "#.&")
    Locate 1 , 11 : Lcd Volt ; "V "                         'ustawienie kursora na 11 miejscu pierwszej linii
 End If
'----------------------------------
Loop
'**************
'*** KONIEC ***
'**************
'==================================
Int_4ms:                                                    'tu co 4ms "skacze" program
 
Incr 4ms                                                    'zwiekszanie licznika dla sekund
 
Incr P                                                      'zwiekszanie licznika dla pomiarow
 Probka = Getadc(0)                                         'zmierz na Pinie 0 ADC
 Napiecie = Napiecie + Probka                               'dodaj kolejne pomiary
  If P >= P_max Then                                        'gdy pomiarow 16
      P = 0
    Napiecie_u = Napiecie / P_max                           'podziel cala sume przez ilosc pomiarow (usrednij)
    Napiecie = 0                                            'zeruj zmienna by dodawac nowe
  End If
 
Return
'=================================

Jak zwykle życzę miłego dnia ;)




Portret użytkownika gosc

hd44780plus2Xds18b20plusCzasplusNapięcie

Mój program na bazie powyższego , ale dodatkowo pomiar na dwóch dallasach 18b20 , oraz zegarek ustawialny dwoma klawiszami PC2 i PC3.

$regfile = "m8def.dat"
$crystal = 8000000
Config Lcd = 16 * 2
Config Lcdpin = Pin , Rs = Pinb.1 , E = Pinb.0 , Db4 = Pinb.5 , Db5 = Pinb.4 , Db6 = Pinb.3 , Db7 = Pinb.2
Cls
 
Config 1wire = Pind.0                                       'odczyt dallasów
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Config Timer0 = Timer , Prescale = 256 , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 1
 
Declare Sub Pomiar                                          'procedura odczytu
Declare Sub Wyb_uklad
 
Declare Sub Int_4ms
 
Dim Nr_ukladu1(8) As Byte                                   'tablica do przechowywania nr 1 układu
Dim Nr_ukladu2(8) As Byte                                   'tablica do przechowywania nr 2 układu
 
Dim I As Byte , A As Byte                                   'zmienne pomocnicze
Dim T(2) As Byte
Dim Temp As Integer                                         'temperatura całkowita
Dim Ulamek As Integer                                       'część ułamkowa
Dim Znak As Byte
Dim Tekst As String * 10
Dim Tempa As Single
Config Clock = Soft
Config Date = Dmy , Separator = /
Time$ = "00:00:00"
Date$ = "01/01/10"
Config Pinc.3 = Input
Config Pinc.2 = Input
Config Pinc.1 = Input
Dim Houre As Byte
Dim Mine As Byte
 
Dim 4ms As Byte                                             'licznik dla 4ms i przy 250 x 4ms bedzie sekunda
 
Dim P As Byte                                               'licznik dla ilosci pomiarow
Dim Probka As Word                                          'wartosc odczytana z przylozonego do ADC
Dim Napiecie As Word                                        'dodaje do siebie kolejne odczyty
Dim Napiecie_u As Single                                    'napiecie usrednione single bo z przecinkiem
Dim Hsingle As Single                                       'pomocnicza zmienna
Dim Volt As String * 5                                      'zmienna "tekstowa" 5 znakow ksztaltowana przez "fusing"
 
Const V_max = 16
 
Config Portc = &B11110000 : Portc = &B00000000
Deflcdchar 0 , 8 , 20 , 8 , 3 , 4 , 4 , 4 , 3
Cls                                                         'kasujemy LCD
 Cursor Off
 
Nr_ukladu1(1) = 1wsearchfirst()                             'pobieramy nr pierwszego układu
Nr_ukladu2(1) = 1wsearchnext()                              'pobieramy nr drugiego układu
 Enable Interrupts
 
Do                                                          'pętla główna
         'Debounce Pinc.2 , 1 , Minutes , Sub                'ustawienie minut
         'Debounce Pinc.3 , 1 , Hours , Sub                  'ustwienie godziny
  Locate 1 , 1
  Lcd Time$
  Call Int_4ms
  Locate 1 , 11
  Lcd Volt ; "V"
  If Pinc.2 = 0 Then Incr _min
  If Pinc.3 = 0 Then Incr _hour
 
 For A = 1 To 2                                             'odczytujemy po kolei temp z czujników
 
 1wreset                                                    'reset magistrali 1wire
 
 
 Call Wyb_uklad                                             'wywołanie układu
 1wwrite &H44                                               'Polecenie konwersji temperatury
 
 
 1wreset                                                    'reset magistrali 1wire
 Call Wyb_uklad                                             'wywołanie układu
 1wwrite &HBE                                               'żądanie odczytania temperatury
 T(1) = 1wread()                                            'lsb
 T(2) = 1wread()                                            'msb
 1wreset                                                    'reset magistrali 1wire
 Tempa = T(2) * 256
  Tempa = Tempa + T(1)
  Tempa = Tempa / 16
  Tekst = Fusing(tempa , "#.##")
  Temp = Temp / 16
  If T(2) = &HFF And T(1) > &HF0 Then Znak = 1              'znak przed temperaturą
 
 
 
 Call Wyb_uklad                                             'wywołanie układu
 1wwrite &H44                                               'Polecenie konwersji temperatury
 Waitms 75                                                  'czas konwersji zgodnie
 
 1wreset                                                    'reset magistrali 1wire
 Call Wyb_uklad                                             'wywołanie układu
 1wwrite &HBE                                               'żądanie odczytania temperatury
 T(1) = 1wread()                                            'lsb
 T(2) = 1wread()                                            'msb
 1wreset                                                    'reset magistrali 1wire
 Tempa = T(2) * 256
  Tempa = Tempa + T(1)
  Tempa = Tempa / 16
  Tekst = Fusing(tempa , "#.##")
  Temp = Temp / 16
  If T(2) = &HFF And T(1) > &HF0 Then Znak = 1
 
 Select Case A:
  Case 1 : Locate 2 , 1
   If Znak = 1 Then Lcd "-";
 Lcd Temp ; Chr(0)
  Case 2 : Locate 2 , 9
   If Znak = 1 Then Lcd "-";
   Lcd Tekst ; Chr(0)
 
 
  End Select:
  Next A :
Loop                                                        'koniec pętli głównej
 
 
Sub Wyb_uklad
 1wwrite &H55                                               'Wybór układu
 For I = 1 To 8
 If A = 1 Then 1wwrite Nr_ukladu1(i)
 If A = 2 Then 1wwrite Nr_ukladu2(i)
 Next I
End Sub
 
 
 
Sub Int_4ms:
 
Incr P
 
 Probka = Getadc(1)                                         'zmierz na Pinie 1 ADC
 Napiecie = Napiecie + Probka                               'dodaj kolejne pomiary
  If P >= V_max Then                                        'gdy pomiarow 16
      P = 0
    Napiecie_u = Napiecie / V_max
    Hsingle = Napiecie_u * 0.0049
    Hsingle = Hsingle * 4
    Volt = Fusing(hsingle , "#.&")
    Napiecie = 0                                            'zeruj zmienna by dodawac nowe
  End If
 
End Sub

Portret użytkownika gosc

O czym zapomniałem ? ano właśnie :)

Po linijkach

If Pinc.2 = 0 Then Incr _min
If Pinc.3 = 0 Then Incr _hour

warto dopisać

If _min > 59 Then _min = 0
If _hour > 23 Then _hour = 0

Jakieś pomysły ktoś ma do istniejącego stanu rzeczy , by było bateryjne podtrzymanie zegarka , by nie trzeba było go ustawiać ponownie przy każdym załączeniu zasilania?

Portret użytkownika gosc

Nie potrzebne jeszcze...

Waitms 75

Portret użytkownika gosc

Dolutowany kwarc zegarkowy do XTAL0 i 1

Klawisze zwierają do masy , podlutowane są poprzez rezystory 4k7 do Vcc.

Ech , roztrzepany jestem dziś .Przepraszam.

Portret użytkownika gosc

Kolejna wersja tego kodu , ale z obsługą baterii (odtrzymanie)

A jak sprawić by zasilanie bateryjne było podtrzymujące działanie samego układu (zliczanie czasu - czyli zegara) ?
Czy taki kod finalnie z procedurą pomiaru napięcia (jego spadku) jest możliwy ?

$regfile = "m8def.dat"
$crystal = 8000000
Config Lcd = 16 * 2
Config Lcdpin = Pin , Rs = Pinb.1 , E = Pinb.0 , Db4 = Pinb.5 , Db5 = Pinb.4 , Db6 = Pinb.3 , Db7 = Pinb.2
Cls
 
Config 1wire = Pind.2                                       'odczyt dallasa
Config 1wire = Pind.3                                       'odczyt dallasa
Config Adc = Single , Prescaler = Auto , Reference = Internal
Config Timer0 = Timer , Prescale = 256 , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 1
 
Declare Sub Pomiar                                          'procedura odczytu
Declare Sub Wyb_uklad
Declare Sub Pomiar_t
Declare Sub Int_4ms
Declare Sub Tryb_bateria
 
Dim Nr_ukladu1(8) As Byte                                   'tablica do przechowywania nr 1 układu
Dim Nr_ukladu2(8) As Byte                                   'tablica do przechowywania nr 2 układu
 
Dim I As Byte , A As Byte                                   'zmienne pomocnicze
Dim Ta(2) As Byte
Dim Tb(2) As Byte
Dim Temp As Integer                                         'temperatura całkowita
Dim Ulamek As Integer                                       'część ułamkowa
Dim Znak1 As Byte
Dim Znak2 As Byte
Dim Tt1 As String * 10
Dim Tt2 As String * 10
Dim Tempa As Single
Dim Kanal As Byte
Dim Power_on As Word
Dim Flaga As Bit
Dim Old_sec As Byte
 
Config Clock = Soft
Config Date = Dmy , Separator = /
Time$ = "00:00:00"
Date$ = "01/01/10"
Config Pinc.3 = Input
'Config Pinc.2 = Input
Config Pinc.1 = Input
Dim Houre As Byte
Dim Mine As Byte
 
Dim 4ms As Byte
 
Dim P As Byte
Dim Probka As Word                                          'wartosc odczytana z przylozonego do ADC
Dim Napiecie As Word                                        'dodaje do siebie kolejne odczyty
Dim Napiecie_u As Single                                    'napiecie usrednione single bo z przecinkiem
Dim Hsingle As Single                                       'pomocnicza zmienna
Dim Volt As String * 5                                      'zmienna "tekstowa" 5 znakow ksztaltowana przez "fusing"
 
Const V_max = 16
 
Config Portc = &B11110000 : Portc = &B00000000
Deflcdchar 0 , 8 , 20 , 8 , 3 , 4 , 4 , 4 , 3
Cls                                                         'kasujemy LCD
 Cursor Off
 Enable Interrupts
 
Do                                                          'pętla główna
  For A = 1 To 15
  Call Tryb_bateria                                         'sprawdź jakie napięcie
  Locate 1 , 1
  Lcd Time$
  Call Int_4ms
  Locate 1 , 11
  Lcd Volt ; "V"
  If Pinc.2 = 0 Then Incr _min
  If Pinc.3 = 0 Then Incr _hour
  If _min > 59 Then _min = 0
  If _hour > 23 Then _hour = 0
 
 
 
  If A = 10 Then Call Pomiar_t
 
 
   Locate 2 , 1
   If Znak1 = 1 Then Lcd "-" Else Lcd " "
   Lcd Tt1 ; Chr(0)
   Locate 2 , 9
   If Znak2 = 1 Then Lcd "-" Else Lcd " "
   Lcd Tt2 ; Chr(0)
   Next A
Loop                                                        'koniec pętli głównej
'funkcje ogólne magistrali 1wire
'Const Search_rom = &HF0
'Const Read_rom = &H33
'Const Match_rom = &H55
'Const Skip_rom = &HCC
'Const Alarm_search = &HEC
'funkcje termometru DS18B20
'Const Convert_t = &H44
'Const Write_scratchpad = &H4E
'Const Read_scratchpad = &HBE
'Const Copy_scratchpad = &H48
'Const Recla_e2 = &HB8
'Const Read_power_supply = &HB4
 
 
Sub Pomiar_t :
 
   1wreset Pind , 2
   1wwrite &HCC , 1 , Pind , 2
   1wwrite &HBE , 1 , Pind , 2
    Ta(1) = 1wread(1 , Pind , 2)                            'lsb
    Ta(2) = 1wread(1 , Pind , 2)                            'msb
   1wreset Pind , 2
   Tempa = Ta(2) * 256
   Tempa = Tempa + Ta(1)
   Tempa = Tempa / 16
   Tt1 = Fusing(tempa , "#.#")
 
   1wwrite &HCC , 1 , Pind , 2
   1wwrite &H44 , 1 , Pind , 2
 
    If Ta(2) = &HFF And Ta(1) > &HF0 Then Znak1 = 1
 
 
   1wreset Pind , 3
   1wwrite &HCC , 1 , Pind , 3
   1wwrite &HBE , 1 , Pind , 3
   'T = 1wread(2 , Pind , Kanal):
    Tb(1) = 1wread(1 , Pind , 3)                            'lsb
    Tb(2) = 1wread(1 , Pind , 3)                            'msb
   1wreset Pind , 3
   Tempa = Tb(2) * 256
   Tempa = Tempa + Tb(1)
   Tempa = Tempa / 16
   Tt2 = Fusing(tempa , "#.#")
 
   1wwrite &HCC , 1 , Pind , 3
   1wwrite &H44 , 1 , Pind , 3
 
 
   If Tb(2) = &HFF And Tb(1) > &HF0 Then Znak2 = 1
 
   '1wreset
 
 
  End Sub
 
 
 
 
Sub Int_4ms:
 
Incr P
 
 Probka = Getadc(1)                                         'zmierz na Pinie 1 ADC
 Napiecie = Napiecie + Probka                               'dodaj kolejne pomiary
  If P >= V_max Then                                        'gdy pomiarow 16
      P = 0
    Napiecie_u = Napiecie / V_max
    Hsingle = Napiecie_u * 0.0049
    Hsingle = Hsingle * 4
    Volt = Fusing(hsingle , "#.&")
    Napiecie = 0                                            'zeruj zmienna by dodawac nowe
  End If
 
End Sub
 
Sub Tryb_bateria :       'przełącznik bateria <>zasilanie 5V
 If Old_sec <> _sec Then
     Old_sec = _sec
 Power_on = Getadc(2)
  If Power_on < 700 Then
   Toggle Flaga
   If Flaga = 0 Then
   Portb = &B00000000
   End If
   Else
   Toggle Flaga
   Initlcd
   End If
   End If
 
End Sub

Portret użytkownika marekszy

ADC przykład pomiaru

Witam, kombinuję z pomiarem prądu za pomocą ACS713-20AT, 185mV/A i jakoś topornie to działa, ma ktoś jakiś przykład jak to napisać? Z ACS przy zerowym prądzie wychodzi napięcie 0,51V które należy jeszcze odjąć od pomiaru aby wynik był 0,0A (inaczej pokazuje 2,7A na starcie), może jakiś sposób na auto-kalibrację lub za pomocą przycisku?

Portret użytkownika marekszy

ADC przykład pomiaru

nie wiem co lepsze i prawidłowe , ale działa w obu przypadkach

Prad_1:
  Hsingle_2 = Prad_a * 0.0049                               'wynik *10000 / 185mV/A dla ACS713
  Convert = Hsingle_2 * 10000                               '-4900 (przy poborze 0A napiecie 0,52V
    Convert_1 = Convert - 4900
    convert_3 = convert_1 / 185                              '/185mV ACS713 185mV/A

Prad_1:
  Hsingle_2 = Prad_a * 0.0049                               'wynik *10000 / 185mV/A dla ACS713
  Convert = Hsingle_2 * 10000
    Convert_1 = Convert / 185
    convert_3 = convert_1 - 27                              '-27 (przy poborze 0A napiecie 0,52V