Fórum témák

» Több friss téma
Fórum » AVR - Miértek hogyanok
 
Témaindító: pakibec, idő: Márc 11, 2006
Témakörök:
WinAVR / GCC alapszabályok:
1. Ha ISR-ben használsz globális változót, az legyen "volatile"
2. Soha ne érjen véget a main() függvény
3. UART/USART hibák 99,9% a rossz órajel miatt van
4. Kerüld el a -O0 optimalizációs beállítást minden áron
5. Ha nem jó a _delay időzítése, akkor túllépted a 65ms-et, vagy rossz az optimalizációs beállítás
6. Ha a PORTC-n nem működik valami, kapcsold ki a JTAG-et
Bővebben: AVR-libc FAQ
Lapozás: OK   667 / 837
(#) gabi20 válasza Gj hozzászólására (») Máj 24, 2015 /
 
Szia ezt interruptal szokás csinálni. Van egy egyszerű programom Slave receiver - ként működik, bár ez ATmega8 - ra íródott. A Slave adresst 255-re inkább ne állítsd.

  1. //*******************************************************************
  2. //                      Name:           I2C slave receiver example
  3. //                      MCU:            ATmega8 AVR CPU @ 8MHz
  4. //                      Date:           2014.09.23.
  5. //                      Author:         Hencze Gabor
  6. //***********************************************************************
  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #include <avr/interrupt.h>
  10.  
  11. volatile unsigned char twi_command = 0;
  12. //**********************************************************************************
  13. //***************************** TWI INTERRUPT VECTOR **********************
  14. ISR(TWI_vect){
  15.        
  16.    if(TWSR == 0x60){                // IF slave adress + w received
  17.  
  18.       TWCR |= 0x80;                  // Clear interrupt flag bit
  19.       while(!(TWCR & 0x80));     // Waiting...
  20.  
  21.       if(TWSR == 0x80){            // IF data received
  22.                                                
  23.          twi_command = TWDR;
  24.          TWCR |= 0x80;          // Clear interrupt flag bit
  25.          while(!(TWCR & 0x80)); // Waiting for stop bit
  26.       }
  27.    }
  28.  
  29.    TWCR |= 0x80;                     // Clear interrupt flag bit
  30. }
  31.  
  32. //************************************************************************
  33. //****************************** MAIN PROGRAM ****************************
  34. int main(void){
  35.  
  36.                   DDRB = 0xFF;                          // Set PORTB direction
  37.                 DDRC = 0x0F;                            // Set PORTC direction
  38.                 DDRD = 0xFF;                            // Set PORTD direction
  39.  
  40.                 TWAR = 0xA0;                            // Slave adress = 0xA0
  41.                 TWCR = 0x45;                            // Enable TWI, interrupt enable
  42.                
  43.                 _delay_ms(10);
  44.                 sei();                                  // General interrupt enable
  45.  
  46.                 while(1){
  47.                                 //.....
  48.                                
  49.                 }
  50. }
A hozzászólás módosítva: Máj 24, 2015
(#) csabeszq válasza gabi20 hozzászólására (») Máj 24, 2015 /
 
Meglepne, hogy működne.

Már csak azért is, mert egy darab ACK-ot nem küld vissza.
Van esély, hogy elsőre talán lefut, de valószínűsítem, hogy másodikra nem fog.
(#) gabi20 válasza csabeszq hozzászólására (») Máj 24, 2015 /
 
Pedig nekem működött gond nélkül...
TWEA bit be van kapcsolva szóval az ACK biteket visszaküldi
A hozzászólás módosítva: Máj 24, 2015
(#) Kovidivi válasza gabi20 hozzászólására (») Máj 24, 2015 / 1
 
Interruptba várakozást nem raknék, nálad 2 is van. Valahogy máshogy kellene megoldani.
(#) killbill válasza zombee hozzászólására (») Máj 24, 2015 /
 
A baj meg mindig az, hogy egy motor 0 aramat, illetve egy felso limitet kell detektalni. Ehhez az egvilagon semmi nem kell, csak a megfelelo ellenallassal lezart aramvalto kimenetet be kell vezetni az A/D-ba es software-esen merni. Feleslegesen bonyolodik az aramkor, de ettol meg a software nem lesz egyszerubb a kerdezo szintjen.
(#) csatti2 válasza zombee hozzászólására (») Máj 24, 2015 / 1
 
Hát azért kicsi a 100nF . Kíváncsiságból bemodelleztem az első áramköröd LTSpice-ba.
Az első ábra 100nF-os a második 5µF-os kondival modellezve készült. A kék görbe az RC előtti feszültség (bár ezt gyanítom kitaláltad volna magad is ).
(#) Gj válasza gabi20 hozzászólására (») Máj 24, 2015 /
 
Nekem nem működik.
(#) Gj válasza Kovidivi hozzászólására (») Máj 24, 2015 /
 
Megnéztem, már a megszakítás sem jön létre. (Vagy nem tudom, hogy kéne kifejezni, nem fut bele a megszakításba?)
(#) gabi20 válasza Gj hozzászólására (») Máj 24, 2015 /
 
Masterként is AVR-t használsz?
Akkor történik megszakítás ha engedélyezed azt, illetve a Slave megkapja a slave
adresst.
(#) Gj válasza gabi20 hozzászólására (») Máj 24, 2015 /
 
Jó hogy szólsz, kapkodtam és kihagytam a kódból a sei() parancsot Így már működik, köszönöm!
(#) Szabi1 hozzászólása Máj 25, 2015 /
 
Sziaszok! Valaki ellenőrizné, hogy helyes-e ez a kód?
  1. #include <avr/io.h>
  2. #include <util/delay.h>
  3.  
  4. uint16_t ReadADC(uint8_t ch)//adc olvasas
  5. {
  6. if (ch==0)ADMUX=(1<< MUX0);
  7. else ADMUX=(1<< MUX1);
  8. ADMUX=(1<<REFS0) ;
  9. ADCSRA|=(1<<ADSC);
  10. while(!(ADCSRA & (1<<ADIF)));
  11. ADCSRA|=(1<<ADIF);
  12. ADMUX= 0b00000000;
  13. return(ADC);
  14. }
  15.  
  16. /*pb1 pb2 rele*/
  17.  
  18. int main(void)
  19. {
  20. unsigned float voltage;
  21. DDRB = 0b11111111;
  22. //adc init
  23. ADMUX=(1<<REFS0);                         // For Aref=AVcc;
  24. ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Prescalar div factor =128
  25.  
  26. while(1)
  27. {
  28.  
  29. adc=ReadADC(0);
  30. voltage=(adc*30)/30;
  31.  
  32.  
  33. if (voltage >27.9)
  34. {
  35.  
  36.     PORTB |= 0b00000100;//rele 2 (PB2) be
  37.     _delay_ms(5000);//delay 5 mp
  38.     PORTB |= 0b00000000;  //rele 2 (PB2)  ki
  39.     PORTB |= 0b00000010;       //rele 1(PB1)  be
  40. }
  41. if (votlage < 24 )
  42. {
  43.     //rele *(PB1) 1 ki
  44.     PORTB |= 0b00000000;
  45. }
  46. _delay_ms(100);
  47. }
  48. }

Atmega 8 mikrovezérlővel szeretnék egy olyan vezérlést készíteni, hogy ADC0-n mér feszültséget, (ellenállásosztóval 30V esetén 5V ot kap) ha eléri 27.9 V-ot akkor PB2-t bekapcsolja 5 másodpercre, utánna bekapcsolja PB1-et. Ha feszültség leesik 24V alá akkor pedig lekapcsolja PB1-et.
(#) Ivan93 válasza Szabi1 hozzászólására (») Máj 25, 2015 /
 
Szia! A 30.sor "voltage=(adc*30)/30;" résznek nem látom az értelmét. A 38.sorban ha 0-t vagyolsz az 1-re az 1 marad. Használd a PORTB&=~(0b00000100)-t, ezzel egy-egy bitet is ki tudsz kapcsolni könnyen(vagy hagyd el a | jelet). Ez igaz a 44.sorra is. A ReadADC() is gyanús, de ezt fejből nem tudom, majd a többiek kijavítják, ha kell.
A hozzászólás módosítva: Máj 25, 2015
(#) yohnsee válasza zombee hozzászólására (») Máj 25, 2015 /
 
Köszönöm. Most talán el tudok indulni, megvan az irány. A részleteket úgyis nekem kell finomhangolnom.
Mindenkinek köszönöm a segítséget, még biztosan fogok kérdezni, amint elakadok.
(#) Szabi1 válasza Ivan93 hozzászólására (») Máj 25, 2015 /
 
Jajj igen tényleg a "vagyolásnál" tényleg hiba van. A 30. sornak az a szerepe, hogy az ADC értéket átalakítja feszültséggé. Az ADC bemeneten egy feszültségosztó lesz, és 30-0V feszültségtartományban kap áramot, a feszültségosztó pedig arra kell, hogy 0-5V közötti feszültségtartományt kapjon az MCU. A képletet rosszúl írtam így volna helyes "voltage=(adc*30)/255" Tehát 5V ra az adc érték 255, és az 30V nak felel meg a feszültségosztó előtt. A reléket a feszültségosztó előtti feszültség alapján kell kapcsolja.
(#) Zsolt2 válasza Szabi1 hozzászólására (») Máj 26, 2015 /
 
Az osztast amennyibol lehet erdemes kerulni, eleg idoigenyes tud lenni. Ebben az esetben az osztast fel lehet kerekiteni 256-ra, ami jobbra-tolast jelet 8-al.
(#) Max26 hozzászólása Máj 26, 2015 /
 
Köszönöm szépen az eddigi hozzászólásotokat.

Bővebben: Link

Elvi működés: Alap esetben a program kiirja az LCD-re az aktuális hőmérséklet és páratartalom értékeket. PIND5 első lenyomására az LCD-n megjelenik "Adatgyujtes..." felirat, majd elindul a mintavételezés, UART adatgyűjtés. PIND5 újbóli lenyomására kilépünk az adatgyűjtésből és visszatérünk a kiinduláshoz.

Az adatgyűjtés inditásával van a probléma. Van, hogy elsőre, de jellemzően 5. 8. alkalomra sikerül csak elindítani az adatgyűjtést. Az elindítási próbálkozások során 0. sorszámot küldi el UART-on 5x-8x mindaddig amíg el nem sikerül "kapni" a helyes időpillanatot. Ettől kezdve már rendesen megy az adatgyűjtés.

Meg tudnátok mondani mitől van ez?
(#) Zsolt2 válasza Max26 hozzászólására (») Máj 26, 2015 /
 
A pergesmetesites rosszul van megoldva. Igy 30mS-nal rovidebb ideig kene lenyomva tartsd a gombot, h jol mukodjon. Legegyszerubben ugy tudod kiegesziteni, hogy a gomb lenyomasa utan teszel egy ciklust amig nyomva tartod a gombot.
  1. if( !(PIND&(1<<PD5)) )
  2. {
  3.  while ( !(PIND&(1<<PD5)) )
  4. _delay_ms(PERGES);
  5. ....
  6. }
(#) killbill válasza Szabi1 hozzászólására (») Máj 26, 2015 /
 
Idézet:
„30-0V feszültségtartományban kap áramot”
Feszultsegtartomanyban áramot??? Feszulteg vagy aram?
Idézet:
„így volna helyes "voltage=(adc*30)/255"”
Így sem helyes, mert a voltage valtozod sosem lesz 27.9, mivel a fenti muveletnek az eredmenye mindig egesz szam lesz. Szerintem te ezt akartad irni: voltage = (adc * 30.0) / 255. De egyebkent semmi ertelme lebegopontos szamitassal kinozni a mikrokontrollert. Ezt ugynevezett fixpontos aritmetikaval illik megoldani, megpedig igy:
  1. #include <stdint.h>
  2. uint16_t  voltage;
  3.  
  4.   voltage = adc * 300L / 255;

Igy a voltage erteke 0-300 kozott lesz, ahol pl. a 21.4V a 214-es ertek.
(#) killbill válasza Zsolt2 hozzászólására (») Máj 26, 2015 /
 
Idézet:
„Az osztast amennyibol lehet erdemes kerulni, eleg idoigenyes tud lenni. Ebben az esetben az osztast fel lehet kerekiteni 256-ra, ami jobbra-tolast jelet 8-al.”
Azon felul az egesz "voltage =" reszre semmi szukseg, mert az ADC erteket egybol 8 bites ertekekkel lehethe osszehasonlitani. Tehet pl:
  1. #define VOLT_2_AD(v)  ((unsigned char)(((v) / 30.0) * 255))
  2.  
  3. if(adc > VOLT_2_AD(27.9))
  4.    ....
Mivel a VOLT_2_AD() makrónak csak konstansokat adunk at, igy az egesz lebegopontos szamitast a C fordito vegzi el forditaskor es az AVR program csak egy sima 8 vagy 16 bites int osszehasonlitast fog csinalni, semmi osztas, szorzas nem lesz benne. Hogy 8 vagy 16 bites komparalasi utasitas lesz a kodban, az mar a C forditon mulik. Elvileg eleg lenne a 8 bit, de a C szabvany szerint minden char int-re konvertalodik, ezert 16 bitesen kellene szamoljon. Ha eleg okos a fordito, akkor csak 8 biten vizsgalodik.
A hozzászólás módosítva: Máj 26, 2015
(#) Max26 válasza Zsolt2 hozzászólására (») Máj 26, 2015 /
 
Mennyire igaz, így már működik! Köszi
(#) killbill válasza Szabi1 hozzászólására (») Máj 26, 2015 /
 
A 8. sorban felulirja a 6. es 7. sorban beallitott MUX0 vagy MUX1 bitet.
ADMUX |= (1 << REFS0); akarna lenni.

Vagy a harom sor sokkal egyszerubben:
ADMUX = (ch == 0) ? (1 << MUX0) | (1 << REFS0) : (1 << MUX1) | (1 << REFS0);
(#) Sick-Bastard hozzászólása Máj 27, 2015 /
 
Üdv!

A következőt szerettem volna elérni:
A PC-ről egy USB-Soros átalakítón keresztül küldök adatot az AVRnek, ami a kapott adatokat egy mátrix-ba illeszti, majd a main()-ben elvégzem amit szeretnék és visszaküldöm UART-on a PC-nek.

A mátrix egy-egy sorában az első 4 byte az PCtől jön, az 5.-dik byte az elvégzendő/elvégzett feladat azonosítására használom.

  1. volatile unsigned char USART_BUFFER_MATRIX_ARRAY[32][5];   // mátrix[sor][oszlop]
  2. volatile unsigned char USART_RX_byte_count = 0;
  3. volatile unsigned char row, col;
  4.  
  5. int main(void)
  6. {
  7.         DDRC |= 0xFF;           // LED
  8.         DDRD |= 0xFF;           // LED
  9.         PORTC |= 0x0B;          // LED
  10.         USART0_Init(12);        // UBRR = 12, U2X0 = 1, BAUD = 115200
  11.         SPI_Init();
  12.         sei();
  13.        
  14.         while(1)
  15.         {
  16.                 for(unsigned char i = 0;i < 32; i++)
  17.                 {
  18.                         if(USART_BUFFER_MATRIX_ARRAY[i][4] != 0)
  19.                         {
  20.                                 UART_TX_LED_OFF;
  21.                                 for(unsigned char y = 0; y < 4; y++)
  22.                                 {
  23.                                         USART0_TXD(USART_BUFFER_MATRIX_ARRAY[i][y]);
  24.                                 }
  25.                                 USART_BUFFER_MATRIX_ARRAY[i][4] = 0;
  26.                                 UART_TX_LED_ON;
  27.                         }
  28.                         PORTD ^= (1<<PIND7); // villog (program fut jelzése)
  29.                 }
  30.         }
  31. }
  32.  
  33. ISR(USART_RX_vect)
  34. {
  35.         UART_INT_LED_OFF;
  36.         row = (USART_RX_byte_count / 4);
  37.     col = (USART_RX_byte_count % 4);
  38.         USART_BUFFER_MATRIX_ARRAY[row][col] = UDR0;
  39.         if(col == 3)
  40.         {
  41.                 if(USART_BUFFER_MATRIX_ARRAY[row][0] < 0x10)
  42.         {
  43.                         USART_BUFFER_MATRIX_ARRAY[row][4] = 4;
  44.         }
  45.         else
  46.         {
  47.                         USART_BUFFER_MATRIX_ARRAY[row][4] = 1;
  48.         }
  49.         }
  50.         USART_RX_byte_count++;
  51.         USART_RX_byte_count &= 0x1F;
  52.  
  53.         UART_INT_LED_ON;
  54. }


A gondom, hogy a fenti lebutított kódnak csak annyi lenne a feladata, hogy minden 4.-dik beérkezett byte után azokat visszaküldje, ám elcsúszva küldi vissza:
Idézet:
„sending: 0F 10 11 12
receiving: 0F 00 00 00
sending: 0F 13 14 15
receiving: 10 11 12 00
sending: 0F 16 17 18
receiving: 0F 11 12 00
sending: 0F 19 1A 1B
receiving: 13 14 15 0F
sending: 0F 1C 1D 1E
receiving: 16 17 18 0F
sending: 0F 1F 20 21
receiving: 0F 19 1A 0F
sending: 0F 22 23 24
receiving: 1B 19 1A 0F
sending: 0F 25 26 27
receiving: 0F 1C 1D 1E”


Tanácstalan vagyok.
(#) shirke hozzászólása Máj 28, 2015 /
 
Sziasztok!
Nemrég rendeltem egy kis panelt egy atmega328-assal gyakorlásnak. Próbálkozok az AD beüzemelésével de valamiért nem működik, tudtok segíteni hogy mit rontottam el?
A PORTD és PORTB-re ledeket kötöttem. A célom csupán annyi volt hogy a ledeken lássam a AD értékét, de ha az ADMUX-ban bármit állítok be, és az ADCn-lábakat bárhová is kötöm mindig világítanak a ledek (tehát PD=PB=0xff)
  1. #include "avr/io.h"
  2. #include "avr/interrupt.h"
  3. int main()
  4. {
  5. DDRD=0xff;
  6. DDRB=0xff;
  7. DDRC=0b0;
  8. ADMUX=0b01001111;
  9. ADCSRA=0b11000000;
  10. while((0b01000000&ADCSRA))
  11. {
  12. }
  13. PORTD=ADCL;
  14. PORTB=ADCH;
  15. while(1)
  16. {
  17. }
  18. return 0;
  19. }
(#) Kovidivi válasza shirke hozzászólására (») Máj 28, 2015 /
 
Az admux-nál a GND-t választod ki? MUX3..0 = 1111 ?
Van kondenzátor a referencia pin-en? Mérsz rajta feszültséget?
És mi van az ADC-re akasztva? Egy poti? Melyik lábon? Ott is ellenőrizd le a feszültséget, hogy meg van-e.
Az interrupt.h teljesen felesleges ide.
A hozzászólás módosítva: Máj 28, 2015
(#) shirke válasza Kovidivi hozzászólására (») Máj 28, 2015 /
 
Ha gnd-t választok akkor is azt csinálja (a fenti kódban pont az van).
Igen mértem rajta, mikor az AVc-re állítottam az Aref-et akkor 5V mikor a belső ref.fesz.-re akkor 1,1V volt az Aref lábon. Sajnos a kondenzátort nem tudom mert még nem silabizáltam ki a panelről, de megpróbálom kideríteni. Az ADC-re próbáltam a tápot rakni (amikor Aref=5V), vagy kettő vagy több ellenállással leosztott feszt raktam.
Igen az csak ottmaradt egy másikból.
(#) Ivan93 válasza shirke hozzászólására (») Máj 28, 2015 /
 
Szerintem a 13-14. sor értékadását a ciklusba kellene tenni mert így csak egyszer fut le, később hiába tekered a potit, nem adja át az értéket.
(#) shirke válasza Ivan93 hozzászólására (») Máj 28, 2015 /
 
Egyelőre annak is örülnék ha a valós értéket akár egyszer is kiadná, de köszi az észrevételt
(#) Kovidivi válasza shirke hozzászólására (») Máj 28, 2015 /
 
Próbáld ki free running módban, és adlar-t állítsd 1-re, és csak 8bit-es értéket olvass ki. Jó lábra van kötve a feszültség osztó, és jó lábat állítasz be az admux-nál? Én így csinálnám. Azt is írja az adatlap, hogy az első konverzió tovább is tart, meg néha el is szokták dobni. 1 mérés nem mérés.
  1. while(1)
  2. {
  3. _ms_delay(300);
  4. PORTD=ADCL;
  5. }
(#) shirke válasza Kovidivi hozzászólására (») Máj 28, 2015 /
 
Elvileg alapból abban működik mert hozzá se nyúltam a ADCSRB-hez. Átállítottam de semmi változás, csak a PD felső két bitje világít, tehát nincs változás, pedig ellenőriztem újra a lábakat, földre kötve is ugyan azokat adja ki a PD-re. Lehet a mikroC-m rossz...
(#) kapu48 válasza shirke hozzászólására (») Máj 28, 2015 /
 
Talán puskáz innen: ADC on Atmega328.
Következő: »»   667 / 837
Bejelentkezés

Belépés

Hirdetés
Lapoda.hu     XDT.hu     HEStore.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem