PIC programmering i C

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
ZigBee
Inlägg: 161
Blev medlem: 2 augusti 2006, 04:48:42
Ort: Jönköping

Inlägg av ZigBee »

Hur gör man om en int till 2 char enheter?

Jag har lite data att sända, variabler i int. KOmmandot som jag sänder de med seriellt är putchar, som skickar en char (byte) åt gången.

Hur kan jag göra om min int till 2 st char för att skcika de efter varandra. Eller fiinns det något smidigare sätt att lösa detta?

Jag har använt mig av en kodexempel som inte verkar fungera från följande länk;

http://www.microchipc.com/HiTechCFAQ/in ... c475127510

Q. If an integer is 16 bits on a PIC, and a byte is 8 bits, how do I reference one of the bytes in an integer?

A. Use the following code:
unsigned int x;
unsigned char y;
#define hibyte(x) (unsigned char)(x>>8 )
#define lobyte(x) (unsigned char)(x & 0xFF)
x=0x1234;
//y=hibyte(x); //now y=0x12
y=lobyte(x); //now y=0x34


Jag har gjort det till en subrutin och använder i mitt program. Men jag får ingen data ut seriellt. Om jag ersätter "lobyte(x)" tex med en konstant då ser jag att jag tar emot data i hyperterminalen. Om jag tar emot "hibyte(x)" då ser jag också i hyperterminalen att jag tar emot data även om det inte ser rätt ut( jag har en räknade som stegar upp med det jag kan se tas emot i ASCII är samma tecken).

Behövs det mer info eller går det att förtälja vad som fel av ovanstående?


Jag har provat seriellkommunikationen genom att skicka bytes och kolla att jag får motsvarande och det fungerarar.


*Edit kod
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Det låter lite som om du blandar ihop binära "bytes" med ACSII "tecken...
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Sända en 16-bitars variabel:

int Ska_Skickas;

UART_TX = *(byte*)&Ska_Skickas; // Sändar byten på låga adressen
UART_TX = *(byte*)(&Ska_Skickas + 1); // Sändar byten på höga adressen

Ett annat sätt är det jag oftast använder:

Kod: Markera allt

union
  {
  unsigned short Word;
  unsigned char Byte[2];
  } Ska_Skickas;
Då kan man komma åt 16-bitarn som 'Ska_Skickas.Word'
och varje byte som 'Ska_Skickas.Byte[0]' och 'Ska_Skickas.Byte[1]'

Kan självklart expanderas MYCKET, t.ex. när jag ska ta emot kommunikation i en del projekt. Då definierar jag kommunikationsblocket som en typedef och lägger den mottagningsbuffer i en 'union' med ett char-array:

Kod: Markera allt

union
  {
  byte     Buffer[N_RX_SIZE];
  T_HEADER Header;
  } Rx0;
Då kan jag komma åt som jag vill utan omskrivningar.
ZigBee
Inlägg: 161
Blev medlem: 2 augusti 2006, 04:48:42
Ort: Jönköping

Inlägg av ZigBee »

sodjan skrev:Det låter lite som om du blandar ihop binära "bytes" med ACSII "tecken...

Sodjan,

Nä jag skickar binära bytes, men ser det i hyperterminalen som ASCII tecken. Så jag blandar inte ihop det. Eftersom jag ska ta emot det i labview sen så vill jag bara kolla att det fungerar.

Icecap, Det du skrev verkar grymmt smidigt och användbart. Ska prova det. Tack för tipset!


Jag var och provade lite mer nu. Såg att problemet är med en global variabel som jag använder( som måste vara global då den används i subrutin, main och ISR). Den är definierad längst upp utanför main. Jag hade råkat omdefiniera i koden den så den fungerade aldrig. Och alltså inte med att göra om int till char, men jag uppskattar hjälpen Icecap nu kan jag göra det på ett effektivare sätt. Det var egentligen det jag sökte efter från bröjan.

**************************************

Snart är denna detta projekt klart och då lägger jag upp lite mer info och bilder.


*Uppdaterat status på programmeringen då problemet är löst.
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Nä jag skickar binära bytes, men ser det i hyperterminalen som ASCII tecken.

Visst, så länge det binära värdet ligger i intervallet "printable characters".
Men hur ser du t.ex h'0A' eller h'0D' som "ASCII tecken" ?

Generellt sätt är det bättre att hålla sig till "printable characters" så slipper
man eventuella konflikter med styr-/kontroll-tecken. Man behöver en
rutin för bin/ASCII konvertering, men det är ett mindre problem...

Så försök att inte skicka binära värden som kan ligga i hela
intervallet h'00' till h'FF' över en vanlig serial lina, det hela blir
bl.a mycket svårare att felsöka...
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Om det är mer än 1 byte som ska skickas (t.ex. 2 olika bytes) är det ALLTID en dålig idé att skicka dom i rått format.

Q: Anledning?
A: Hur ska mottagaren veta vad som är vad? Det kommer ALLTID att gå otakt om det är vitalt att det inte gör det!

För min del betyder det att jag skickar värden med tecken. Jag har ofta en block som startar med STX (0x02) och avslutas med ETX (0x03), då har jag en klar avgränsning. STX rensar input-buffer och ETX trigger "kolla kommunikationen"-rutinen. Sedan lägger jag till en timer som gör att ett block bara är giltigt en viss tid då jag under "giltig"-tiden inte tillåter mottagning.

Alla värden skriv ut i "klartext", ska jag skicka värdet 57 kommer det en '5' och en '7' och ett block ser alltså ut som följer (mellanslag bara för tydligheten):
STX 57 ETX

Men ska man skicka fler värden med olika betydelse måste man ju indikera VAD som kommer, detta gör jag med en delimiter (t.ex. komma):
STX 1,57 ETX som betyder "värde#1 är 57".

På detta sätt kan jag överföra ordentligt stora värden utan problem:
STX 0,4294967295 ETX (Värde#0 = 0xFFFFFFFF)

På detta vis kan man dels kolla att alla tecken är "legala", dels vet man var det startar och slutar, man vet vilket värde som skickas och man kan "sniffa" med ett terminalprogram och se om det ser vettigt ut.

Overheaden är lite större men kommunikationen är avsevärd mer säker och tydlig.
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> att skicka dom i rått format.

D.v.s med svansen sist ? :-)

Men visst håller jag med, eftersom det var ungefär det jag skrev... :-)
ZigBee
Inlägg: 161
Blev medlem: 2 augusti 2006, 04:48:42
Ort: Jönköping

Inlägg av ZigBee »

Sodjan,

Ok nu förstår jag vad du menar! Helt rätt ju.


Icecap

Jag hänger nog inte med riktigt, har du möjlighet att förtydliga så att en novis programmerare förstår? Har skickat pm.
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

I allmän intresse:
Om man ska överföra data som består av mer än 1 byte (eller vilken storlek som är aktuellt, i en UART är det just 1 byte) är det knappast ett problem att överföra eller ta emot samt att dela upp/packa ihop datan.

Om en datamängd på >1 bytes ska överföras blir det alltså i block vars storlek kan vara fast eller variera, beroende på projektet.

Det svåra är att se till att mottagaren kan bedöma att ett helt block har mottagits, man ska leka med tanken att ett värde (byte) har blivit fel på vägen, vad händer då?

Av den anledning har jag vald att överföra data i textform och använda STX och ETX som avgränsare. Detta medför att när min enhet tar emot en STX kan jag nolla alla pekare och rensa min input-buffer. Sedan kommer det en massa text och när den är klar kommer det en ETX.

Denna ETX sätter en timer som betyder att det finns ett block att ta hand om, under tiden den timer är aktiv kan INGEN nya bytes läggas till i inputbuffern. Lite saxande:

Kod: Markera allt

__interrupt void UART0_Rx(void)
  { /* Communication input Interrupt */
  BYTE Rx;
  if(SSR0 & 0xE0) /* Any errors ??? */
    {
    SCR0_REC      = 0; /* Clear any recieving errors */
    Rx            = SIDR0;   /* Clear the interrupt flag */
    Ser0.Rx_Input = 0;
    }
  else
    {
    Rx = SIDR0; /* Read the recieved character and clear the interrupt flag */
    if(!Valid_PC_Block) /* Valid_PC_Block is a timer counting down to zero by a timer interrupt */
      {
      switch(Rx)
        {
        case STX:
          Ser0.Rx_Input  = 0;
        break;
        case ETX:
          if(Ser0.Rx_Input >= 10) /* At least: "0,0,0,0,FF in this project */
            {
            .... /* really does some converting */
            Valid_PC_Block = SERIAL_BLOCK_TIME;
            }
        break;
        default:
          if(Ser0.Rx_Input < SERIAL_BUFFER_SIZE) Ser0.Rx_Buffer[Ser0.Rx_Input++] = Rx; /* Fill into buffer */
        }
      }
    }
  }
Detta kör med UART-interrupt och main-rutinen lägger alltså ingen krut på att ta emot, den kollar enbart om timern är "icke-noll", om den är det exekverar den rutinen som kollar kommunikationen och sedan är det klart.

Man kan även dela blockar med tid, detta kan vara användbart också men man kan ha svårt att få upp hastigheten då det ska finnas ett visst minimum av tid mellan varje block.
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Inlägg av mri »

För generell överföring av rådata (datapaket av varierande längd) används HDLC som grund i ett otal protokoll. Dvs datapaketet omsluts av HDLC start- och slut-flagga med "bitstuffing" av själva rådatan däremellan. Kräver ju lite processering på bitnivå men som metod är den rätt genialisk.
ZigBee
Inlägg: 161
Blev medlem: 2 augusti 2006, 04:48:42
Ort: Jönköping

Inlägg av ZigBee »

mri,

Tack för tipset.

Att det är ISO gör ju inte saken sämre.

Det skulle vara toppen om det fanns någon tutorial eller färdig kodsnutt så man ser exakt hur allt ska göras, när det gäller protokoll vid dataöverföring. Det är ganska nytt för mig.
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Inlägg av mri »

Jag har implementerat detta ett antal gånger men har ingen kod som jag kan copy/paste här på forumet, men det är inte många rader C kod. Sök på Google efter 'HDLC framing and bitstuffing' och du hittar massor av info. Det här är trots allt en mycket vanlig metod.

Det finns en annan HDLC variant var "stuffingen" görs på hela tecken, liknar Icecap's metod, som kan vara helt ok också, beroende på vad du skall överföra.
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Läser man länken om HDLC står det just att med UART-kommunikation är 8 bit det "naturliga" och hur man använder det.

Absolut ett bra sätt, "min" metod har dock fördelen att man kan "sniffa" på kommunikationen och få ut det i "klarspråk" vilket kan vara nog så viktigt vid debug.
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Synkrona protokoll har normalt fördelen av effektivare överföring,
men är å andra sidan generellt mer komplexa att hantera.
Jag har lite svårt att se vad ZigBee skulle vinna i det aktuella
fallet med att köra synkront. Mitt tips är att glömma allt om HDLC
och kör vanlig asynk kommunikation istället...
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Inlägg av mri »

Det finns inget protokoll som är bäst på allt, det är helt klart. Allt beror på vad man tänkt överföra, och vilken prestanda man önskar. HDLC med bitorienterad stuffing är bra på ganska mycket, men pasar nog bäst för synkrona bitströmmar, och "character oriented stuffing" är nog det mest naturliga valet för async (UART) överföring, som du skriver. I async överföring har man ju redan avgränsat tecknen med start och stopbit, så det är dumt att inte utnyttja det. En lite udda fördel med att köra bitorienterad stuffing över UART är att metoden fungerar lika bra fast man kör med 5,6,7,8 eller 9 databitar på UART'en.

Edit: Lite sen. Vad är "vanlig asynk kommunikation"? :-)
Skriv svar