Dagens klantigheter, C

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

Dagens klantigheter, C

Inlägg av Icecap »

Har ett hastighetsmätningssystem som mäter tiden mellan två punkter och via det värde för avstånd mellan de två punkter kan det räkna ut hastigheten. Denna visas sedan på display. Vissa känner igen det från halkbanan... ja, det är oss.

Har ju en ny version som är i drift på en bana - men det var problem. Displayen (via RS485) visade knasigt ibland - men inget som störde den riktiga visningen av hastigheten, det knasiga kom "efter". Det bestod av "d ou" som visades och efter en snabb sökning i källkoden kom det fram att det var ett debug-meddelanden ("Display#? blanked out due to new speed.") som det kom ifrån.

Men hur FAN kom det dit? Jag använde INTE den buffer som användes till att skriva det i i själva skicka-till-display-rutinen.
Efter att ha klurat lite kom jag fram till att jag ju skrev ett värde i just den buffer och OM displayen samtidig visade ett "gammalt" värde skulle det rensas blev det skickad en rensningskommando.

Detta KUNDE då utlösa ett debugmeddelande (om den bit var aktiverat) för att skriva i klartext på den seriella monitor att det hände och DÅ var värdet pajat.

Då jag väl insåg detta var det ju hyperenkelt att reservera en egen buffer för överföring av data till rutinen och sedan BARA använda textbuffern till just texter.

Jag hade även en klantighet mer. I Config-data har jag en samling bits som anger vilka debug-utskrifter som ska komma. Jag har gjort det så att jag skapade en union i Config-strukturen:

Kod: Markera allt

  struct
    {
    union
      {
      _UWORD Sys         : 1; // 0x0001
      _UWORD Measurement : 1; // 0x0002
      _UWORD Queue_In    : 1; // 0x0004
      _UWORD Queue_Out   : 1; // 0x0008
      _UWORD Specific    : 1; // 0x0010
      _UWORD RS485       : 1; // 0x0020
      } Bits;
    _UWORD Total;
    } Debug;
Satte jag sedan Config.Debug.Bits.RS485 till 1 skulle det bara komma ut de debug-medelanden som hade med det att göra - men allt kom hela tiden.

Jag skrev ut värdet på dessa bit, bit för bit och var en på var alla på. Och det var ju helt jävla fel!
Men då slog det mig - någon av programmörerna hade gjort fel och då jag är den enda som programmerar på detta kan man ju gissa vem klappträet var...

Sedan ändrade jag till:

Kod: Markera allt

  union
    {
    struct
      {
      _UWORD Sys         : 1; // 0x0001
      _UWORD Measurement : 1; // 0x0002
      _UWORD Queue_In    : 1; // 0x0004
      _UWORD Queue_Out   : 1; // 0x0008
      _UWORD Specific    : 1; // 0x0010
      _UWORD RS485       : 1; // 0x0020
      } Bits;
    _UWORD Total;
    } Debug;
Och BINGO: jag var i mål.

Och för dom som inte är helt bekväma med detta är det "ganska enkelt" egentligen:
'union' betyder att de delar som ingår i deklarationen alla ligger "ovanpå varandra" så att säga, de börjar alltså på samma adress.

Om jag deklarerar "_UWORD Something : 1;" betyder det att Something fyller 1 bit i en Unsigned Word.

Det som hände först var att bitsen alla var samma union, alltså att alla bitsen var bit 1.

Då jag fick justerat till rätt sätt är bitsen en struct vilket betyder att de får fortlöpande bits i samma _UWORD och att unionen sker så att _UWORD'en med bitsen ligger på samma plats om _UWORD Total.

Så jag kan alltså komma åt värdet antingen bit för bit eller som en 16-bit samling. Till en del funktioner är detta väldigt bra och på väldigt många µC används detta sätt för att definiera olika bits i register.

Jag har ibland en union som följer:

Kod: Markera allt

union
  {
  uint32_t Big_One;
  uint8_t Small_Ones[4];
  } Ett_Namn;
Då kan man enkelt lägga ner ett 32-bit värde och plocka de olika bytes - men detta sätt fungerar bara "säkert" på en 8-bittare! Kommer man upp i att RAM är på 16 bit eller mer kan värden kastas hur som helst in och det kan vara svårt med att de "passar ihop".

Så man kan använda detta trick i bestämda miljöer men man ska undvika det i kod som ska migrera. Kan man inte undvika det MÅSTE man testa det i det nya miljö innan man liter på att det blir bra.

Och om man byter endian kan det bli helt jävla knasigt också...
ie
EF Sponsor
Inlägg: 1274
Blev medlem: 23 oktober 2006, 13:12:57
Ort: Tyresö

Re: Dagens klantigheter, C

Inlägg av ie »

Kan tipsa om hur man löser problemet med olika data-bredder (för de som undrar). Jag utvecklade ett program på ATmega328 som jag sedan ville köra även på Rpi.

Kod: Markera allt

		union
		{

			struct					// AT command
			{
				uint8_t frame_id;	// Frame id, 0=No response (must be >0)
				uint8_t at[2];		// Two char AT command
				uint8_t data[DATA_SIZE];	// 0 char=Query, >0 chars=set param (strings are \0-terminated)
			}__attribute__ ((packed)) x08;

			struct				// Transmit request
			{
				uint8_t frame_id;	// Frame id, 0=No response
				char address[10];	// Receiver address
				uint8_t maxhops;	// 0=Max (10) hops
				uint8_t options;	// 0x01=No ack
				uint8_t data[DATA_SIZE];	// Data (max 72)
			}__attribute__ ((packed)) x10;
Det finns alltså ett direktiv som ser till att datat packas som bytes.
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Dagens klantigheter, C

Inlägg av Micke_s »

Funkar så länge man inte byter mellan gcc och något annat...
ie
EF Sponsor
Inlägg: 1274
Blev medlem: 23 oktober 2006, 13:12:57
Ort: Tyresö

Re: Dagens klantigheter, C

Inlägg av ie »

Ja, så är det nog. Jag är dock imponerad över hur lätt det var att porta över koden. Väldigt få korrigeringar behövdes. Främst HW-relaterade naturligtvis. Dessutom har jag lagt AVR resp Rpi-specifik kod i #if-satser, så att rätt del av koden kompileras i resp miljö, men att jag fortfarande bara använder en source-fil för båda.
Användarvisningsbild
AndLi
Inlägg: 17116
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: Dagens klantigheter, C

Inlägg av AndLi »

För att höja min effektiva datahastighet idag tänkte jag optimera bort de 2x4 bits som blir över om man överför 2 12 bitars AD resultat i 4 bytes.

De lägre bytes kom alltid över korrekt, men min sammanslagning av de två övre nibblarna ville sig inte, hur svårt kan det vara tyckte ja.
Ta 4 bitar flytta de 4 eller 8 steg och stoppa in i en byte. Mina testloopar mellan 0-1400 funkade utmärkt...

Ökade på värdena, 3276 funka fint, men det sket sig med 4916, försökte manuellt... hmm högsta byten är 0x13... Svårt att få in i en nibble.
Det var då jag kom ihåg att jag ju samplar varje värde två gånger och lägger ihop. Helt plötsligt blir ju mitt 12 bitars tal faktisk ett 13 bitars tal.

Efter ha tagit bort översamplingen, så funkade såklart allt utmärkt...
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45270
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Dagens klantigheter, C

Inlägg av TomasL »

He he, dagens klantighet från mig.

Jo jag har en bunt enumar (gillar enum, då det är enkelt? att debugga).
ANvänder dem mest i switch/case satser för att få saker tydliga.
Nåväl, jag har en bunt Switch/Case som använder samma enum, lade till ett värde och ändrade i den första switch /case satsen, dock hade jag glömt att jag har en bunt switch/case satser till som använder samma enum, och eftersom jag, som man skall göra, alltid har ett "default" så blev det lite fel.
Gissa om det tog tid att hitta.
Till saken hör att det är svårt att debugga, eftersom maskinen måste vara i drift när man debuggar, och man vill inte stanna koden för länge med tanke på att externa enheter larmar ut om kommunikation uteblir samt även säkerhetsfunktioner mm blir åsidosatta..
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Dagens klantigheter, C

Inlägg av Micke_s »

default i switch satser brukar jag använda som fel när man inte använder case satsen.
-Wswitch-enum -Wswitch-default
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45270
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Dagens klantigheter, C

Inlägg av TomasL »

Jo, men i detta fallet så gick det inte, av olika anledningar.
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Dagens klantigheter, C

Inlägg av Micke_s »

Är man mer lag åt hållet masochist-hållet så finns -Wall -Werror

Edit: glömde -Wextra
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45270
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Dagens klantigheter, C

Inlägg av TomasL »

Jo, men den detekterar inte detta, kör det per default.
hmm Wextra får jag testa.
Baroon
Inlägg: 35
Blev medlem: 11 mars 2016, 23:00:09
Ort: Linköping

Re: Dagens klantigheter, C

Inlägg av Baroon »

och vill man självplåga sig finns statisk kodanalysverktyg ex klocwork. Man kodar en dag och rättar remarks i två :)
Skriv svar