Jag vill alltså skriva i flyttals-form, men att kompilatorn använder talet som ett heltal, bara för att man ska kunna ange parametrar i "klartext", precis som Icecap gör i sitt exempel.
Gimbal skrev:Ogillar att ange konstanter med högre precision än vad som sedan verkligen används. Det om något är väl förvirrande?
Jo, men det gör jag ju inte.
Nu filosoferar jag lite mer om detta...
Det bästa vore ju om man kunde ange någon form av fixed-point form som egen typ, och att en preprocessor omvandlar dessa till heltal, skulle vara jättesmidigt... hur man nu skulle döpa sådana typer?
Kod: Markera allt
/* heltalstyp: fix_d2: */
/* 16-bitars fixtal som anges i hundradelar */
/* typen har omfånget 0 - 655.36 */
/* konstanter anges som d2(1.00) */
#define d2(x) ((uint16_t)(x * 100);
typedef uint16_t fix_d2;
fix_d2 current = d2(3.75); // Ampere
if (current > d2(3.5)) ...
istället för att skriva bara
Kod: Markera allt
uint16_t current = 375; // Ampere
if (current > 350) ...
Det senare ser ju betydligt mer läsbart ut.... Frågan är om det allra vettigaste ändå är att skriva allt som heltal ändå:
Kod: Markera allt
#define MAX_CURRENT 2500 // Ampere * 100: upper limit for allowed curent.
eller
Kod: Markera allt
#define MAX_CURRENT 25*100 // Ampere * 100: upper limit for allowed curent.
Allra helst skulle man vilja kunna skriva in formler med delresultat som i sin helhet beräknas och omvandlas till rätt typ innan det når kompilatorn. jag vill gärna göra så här t.ex.
Kod: Markera allt
/********************************** mätning High Volt ******************
Spänningsdelare R1 = 330k * 4, R2 = 18k ger kvoten 1/74.333 = .013453
Spänningen jämförs med 2.50 volt referens.
t.ex. 129,6 volt --> 1.74V vilket är 69,74% av 2.50V ref.
100% motsvaras av 4096, så 69,74%*4196 = 2856 ADC RÅDATA.
Omvänt så tar man rådatavärdet och dividerar med 22.04 så får man spänningen i volt:
2856 / 22.04 = 129,6 volt. Spänningen sparas i formen V*10
**********************************************************************/
#define R1 1320.0 // kiloohm
#define R2 18.0 // kiloohm
#define SP_DEL (R2/(R1 + R2)) // spänningsdelning 330k+18k --> 0.01345
#define LSB_VAL ((2.50 / 4096) / SP_DEL) // ref 2.50V = 4096.
#define SP_DELARE (u16)(LSB_VAL * 65536 * 10) // divsor 65536, spänning anges i volt*10
Här har jag krånglat till det något, men att skriva det kortare skulle bli ännu svårare att förstå.
Först skriver jag in värden på två motstånd och räknar ut vad kvoten blir mellan U och U1 i en spänningsdelare (SL_DEL).
Sedan tar jag referensspänningen till ADC:n och dividerar med upplösningen och med kvoten.
Svaret blir vad 1 LSB i ADC'n motsvarar i volt innan spänningsdelaren (LSB_VAL).
Av detta skapar jag en konstant som jag ska multiplicera mitt ACD-värde med för att direkt få ut spänning i volt * 10, om jag bara delar resultatet med 65536 (SP_DELARE).
värdet används sedan när jag vill veta hur många volt jag har:
Kod: Markera allt
u16 readHighVolt(void) // volt*10 - driftbatteri, max 185.6 volt mätbart.
{
return ((u32)mcp3301_read(ADC_HVOLT) * HV_SP_DELARE) >> (16);
}
Det jag inte gillar med den metoden är att man skapar en massa globala #defines som kanske krockar med andra #defines med samma eller liknande namn. Och ju fler defines man har desto svårare att hålla reda på till vilken programsnutt de hör till. I fallet med spänningsdelare kan man ju använda
const istället och lägga det lokalt i funktionen. Då blir det ordning och reda. Det enda som skulle vara lämpligt att lägga utanför själva funktionen är ju värdena på R1 och R2 - dessa kanske man vill definiera som parametrar i en header-fil ihop med övriga hårdvarurelaterade parametrar. Vad man inte vill är ju att sprida ut sådana data överallt i programmet så att det blir ett hel* att hitta det sedan om man ska ändra på det.
Det lutar åt att jag borde göra något som liknar detta:
Kod: Markera allt
/* otestad kod */
/* Spänningsdelare för high-volt ADC */
/* Hårdvaruparametrar */
const u16 r1 = 1320; // kiloohm
const u16 r2 = 18; // kiloohm
const float referens_voltage = 2.50; // ADC referensspänning, i volt
...
u16 readHighVolt(void) // volt*10 - driftbatteri, max 185.6 volt mätbart.
{
/* Använder sig av konstanterna r1 och r2 för att beräkna spänningen */
const float kvot = (r2*1.0/(r1+ r2)) // beräkna spänningsdelning
const float volt_per_LSB = ((referens_voltage / 4096) / kvot) // ADC upplösning = 4096
const u32 heltal_multiplikator = (volt_per_LSB * 65536 * 10) // divsor 65536, spänning lagras som volt*10
return ((u32)mcp3301_read(ADC_HVOLT) * heltal_multiplikator) >> (16);
}
Detta blir mer och mer förvirrande... Det viktigaste är kanske att man är konsekvent och gör på samma sätt i hela koden, så att man inte blandar de olika metoderna vilt... Mitt problem är väl att jag inte kan bestämma mig för vad som är vettigast att göra.
