Dagens klantigheter, C
Postat: 29 november 2018, 14:23:35
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:
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:
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:
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å...
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;
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 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;
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å...