C-30 #define fråga

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

C-30 #define fråga

Inlägg av dangraf »

Hallå!
Jag sitter och försöker skriva kod för att öppna en UART och där man lätt
kan ställa in baudrate osv med hjälp av defines.

Jag skulle vilja kunna definiera upp att jag vill t.ex köra med baudrate 9600 och därefter räknar pre-processorn ut värdet för t.ex BRG registret i min PIC.

Det jag skrivit hittills är:

Kod: Markera allt


#define CLOCK_SPEED	 7370000	//7.37Mhz internal RC oscillator
#define BAUD_RATE	9600
#define UART_NR		1//1 or 2 depending on UART

//#define UART_BUFF_INT	1	// enables buffert interrupt
///------------------------------------------
#define BRG_1  	(CLOCK_SPEED/BAUD_RATE/16) - 1 // upper, 14.02 = (int)14
#define BRG_2  		(CLOCK_SPEED/BAUD_RATE/16)		// lower, 13.99 = int(13)
#define TEST_1  	CLOCK_SPEED/(16*(BRG_1)+16)           // test calculation  using BRG_1 value
#define TEST_2  	CLOCK_SPEED/(16*(BRG_2) +16)         // test calculation of baudrate using BRG_2 value



#if TEST_1 > BAUD_RATE
	#if (TEST_1- BAUD_RATE) < 20
		#define BRG  BRG_1
	#endif
#else
	#if (BAUD_RATE - TEST_1) < 20
		#define BRG  (int)BRG_1
	#endif
#endif


#if TEST_2 > BAUD_RATE
	#if (TEST_2- BAUD_RATE) < 20
		#define BRG  BRG_2
	#endif
#else
	#if (BAUD_RATE - TEST_2) < 20
		#define BRG  BRG_2
	#endif
#endif


#ifndef BRG
	#error "BRG is not properly calculated"
#endif

Det jag vill göra med ovanstående kod är att beräkna ett värdet (BRG) därefter kontrollea att det uträknade värdet ligger inom vissa gränser, annars skall ett felmeddelande dyka upp vid kompileringen.

Problemet som uppstår är att när jag kontrollräknar så verkar det som att uträkningen av BRG_1 och BRG_2 är flyttal vilket gör att min kontroll-uträkning inte stämmer.

Om jag kör en cast på BRG_1 och 2 så får jag felmeddelanden vid kompileringen.

T.ex om jag skulle skriva:

Kod: Markera allt

#define BRG_1  		(int)(CLOCK_SPEED/BAUD_RATE/16) - 1	// upper, 14.02 = (int)14
#define BRG_2  		(int)(CLOCK_SPEED/BAUD_RATE/16)	
eller

Kod: Markera allt

#define TEST_1  	CLOCK_SPEED/(16*(int)(BRG_1)+16)
#define TEST_2  	CLOCK_SPEED/(16*(int)(BRG_2) +16)
så får jag felmeddelandena:

Kod: Markera allt

pic30-coff-cc1.exe: warning: Options have been disabled due to expired license
printf.c:16:5: error: missing binary operator before token "("
printf.c:21:19: error: missing binary operator before token "("
printf.c:27:5: error: missing binary operator before token "("
printf.c:32:19: error: missing binary operator before token "("
printf.c:39:3: error: #error "BRG is not properly calculated"
printf.c: In function 'vInitUart':
printf.c:63: error: 'BRG' undeclared (first use in this function)
printf.c:63: error: (Each undeclared identifier is reported only once
printf.c:63: error: for each function it appears in.)
Halting build on first failure as requested.
raderna som den hänvisar till är:
#if TEST_1 > BAUD_RATE
Har ni någon aning om vad detta felet beror på?
Jag känner själv att jag kanske inte är allt för grym på att skriva sådan här "pre-processor kod" och undrar även om ni vet någon bra sida där man kan läsa sig till lite olika tips och knep? T.ex finns det någon ABS funktion som kan anvnädas när man gör jämförelser osv så man slipper alla if satser?

// Daniel
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

#define är väl för att definiera text-strängar, jag är inte helt säker
på att det går att göra så där. Det kan vara så att t.ex

> #define BRG_2 (CLOCK_SPEED/BAUD_RATE/16)

bara gör att :

BRG_2 = "(CLOCK_SPEED/BAUD_RATE/16)", och inte det beräknade värdet...

Lite på djupt vatten här, dock... :-)
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Det är nog sant som du säger att alla defines bara byter ut tecken strängen mot det man definierat det som. If-satsen står det antagligen ett jätteuttryck där Men någon gång så måste väl värdet beräknas, eftersom det inte sker i själva koden när programmet körs?
Det låter märkligt om defines enbart används till text-strängar. isf, missbrukas det av väldigt många.
pheer
EF Sponsor
Inlägg: 1283
Blev medlem: 16 januari 2005, 18:05:21

Inlägg av pheer »

Ta en titt i spbrgselect.inc i tiny pic bootloader...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> spbrgselect...

OK, assembler, visst, det är inget konstigt där.
Men hur skriver man motsvarande i C30 pre-compilern ?

> Men någon gång så måste väl värdet beräknas,

Kanske, jag vet inte...

> isf, missbrukas det av väldigt många.

Kanske, men jag har inte hittat något i C30 manualen som
stöder att beräkningar utförs så där. Men jag kanske bara är
ovan vid C pre-compiler... :-)

Jag har å andra sidan inte hittat någon motsvarighet till
ASM pre-assembly ".SET" syntaxen, så jag är lite lost... :-)
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag tittade lite på wikipedia om pre-processorn och vad man kan göra där

http://en.wikipedia.org/wiki/C_preprocessor


där det står lite om defines och macron, men inget om mattematiska uttryck, som jag använt mina defines till. Jag har lyckats skriva min egen pre-processor ABS funktion, men får fortfarande felmeddelanden om jag försöker köra en "cast".

Jag har även tittat i "spbrgselect.inc" som jag ifs hade kunnat ta rätt av. Men nu vill jag förstå hur det fungerar i C :wink:
Användarvisningsbild
BER
Inlägg: 399
Blev medlem: 9 mars 2005, 00:02:10
Ort: Östergötland

Inlägg av BER »

Jag har gjort enligt följande till två stycken mjukvaru uartar i en PIC. Där jag ville beräkna bittiden att ladda räknarna med.

Kod: Markera allt

#define OSCspeed	10000000
#define BaudRate_1	9600
#define prescaler_1	1

#define p_1bit1		0xFFFF - OSCspeed/BaudRate_1/prescaler_1 + 20
#define p_1bit1_5	0xFFFF - (OSCspeed/BaudRate_1/prescaler_1)*1.5 + 20

#define BaudRate_2	4800
#define prescaler_2	1

#define g_1bit1		0xFFFF - OSCspeed/BaudRate_2/prescaler_2
#define g_1bit1_5	0xFFFF - (OSCspeed/BaudRate_2/prescaler_2)*1.5
Och i en av funktionerna där värdet används

Kod: Markera allt

char M_Send(char data)
{
	if (!SM_TX.flag.busy)
	{
		SM_TX.flag.enable = 1;
		SM_TX.sdata.Byte = data;
		SM_TX.bitCount.Byte = 0;
		SM_TX.flag.busy = 1;
		TMR1H = 0xFF;
		TMR1L = ((unsigned char)p_1bit1);
		PIR1bits.TMR1IF = 0;
		PIE1bits.TMR1IE = 1;
		return 0;
	}
	else
		return 1;
}

Du kan testa om din kompilator köper det. Det fungerade bra med C18 i alla fall.[/code]
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag har inget svar i sakfrågan men jag har ett par tips som gäller allmänt om #define med uträkning i:
1: Omge det med en parentes!
2: ALDRIG kommentarer med // efter!

Exempel tagit ur det verkliga livet:
#define UART_NR 1 // 1 or 2 depending on UART
Problem: Om UART_NO sedan används kommer ALLT på raden EFTER 'UART_NO' att vara bortkommenterat.
Lösning: Kommentera ENBART med '/*' och '*/'
Rätt definition:
#define UART_NR 1 /* 1 or 2 depending on UART */

Ett annat exempel:
#define BRG_1 (CLOCK_SPEED/BAUD_RATE/16) - 1 // upper, 14.02 = (int)14
Problem: Samma här med kommentaren + när man använder BRG_1 kommer den att ersättas av:
"(CLOCK_SPEED/BAUD_RATE/16) - 1"
Detta kan gå bra men med liiiite oflyt (har det någonsin hänt vid programmering?) används uttrycket i en beräkning och då kan det gå hur som helst.

Den bör alltså definieras som följer:
#define BRG_1 ((CLOCK_SPEED/BAUD_RATE/16) - 1) /* upper, 14.02 = (int)14 */

EDIT: just i detta fall lär det väl knappast vara ett problem men om man definierar en "konstant" som sedan används för att multiplicera med en viss faktor, t.ex. X = BRG_1 * 16; kommer detta att resultera i:
X = (CLOCK_SPEED/BAUD_RATE/16) - 1 * 16 vilket tolkas till:
X = (CLOCK_SPEED/BAUD_RATE/16) - (1 * 16) vilket ju är fel.
Anledningen är att multiplikation och division har "företräde" framför addition och subtraktion.

Med "rätt" definition blir det plötsligt:
X = ((CLOCK_SPEED/BAUD_RATE/16) - 1) * 16 vilket ju är rätt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Intressant, Icecap !
C är underbart... :-)
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

C är väl som andra språk: fördelar och nackdelar. Det lär väl knappast finnas något språk som inte har sina nackdelar, även med macro i assembler kan det bli intressant om man inte har skapligt koll på vad man gör.

Personligt gillar jag assembler men när man ska åstadkomma större program utan exceptionella timingkrav är det ganska ineffektivt, då uppfattar jag C som "lagom nära" assembler samtidig som det medger högnivåfunktioner.

Jag har i dagarna lyckats porta ett stort program så att jag kan kompilera SAMMA C-källfil i kompilern till Fujitsu-processorn samt till Renasas-processorn. Detta självklart med separata filer för hårdvara-åtkomst och setup men på det sätt kan jag utveckla projektet fortlöpande och ändå underhålla 2 olika hårdvaruversioner.

Detta är självklart enbart möjligt om jag använder ANSI-C till den gemensamma programdelen.

Så C har fördelat också.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

>> Icecap: Jag har testat att ta bort alla kommentatarer eller ändra om dem till "/* */" och har även lagt till () som du rekomenderade. Tack för tipsen, det e lätt att halka när man inte ser eller debuggar sina defines. Tyvärr hjälpte det inte. jag misstänker fortfarande att det är nått med min cast som den inte gillar.

>> BER: tackar för koden, men jag använder mina timers till andra saker, så det får nog bli de inbyggda iaf..
Användarvisningsbild
BER
Inlägg: 399
Blev medlem: 9 mars 2005, 00:02:10
Ort: Östergötland

Inlägg av BER »

Koden jag skickade var för att jämföra med kod som i alla fall fungerade i C18 kompilatorn med define och uträkningar. Om man har en ledig hårvaruuart så är det förmodligen att rekommendera att använda den i första hand. I mitt projekt så hade jag 3 uartar, en i hårdvara och två i mjukvara. Hoppas koden var till lite hjälp i alla fall.

Såg nu när jag tittade på min egen kod, och efter att ha läst Icecap inlägg att jag även borde ha adderat 0.5 på mina definierade beräknade konstant er för att få rätt avrundning vid castning.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Dina uträkningar verkar konstiga!
#define BRG_1 ((CLOCK_SPEED/BAUD_RATE/16)-1) /* upper, 14.02 = (int)14 */
#define BRG_2 ((CLOCK_SPEED/BAUD_RATE/16)) /* lower, 13.99 = int(13) */
#define TEST_1 (CLOCK_SPEED/(16*(BRG_1)+16)) /* test calculation using BRG_1 value */
#define TEST_2 (CLOCK_SPEED/(16*(BRG_2)+16)) /* test calculation of baudrate using BRG_2 value */

Den enda skillnad i uträkningerna är under BRG_1 och BRG_2, TEST_1 och TEST_2 är identiska!

Alltså kommer du sannolikt i en situation där ingen av dom fungerar, jag misstänker att du har kopierat och glömt att ändra 16 till 64 eller liknande.
Senast redigerad av Icecap 3 augusti 2007, 22:19:31, redigerad totalt 1 gång.
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Jag fliker in med en fråga och undrar om det finns något sätt att få kompilatorn att spotta ut värden från defines utan att avbryta, alltså motsvarande det man gör med #error, fast utan att avbryta. Det kanske kan användas för att kolla att man definat rätt saker?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Du kan väl ha en #error som du flyttar runt lite.
Att det avbryts gör ju inte så mycket när du labbar.
Debuggning är debuggning... :-)
Skriv svar