Dela en variabel mellan 2 rutiner men ingen andra, går det?

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Dela en variabel mellan 2 rutiner men ingen andra, går det?

Inlägg av Icecap »

Jag vill gärna dela en (eller fler) variabler mellan två rutiner men hålla variabeln "hemlig" för alla andra.

Det går såklart vid att lägga dessa två rutiner i en egen fil och sedan deklarera vaiabeln som static, alternativt köra C++ - som faller bort av olika orsaker.

Men mitt problem är att den ena rutin samtidig tar hand ganska många andra variabler i main-loop så det blir ganska oöverskådligt om jag ska separera till egen fil.

Så om man kunde göra precis som med variabler: en struct fast med funktioner.

Då kunde man innesluta de två funktioner i en gemensam funktion och deklarera deras gemensamma-men-hemliga-för-andra variabler enkelt.

Men går det ens i ANSI C, C99 eller C11?
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

Varför inte ha två funktioner, en för skrivning av variabler och en för läsning, som du anropar när du vill manipulera dina "hemliga" variabler?
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Icecap »

Det vore såklart en möjlighet men det rör sig om två interrupt som delvist samverkar.

Jag har (ofta) en RTC som ger 1-sek pulser till en extern interrupt-ingång. Oftast använder jag denna puls/interrupt till att inkrementa den interna UNIX-liknande tidräknar-variabel då detta sätt är mycket snabbare än att polla RTC'n via I²C.

Men ibland vill jag låsa den interna "system-timer" till denna puls för att då få en noga tid, eller om du vill: dela upp dessa sekunder i kanske ms. Jag kör ganska ofta en intern 1ms klocka för att kunde ge saker som ska slås på en viss tid för att göra detta, göra timeout på olika funktioner osv.

Men då µC'n kör med intern oscillator finns det en viss drift. Den är låg men den finns. Vid att ha en variabel som timer-interrupten stegar upp och som RTC-interrupten kan "se" kan RTC-interrupten justera timerns timing-register i små steg så att jag "alltid" får ut den önskade upplösning.

Detta är viktigt om jag t.ex. gör en tidräknare som ska vara "exakt" och ändå ha bra upplösning och ja, det har varit sådana projekt. Med den RTC jag använder (DS3232) har jag en trevlig låg drift.

Av denna orsak ska dessa två rutiner dela denna variabel men jag skulle gärna gömma den för alla andra rutiner. Och då det just är hårdvara-interrupts det rör sig om är detta med set/get inte helt enkelt att utföra på ett snabbt sätt, det blir en onödig overhead som jag inte gärna vill undvara.

Funktionen fungerar i övrigt riktigt bra, jag har testat med värme och kyla och en indikering av huruvida det sker en reglering. Reglering sker såklart, den är dock på få steg och avklarat ganska snabbt.

Detta att "skydda" variabeln är såklart ett lyx-problem men det som är intressant för mig är om det går.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

Jag kanske har missat något men jag skulle alltid använda interna timern och externa RTC för att få ett "justeringsvärde" som jag använder för att justera för driften i interna klockan.
Nerre
Inlägg: 27188
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Nerre »

Det är väl ungefär det han ska göra, men han vill inte riskera att andra funktioner pillar på justeringsvärdet.

Det blir väl en slags digital PLL om jag tolkar det hela rätt.

Men vänta nu, går det inte att hantera bägge interrupten med samma funktion istället för två funktioner? Det behövs då en liten IF-sats i början som identifierar vilket interrupt som triggat, men det kanske inte är trivialt att lösa? Och variabeln blir en static i funktionen bara, ej åtkomlig utifrån.
svanted
Inlägg: 5276
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av svanted »

vilken platfor? för unix?
jag har använt shared memory/shmget/shmset typ, för att kommunicera mellan två program...
det kanske kan fungera..?
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Icecap »

svanted: inget sådant! En helt vanlig Renesas RX210 (32 bit, 50MHz), inget OS, RTOS eller liknande.

lillahuset: jag har letat i databladet (1600+ sidor) men det finns inget "oscillator trim" register.
Därför justerar jag på timerns delningsregister.

Nerre: Just exakt så! Men det är definitivt inte samma interrupt! Det ska kanske gå att speca dom som samma interrupt och sedan välja med en if() men då är det jo onödigt overhead igen.

µC'n är en sådan med en interrupt för varje hårdvara funktion (samt ett antal mjukvara-vektorer). Varje serieport har 4 interrupts (Tx, Rx, Tx helt tom, Rx error), alltså olika vektorer.
Nerre
Inlägg: 27188
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Nerre »

Jo, lite extra overhead blir det ju om man trycker in bägge i samma funktion, men det kanske går att få ner till 1-2 instruktioner. Det beror ju på man kan identifiera aktuell interrupt.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

Det var inte så jag menade. Jag menade att timern får snurra på som vanligt med den hastighet den råkar ha. Det är först vid användningen av data från timern man justerar svaret och om man ska sätta upp en fördröjning i timern justerar man värdet man skriver till timern.

Annars är ju Nerres förslag bra. Du pekar bara båda interrupten till samma rutin. Jag brukar göra så när jag har flera UARTar som fungerar på samma sätt. Allt interruptrutinerna gör är att anropa en gemensam funktion med ett argument som talar om vilken UART det gäller. Man förlorar några cykler men man slipper underhålla flera nästan identiska rutiner.
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Icecap »

Jo, det är en möjlighet. Men jag har redan löst allt detta med "standard"filer och då t.ex. de seriella portar kan ha olika stora buffrar för Rx och Tx, alltså också så att Tx-buffern är olika stora mellan olika portar fungerar detta inte speciellt bra. Det blir många undantag och därmed overhead.

Jag har istället gjort så att jag har skapat ett "system" som är baserat på det styrkort jag har ritat. Det finns en "system"fil som definierar alla pinnar & portar som används på kretskortet.

I projekten ska jag definiera ett antal saker, allt efter vad jag behöver att använda:
USE_RS232_A # Same as USE_RS232_A_RX + USE_RS232_A_TX
USE_RS232_B # Same as USE_RS232_B_RX + USE_RS232_B_TX
USE_RS485 # Same as USE_RS485_RX + USE_RS485_TX
USE_MODBUS # Same as USE_RS485 + USE_CMT2
USE_RADIO # Same as USE_RADIO_RX + USE_RADIO_TX
USE_LAN # Defines void LAN_Tx_ISR(void) & void LAN_TEI_ISR(void) & void LAN_Rx_ISR(void) & void LAN_ERI_ISR(void)
USE_1_WIRE # Defines void CMT1_ISR(void)
USE_CMT0 # Defines void CMT0_ISR(void)
USE_CMT1 # Defines void CMT1_ISR(void)
USE_CMT2 # Defines void CMT2_ISR(void)
USE_CMT3 # Defines void CMT3_ISR(void)
USE_IRQ4 # Defines void IRQ4_ISR(void)
USE_S12AD # Defines void S12ADIO_ISR(void)
USE_S12AD_DELAY # Same as USE_S12AD but sets S12AD in single shot mode, activated by calling S12AD_Single()
USE_IIC_INT # Defines void IIC_EEI_ISR(void) & void IIC_RXI_ISR(void) & void IIC_TXI_ISR(void) & void IIC_TEI_ISR(void)
USE_MTU0_TGIA0 # Defines void MTU0_TGIA0_ISR(void)
USE_MTU0_TGIC0 # Defines void MTU0_TGIC0_ISR(void)
USE_PWM_ON_PIN13 # Defines void PWM_Initiate(_UDWORD Speed) & void Set_Intensity(_UWORD Value)
USE_PWM_ON_PIN13_INT # Defines void MTU0_TGIA0_ISR(void) & void PWM_Initiate(_UDWORD Speed) & void Set_Intensity(_UWORD Value)
USE_PWM_ON_PIN15 # Defines void PWM_Initiate(_UDWORD Speed) & void Set_Intensity(_UWORD Value)
USE_PWM_ON_PIN15_INT # Defines void MTU0_TGIC0_ISR(void) & void PWM_Initiate(_UDWORD Speed) & void Set_Intensity(_UWORD Value)
USE_MTU3_TGIA3 # Defines void MTU3_TGIA3_ISR(void) & void MTU3_Overflow_ISR(void) (Capture for In_6)
USE_MTU3_TGIB3 # Defines void MTU3_TGIB3_ISR(void) & void MTU3_Overflow_ISR(void) (Capture for In_4)
USE_MTU3_TGIC3 # Defines void MTU3_TGIC3_ISR(void) & void MTU3_Overflow_ISR(void) (Capture for In_7)
USE_MTU3_TGID3 # Defines void MTU3_TGID3_ISR(void) & void MTU3_Overflow_ISR(void) (Capture for In_5)
USE_MTU4_TGIA4 # Defines void MTU4_TGIA4_ISR(void) & void MTU4_Overflow_ISR(void) (Capture for In_1)
USE_MTU4_TGIB4 # Defines void MTU4_TGIB4_ISR(void) & void MTU4_Overflow_ISR(void) (Capture for In_3)
USE_MTU4_TGIC4 # Defines void MTU4_TGIC4_ISR(void) & void MTU4_Overflow_ISR(void) (Capture for In_0)
USE_MTU4_TGID4 # Defines void MTU4_TGID4_ISR(void) & void MTU4_Overflow_ISR(void) (Capture for In_2)
USE_SOFTWARE_RESET # Defines void Software_Reset(void)

To set HOCO-Speed, use ONE of:
USE_HOCO32MHZ
USE_HOCO36MHZ
USE_HOCO40MHZ
USE_HOCO50MHZ

USE_EXT_AD # Enables CN16 A/D inputs
USE_POWER_NOPROTECT # Disable the check of voltage to power module as well as releases the LED_Red

Dessa anger jag som "projektdefinitioner", alltså skriver in i projektet som globala definitioner.

När jag sedan startar programmet är den första kommando jag kallar Start_Hardware(), då ställs alla portpinnar i rätt läge, intern-oscillatorn aktiveras i rätt hastighet och en programsnudd för intern EEPROM-funktion kopieras.

Samtidig gör dessa definitioner att vektortabellen har de aktuella interrupts med och det enda jag ska göra är att definiera själva rutinen och skriva koden till den.

Fast många av funktionerna har redan färdiga rutiner med "allt" i. Jag har t.ex. en "Standard_RS232_A_100.c", "Standard_RS232_B_100.c" och "Standard_RS485_100.c", de tar hand om allting med buffring i minne, kolla av overload, initieringen osv.

Det finns "RSxxx_Send_String()", "RSxxx_Send_Byte()", "RSxxx_Send_Block()", "RSxxx_Status()", "RSxxx_Buffer()" (xxx kan vara 232_A, 232_B eller 485) vilket gör att jag inte behöver göra något som inte är speciellt. Jag kan skicka en sträng eller ett block med känd storlek (binär överföring, t.ex. MODBUS), kolla om det finns inkomna data och finns det kan jag få en pekare på buffern samt antalet bytes som är mottagna.

A/D-omvandlaren är "totalt" självkörande, jag kan få värden men det enda jag ska göra är att initiera den.

Så jag har skapad ett "standard" ramverk som gör det mycket enkelt att skapa ett projekt och att börja slå ihop t.ex. serierutinerna vill kanske nog spara lite programminne och overheaden blir inte allt för allvarlig så det är definitivt möjligt! Men nu har jag redan allt klart på det vis, det är bara när jag behöver göra specialgrejer som det blir tungt.

En sak jag gör stor bruk av är att alla projekt ska innehålla en "Project_Settings.h"!!! I den ska det definieras alla dessa "avvikelser" som behövs, därför tar alla "standard"filerna denna med i deras #include.

Då jag även lägger in sökvägen till mitt funktions-lib med i projekten får jag såklart INTE ha en "Project-Settings.h" i den sökväg förutom just i de enskilda projekters src-lib.

Det har varit en hel del jobb att komma hit, det har blivit många ändringar på vägen men ju fler projekt jag gör, ju färre ändringar blir det.

Då jag t.ex. skulle byta ut ett styrkort till en tid & temperatur skylt var själva RTC-delen bara att inkludera ett par filer, så körde det. Klockan skulle kunde ställas, alltså lagde jag till min rutin för att hitta kommandon i text.

För att läsa och kontrollera giltigheten av datum/tid lade jag till min rutin för att läsa och kolla detta.

Intensiteten skulle regleras efter den ljussensor jag använder, det finns såklart färdig rutin för det också. Den reglerar exponentiellt vilket passa riktigt bra med ögats känslighet och det jag behövde göra var att definiera USE_PWM_ON_PIN13 och sedan initiera PWM-funktionen med den önskade PWM-frekvens.

För att ställa intensiteten rätt kallar jag Display_Set_Intensity(Light_Intensity(Min_Styrka, Max_Styrka)) lite då och då, så är den saken biff.

Det svåraste var faktisk att räkna på utskriften till displayen, den var 80 cm hög och jag var tvungen att rita egen bitmap för siffror och de saker som behövdes. Det tog runt 70% av arbetstiden for det projekt.

Så efter ett par dagars arbete, inkl. att bygga en del av displayytan för test, var det klart och skylten visar nu tid & temperatur med mycket finare font än innan, bättre noggrannhet (DS3232) och automatisk växling mellan sommar- och vintertid.

Just växlingen mellan sommar- och vintertid saknades förut varför vi fick åka dit två gångar/år för att ställa klockan.

Så ett projekt kan bestå av ganska få filer i projektbiblioteket men ha en uppsjö av funktionsfiler med i listan.

Alla funktionsfiler inkluderar "Project_Settings.h" och den filen måste alltså vara med i projektet. Men den kan vara tom om man vill det, alla funktionsfiler har default parameter för de saker som måste vara definierat på något vis - men definierar man dom i "Project_Settings.h" gäller de definitioner såklart.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

Skillnad på bufferstorlekar är trivialt att hantera:

Kod: Markera allt

/* circular buffer, buffer size must be a power of 2 and <= 65536 */
typedef struct {
  volatile uint16_t put;	/* put index */
  volatile uint16_t get;	/* get index */
  uint16_t mask;		/* wrap around mask */
  uint8_t *buf;			/* pointer to buffer */
} circBufU8_t;
Det blir ganska lite overhead (beroende på processor naturligtvis) och inga specialfall om man pekar på structarna och har pekarna i en array som man använder kanalnumret som index till. Pekare, structar och arrayer underlättar mycket. Utom när de pekar åt helvete förståss. :D
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

En liten undran. Hur håller du reda på sommar/vinter-tid?
Har man en produkt för bara en marknad är det inte så märkvärdigt. Gäller det många marknader blir det ganska jobbigt. Vi skippade sommartid i vår senaste produkt sedan vi hade läst på. Reglerna har en tendens att ändras.
https://en.wikipedia.org/wiki/Daylight_ ... by_country
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Icecap »

Än är sommar- och vintertid bara använd i Sverige men att anpassa det efter andra regler är enkelt.

I grunden man in den tidzon skylten är i, när man sedan ställer datum/tid räknas den om till UTC varefter den räknas om till UNIX-tid.

Omräkningen till UTC innehåller rutin för att kolla om det är sommar eller vintertid. Detta innebär att det kollas veckodag vid specifika datum osv. och att göra om denna del till att använda en annan regel för när det är sommar och vintertid är enkelt. Man kan ju helt enkelt, precis som med tidzon lägga in landskoden och sedan använda den som DTS-regel.

Vid att ha tid i UNIX-format (sekunder sedan specifikt datum) betyder att när enheten slås på sker det en utläsning av RTC'n, sedan en omräkning av de lästa BCD-värden och det är allt. Efter det ger RTC'n en 1 Hz puls som går till en interrupt-ingång, den interrupt räknar sedan upp UNIX-tiden med 1.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av lillahuset »

Om du kollar länken jag postade kan du se att sommartid inte är speciellt statiskt. Reglerna ändras av politiska skäl.
Användarvisningsbild
Icecap
Inlägg: 26631
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Dela en variabel mellan 2 rutiner men ingen andra, går d

Inlägg av Icecap »

Kollade länken och kom fram till att det finns 12 olika regler för DST + såklart att DST inte används. Att lägga med en parameter i inställningerna som väljer ingen eller 1-av-12 lär inte vara ett problem värd att nämna.

Går klockan korrekt enl. UTC och det finns tidzon med kan man välja DST-regel fritt. Det är verkligen så enkelt som att koppla på en sladd till en seriell port och ge ett kommando via ett terminalprogram.
Skriv svar