|
É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....)
/** Decimális kiíratás adott számú tizedesjegyre.
* \param data a kiírandó szám (előjelesen)
* \param ndigits a kiírandó tizedesek száma
*/
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);
}
A hozzászólás módosítva: Ápr 2, 2020
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.
Közben megoldottam magam is a kérdést:
void outdec(long data, unsigned int ndigits, unsigned int maxtizedes) {
static char sign, s[12], volt;
unsigned int x;
x=0; sign='+'; volt='v';
if(data<0) { sign='-'; data = -data;}
do {
s[x]=data%10 + '0';
data=data/10;
x++;
if(x==ndigits) {s[x]='.'; x++;}
}
while(data>0 || x<ndigits+2);
_user_putc(sign);
do{
if(x>=maxtizedes){
_user_putc(s[--x]);
}else{ break; }
}
while(x);
_user_putc(volt); //Volt "v" kiíratása a végére
printf(" "); //LCD sor frissítése
}
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
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
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.
// float flo_at = 12.334563; <--- ezt felejtsd el! Helyette:
long no_float = 12334563;
outdec(no_float,6);
A kiírató rutint a PICCOLO projektben megtalálod:
/** Decimális kiíratás adott számú tizedesjegyre.
* \param data a kiírandó szám (előjelesen)
* \param ndigits a kiírandó tizedesek száma
*/
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);
}
Felteteleztem, hogy az _user_putc() függvényt úgy definiáltad, hogy az LCD-re írjon.
Main-on kívűl:
volatile unsigned int a;
volatile unsigned float v;
volatile unsigned float mv = 5000; //5v
volatile unsigned float o = 1023; //poti maxra tekerve
Main-on és wile-n belül:
a = ReadADC();
v = ((mv / o) * a)/1000;
printf("Poti: %04d", a); //mert ha kisebb a szám 1000-nél nem törli az utolsó karaktert
lcd_write(0xC0,0,1,1);
printf("Fesz: %3.2f", v); //elvileg kerekítene 2 tizedesre
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
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.
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!
/**------------------------------------------------------------
* Decimális kiíratás adott számú tizedesjegyre.
*-------------------------------------------------------------
* data - a kiírandó szám (előjelesen)
* ndigits - a kiírandó tizedesek száma
*/
void sw_uart_outdec(int32_t data, uint8_t ndigits) {
static char sign, s[12];
uint8_t 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 || i < ndigits+2); //<--itt a lényeg!
sw_uart_putc(sign);
do {
sw_uart_putc(s[--i]);
} while(i);
}
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.
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ó.
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.
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.
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);
}
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!
void outdec(long data) {
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++;
} while(data>0);
lcd_putc(sign);
do{
lcd_putc(s[--i]);
} while(i);
}
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):
/**------------------------------------------------------------
* Decimális kiíratás adott számú tizedesjegyre.
*-------------------------------------------------------------
* data - a kiírandó szám (előjelesen)
* ndigits - a kiírandó tizedesek száma
*/
void outdec(long data, char ndigits) {
static char sign, s[12];
char 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 || i < ndigits+2);
lcd_putc(sign);
do {
lcd_putc(s[--i]);
} while(i);
}
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...
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:
while(1){
if(uart){
_DINT();
P1OUT ^= BIT0;
long captured=0, cap_val=0;
unsigned int captured_rpm=0, captured_hz=0;
for(char j=1; j<6;j++){
cap_val += capture_buffer[j];
}
captured = cap_val / 5;
captured_hz = frequency / captured;
captured_rpm = (captured_hz<<2)+(captured_hz<<1);
sw_uart_puts("\r\nFrequency = ");
sw_uart_outdec(captured_hz,0);
sw_uart_puts(" Hz Fordulat = ");
sw_uart_outdec(captured_rpm,0);
sw_uart_puts(" RPM");
}
__low_power_mode_0();
}
}
#pragma vector=TIMERA1_VECTOR
__interrupt void TimerA1(void){
new_capture = TACCR1;
capture_buffer[count++] = new_capture - old_capture;
if (count==6){
count=0;
uart=1;
TACCTL1 &= ~CCIFG;
__low_power_mode_off_on_exit();
}
old_capture = new_capture;
TACCTL1 &= ~CCIFG;
}
A hozzászólás módosítva: Márc 12, 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:
while(1){
if(uart){
_DINT();
P1OUT ^= BIT0;
captured=0;
for(char j=1; j<6;j++){
captured += capture_buffer[j];
}
captured /=5;
sw_uart_outdec(captured,0);
sw_uart_puts("\r\n");
}
__low_power_mode_0();
}
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.
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:
#include <stdint.h>
#include <stdio.h>
#include "hw_uart_buf.h"
int putchar(int outChar) {
uart_putc((uint8_t)outChar);
return outChar;
}
char c;
int main( void ) {
WDTCTL = WDTPW + WDTHOLD; //Letiltjuk a watchdog időzítőt
DCOCTL = CALDCO_1MHZ; //DCO beállítása a gyárilag kalibrált
BCSCTL1 = CALBC1_1MHZ; //1 MHz-es frekvenciára
uart_init(BPS_9600);
printf("NLIsten hozott a Launchpad projekthez!");
printf("hello_print program (hw_uart_buf)NL");
while (1) {
c=uart_getc();
printf("Vett karakter: %c = %dNL",c,c);
}
}
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:
#include <stdint.h>
#include "hw_uart_buf.h"
char c;
int main( void ) {
WDTCTL = WDTPW + WDTHOLD; //Letiltjuk a watchdog időzítőt
DCOCTL = CALDCO_1MHZ; //DCO beállítása a gyárilag kalibrált
BCSCTL1 = CALBC1_1MHZ; //1 MHz-es frekvenciára
uart_init(BPS_9600);
uart_puts("NLIsten hozott a Launchpad projekthez!NL");
uart_puts("hello_int program (hw_uart_buf)NL");
while (1) {
c=uart_getc();
uart_puts("Vett karakter: ");
uart_putc(c);
uart_puts(" = ");
uart_outdec((int32_t)c,0);
uart_puts(" NL");
}
}
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.
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).
/**------------------------------------------------------------
* Decimális kiíratás adott számú tizedesjegyre.
*-------------------------------------------------------------
* data - a kiírandó szám (előjelesen)
* ndigits - a kiírandó tizedesek száma
*/
void sw_uart_outdec(int32_t data, uint8_t ndigits) {
static char sign, s[12];
uint8_t 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 || i < ndigits+2);
sw_uart_putc(sign);
do {
sw_uart_putc(s[--i]);
} while(i);
}
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
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:
/** Decimális kiíratás adott számú tizedesjegyre.
* \param data a kiírandó szám (előjelesen)
* \param ndigits a kiírandó tizedesek száma
*/
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);
}
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.
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...
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <stdbool.h> //bool típushoz
////////////////////////////////
#define BAUD 38400///38400bps
#define UBRR ((F_CPU / (BAUD * 16L)) - 1)
////////////////////////////////
//változók
volatile unsigned char rec[15];//string buffeer
volatile unsigned char buffer; //byte buffet
volatile unsigned char stat=0;//string karakter száma
volatile int se[12]; //bejövő adat
volatile int servo[12]; ///szervo pozíció
volatile bool inter=0;//(0-1) szemafor
//////////////////
/////
void uart_init(void)
{
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
// baud rate
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;
// format: 8data, 2stop bit
UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
}
///////UartKüld
void UARTKuld(unsigned char c){
while((UCSR0A & (1<<UDRE0)) == 0) {}
UDR0 = c;
}
///////szövegküld
void UARTSzovegKuld( char *p)
{
while(*p)
{
UARTKuld( *p++);
}
}//szövegküld vége
void delrec(void){
for(int i=0; i<15;i++){
rec[i]=' ';
stat=0;};
}
void kuldrec(void){
for(int i=0; i<stat ;i++){
UARTKuld(rec[i]);}
}
//decimális szám küldése:
void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
static char sign, s[12];
_delay_us(10);
unsigned int i;
i=0; sign=' '; //alapvetően nincs előtte semmi
if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
do {
s[i]=data%10 + '0'; //integer átírása ASCII ba
data=data/10;
i++;
if(i==ndigits) {s[i]='.'; i++;}
} while(data>0);
UARTKuld(sign);
do{
UARTKuld(s[--i]); //összes karakteren végigmenni
} while(i);
}
uint8_t comm( char *p){
char azonos=1;
int szam=0;
for(szam=0; szam < 15; szam++)
{
if (rec[szam]!=( *p++))
{
azonos = 0;
break;
}
if(!*p) break;
}
return (azonos);}
uint16_t strtoint(int szam){
int ertek=0;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
return (ertek);}
void ready(void){
for(int i=0; i<14;i++)
{servo[i]=se[i];}
}
void init_servo(void){//servo init
//16bit pwm
DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1); //pwm portd1 2 3
TCCR1A = (1<<COM1A1)| (1<<COM1B1);
TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
ICR1 = 10000; //periódus: 20ms
OCR1B = 750;//servo2 1500us
}
uint16_t afterdelay(void){
int ertek=0;
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];
return(20000-ertek);}
void delay_1us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
while(delay_data--) _delay_us(1); }
void s_pwm(void){
///////////////software pwm
PORTD=4;
delay_1us(servo[0]);
PORTD=8;
delay_1us(servo[1]);
PORTD=16;
delay_1us(servo[2]);
PORTD=32;
delay_1us(servo[3]);
PORTD=64;
delay_1us(servo[4]);
PORTD=128;
delay_1us(servo[5]);
PORTD=0;
PORTB=1;
delay_1us(servo[6]);
PORTB=8;
delay_1us(servo[7]);
PORTB=16;
delay_1us(servo[8]);
PORTB=32;
delay_1us(servo[9]);
PORTB=0;
PORTC=1;
delay_1us(servo[10]);
PORTC=2;
delay_1us(servo[11]);
PORTC=0;
}
int main(void){
bool echo=0; //(0-1)visszhang szemafor
DDRB=255;
PORTB=0;
DDRD=255;
PORTB=0;
DDRC=3;
PORTB=0;
delrec();
uart_init();
UARTSzovegKuld("Uart Online! Ready To Serial communication!");
init_servo();
sei();
se[0]=1000;
se[1]=1000;
se[2]=1000;
se[3]=1000;
se[4]=1000;
se[5]=1000;
se[6]=1000;
se[7]=1000;
se[8]=1000;
se[9]=1000;
se[10]=1000;
se[11]=1000;
ready();
///////
while(1){
s_pwm();
if (afterdelay()>0){delay_1us(afterdelay()/3);}
//uart kiértékelése
if (inter==1){
if (echo){UARTKuld(buffer);};
if (buffer==8){
delrec();
}
if (buffer=='?'){
kuldrec();
delrec();
}
if (buffer=='!'){
if (comm(">online")) {UARTSzovegKuld("System online!");}else
if (comm(">echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
if (comm(">eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
if (comm (">info")) {UARTSzovegKuld ("Uart Online! "); UARTSzovegKuld ("| 38400bps | atmega48 | Majlath.tech 2012"); }
else {
UARTSzovegKuld("ERROR");
}
delrec();
}
if (buffer=='='){ //servo pos módisítás
UARTSzovegKuld("Servo modified!");
UARTKuld(' ');
UARTKuld(rec[0]);
UARTKuld(':');
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
se[rec[0]-'a']=strtoint(1);
outdec(se[0],0);} else {UARTSzovegKuld("ERROR IN SERVO TITLE!");
};
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
if (rec[0]=='A'){OCR1A=strtoint(1); outdec(OCR1A,0);} else
if (rec[0]=='B'){OCR1A=strtoint(1); outdec(OCR1B,0);}
else {UARTSzovegKuld("ERROR IN SERVO TITLE!");};
};
delrec();
buffer=0;
}
if (buffer=='%'){
int number=strtoint(1);
outdec(number,0);
delrec();}
if (buffer=='<'){
ready();
delrec();
}
//led jelzés
PORTB=1;
_delay_ms(1);
PORTB=0;
inter=0;
};
}
}
ISR(USART_RX_vect)
{
if(UCSR0A & (1 << RXC0)) {buffer = UDR0;}
rec[stat]=buffer;
stat+=1;
inter=1;
}
Mit gondolsz?
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...
//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
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <stdbool.h> //bool típushoz
////////////////////////////////
#define BAUD 38400///38400bps
#define UBRR ((F_CPU / (BAUD * 16L)) - 1)
////////////////////////////////
//változók
volatile unsigned char rec[15];//string buffeer
volatile unsigned char buffer; //byte buffet
volatile unsigned char stat=0;//string karakter száma
volatile int servo[3]; ///szervo pozíció
volatile bool echo=0; //visszhang(0-1)
volatile bool inter=0;//(0-1) szemafor
//////////////////
/////
void uart_init(void)
{
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
// baud rate
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;
// format: 8data, 2stop bit
UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
}
///////UartKüld
void UARTKuld(unsigned char c){
while((UCSR0A & (1<<UDRE0)) == 0) {}
UDR0 = c;
}
///////szövegküld
void UARTSzovegKuld( char *p)
{
while(*p)
{
UARTKuld( *p++);
}
}//szövegküld vége
void delrec(void){
for(int i=0; i<50;i++){
rec[i]=' ';
stat=0;};
}
void kuldrec(void){
for(int i=0; i<stat ;i++){
UARTKuld(rec[i]);}
}
//decimális szám küldése:
void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
static char sign, s[12];
_delay_us(10);
unsigned int i;
i=0; sign=' '; //alapvetően nincs előtte semmi
if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
do {
s[i]=data%10 + '0'; //integer átírása ASCII ba
data=data/10;
i++;
if(i==ndigits) {s[i]='.'; i++;}
} while(data>0);
UARTKuld(sign);
do{
UARTKuld(s[--i]); //összes karakteren végigmenni
} while(i);
}
uint8_t comm( char *p){
char azonos=1;
int szam=0;
for(szam=0; szam < 15; szam++)
{
if (rec[szam]!=( *p++))
{
azonos = 0;
break;
}
if(!*p) break;
}
return (azonos);}
uint16_t strtoint(int szam){
int ertek=0;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
return (ertek);}
void init_servo(void){//servo init
//16bit pwm
DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1); //pwm portd1 2 3
TCCR1A = (1<<COM1A1)| (1<<COM1B1);
TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
ICR1 = 10000; //periódus: 20ms
OCR1B = 750;//servo2 1500us
}
void delay_1us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
while(delay_data--) _delay_us(1); }
void s_pwm(void){
///////////////software pwm
PORTB=2;
delay_1us(servo[0]);
PORTB=0;
}
int main(void){
//init_servo();
DDRB=255;
PORTB=0;
delrec();
uart_init();
UARTSzovegKuld("Uart Online! Ready To Serial communication!");
sei();
servo[0]=1000;
///////
while(1){
s_pwm();
_delay_ms(18);
//uart kiértékelése
if (inter==1){
if (echo){UARTKuld(buffer);};
if (buffer==8){
delrec();
}
if (buffer=='?'){
kuldrec();
}
if (buffer=='!'){
if (comm("alma")) {UARTSzovegKuld("alma fogadva!");delrec();}else
if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;delrec();}else
if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;delrec();} else
if (comm ("info")) {UARTSzovegKuld ("Uart Online! "); UARTSzovegKuld ("| 38400bps | atmega48 | string.c");delrec (); }
else {
UARTSzovegKuld("ERROR");
delrec();}
}
if (buffer=='='){
if (rec[0]=='a'){servo[0]=strtoint(2);
UARTSzovegKuld("Servo modified!");
UARTSzovegKuld("a=");
outdec(servo[0],0);
delrec();
buffer=0;};
}
if (buffer=='%'){
int number=strtoint(1);
outdec(number,0);
delrec();}
//led jelzés
PORTB=1;
_delay_ms(1);
PORTB=0;
inter=0;
};
}
}
ISR(SIG_USART_RECV)
{
if(UCSR0A & (1 << RXC0)) {buffer = UDR0;}
rec[stat]=buffer;
stat+=1;
inter=1;
}
Üdv.: Zoltán
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:
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.
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
////////////////////////////////
#define BAUD 38400///38400bps
#define UBRR ((F_CPU / (BAUD * 16L)) - 1)
////////////////////////////////
//váltoizók
unsigned char rec[15];//string buffeer
unsigned char buffer; //byte buffet
unsigned char stat=0;//string karakter
int se[18];
int servo=0;
char echo=0; //visszhang(0-1)
char inter=0;
////////////////////////
void uart_init(void)
{
/* Aktivieren des Empf?ngers, des Senders und des "Daten empfangen"-Interrupts */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
// baud rate
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;
// format: 8data, 2stop bit
UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
}
///////UartKüld
void UARTKuld(unsigned char c){
while((UCSR0A & (1<<UDRE0)) == 0) {}
UDR0 = c;
}
///////szövegküld
void UARTSzovegKuld( char *p)
{
while(*p)
{
UARTKuld( *p++);
}
}//szövegküld vége
void delrec(void){
for(int i=0; i<50;i++){
rec[i]=' ';
stat=0;};
}
void kuldrec(void){
for(int i=0; i<stat ;i++){
UARTKuld(rec[i]);}
}
//decimális szám küldése:
void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
static char sign, s[12];
_delay_us(10);
unsigned int i;
i=0; sign=' '; //alapvetően nincs előtte semmi
if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
do {
s[i]=data%10 + '0'; //integer átírása ASCII ba
data=data/10;
i++;
if(i==ndigits) {s[i]='.'; i++;}
} while(data>0);
UARTKuld(sign);
do{
UARTKuld(s[--i]); //összes karakteren végigmenni
} while(i);
}
uint8_t comm( char *p){
char azonos=1;
int szam=0;
while(*p)
{
if (rec[szam]==( *p++)) {azonos=1;} else {azonos=0;};
szam+=1;
}
return (azonos);}
uint16_t strtoint(int szam){
int ertek=0;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
return (ertek);}
void init_servo(void){//servo init
//16bit pwm
DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1); //pwm portd1 2 3
TCCR1A = (1<<COM1A1)| (1<<COM1B1);
TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
ICR1 = 10000; //periódus: 20ms
OCR1B = 750;//servo2 1500us
}
void delay_5us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
while(delay_data--) _delay_us(5); }
void s_pwm(void){
///////////////software pwm
PORTB=2;
_delay_ms(1);
if (buffer=='='){
if (rec[0]=='a'){servo=strtoint(2);};
UARTSzovegKuld("Servo modified!");
delrec();
buffer=0;
}
delay_5us(servo);
PORTB=0;
}
int main(void){
//init_servo();
DDRB=255;
PORTB=0;
uart_init();
UARTSzovegKuld("Uart Online! Ready To Serial communication!");
sei();
PORTB=1;
///////
while(1){
s_pwm();
_delay_ms(18);
if (inter==1){
PORTB=1;
_delay_ms(5);
PORTB=0;
inter=0;
};
}
}
ISR(SIG_USART_RECV)
{
if(UCSR0A & (1 << RXC0)) {
buffer = UDR0;}
rec[stat]=buffer;
stat+=1;
if (echo){UARTKuld(buffer);};
if (buffer==8){
delrec();
}
if (buffer=='?'){
kuldrec();
}
if (buffer=='!'){
if (comm("alma")) {UARTSzovegKuld("alma fogadva!");}else
if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
if (comm ("info")) {UARTSzovegKuld ("Uart Online! "); UARTSzovegKuld ("| 38400bps | atmega48 | string.c"); }
}
if (buffer=='%'){
int number=strtoint(1);
outdec(number,0);}
inter=1;
}
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)
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
////////////////////////////////
#define BAUD 38400///38400bps
#define UBRR ((F_CPU / (BAUD * 16L)) - 1)
////////////////////////////////
//váltoizók
unsigned char rec[15];//string buffeer
unsigned char buffer; //byte buffet
unsigned char stat=0;//string karakter
int se[18];
int servo=0;
char echo=0; //visszhang(0-1)
////////////////////////
void uart_init(void)
{
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
// baud rate
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;
// formátum: 8data, 2stop bit
UCSR0C = (1<<UMSEL01)| (1<<USBS0) | (3<<UCSZ00);
}
///////UartKüld
void UARTKuld(unsigned char c){
while((UCSR0A & (1<<UDRE0)) == 0) {}
UDR0 = c;
}
///////szövegküld
void UARTSzovegKuld( char *p)
{
while(*p)
{
UARTKuld( *p++);
}
}//szövegküld vége
void delrec(void){
for(int i=0; i<50;i++){
rec[i]=' ';
stat=0;};
}
void kuldrec(void){
for(int i=0; i<stat ;i++){
UARTKuld(rec[i]);}
}
//decimális szám küldése:
void outdec(long data, unsigned int ndigits) { //integer to dec=>string, és érték kiírása
static char sign, s[12];
_delay_us(10);
unsigned int i;
i=0; sign=' '; //ha pozitív, előtte space
if(data<0) { sign='-'; data = -data;} //ha minusz, akk elé: -
do {
s[i]=data%10 + '0'; //integer átírása ASCII ba
data=data/10;
i++;
if(i==ndigits) {s[i]='.'; i++;}
} while(data>0);
UARTKuld(sign);
do{
UARTKuld(s[--i]); //összes karakteren végigmenni
} while(i);
}
uint8_t comm( char *p){
char azonos=1;
int szam=0;
while(*p)
{
if (rec[szam]==( *p++)) {azonos=1;} else {azonos=0;};
szam+=1;
}
return (azonos);}
uint16_t strtoint(int szam){
int ertek=0;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*1000;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*100;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0')*10;};
szam+=1;
if (rec[szam]>='0' && rec[szam]<='9') {ertek += (rec[szam] - '0');};
return (ertek);}
void init_servo(void){//servo init
//16bit pwm
DDRB|= _BV(DDB1)|_BV(DDB2)|_BV(DDB1); //pwm portd1 2 3
TCCR1A = (1<<COM1A1)| (1<<COM1B1);
TCCR1B = (1<<WGM13) | (1<<CS11) ;//Posztás 8al
ICR1 = 10000; //periódus: 20ms
OCR1B = 750;//servo2 1500us
}
void delay_5us(uint16_t delay_data) {//5us es késleltetés(így kevés memóriát foglal)
while(delay_data--) _delay_us(5); }
void s_pwm(void){
///////////////software pwm
PORTB=2;
_delay_ms(1);
delay_5us(servo);
PORTB=0;
_delay_ms(20);
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!*/
}
int main(void){
//init_servo();
DDRB=255;
PORTB=0;
uart_init();
UARTSzovegKuld("Uart Online! Ready To Serial communication!");
sei();
PORTB=1;
///////
while(1){
s_pwm();
_delay_ms(18);
};
}
SIGNAL(SIG_USART_RECV)
{
if(UCSR0A & (1 << RXC0)) {
buffer = UDR0;}
rec[stat]=buffer;
stat+=1;
if (echo){UARTKuld(buffer);};
if (buffer==8){//backspace
delrec();
}
if (buffer=='?'){
kuldrec();
}
if (buffer=='!'){
if (comm("alma")) {UARTSzovegKuld("alma fogadva!");}else
if (comm("echo")) {UARTSzovegKuld("Echo ON!"); echo=1;}else
if (comm("eoff")) {UARTSzovegKuld("Echo Off!"); echo=0;} else
if (comm ("info")) {UARTSzovegKuld ("Uart Online! "); UARTSzovegKuld ("| 38400bps | atmega48 | string.c"); }
}
if (buffer=='%'){
int number=strtoint(0);
outdec(number,0);}
if (buffer=='='){
UARTSzovegKuld("Servo modified!");
if (rec[0]=='a'){servo=strtoint(2);}
}
PORTB=1;
_delay_ms(5);
PORTB=0;
}
Valaki tudna segíteni? Előre is köszönet,
Zoltán
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.
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ó)
/**------------------------------------------------------------
* Decimális kiíratás adott számú tizedesjegyre.
*-------------------------------------------------------------
* data - a kiírandó előjeles szám (int32_t)
* ndigits - a kiírandó tizedesek száma (uint8_t)
*/
void sw_uart_outdec(int32_t data, uint8_t ndigits) {
static char sign, s[12];
int8_t 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);
sw_uart_putc(sign);
do {
sw_uart_putc(s[--i]);
} while(i);
}
A te kódrészleted számomra értelmezhetetlen, mert a változó típusokat nem adtad meg benne.
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:
/* ADC10 Calibration Data - added by I. Cserny */
__no_init unsigned __READ int CAL_ADC_25T85 @ 0x10EA;
__no_init unsigned __READ int CAL_ADC_25T30 @ 0x10E8;
__no_init unsigned __READ int CAL_ADC_25VREF_FACTOR @ 0x10E6;
__no_init unsigned __READ int CAL_ADC_15T85 @ 0x10E4;
__no_init unsigned __READ int CAL_ADC_15T30 @ 0x10E2;
__no_init unsigned __READ int CAL_ADC_15VREF_FACTOR @ 0x10E0;
__no_init unsigned __READ int CAL_ADC_OFFSET @ 0x10DE;
__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:
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...
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á:
char c;
unsigned int adat;
long a;
void InitADC(void)
{
TRISAbits.TRISA0=1;
TRISAbits.TRISA1=1;
TRISAbits.TRISA2=1;
TRISAbits.TRISA3=1;
//ADCON1 = 0b00101100;//Analóg bemenetek beállítása
ADCON0 = 0b00001000;//AN2 kiválasztása, ADC még letiltva!
ADCON1 &= 0b00001100; //VREF+=VDD, VREF-=VSS (EZ LEHET, HOGY NEM SZÜKSÉGES IDE, MERT FENTEBB MÁR BE LETT ÁLLÍTVA! )
ADCON2 = 0xBE;//20TAD, FOSC/64, jobbra igazítás
ADCON0bits.ADON=1;//Az ADC engedélyezése
}
unsigned int ReadADC(unsigned char chan)
{
ChangeBits(ADCON0, chan<<2, 0b00111100);
ADCON0bits.GO = 1;//Start AD conversion
while (ADCON0bits.NOT_DONE)//Wait for conversion
{
return (((unsigned int)ADRESH)<<8)|(ADRESL);
}
}
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);
}
void main(void)
{
InitializeSystem();
InitADC();
CVRCON = 0b10101000;
while (!usb_cdc_kbhit())
{
ProcessIO();
}
outString("PICCOLO test p18f4550-el\n");
while (1)
{
do
{
c=usb_cdc_getc();
} while (c!='#');
c=usb_cdc_getc();
usb_cdc_putc(c);
switch (c)
{
case 'A':
ADCON0 = get2hex();
ADCON1 = get2hex();
ADCON2 = get2hex();
break;
case 'D':
LEDport = get2hex();
break;
case 'H':
outString("Help:\n");
outString("#Akkmmnn - ADC konfigurálás\n");
outString("#Dnn - LEDport beállítása\n");
outString("#H - Help\n");
outString("#L - LED villogtatás tiltás/engedélyezése\n");
outString("#Mnn - ADC(nn) csatorna kiolvasása\n");
outString("#Vkk - VREF modul konfigurálása\n");
break;
case 'L':
BlinkUSBStatus_enabled=!BlinkUSBStatus_enabled;
if (BlinkUSBStatus_enabled)
{
usb_cdc_putc('1');
}
else
{
usb_cdc_putc('0');
}
break;
case 'M':
a=0;
c=get2hex();
usb_cdc_putc(' ');
adat=ReadADC(c);
out4hex(adat);
a+=adat;
outString(" U=");
a=adat*4930L/1024L;
outdec_(a,3);
outString("Volt");
break;
case 'V':
CVRCON = get2hex();
break;
}
outString("\n");
}
}
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!
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.
|
|