Fórum témák

» Több friss téma
Fórum
Keresés
Lapozás: OK   1 / 2
(#) icserny válasza szucsistvan123 hozzászólására (») Ápr 2, 2020
Én ezt használtam (C18-hoz készült, de szerintem más C fordító is megeszi).
A _user_putc() helyére egy karakterkiíró függvényt írj, amit használsz).
(Utóirat: Bocs, most látom, hogy nem egészen erre gondoltál....)
  1. /** Decimális kiíratás adott számú tizedesjegyre.
  2.  * \param data a kiírandó szám (előjelesen)
  3.  * \param ndigits a kiírandó tizedesek száma
  4.  */
  5. void outdec(long data, unsigned int ndigits) {
  6. static char sign, s[12];
  7. unsigned int i;
  8.         i=0; sign='+';
  9.         if(data<0) { sign='-'; data = -data;}
  10.         do {
  11.                 s[i]=data%10 + '0';
  12.                 data=data/10;
  13.                 i++;
  14.                 if(i==ndigits) {s[i]='.'; i++;}
  15.         } while(data>0);
  16.         _user_putc(sign);
  17.         do{
  18.                 _user_putc(s[--i]);
  19.         } while(i);
  20. }
A hozzászólás módosítva: Ápr 2, 2020
(#) icserny válasza uli hozzászólására (») Ápr 30, 2014
Ezen az oldalon mindjárt az első mintapélda is tartalmazza az sw_uart_outdec() függvényt, amelyet könnyen át lehet írni LCD kijelzésre (a függvény nevét, meg az egy karaktert kiíró sw_uart_putc() hívásokat kell megváltoztatni benne.
(#) don_peter válasza don_peter hozzászólására (») Márc 8, 2014
Közben megoldottam magam is a kérdést:
  1. void outdec(long data, unsigned int ndigits, unsigned int maxtizedes) {
  2.     static char sign, s[12], volt;
  3.     unsigned int x;
  4.     x=0; sign='+'; volt='v';
  5.     if(data<0) { sign='-'; data = -data;}
  6.     do {
  7.             s[x]=data%10 + '0';
  8.             data=data/10;
  9.             x++;
  10.             if(x==ndigits) {s[x]='.'; x++;}
  11.     }
  12.         while(data>0 || x<ndigits+2);
  13.         _user_putc(sign);
  14.     do{
  15.                 if(x>=maxtizedes){
  16.                 _user_putc(s[--x]);
  17.                 }else{ break; }
  18.     }
  19.         while(x);
  20.         _user_putc(volt); //Volt "v" kiíratása a végére
  21.         printf("                    "); //LCD sor frissítése
  22. }

Ez már úgy van átalakítva, hogy ha kisebb 1nél az érték akkor a tizedes pont elé teszt be egy nullát és meghatható hány tizedesig írjon ki.
Pl:
Volt = 345678
outdec(volt, 3, 2);
Eredmény: +3.45v
Ha van szebb és hatásosabb megoldás akkor kérlek jelezzétek.
Köszi.
A hozzászólás módosítva: Márc 8, 2014
(#) icserny válasza don_peter hozzászólására (») Márc 8, 2014
Idézet:
„Ez a függvény nekem nem volt benne az LCD driverben.”
Miért is volna benne, amikor semmi köze az LCD-hez? Az a felhasználó magánügye, hogy az _user_putc()-t hova definiálja... Egyébként a piccolo_usb.c-ben használom/definiálom az outdec() függvényt.
A hozzászólás módosítva: Márc 8, 2014
(#) icserny válasza don_peter hozzászólására (») Márc 8, 2014
Idézet:
„Uraim, mondja már el valaki nekem, hogy miért nem tudok lebegőpontos (float) változót kiíratni az LCD kijelzőre?”
Azért, mert nem úgy csinálod, ahogy mondtam.

  1. // float flo_at = 12.334563; <--- ezt felejtsd el! Helyette:
  2. long no_float = 12334563;
  3. outdec(no_float,6);


A kiírató rutint a PICCOLO projektben megtalálod:

  1. /** Decimális kiíratás adott számú tizedesjegyre.
  2.  * \param data a kiírandó szám (előjelesen)
  3.  * \param ndigits a kiírandó tizedesek száma
  4.  */
  5. void outdec(long data, unsigned int ndigits) {
  6. static char sign, s[12];
  7. unsigned int i;
  8.         i=0; sign='+';
  9.         if(data<0) { sign='-'; data = -data;}
  10.         do {
  11.                 s[i]=data%10 + '0';
  12.                 data=data/10;
  13.                 i++;
  14.                 if(i==ndigits) {s[i]='.'; i++;}
  15.         } while(data>0);
  16.         _user_putc(sign);
  17.         do{
  18.                 _user_putc(s[--i]);
  19.         } while(i);
  20. }


Felteteleztem, hogy az _user_putc() függvényt úgy definiáltad, hogy az LCD-re írjon.
(#) don_peter válasza icserny hozzászólására (») Márc 7, 2014
Main-on kívűl:
  1. volatile unsigned int a;
  2. volatile unsigned float v;
  3. volatile unsigned float mv = 5000; //5v
  4. volatile unsigned float o = 1023; //poti maxra tekerve

Main-on és wile-n belül:
  1. a = ReadADC();
  2.           v = ((mv / o) * a)/1000;
  3.      printf("Poti: %04d", a); //mert ha kisebb a szám 1000-nél nem törli az utolsó karaktert
  4.         lcd_write(0xC0,0,1,1);  
  5.       printf("Fesz: %3.2f", v); //elvileg kerekítene 2 tizedesre
  6.         lcd_write(0x94,0,1,1);

Az outdec() függvény nekem nincs benne vagy legalább is nem találja.
Az LCD drivert amit írtál teljesen külön raktam és átírtam a portokat.

ui: melyik fájlban találhatom meg az outdec() függvényt?
A hozzászólás módosítva: Márc 7, 2014
(#) icserny válasza don_peter hozzászólására (») Márc 7, 2014
Ha a feszültséget mV-ban számolod ki (5 helyett 5000-rel kell szorozni), akkor az eredmény long típusú változóban előjeles egészként tárolható/kezelhető, s az outdec() függvénnyel tetszőleges tizedesjeggyel kiíratható.

Idézet:
„Ha ezen driver segítségével nem lehet kiíratni...”
Nem értem az összefüggést.
(#) icserny válasza VSzabi hozzászólására (») Feb 27, 2014
Idézet:
„Hogyan kellene megváltoztatni a decimális kiíratást hogy kiírjon 0-val kezdődőt is pl. 0.275 ?”

Valahogy így!
  1. /**------------------------------------------------------------
  2.  * Decimális kiíratás adott számú tizedesjegyre.
  3.  *-------------------------------------------------------------
  4.  * data - a kiírandó szám (előjelesen)
  5.  * ndigits - a kiírandó tizedesek száma
  6.  */
  7. void sw_uart_outdec(int32_t data, uint8_t ndigits) {
  8.   static char sign, s[12];
  9.   uint8_t i;
  10.   i=0; sign=' ';
  11.   if(data<0) { sign='-'; data = -data;}
  12.     do {
  13.       s[i]=data%10 + '0';
  14.       data=data/10;
  15.       i++;
  16.       if(i==ndigits) {s[i]='.'; i++;}
  17.     } while(data > 0 || i < ndigits+2);  //<--itt a lényeg!
  18.     sw_uart_putc(sign);
  19.     do {
  20.       sw_uart_putc(s[--i]);
  21.     } while(i);
  22. }


Bocs, ez momentán MSp430-hoz és szoftveres UART kimenethez készült, de a lényeget biztosan ki tudod hámozni belőle! A lényeg a leállásí feltétel kibővítése. Akkor állunk le, ha már egyik feltétel se teljesül, azaz a kiírandó szám "elfogyott" és a tizedesjegy előtt legalább egy számjegyet már kiírtunk.
(#) icserny válasza VSzabi hozzászólására (») Feb 25, 2014
Idézet:
„Error [1109] type mismatch in redeclaration of 'outdec'”
Ha egynél több helyen deklaráltad, akkor csak szinkronban változtathatsz rajta, erre figyelmeztet a fordító.
(#) VSzabi válasza icserny hozzászólására (») Feb 24, 2014
Köszönöm a gyors választ!
Megpróbálom összehozni a pillanatnyi és az átlag kijelzést is.
Még érdekelne a decimális átváltás és mitől függ, hogy hány elemű a tömb.
(Gory CDC cikkében is van hasonló átalakítás (binár-decimál) de ott sem találtam konkrét leírást az átalakítás folyamatáról.
for(i=4;i>0;i--)
{
tempString[i] = (((char)(temp._word % 10)) & 0x0F) | 0x30;
temp._word /= 10;
}//end for)

Átírtam egyszer az outdec-et unsigned int-re mert 0-16 voltnál nem kell többet kiírni, ez pedig millivoltba és binárisan sem nagyobb mint 11 bit. Próbáltam visszaírni, de azóta a fordító nem engedi vissza long-ra.
void outdec(unsigned int data, unsigned int ndigits) -> void outdec(long data, unsigned int ndigits)
Error [1109] type mismatch in redeclaration of 'outdec'
Nekem kell egyáltalán long?
Volt márt majdnem pontos is a mérés de addig javítottam míg jelen pillanatban csak a reléket tudom kapcsolni, a küldött értékek helyett csak +0 jelenik meg.
(#) icserny válasza VSzabi hozzászólására (») Feb 22, 2014
Idézet:
„A decimális átváltás nem egészen világos.”
Az outdec() függvény feltételezi, hogy valamilyen kisebb egységben tárolod az eredményt. Például feszültségmérésnél mV-okban, hőmérésnél tizedfokokban. Ez teszi lehetővé, hogy egész típusú változóban (előjeles, 32 bites!) tárolhassunk minden értékes jegyet.

A kiíratásnál pedig megmondjuk, hogy hány tizedesjegyet "vágjunk le", hogy a nagyobb eygséget kapjunk. Pl. mV -> V esetén 3-at, tizedfok -> fok esetén 1-et.

Ha nem sürget az idő, én felszorzás helyett megfelelő számú mérés összeadását javaslom. Így végeredményben sok mérés átlagát küldöd ki, ami stabilabb eredményt ad.
(#) VSzabi hozzászólása Feb 22, 2014
Sziasztok!
Segítségeteket szeretném kérni a problémám megoldásához. A piccolo alapján, PIC14K50-nel csináltam egy relépanelt áram és fesz méréssel.
A pic minden lábhoz van funkció rendelve. B6 B7 C4 C5 digit kimenetek a relék ki be kapcsolásához.
A többi AN4-AN11 analóg bemenet az áram és fesz méréshez. A ref fesz. 1,024V így az átszámítással nem kell foglalkozni (1024/1023).
A relék 14V-ot kapcsolgatnak ezért 1:15 feszosztót tettem a bemenetre. 4-es eltolással szeretném megkapni a mért feszt. A digitális kimenetekkel nincs gondom a reléket tudom kapcsolgatni de az analóg nem úgy működik ahogy én szeretném. Valamiért ha kikapcsolok egy relét akkor 0 értéket kapok, ez jó is, de eközben megváltozik egy másik csatornán mért érték amit a pc fele küld, amin nem is változtattam.
Amit még tapasztaltam, az a kisebb értékek 0-nak jelennek meg. Ha a küldés előtt megnövelem a konverzió eredményét, szorzással vagy eltolással, akkor valamit átküld. Csatoltan a main.

A decimális átváltás nem egészen világos. Esetleg ha ezt valaki elmagyarázná nagyon megköszönném.
Ebben a függvényben van definiálva. A tömb és a modulo művelet amit szeretnék érteni, hogy hogyan hajtódik végre.
void outdec(long data, unsigned int ndigits) {
static char sign, s[12];
unsigned int i;
i=0; sign='+';
if(data<0) { sign='-'; data = -data;}
do {
s[i]=data%10 + '0';
data=data/10;
i++;
if(i==ndigits) {s[i]='.'; i++;}
} while(data>0);
_user_putc(sign);
do{
_user_putc(s[--i]);
} while(i);
}
(#) icserny válasza Lüke Aladár hozzászólására (») Máj 21, 2013
Az alábbi eljárás 32 bites előjeles (long) típusú paramétert alakít karakterekké és ír ki.
lcd_putc() helyére az egy karakter kiíró eljárásod nevét helyettesítsd be!
  1. void outdec(long data) {
  2. static char sign, s[12];
  3. unsigned int i;
  4.         i=0; sign='+';
  5.         if(data<0) { sign='-'; data = -data;}
  6.         do {
  7.                 s[i]=data%10 + '0';
  8.                 data=data/10;
  9.                 i++;
  10.         } while(data>0);
  11.         lcd_putc(sign);
  12.         do{
  13.                 lcd_putc(s[--i]);
  14.         } while(i);
  15. }


Kis módosításokkal, ugyanezzel az eljárással, felskálázott értékeket adott tizedesjegyre is kiírathatunk (pl. millivoltokra átszámított feszültséget 3 tizedesre, vagy tizedfokokban mért hőmérsékletet 1 tizedesre):

  1. /**------------------------------------------------------------
  2.  * Decimális kiíratás adott számú tizedesjegyre.
  3.  *-------------------------------------------------------------
  4.  * data - a kiírandó szám (előjelesen)
  5.  * ndigits - a kiírandó tizedesek száma
  6.  */
  7. void outdec(long data, char ndigits) {
  8.   static char sign, s[12];
  9.   char i;
  10.   i=0; sign=' ';
  11.   if(data<0) { sign='-'; data = -data;}
  12.     do {
  13.       s[i]=data%10 + '0';
  14.       data=data/10;
  15.       i++;
  16.       if(i==ndigits) {s[i]='.'; i++;}
  17.     } while(data > 0 || i < ndigits+2);
  18.     lcd_putc(sign);
  19.     do {
  20.       lcd_putc(s[--i]);
  21.     } while(i);
  22. }
(#) icserny válasza qbit hozzászólására (») Ápr 15, 2013
A b=read_ADC(CH_FORWARD); konverzió eredményét kellene ellenőrizni, mert nem tudni, hogy a későbbi skálázásnál mit csinál a programod. Mellesleg a float típust jó volna kiküszöbölni. Nem hiszem, hogy nélkülözhetetlen volna. Számold át az eredményeket inkább millivoltokba! 32 bites (long) változó kell hozzá.

fesz = b*5000L/1023L;

Ezt könnyen kiírathatod a PICCOLO projektben található outdec() függvénnyel...
(#) szitko hozzászólása Márc 12, 2013
Sziasztok.

Egy kicsit bizonytalan vagyok. Összehoztam egy egyszerű fordulatszámmérőt, de nem vagyok benne biztos, hogy jól számoltam-e.
A hardverről csak annyit, hogy egy CD-ből kioperált motorra ragasztottam egy mágnest, és elé raktam egy HALL szenzort (TLE4905), és a jelét egy ellenállás osztón keresztül kapja meg a g2231 capture modulja. (természetesen 100nF-al szűrve)
Beállítottam a motor fordulatszámát ~6000-re, de szerintem nem forog annyit a motor. Hogy tudnám azt leellenőrizni, hogy jó-e a mért értékem?
Prog:
  1. while(1){
  2.           if(uart){
  3.                _DINT();
  4.                P1OUT ^= BIT0;
  5.                long captured=0, cap_val=0;
  6.                unsigned int captured_rpm=0, captured_hz=0;
  7.                for(char j=1; j<6;j++){
  8.                     cap_val += capture_buffer[j];
  9.                }
  10.                captured = cap_val / 5;
  11.                captured_hz = frequency / captured;
  12.                captured_rpm = (captured_hz<<2)+(captured_hz<<1);
  13.                sw_uart_puts("\r\nFrequency = ");
  14.                sw_uart_outdec(captured_hz,0);
  15.                sw_uart_puts(" Hz Fordulat = ");
  16.                sw_uart_outdec(captured_rpm,0);
  17.                sw_uart_puts(" RPM");
  18.           }
  19.           __low_power_mode_0();
  20.      }
  21. }
  22.  
  23. #pragma vector=TIMERA1_VECTOR
  24. __interrupt void TimerA1(void){
  25.      new_capture = TACCR1;
  26.      capture_buffer[count++] = new_capture - old_capture;
  27.      if (count==6){
  28.           count=0;
  29.           uart=1;
  30.           TACCTL1 &= ~CCIFG;
  31.           __low_power_mode_off_on_exit();
  32.      }
  33.      old_capture = new_capture;
  34.      TACCTL1 &= ~CCIFG;
  35. }
A hozzászólás módosítva: Márc 12, 2013
(#) szitko válasza icserny hozzászólására (») Márc 10, 2013
Valóban!
Köszönöm. Egy másik MCU-val (g2252) előállítottam, szkóp és freki mérő szerint pontosan 500Hz-et. Ezt mérem a g2231-el, a lenti programmal, és a kiírt eredmény "1974". Nem 2000 kéne legyen?
Kiíró és számoló rutin:
  1. while(1){
  2.           if(uart){
  3.                _DINT();
  4.                P1OUT ^= BIT0;
  5.                captured=0;
  6.           for(char j=1; j<6;j++){
  7.                captured += capture_buffer[j];
  8.           }
  9.           captured /=5;
  10.                sw_uart_outdec(captured,0);
  11.                sw_uart_puts("\r\n");
  12.           }
  13.           __low_power_mode_0();
  14.      }

Capture_2.jpg
    
(#) szitko válasza ban.laszlo hozzászólására (») Jan 20, 2013
A program elején (#define LCM_PIN_RS BIT0......) található az LCD bekötése:
LCD RS=P1.0, LCD EN=P1.1 stb.
Ezek után, az "int main(){" részben vedd ki kommentből az inicializálást, és a képernyő törlést, állítsd be a kurzor pozíciót, és az UART küldés után, elé, rakd be a HD44780_outdec..... sort.
(#) icserny hozzászólása Nov 20, 2012
Az MSP430G2553 hardveres UART full duplex használatához portoltam a PICula projektemben kidolgozott szoftveres bufferelésű (gyűrű táras) és interruptos kezelésű uart_putc(), uart_getc() függvényeket.

Használata: A projektekbe fel kell venni a hw_uart_buf.c állományt, s a fenti függvényket használó fordítási egységekbe (pl. főprogram) be kell csatolni hw_uart_buf.h fejléc állományt.

Egy kis bónusz: IAR EW esetén ha felüldefiniáljuk a putchar() függvényt, akkor a printf() függvény is használható a kiírásra. Ugye, milyen egyszerű? Mintapélda:
  1. #include <msp430.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include "hw_uart_buf.h"
  5.  
  6. int putchar(int outChar) {
  7.   uart_putc((uint8_t)outChar);
  8.   return outChar;
  9. }
  10.  
  11. char c;
  12. int main( void ) {
  13.   WDTCTL = WDTPW + WDTHOLD;            //Letiltjuk a watchdog időzítőt
  14.   DCOCTL = CALDCO_1MHZ;                //DCO beállítása a gyárilag kalibrált
  15.   BCSCTL1 = CALBC1_1MHZ;               //1 MHz-es frekvenciára  
  16.   uart_init(BPS_9600);
  17.   printf("NLIsten hozott a Launchpad projekthez!");
  18.   printf("hello_print program (hw_uart_buf)NL");
  19.   while (1) {
  20.     c=uart_getc();
  21.     printf("Vett karakter: %c = %dNL",c,c);
  22.   }
  23. }



Ha a printf() függvényt nem akarjuk használni, akkor a kiíratást a hw_uart_buf.c állományban definiált (itt már többször bemutatott) függvények segitségével is végezhetjük. Például így:
  1. #include <msp430.h>
  2. #include <stdint.h>
  3. #include "hw_uart_buf.h"
  4.  
  5. char c;
  6. int main( void ) {
  7.   WDTCTL = WDTPW + WDTHOLD;            //Letiltjuk a watchdog időzítőt
  8.   DCOCTL = CALDCO_1MHZ;                //DCO beállítása a gyárilag kalibrált
  9.   BCSCTL1 = CALBC1_1MHZ;               //1 MHz-es frekvenciára  
  10.   uart_init(BPS_9600);
  11.   uart_puts("NLIsten hozott a Launchpad projekthez!NL");
  12.   uart_puts("hello_int program (hw_uart_buf)NL");
  13.   while (1) {
  14.     c=uart_getc();
  15.     uart_puts("Vett karakter: ");
  16.     uart_putc(c);
  17.     uart_puts(" = ");
  18.     uart_outdec((int32_t)c,0);
  19.     uart_puts(" NL");
  20.   }
  21. }


Megjegyzések:
1. Sajnos, a fórummotor nem engedi berakni a newline karaktereket, ezért NL-lel helyettesítettem!
2. Az IAR EW projekt opcióknál célszerű a printf függvény használatát "Auto"-ra állítani, hogy fölösleges formátumok kezelésével ne tömje tele a programunkat.
(#) icserny hozzászólása Okt 1, 2012
HIBAIGAZÍTÁS:

Hibát találtam a mintaprogramjaimban használt számkiírató eljárás működésében: Ha a kiírandó érték a 10-zel történő osztásoknál "elfogy", mielőtt a tizedespontot kiírnánk, akkor a tizedes pont nem kerül kiírásra, s így hamis lesz a kiírt érték. Például 0.075V helyett 75V eredményt kapunk!

Javítás: A hiba orvoslására figyelnünk kell azt is, hogy legalább annyi számjegyet mindenképp írassunk ki, mint ahány tizedesjegyet ki akartunk íratni.

Példa: Az alábbi példában legalább egy számjegyet kiíratunk a tizedespont előtt, tehát az értéktelen nulla egész is kiírásra kerül (pl. .735 helyett 0.735).
  1. /**------------------------------------------------------------
  2.  * Decimális kiíratás adott számú tizedesjegyre.
  3.  *-------------------------------------------------------------
  4.  * data - a kiírandó szám (előjelesen)
  5.  * ndigits - a kiírandó tizedesek száma
  6.  */
  7. void sw_uart_outdec(int32_t data, uint8_t ndigits) {
  8.   static char sign, s[12];
  9.   uint8_t i;
  10.   i=0; sign='+';
  11.   if(data<0) { sign='-'; data = -data;}
  12.     do {
  13.       s[i]=data%10 + '0';
  14.       data=data/10;
  15.       i++;
  16.       if(i==ndigits) {s[i]='.'; i++;}
  17.     } while(data > 0 || i < ndigits+2);
  18.     sw_uart_putc(sign);
  19.     do {
  20.       sw_uart_putc(s[--i]);
  21.     } while(i);
  22. }

További módosítási lehetőség: A sign='+'; utasításban a pluszjel helyett szóközt is írhatunk a fölösleges előjel kiíratásának elkerülésére.
A hozzászólás módosítva: Okt 1, 2012
(#) icserny válasza diablo hozzászólására (») Szept 16, 2012
Idézet:
„egészrész = eredmény / 10000; (2 byte)
törtrész = eredmény % 10000; (2 byte)”
Nem tudom, hogy van-e értelme külön tárolni az egészrészt és törtrészt. Én feszültséget mV, hőmérsékletet tizedfok egységekben számolok, s az egészrész meg a törtrész kiszámítása helyett csak kiíratásnál határozom meg a tizedespont helyét. Lásd például ezen az oldalon! Az outdec() függvény így néz ki:
  1. /** Decimális kiíratás adott számú tizedesjegyre.
  2.  * \param data a kiírandó szám (előjelesen)
  3.  * \param ndigits a kiírandó tizedesek száma
  4.  */
  5. void outdec(long data, unsigned int ndigits) {
  6. static char sign, s[12];
  7. unsigned int i;
  8.         i=0; sign='+';
  9.         if(data<0) { sign='-'; data = -data;}
  10.         do {
  11.                 s[i]=data%10 + '0';
  12.                 data=data/10;
  13.                 i++;
  14.                 if(i==ndigits) {s[i]='.'; i++;}
  15.         } while(data>0);
  16.         _user_putc(sign);
  17.         do{
  18.                 _user_putc(s[--i]);
  19.         } while(i);
  20. }

(#) icserny válasza ban.laszlo hozzászólására (») Szept 6, 2012
Nézz szét a topikban ("outdec" a varázsszó), találsz rá megoldást! A hőmérsékletet tizedfok egységekre konvertáld, s a kiíratásnál jelezzük, hogy egy tizedesre kérjük a kiíratást.

Ugyanezt a módszert használom soros porti kiíratásnál is. Bővebben: link.
(#) mzozo95 válasza sgt hozzászólására (») Júl 28, 2012
Szia!
Köszönöm, így a megszakítás már tökéletes.

Amit lehetett, mindent bepakoltam lokális változónak, de sajnos a main sok másik függvényt meghív, amiknek globális változó kell(+ az interruptos változók)

A pointert ahol lehetett alkalmaztam(kivéve az interruptban, így láttam ésszerűbbnek), de engem igazából a globális pointerek jobban összezavarnak, mint ahogy most írtam...

AZ átláthatatlanságot a sok kis függvény okozhatja, ami a mainban van, a program így tökéletesen működik, 12ch software pwm + 2ch hardware pwm...

  1. #define F_CPU 8000000
  2. #include <avr/io.h>
  3. #include <util/delay.h>
  4. #include <avr/interrupt.h>
  5. #include <inttypes.h>
  6.  
  7. #include <stdbool.h> //bool típushoz
  8.  
  9. ////////////////////////////////
  10. #define BAUD 38400///38400bps
  11. #define UBRR ((F_CPU / (BAUD * 16L)) - 1)
  12. ////////////////////////////////
  13. //változók
  14. volatile unsigned char rec[15];//string buffeer
  15. volatile unsigned char buffer; //byte buffet
  16.  
  17. volatile unsigned char stat=0;//string karakter száma
  18.  
  19. volatile int se[12]; //bejövő adat
  20.  
  21. volatile int servo[12]; ///szervo pozíció
  22. volatile bool inter=0;//(0-1) szemafor
  23. //////////////////
  24. /////
  25. void uart_init(void)
  26. {
  27. UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
  28. // baud rate
  29. UBRR0H = (unsigned char) (UBRR>>8);
  30. UBRR0L = (unsigned char) UBRR;
  31. //  format: 8data, 2stop bit
  32. UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
  33. }
  34.  
  35. ///////UartKüld
  36.   void UARTKuld(unsigned char c){
  37.                 while((UCSR0A & (1<<UDRE0)) == 0) {}
  38.        
  39.             UDR0 = c;
  40. }
  41. ///////szövegküld
  42.    void UARTSzovegKuld( char *p)
  43. {
  44.         while(*p)
  45.         {
  46.           UARTKuld( *p++);
  47.         }
  48. }//szövegküld vége
  49.  
  50. void delrec(void){
  51.  for(int i=0; i<15;i++){
  52.   rec[i]=' ';
  53. stat=0;};
  54.  }
  55.  
  56. void kuldrec(void){
  57. for(int i=0; i<stat ;i++){
  58.  UARTKuld(rec[i]);}
  59.  }
  60.  
  61. //decimális szám küldése:
  62. void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
  63.     static char sign, s[12];
  64.     _delay_us(10);
  65.     unsigned int i;
  66.             i=0; sign=' ';  //alapvetően nincs előtte semmi
  67.             if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
  68.             do {
  69.                     s[i]=data%10 + '0'; //integer átírása ASCII ba
  70.                     data=data/10;
  71.                     i++;
  72.                     if(i==ndigits) {s[i]='.'; i++;}
  73.             } while(data>0);
  74.             UARTKuld(sign);
  75.             do{
  76.                       UARTKuld(s[--i]); //összes karakteren végigmenni
  77.             } while(i);
  78. }
  79.  
  80. uint8_t comm( char *p){
  81. char azonos=1;
  82. int szam=0;
  83. for(szam=0; szam < 15; szam++)
  84. {
  85.     if (rec[szam]!=( *p++))
  86.     {
  87.        azonos = 0;
  88.        break;
  89.     }
  90.     if(!*p) break;
  91.  }
  92. return (azonos);}
  93.  
  94.  
  95. uint16_t strtoint(int szam){
  96. int ertek=0;
  97.  
  98. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
  99. szam+=1;
  100. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
  101. szam+=1;
  102. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
  103. szam+=1;
  104. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
  105. return (ertek);}
  106.  
  107. void ready(void){
  108. for(int i=0; i<14;i++)
  109. {servo[i]=se[i];}
  110. }
  111.  
  112. void init_servo(void){//servo init
  113. //16bit pwm
  114. DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1);   //pwm portd1 2 3
  115.  
  116. TCCR1A = (1<<COM1A1)| (1<<COM1B1);
  117. TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
  118. ICR1 = 10000;//periódus: 20ms
  119. OCR1A = 750;//servo1 1500us
  120. OCR1B = 750;//servo2 1500us
  121. }
  122.  
  123. uint16_t afterdelay(void){
  124. int ertek=0;
  125. ertek+=se[0]+se[1]+se[2]+se[3]+se[4]+se[5]+se[6]+se[7]+se[8]+se[9]+se[10]+se[11];
  126. return(20000-ertek);}
  127.  
  128. void delay_1us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
  129.          while(delay_data--) _delay_us(1); }
  130.  
  131. void s_pwm(void){
  132. ///////////////software pwm
  133. PORTD=4;
  134. delay_1us(servo[0]);
  135.  
  136. PORTD=8;
  137. delay_1us(servo[1]);
  138.  
  139. PORTD=16;
  140. delay_1us(servo[2]);
  141.  
  142. PORTD=32;
  143. delay_1us(servo[3]);
  144.  
  145. PORTD=64;
  146. delay_1us(servo[4]);
  147.  
  148. PORTD=128;
  149. delay_1us(servo[5]);
  150.  
  151. PORTD=0;
  152. PORTB=1;
  153. delay_1us(servo[6]);
  154.  
  155. PORTB=8;
  156. delay_1us(servo[7]);
  157.  
  158. PORTB=16;
  159. delay_1us(servo[8]);
  160.  
  161. PORTB=32;
  162. delay_1us(servo[9]);
  163.  
  164. PORTB=0;
  165. PORTC=1;
  166. delay_1us(servo[10]);
  167.  
  168. PORTC=2;
  169. delay_1us(servo[11]);
  170. PORTC=0;
  171. }
  172.  
  173. int main(void){
  174.  
  175. bool echo=0; //(0-1)visszhang szemafor
  176.  
  177. DDRB=255;
  178. PORTB=0;
  179. DDRD=255;
  180. PORTB=0;
  181. DDRC=3;
  182. PORTB=0;
  183.  
  184. delrec();
  185.  
  186. uart_init();
  187.  
  188. UARTSzovegKuld("Uart Online! Ready To Serial communication!");
  189.  
  190. init_servo();
  191.  
  192. sei();
  193.  
  194. se[0]=1000;
  195. se[1]=1000;
  196. se[2]=1000;
  197. se[3]=1000;
  198. se[4]=1000;
  199. se[5]=1000;
  200. se[6]=1000;
  201. se[7]=1000;
  202. se[8]=1000;
  203. se[9]=1000;
  204. se[10]=1000;
  205. se[11]=1000;
  206. ready();
  207.  
  208. ///////
  209. while(1){
  210. s_pwm();
  211. if (afterdelay()>0){delay_1us(afterdelay()/3);}
  212. //uart kiértékelése
  213.  if (inter==1){
  214.  
  215. if (echo){UARTKuld(buffer);};
  216.  
  217. if (buffer==8){
  218.  delrec();
  219.    }
  220.   if (buffer=='?'){
  221.     kuldrec();
  222. delrec();
  223.    }
  224.  
  225. if (buffer=='!'){
  226.   if (comm(">online")) {UARTSzovegKuld("System online!");}else
  227.   if (comm(">echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
  228.   if (comm(">eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
  229.   if (comm(">info")) {UARTSzovegKuld("Uart Online! "); UARTSzovegKuld("| 38400bps | atmega48 | Majlath.tech 2012");}
  230.   else {
  231.   UARTSzovegKuld("ERROR");
  232.   }
  233.   delrec();
  234.   }
  235.  
  236.     if (buffer=='='){ //servo pos módisítás
  237.  
  238. UARTSzovegKuld("Servo modified!");
  239. UARTKuld(' ');
  240. UARTKuld(rec[0]);
  241. UARTKuld(':');
  242.  
  243.  
  244. if (rec[0]>='a' && rec[0] <='z'){ //angol abc szerinti abc sorrendbeli betűk elhelyezkedésének sorszáma-1 számú szervó pozíciójának módosítása
  245. se[rec[0]-'a']=strtoint(1);
  246. outdec(se[0],0);} else {UARTSzovegKuld("ERROR IN SERVO TITLE!");
  247. };
  248.  
  249.  
  250. if (rec[0]>='A' && rec[0] <='Z'){ //angol abc szerinti abc sorrendbeli betűk elhelyezkedésének sorszáma-1 számú szervó pozíciójának módosítása
  251. if (rec[0]=='A'){OCR1A=strtoint(1); outdec(OCR1A,0);} else
  252. if (rec[0]=='B'){OCR1A=strtoint(1); outdec(OCR1B,0);}
  253.  else {UARTSzovegKuld("ERROR IN SERVO TITLE!");};
  254.  };
  255.  
  256. delrec();
  257. buffer=0;
  258. }
  259.  
  260. if (buffer=='%'){
  261. int number=strtoint(1);
  262. outdec(number,0);
  263. delrec();}
  264.  
  265. if (buffer=='<'){
  266. ready();
  267. delrec();
  268. }
  269.  
  270. //led jelzés
  271. PORTB=1;
  272. _delay_ms(1);
  273. PORTB=0;
  274. inter=0;
  275. };
  276. }
  277. }
  278.  
  279. ISR(USART_RX_vect)
  280. {  
  281.    if(UCSR0A & (1 << RXC0)) {buffer = UDR0;}
  282.  
  283. rec[stat]=buffer;
  284. stat+=1;
  285.  
  286. inter=1;
  287. }

Mit gondolsz?
(#) mzozo95 válasza sgt hozzászólására (») Júl 26, 2012
Elkészült az uartos software pwm, az interruptban a signal os név kell az ISR-nél is, mert ha nem lefagy az avr, és resetel állandóan, de így jól működik.
Mellékelem a kódot, hátha segít majd valakinek...


  1. //hardware: atmega48, 1db servo, portb1en , 1db led port B-0on; adat fogadása: betű- space- 4jegyű szám(esetenként elején 0-val)  + '=', példa:'a 0587=', parancsok: echo, eoff, info, alma
  2. #define F_CPU 8000000
  3. #include <avr/io.h>
  4. #include <util/delay.h>
  5. #include <avr/interrupt.h>
  6. #include <inttypes.h>
  7.  
  8. #include <stdbool.h> //bool típushoz
  9.  
  10.  
  11. ////////////////////////////////
  12. #define BAUD 38400///38400bps
  13. #define UBRR ((F_CPU / (BAUD * 16L)) - 1)
  14. ////////////////////////////////
  15. //változók
  16. volatile unsigned char rec[15];//string buffeer
  17. volatile unsigned char buffer; //byte buffet
  18.  
  19. volatile unsigned char stat=0;//string karakter száma
  20.  
  21. volatile int servo[3]; ///szervo pozíció
  22.  
  23. volatile bool echo=0; //visszhang(0-1)
  24.  
  25. volatile bool inter=0;//(0-1) szemafor
  26. //////////////////
  27. /////
  28. void uart_init(void)
  29. {
  30. UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
  31. // baud rate
  32. UBRR0H = (unsigned char) (UBRR>>8);
  33. UBRR0L = (unsigned char) UBRR;
  34. //  format: 8data, 2stop bit
  35. UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
  36. }
  37.  
  38. ///////UartKüld
  39.   void UARTKuld(unsigned char c){
  40.                 while((UCSR0A & (1<<UDRE0)) == 0) {}
  41.        
  42.             UDR0 = c;
  43. }
  44. ///////szövegküld
  45.    void UARTSzovegKuld( char *p)
  46. {
  47.         while(*p)
  48.         {
  49.           UARTKuld( *p++);
  50.         }
  51. }//szövegküld vége
  52.  
  53. void delrec(void){
  54.  for(int i=0; i<50;i++){
  55.   rec[i]=' ';
  56. stat=0;};
  57.  }
  58.  
  59. void kuldrec(void){
  60. for(int i=0; i<stat ;i++){
  61.  UARTKuld(rec[i]);}
  62.  }
  63.  
  64. //decimális szám küldése:
  65. void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
  66.     static char sign, s[12];
  67.     _delay_us(10);
  68.     unsigned int i;
  69.             i=0; sign=' ';  //alapvetően nincs előtte semmi
  70.             if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
  71.             do {
  72.                     s[i]=data%10 + '0'; //integer átírása ASCII ba
  73.                     data=data/10;
  74.                     i++;
  75.                     if(i==ndigits) {s[i]='.'; i++;}
  76.             } while(data>0);
  77.             UARTKuld(sign);
  78.             do{
  79.                       UARTKuld(s[--i]); //összes karakteren végigmenni
  80.             } while(i);
  81. }
  82.  
  83. uint8_t comm( char *p){
  84. char azonos=1;
  85. int szam=0;
  86. for(szam=0; szam < 15; szam++)
  87. {
  88.     if (rec[szam]!=( *p++))
  89.     {
  90.        azonos = 0;
  91.        break;
  92.     }
  93.     if(!*p) break;
  94.  }
  95. return (azonos);}
  96.  
  97.  
  98. uint16_t strtoint(int szam){
  99. int ertek=0;
  100.  
  101. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
  102. szam+=1;
  103. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
  104. szam+=1;
  105. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
  106. szam+=1;
  107. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
  108. return (ertek);}
  109.  
  110.  
  111. void init_servo(void){//servo init
  112. //16bit pwm
  113. DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1);   //pwm portd1 2 3
  114.  
  115. TCCR1A = (1<<COM1A1)| (1<<COM1B1);
  116. TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
  117. ICR1 = 10000;//periódus: 20ms
  118. OCR1A = 750;//servo1 1500us
  119. OCR1B = 750;//servo2 1500us
  120. }
  121.  
  122. void delay_1us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
  123.          while(delay_data--) _delay_us(1); }
  124.  
  125. void s_pwm(void){
  126. ///////////////software pwm
  127. PORTB=2;
  128. delay_1us(servo[0]);
  129. PORTB=0;
  130. }
  131.  
  132. int main(void){
  133.  
  134. //init_servo();
  135.  
  136. DDRB=255;
  137. PORTB=0;
  138.  
  139. delrec();
  140.  
  141. uart_init();
  142. UARTSzovegKuld("Uart Online! Ready To Serial communication!");
  143.  
  144. sei();
  145.  
  146. servo[0]=1000;
  147. ///////
  148. while(1){
  149. s_pwm();
  150. _delay_ms(18);
  151.  
  152.  
  153. //uart kiértékelése
  154.  if (inter==1){
  155.  
  156. if (echo){UARTKuld(buffer);};
  157.  
  158. if (buffer==8){
  159.  delrec();
  160.    }
  161.   if (buffer=='?'){
  162.     kuldrec();
  163.    }
  164.  
  165. if (buffer=='!'){
  166.   if (comm("alma")) {UARTSzovegKuld("alma fogadva!");delrec();}else
  167.   if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;delrec();}else
  168.   if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;delrec();} else
  169.   if (comm("info")) {UARTSzovegKuld("Uart Online! "); UARTSzovegKuld("| 38400bps | atmega48 | string.c");delrec();}
  170.   else {
  171.   UARTSzovegKuld("ERROR");
  172.   delrec();}
  173.   }
  174.  
  175.     if (buffer=='='){
  176. if (rec[0]=='a'){servo[0]=strtoint(2);
  177. UARTSzovegKuld("Servo modified!");
  178. UARTSzovegKuld("a=");
  179. outdec(servo[0],0);
  180. delrec();
  181. buffer=0;};
  182. }
  183.  
  184. if (buffer=='%'){
  185. int number=strtoint(1);
  186. outdec(number,0);
  187. delrec();}
  188. //led jelzés
  189. PORTB=1;
  190. _delay_ms(1);
  191. PORTB=0;
  192. inter=0;
  193. };
  194. }
  195. }
  196.  
  197. ISR(SIG_USART_RECV)
  198. {  
  199.    if(UCSR0A & (1 << RXC0)) {buffer = UDR0;}
  200.  
  201. rec[stat]=buffer;
  202. stat+=1;
  203.  
  204. inter=1;
  205. }


Üdv.: Zoltán
(#) mzozo95 válasza sgt hozzászólására (») Júl 24, 2012
Köszönöm, az interruptot módosítottam, ISR re, használtam szemafor szerű dolgot, az igazi szemafor hogy működik? Nem találtam rá példát avr-ben. Vagy csak egy PORT bitet kellene "billegtetni"? Az a megoldás azért nem lenne jó, mert nem nagyon akad felesleges láb majd az avr-en.

Végül sajnos még mindig nem akart működni a dolog. Ezt már észrevettem máskor is, hogy ha a végtelen ciklust megszakító interruptban megváltozik egy globális változó, akkor a végtelen ciklusban a változót használó folyamatban nem mindig töténik változás... Ez miért van? Vagy a C nyelv hiányossága?

bool változótípus nincs a c-ben? mejnek értéke 0 vagy 1? Mert az lenne a legegyszerűbb szemafor, és nem foglalna sok helyet(mint a mostani char-os megoldás) Ha így próbálon definiálni:
  1. bool a=0;

hibát ír a fordító...

Így néz ki a mostani, működő program, kicsit csúnya elemzéssel az s_pwm függvényben.


  1. #define F_CPU 8000000
  2. #include <avr/io.h>
  3. #include <util/delay.h>
  4. #include <avr/interrupt.h>
  5. #include <inttypes.h>
  6.  
  7. ////////////////////////////////
  8. #define BAUD 38400///38400bps
  9. #define UBRR ((F_CPU / (BAUD * 16L)) - 1)
  10. ////////////////////////////////
  11. //váltoizók
  12. unsigned char rec[15];//string buffeer
  13. unsigned char buffer; //byte buffet
  14.  
  15. unsigned char stat=0;//string karakter
  16.  
  17. int se[18];
  18.  
  19. int servo=0;
  20.  
  21. char echo=0; //visszhang(0-1)
  22.  
  23. char inter=0;
  24. ////////////////////////
  25. void uart_init(void)
  26. {
  27. /* Aktivieren des Empf?ngers, des Senders und des "Daten empfangen"-Interrupts */
  28. UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
  29. // baud rate
  30. UBRR0H = (unsigned char) (UBRR>>8);
  31. UBRR0L = (unsigned char) UBRR;
  32. //  format: 8data, 2stop bit
  33. UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
  34. }
  35.  
  36.  
  37. ///////UartKüld
  38.   void UARTKuld(unsigned char c){
  39.                 while((UCSR0A & (1<<UDRE0)) == 0) {}
  40.        
  41.             UDR0 = c;
  42. }
  43.  
  44. ///////szövegküld
  45.    void UARTSzovegKuld( char *p)
  46. {
  47.         while(*p)
  48.         {
  49.           UARTKuld( *p++);
  50.         }
  51. }//szövegküld vége
  52.  
  53. void delrec(void){
  54.  for(int i=0; i<50;i++){
  55.   rec[i]=' ';
  56. stat=0;};
  57.  }
  58.  
  59. void kuldrec(void){
  60. for(int i=0; i<stat ;i++){
  61.  UARTKuld(rec[i]);}
  62.  }
  63.  
  64. //decimális szám küldése:
  65. void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
  66.     static char sign, s[12];
  67.     _delay_us(10);
  68.     unsigned int i;
  69.             i=0; sign=' ';  //alapvetően nincs előtte semmi
  70.             if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
  71.             do {
  72.                     s[i]=data%10 + '0'; //integer átírása ASCII ba
  73.                     data=data/10;
  74.                     i++;
  75.                     if(i==ndigits) {s[i]='.'; i++;}
  76.             } while(data>0);
  77.             UARTKuld(sign);
  78.             do{
  79.                       UARTKuld(s[--i]); //összes karakteren végigmenni
  80.             } while(i);
  81. }
  82.  
  83. uint8_t comm( char *p){
  84. char azonos=1;
  85. int szam=0;
  86. while(*p)
  87.         {
  88. if (rec[szam]==( *p++)) {azonos=1;} else {azonos=0;};
  89. szam+=1;
  90. }
  91. return (azonos);}
  92.  
  93. uint16_t strtoint(int szam){
  94. int ertek=0;
  95.  
  96. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
  97. szam+=1;
  98. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
  99. szam+=1;
  100. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
  101. szam+=1;
  102. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
  103. return (ertek);}
  104.  
  105.  
  106. void init_servo(void){//servo init
  107. //16bit pwm
  108. DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1);   //pwm portd1 2 3
  109.  
  110. TCCR1A = (1<<COM1A1)| (1<<COM1B1);
  111. TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
  112. ICR1 = 10000;//periódus: 20ms
  113. OCR1A = 750;//servo1 1500us
  114. OCR1B = 750;//servo2 1500us
  115. }
  116.  
  117. void delay_5us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
  118.          while(delay_data--) _delay_us(5); }
  119.  
  120. void s_pwm(void){
  121. ///////////////software pwm
  122. PORTB=2;
  123. _delay_ms(1);
  124. if (buffer=='='){
  125. if (rec[0]=='a'){servo=strtoint(2);};
  126. UARTSzovegKuld("Servo modified!");
  127. delrec();
  128. buffer=0;
  129. }
  130. delay_5us(servo);
  131. PORTB=0;
  132. }
  133.  
  134. int main(void){
  135.  
  136. //init_servo();
  137.  
  138. DDRB=255;
  139. PORTB=0;
  140.  
  141. uart_init();
  142. UARTSzovegKuld("Uart Online! Ready To Serial communication!");
  143.  
  144. sei();
  145.  
  146. PORTB=1;
  147. ///////
  148. while(1){
  149.  
  150. s_pwm();
  151. _delay_ms(18);
  152. if (inter==1){
  153. PORTB=1;
  154. _delay_ms(5);
  155. PORTB=0;
  156. inter=0;
  157. };
  158. }
  159. }
  160.  
  161. ISR(SIG_USART_RECV)
  162. {  
  163.    if(UCSR0A & (1 << RXC0)) {
  164.         buffer = UDR0;}
  165.  
  166. rec[stat]=buffer;
  167. stat+=1;
  168.  
  169. if (echo){UARTKuld(buffer);};
  170.  
  171.  if (buffer==8){
  172.  delrec();
  173.    }
  174.  
  175.  
  176.    if (buffer=='?'){
  177.     kuldrec();
  178.    }
  179.  
  180. if (buffer=='!'){
  181.   if (comm("alma")) {UARTSzovegKuld("alma fogadva!");}else
  182.   if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
  183.   if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
  184.   if (comm("info")) {UARTSzovegKuld("Uart Online! "); UARTSzovegKuld("| 38400bps | atmega48 | string.c");}
  185.   }
  186.  
  187. if (buffer=='%'){
  188. int number=strtoint(1);
  189. outdec(number,0);}
  190.  
  191. inter=1;      
  192. }
(#) mzozo95 hozzászólása Júl 24, 2012
Sziasztok!
Írtam egy egyszerű soros port, hardware pwm programot, csak van egy gondom, ha az s_pwm függvénybőlé kiveszem az outdec() függvényt, akkor nem működőképes a program, tehát nem változik meg a pwm kitöltési tényezője, míg ha benne van, minden tökéletesen fut, csak közben rengeteg adatot küld ki a tx lábon... ( egy parancs felépítése pl "a 0100=") Emellett nem sikerült az interruptban, az elemző függvényben entert('/n') alkalmazni '=' helyett, ez valyon miért lehet? (mármint, hogy ha ez a karakter van, akkor csináljon valamit az if ben, egyszerűen nem ismeri fel az entert, pedig a terminal programban leütöm...)
A pwm egyszerűbb lenne hardweresen, de nekem sajnos most szoftweresre van szükségem, a hardwereseket másra fogom használni, ott simán működött, ha megadtam az interruptban, hogy pl OCR1A=servo)
  1. //atmega48 software pwm + uart
  2. #define F_CPU 8000000
  3. #include <avr/io.h>
  4. #include <util/delay.h>
  5. #include <avr/interrupt.h>
  6. #include <inttypes.h>
  7.  
  8. ////////////////////////////////
  9. #define BAUD 38400///38400bps
  10. #define UBRR ((F_CPU / (BAUD * 16L)) - 1)
  11. ////////////////////////////////
  12. //váltoizók
  13. unsigned char rec[15];//string buffeer
  14. unsigned char buffer; //byte buffet
  15.  
  16. unsigned char stat=0;//string karakter
  17.  
  18. int se[18];
  19.  
  20. int servo=0;
  21.  
  22. char echo=0; //visszhang(0-1)
  23. ////////////////////////
  24. void uart_init(void)
  25. {
  26. UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
  27. // baud rate
  28. UBRR0H = (unsigned char) (UBRR>>8);
  29. UBRR0L = (unsigned char) UBRR;
  30. //  formátum: 8data, 2stop bit
  31. UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
  32. }
  33.  
  34.  
  35. ///////UartKüld
  36.   void UARTKuld(unsigned char c){
  37.                 while((UCSR0A & (1<<UDRE0)) == 0) {}
  38.        
  39.             UDR0 = c;
  40. }
  41.  
  42. ///////szövegküld
  43.    void UARTSzovegKuld( char *p)
  44. {
  45.         while(*p)
  46.         {
  47.           UARTKuld( *p++);
  48.         }
  49. }//szövegküld vége
  50.  
  51. void delrec(void){
  52.  for(int i=0; i<50;i++){
  53.   rec[i]=' ';
  54. stat=0;};
  55.  }
  56.  
  57. void kuldrec(void){
  58. for(int i=0; i<stat ;i++){
  59.  UARTKuld(rec[i]);}
  60.  }
  61.  
  62. //decimális szám küldése:
  63. void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
  64.     static char sign, s[12];
  65.     _delay_us(10);
  66.     unsigned int i;
  67.             i=0; sign=' ';  //ha pozitív, előtte space
  68.             if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
  69.             do {
  70.                     s[i]=data%10 + '0'; //integer átírása ASCII ba
  71.                     data=data/10;
  72.                     i++;
  73.                     if(i==ndigits) {s[i]='.'; i++;}
  74.             } while(data>0);
  75.             UARTKuld(sign);
  76.             do{
  77.                       UARTKuld(s[--i]); //összes karakteren végigmenni
  78.             } while(i);
  79. }
  80.  
  81. uint8_t comm( char *p){
  82. char azonos=1;
  83. int szam=0;
  84. while(*p)
  85.         {
  86. if (rec[szam]==( *p++)) {azonos=1;} else {azonos=0;};
  87. szam+=1;
  88. }
  89. return (azonos);}
  90.  
  91. uint16_t strtoint(int szam){
  92. int ertek=0;
  93.  
  94. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
  95. szam+=1;
  96. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
  97. szam+=1;
  98. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
  99. szam+=1;
  100. if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
  101. return (ertek);}
  102.  
  103.  
  104. void init_servo(void){//servo init
  105. //16bit pwm
  106. DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1);   //pwm portd1 2 3
  107.  
  108. TCCR1A = (1<<COM1A1)| (1<<COM1B1);
  109. TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
  110. ICR1 = 10000;//periódus: 20ms
  111. OCR1A = 750;//servo1 1500us
  112. OCR1B = 750;//servo2 1500us
  113. }
  114.  
  115. void delay_5us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
  116.          while(delay_data--) _delay_us(5); }
  117.  
  118. void s_pwm(void){
  119. ///////////////software pwm
  120. PORTB=2;
  121. _delay_ms(1);
  122. delay_5us(servo);
  123. PORTB=0;
  124. _delay_ms(20);
  125. outdec(servo,0);/* HA EZT KIVESZEM NEM MŰKÖDIK HELYESEN A PWM, AZAZ NEM VÁLTOZIK A KITÖLTÉSI TÉNYEZŐ, HA VÁLTOZIK AZ INTERRUPTBAN A 'SERVO' ÉRTÉKE!*/
  126. }
  127.  
  128. int main(void){
  129.  
  130. //init_servo();
  131.  
  132. DDRB=255;
  133. PORTB=0;
  134.  
  135. uart_init();
  136. UARTSzovegKuld("Uart Online! Ready To Serial communication!");
  137.  
  138. sei();
  139.  
  140. PORTB=1;
  141. ///////
  142. while(1){
  143. s_pwm();
  144. _delay_ms(18);
  145. };
  146. }
  147.  
  148. SIGNAL(SIG_USART_RECV)
  149. {  
  150.    if(UCSR0A & (1 << RXC0)) {
  151.         buffer = UDR0;}
  152.  
  153. rec[stat]=buffer;
  154. stat+=1;
  155.  
  156. if (echo){UARTKuld(buffer);};
  157.  
  158.  if (buffer==8){//backspace
  159.  delrec();
  160.    }
  161.  
  162.  
  163.    if (buffer=='?'){
  164.     kuldrec();
  165.    }
  166.  
  167. if (buffer=='!'){
  168.   if (comm("alma")) {UARTSzovegKuld("alma fogadva!");}else
  169.   if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
  170.   if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
  171.   if (comm("info")) {UARTSzovegKuld("Uart Online! "); UARTSzovegKuld("| 38400bps | atmega48 | string.c");}
  172.   }
  173.  
  174. if (buffer=='%'){
  175. int number=strtoint(0);
  176. outdec(number,0);}
  177.  
  178. if (buffer=='='){
  179. UARTSzovegKuld("Servo modified!");
  180. if (rec[0]=='a'){servo=strtoint(2);}
  181. }
  182.  
  183.    PORTB=1;
  184.    _delay_ms(5);
  185.    PORTB=0;
  186.    
  187.  
  188.                }


Valaki tudna segíteni? Előre is köszönet,
Zoltán
(#) Pepebá válasza marek hozzászólására (») Júl 19, 2012
Hali!
Javaslom Neked az icserny PICCOLO projektjét. Ott példaprogramokkal illuszrálva ilyen feladat. (Én is hasonló projekten ügyködöm, PIC18f4550-l.)
USBDeviceTasks(); meghívása interrupt szinten történik, a ProcessIO(); pedig a főmenü végtelen ciklusában.
A PICCOLO projektben saját függvénnyel történik az adat küldés a PC-fele pl: outdec(Aadat2,0);
Üdv.
(#) icserny válasza szitko hozzászólására (») Júl 12, 2012
Nem szép dolog, hogy az átlagolást nem kettő hatványa szerint csinálod! (16 vagy 32 minta esetén az osztás jobbra léptetéssel megoldható).

A negatív számokat én a kiíratásnál ellenőrzöm, az if(data<0) { sign='-'; data = -data;} sorban.

Unsigned változó esetén így kellene: if((a=b)>32767) a= 65536-a; (Itt a az unsigned16 b pedig az előjeles változó)


  1. /**------------------------------------------------------------
  2.  * Decimális kiíratás adott számú tizedesjegyre.
  3.  *-------------------------------------------------------------
  4.  * data - a kiírandó előjeles szám (int32_t)
  5.  * ndigits - a kiírandó tizedesek száma (uint8_t)
  6.  */
  7. void sw_uart_outdec(int32_t data, uint8_t ndigits) {
  8.   static char sign, s[12];
  9.   int8_t i;
  10.   i=0; sign=' ';
  11.   if(data<0) { sign='-'; data = -data;}
  12.     do {
  13.       s[i]=data%10 + '0';
  14.       data=data/10;
  15.       i++;
  16.       if(i==ndigits) {s[i]='.'; i++;}
  17.     } while(data>0);
  18.     sw_uart_putc(sign);
  19.     do {
  20.       sw_uart_putc(s[--i]);
  21.     } while(i);
  22. }


A te kódrészleted számomra értelmezhetetlen, mert a változó típusokat nem adtad meg benne.
(#) icserny hozzászólása Júl 4, 2012
A belső hőmérő használata gyári kalibrációs adatokkal

Az MSP430G2452 és MSP430G2553 mikrovezérlők az ADC-hez is tartalmaznak gyári kalibrációs adatokat. A fejléc állományokban azonban nincs definiálva hozzájuk szimbolikus név, ezért vagy a programunkba, vagy a fejléc állományokba helyezzük el az alábbi sorokat:
  1. /* ADC10 Calibration Data - added by I. Cserny */
  2. __no_init unsigned __READ int CAL_ADC_25T85 @ 0x10EA;
  3. __no_init unsigned __READ int CAL_ADC_25T30 @ 0x10E8;
  4. __no_init unsigned __READ int CAL_ADC_25VREF_FACTOR @ 0x10E6;
  5. __no_init unsigned __READ int CAL_ADC_15T85 @ 0x10E4;
  6. __no_init unsigned __READ int CAL_ADC_15T30 @ 0x10E2;
  7. __no_init unsigned __READ int CAL_ADC_15VREF_FACTOR @ 0x10E0;
  8. __no_init unsigned __READ int CAL_ADC_OFFSET @ 0x10DE;
  9. __no_init unsigned __READ int CAL_ADC_GAIN_FACTOR @ 0x10DC;


A definíciókból kihagytam a volatile módosítót, feltételezve, hogy programfutás közben úgysem változnak ezek az adatok...

A CAL_ADC_GAIN_FACTOR és az CAL_ADC_OFFSET elvileg az ADC-ből kiolvasott eredmény korrekciójához kell. Nálam ezek annyira közel esnek 1-hez és 0-hoz, hogy nem érdemes veszkődni vele.

A mellékelt programban a 2,5 V-os belső referenciát használjuk, ezért a belső hőmérő kiolvasott értékének átszámításához a 2,5 V-os referenciával 30 és 85 fokon mért értékeket használjuk a C-fokra történő átszámításhoz, lineáris összefüggést feltételezve:

  1. TCelsius = 55 * (ADC10MEM - CAL_ADC_25T30)/(CAL_ADC_25T85 - CAL_ADC_25T30) + 30;


Vagyis a 30 fokhoz viszonyítunk, s az 55 fokos különbségnél (85 C - 30 C ) kapott gyári értékekből határozzuk meg a meredekséget is.

A tapasztalat szerint az így kiszámolt érték kb. 3 fokkal fölé lőtt a szobahőmérőnek, ezért a továbbiakban 30 fok helyett csak 27 fokot használok a képletben. Ha tizedfokokat is ki akarunk íratni (bár sok értelme nincs), akkor a fenti képletben 10-zel kell szorozni a konstansokat (tehát 55 helyett 550, 30 helyett 300, vagy 27 helyett 270).

A mellékelt mintaprogramban a P1.5 bemenetre kapcsolt feszültséget (0 - 2,5 V) is mérjük, valamint a 11. csatornában a VDD/2 feszültséget is. Utóbbiból meghatározhatjuk a tápfeszültséget, felhasználva, hogy most független referenciánk van. A feszültségeket millivoltokban célszerű kiszámolni.

Ha takarékoskodni akarunk a mérési idővel, akkor nem túl nagy csalás, ha 1023 helyett 1024-gyel osztunk (hogy léptetéssel megoldható legyen), de a programban nem éltem ezzel a lehetőséggel.

A kiírást a korábban már ismertetett outdec() függvénnyel végezzük, ahol második paraméterként a levágandó tizedesjegyek számát kell megadni (hőmérésnél 1, mV-ban kiszámolt feszültségnél pedig 3).

A program érdekessége, hogy nem használunk benne float változót, s a kiíratáshoz a korábban bemutatott egyirányú szoftveres UART kezelést használjuk.

A mellékelt képen P1.5 összevissza kóvályog, mert csak a felszedett zajt mérte...
(#) Simon Kornél hozzászólása Máj 1, 2012
Sziasztok!

Nekem is lenne egy kérdésem. Remélem ebbe a topicba való.

Van egy 18F4550 pic-em, az első négy analóg csatornáját szeretném használni, azaz analóg jelet mérni. Most a négy analóg csatornán négy 10KOhm-os potenciométer van felrakva és azokat figyelem/szabályzom. Az a problémám, hogy a pic-ken mért feszültség eltér a voltmérőmön mért feszültségtől. Az eltérés tizedes nagyságrendű.
Nem tudom, hogy ez még belefér a tűrésbe vagy sem? Vagy én állítottam be valamit rosszul?

A potenciométereket úgy kötöttem be, hogy az egyik fix lábát a földre a másikat a +5V-ra kötöttem és a harmadik lábát egy 1KOhmo-os ellenálláson keresztül kötöttem a PIC analóg lábára, illetve egy 100n kondin keresztül a földre kötöttem.
Ezt szerintem jól kötöttem be, mert két analóg bemeneten is tudok mérni.

Az alábbi programot használom hozzá:
  1. char c;
  2. unsigned int adat;
  3. long a;
  4.  
  5.  
  6. void InitADC(void)
  7. {
  8. TRISAbits.TRISA0=1;
  9. TRISAbits.TRISA1=1;
  10. TRISAbits.TRISA2=1;
  11. TRISAbits.TRISA3=1;
  12. //ADCON1 = 0b00101100;//Analóg bemenetek beállítása
  13. ADCON0 = 0b00001000;//AN2 kiválasztása, ADC még letiltva!
  14. ADCON1 &= 0b00001100;//VREF+=VDD, VREF-=VSS (EZ LEHET, HOGY NEM SZÜKSÉGES IDE, MERT FENTEBB MÁR BE LETT ÁLLÍTVA! )
  15. ADCON2 = 0xBE;//20TAD, FOSC/64, jobbra igazítás
  16. ADCON0bits.ADON=1;//Az ADC engedélyezése
  17. }
  18.  
  19. unsigned int ReadADC(unsigned char chan)
  20. {
  21. ChangeBits(ADCON0, chan<<2, 0b00111100);
  22. ADCON0bits.GO = 1;//Start AD conversion
  23. while (ADCON0bits.NOT_DONE)//Wait for conversion
  24. {
  25. return (((unsigned int)ADRESH)<<8)|(ADRESL);
  26. }
  27. }
  28.  
  29. void outdec_(long  data, unsigned int ndigits) {
  30. static char sign, s[12];
  31. unsigned int i;
  32. i=0; sign='+';
  33.  
  34. if(data<0) { sign='-'; data = -data;}
  35.  
  36. do {
  37. s[i]=data%10 + '0';
  38.  
  39. data=data/10;
  40. i++;
  41. if(i==ndigits) {s[i]='.'; i++; }
  42.  
  43. } while(data>0);
  44. _user_putc(sign);
  45. do{
  46. _user_putc(s[--i]);
  47. } while(i);
  48. }
  49.  
  50.  
  51. void main(void)
  52. {
  53. InitializeSystem();
  54. InitADC();
  55. CVRCON = 0b10101000;
  56.  
  57. while (!usb_cdc_kbhit())
  58. {
  59. ProcessIO();
  60. }
  61.  
  62. outString("PICCOLO test p18f4550-el\n");
  63.  
  64. while (1)
  65. {
  66. do
  67. {
  68. c=usb_cdc_getc();
  69. } while (c!='#');
  70.  
  71. c=usb_cdc_getc();
  72. usb_cdc_putc(c);
  73. switch (c)
  74. {
  75. case 'A':
  76. ADCON0 = get2hex();
  77. ADCON1 = get2hex();
  78. ADCON2 = get2hex();
  79. break;
  80. case 'D':
  81. LEDport = get2hex();
  82. break;
  83. case 'H':
  84. outString("Help:\n");
  85. outString("#Akkmmnn - ADC konfigurálás\n");
  86. outString("#Dnn     - LEDport beállítása\n");
  87. outString("#H       - Help\n");
  88. outString("#L       - LED villogtatás tiltás/engedélyezése\n");
  89. outString("#Mnn     - ADC(nn) csatorna kiolvasása\n");
  90. outString("#Vkk     - VREF modul konfigurálása\n");
  91. break;
  92. case 'L':
  93. BlinkUSBStatus_enabled=!BlinkUSBStatus_enabled;
  94. if (BlinkUSBStatus_enabled)
  95. {
  96. usb_cdc_putc('1');
  97. }
  98. else
  99. {
  100. usb_cdc_putc('0');
  101. }
  102. break;
  103. case 'M':
  104. a=0;
  105. c=get2hex();
  106. usb_cdc_putc(' ');
  107. adat=ReadADC(c);
  108. out4hex(adat);
  109. a+=adat;
  110.  
  111. outString(" U=");
  112.  
  113. a=adat*4930L/1024L;
  114. outdec_(a,3);
  115.  
  116. outString("Volt");
  117. break;
  118. case 'V':
  119. CVRCON = get2hex();
  120. break;
  121. }
  122. outString("\n");
  123. }
  124. }


Remélem tudtok nekem segíteni, hogy mit ronthattam el, hogy nem pontos értéket kapok vissza.

Segítséget előre is köszönöm!
(#) Pepebá válasza icserny hozzászólására (») Ápr 26, 2012
Köszi az infót, igen hasznos volt, sokat segített. Az outdec() függvényt már nézegettem, sőt belepiszkáltam. Pozitív hőmérsékleteknél az előjel kiírást megszüntettem.
Átalakítást illetve új függvény LCD-re kiírást megcsinálom.
Következő: »»   1 / 2
Bejelentkezés

Belépés

Hirdetés
XDT.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