Sida 1 av 3

Virrigt problem med PIC-kod.

Postat: 3 januari 2007, 11:12:53
av JimmyAndersson
Jag kom inte på något annat kortfattat sätt att beskriva problemet. :)

Lägre förklaring:
Jag har en MikroBasic-kod som bl.a består av en liten procedur för att skriva ut tecken på valfri plats på en LCD-display. Genom att skriva t.ex lcd_skriv("H", 3, %1100, %0001) så hamnar det ett H på kolumn 1, rad 2. (Trean betyder att jag vill ange en position.)


För att displayen ska visa innehållet i en variabel har jag tidigare skrivit:

Kod: Markera allt

    ByteToStr(value_c, hela)
    antal = length(hela)
    for tecken = 0 to antal
      skriv = hela[tecken]
      lcd_skriv(skriv, rs_bit_c, var1_c, var2_c)
    next tecken
och då sett innehållet i variabeln value_c på displayen.


För att slippa skriva det varje gång så ordnade jag en procedur så att man bara behöver skriva lcd_variabel2(value_c, 3, %1100, %0001). Den proceduren ser ut såhär:

Kod: Markera allt

sub procedure lcd_variabel2(dim value_c, rs_bit_c, var1_c, var2_c as byte)
    ByteToStr(value_c, hela)
    antal = length(hela)
    for tecken = 0 to antal
      skriv = hela[tecken]
      lcd_skriv(skriv, rs_bit_c, var1_c, var2_c)
    next tecken
end sub

Nu kommer vi till problemet: När jag har med raden lcd_variabel2(dim value_c, rs_bit_c, var1_c, var2_c as byte) så blir den översta raden på displayen full med svarta rutor. Den undre raden är tom. Om jag plockar bort kod-raden ovan så fungerar hela programmet (som bl.a visar en meny på displayen.)

Vad 17 beror detta fel på?


Jag har en liknande procedur som den ovan som fungerar fint. Den gör att man kan skriva ut innehållet i strängar på displayen:

Kod: Markera allt

sub procedure lcd_variabel(dim value_b as string[3], dim rs_bit_b, var1_b, var2_b as byte)
    'Gör så att man kan skicka hela ORD till displayen.

    'Skicka data om vilken position som texten ska skrivas ut på.
    if rs_bit_b = 3 then
      RS = 0 ' Instruktionsläge
      LATA = var1_b
      lcd_vanta
      LATA = var2_b
      lcd_vanta
      RS = 1 ' Teckenläge
      rs_bit = 1
    end if

    antal = length(value_b)
    for tecken = 0 to antal
      skriv = value_b[tecken]
      lcd_skriv(skriv, rs_bit, var1_b, var2_b)
    next tecken
end sub
Strängen "hela" är förresten dimensionerad såhär: dim hela as string[3]



Någon som har en idé på vad felet beror på?




Avslutar med koden för proceduren lcd_skriv:

Kod: Markera allt

sub procedure lcd_skriv(dim value, rs_bit, var1, var2 as byte)
  'value = vad som ska skrivas.
  'rs_bit = RS-läget. Om det är 3 så körs positions-delen.
  'var = Tja, Vilken position det ska skrivas på.

  ' 1 för att skriva text. 0 för data.
  if rs_bit = 1 then RS = 1 end if
  if rs_bit = 0 then RS = 0 end if

  'Skicka data om vilken position som texten ska skrivas ut på.
  if rs_bit = 3 then
    RS = 0 ' Instruktionsläge
    LATA = var1
    lcd_vanta
    LATA = var2
    lcd_vanta
    RS = 1 ' Teckenläge
    rs_bit = 1 ' För att resten ska flyta på som om man haft rs_bit = 1 från början.
  end if

  oversta = 0
  understa = 0
  flytta = 0
  skicka = 0

  'Tar value och delar till varsin variabel.
  'T.ex om value = 01000010 så delas det så att oversta = 0100 och understa = 0010.
  oversta = value >> 4
  if rs_bit = 1 then skicka = oversta OR 16 end if' Lägg till en RS-bit.
  LATA = skicka ' Skicka översta delen
  lcd_vanta ' E och vänta

  flytta = value << 4 'Flyttar fyra steg åt vänster för att de fyra översta ska försvinna.
  understa = flytta >> 4 'Flytta tillbaka igen och nu har de tidigare översta försvunnit.
  if rs_bit = 1 then skicka = understa OR 16 end if' Lägg till en RS-bit.
  LATA = skicka ' Skicka understa delen
  lcd_vanta ' E och vänta
end sub

Postat: 3 januari 2007, 11:57:50
av Icecap
Fel #1: BASIC!!!
Fel #2: understa = value AND 0x0F 'Maskar ut be lägsta bitsen

Herrejösses vilken kod....

Som jag förstår kan du (vill du kunna) placera cursorn på valfri position och skriva ut en variabel eller hur?

Jag har gjort en del med LCD-kommunikation och jag har 0x10 som "nästa är position" indikator, när jag ska skriva ut på första position blir det alltså:
sprintf(Buffer,"\x10\x01%3u",Value);
Send2LCD(Buffer);

Detta placerar cursorn på position 1 och skriver ut värdet 'Value' med 3 tecken, om det är längre skrivar den ut fler tecken, är den kortare fyller den upp med mellanslag.

Jag har vald att skriva ut till en minnesbuffer först men det går att fixa på andra sätt om man bara har ett output (LCD-modul t.ex.).

Som jag ser det har du mer eller mindre skapad så besvärlig kod att du inte ens själv kan klura ut vad som går fel.

Varför ska man i LCD-Skriv() ange %1100 och %0001? Om de är fasta ska de vara det och behövs inte att anges i kallet, de tar ytterligare extra minne + tid att överföra i kallet.

Sen var det:

Kod: Markera allt

    if rs_bit_b = 3 then
      RS = 0 ' Instruktionsläge
      LATA = var1_b
      lcd_vanta
      LATA = var2_b
      lcd_vanta
      RS = 1 ' Teckenläge
      rs_bit = 1
    end if
Var skakar den Enable? Den ska väl höja och sänka LCD enable innan varje 'lcd_vanta' eller hur?

Postat: 3 januari 2007, 12:25:17
av JimmyAndersson
Börjar med att svara på det sista. Enable-pinnen fixas i lcd_vanta som ser ut såhär:

Kod: Markera allt

sub procedure lcd_vanta
   delay_us(500)
   E = 1
   delay_us(500)
   E = 0
   delay_us(500)
end sub

Tyvärr hjälpte det inte att ändra till understa = value AND 0x0F.


Håller med om att det är en osmidig kod, men jag förstår den. Det jag inte förstår är hur proceduren lcd_variabel2 kan ge ett sånthär fel. Jag har använt samma kod (fast utanför proceduren) i en tidigare version av koden och då fungerade det fint.


Men om man backar lite. Hur skulle man kunna göra funktionerna på ett bättre sätt?
Det jag vill med de listade procedurerna är alltså att kunna skriva ut:
1) Enskilda bokstäver, t.ex "A" eller motsvarande ascii-kod på displayen.
2) Hela ord, t.ex "SET".
3) Innehållet i en sträng eller variabel.

Proceduren lcd_skriv tycker jag inte kan se så värst mycket annorlunda ut. Om jag inte förstått fel så borde det vara en fördel att ha tre mindre procedurer istället för en stor, särskillt eftersom det inte är alla delar som behöver köras igenom varje gång.


Men jag tar tacksamt emot alla tips på ändringar.

Postat: 3 januari 2007, 13:34:29
av bengt-re
*ler*

För att göra det bättre - skriv egen rutin i assambler som du anropar med önskat tecken i W... enkelt och smidigt.

Postat: 3 januari 2007, 14:07:12
av sodjan
Varför har lcd_variabel "dim rs_bit_b" medan lcd_variabel2 saknar "dim" ?
Kasnke inte spelar någon roll...

Postat: 3 januari 2007, 14:08:48
av JimmyAndersson
bengt-re:
Första tanken är att det känns lite knäppt att skriva om 65 rader Basickod till assembler när det är *max* 8 av dem som inte fungerar. Det känns lite som om jag skulle smita undan problemet istället för att lösa det. Men visst, det vore lite kul att börja med assembler igen.

Första kunskapsluckan är hur man gör i asm så att rutinen kan läsa av flera variabler som är separerade med kommatecken. Sedan minns jag inte hur man gör om strängar till bytes och tvärt om.

Det tredje, och största frågetecknet är hur pass bra min ursprungliga tanke är. Dvs om jag valt rätt sätt att få det resultatet jag vill. (Bortsett från det valda språket förstås.)


Jag behöver kort sagt lite mer input och idéer från er oavsett vilken metod jag väljer.

Postat: 3 januari 2007, 14:12:24
av JimmyAndersson
sodjan: Nu är jag rädd för att jag inte hänger med. Båda har dim. :)


lcd_variabel(dim value_b as string[3], dim rs_bit_b, var1_b, var2_b as byte)

lcd_variabel2(dim value_c, rs_bit_c, var1_c, var2_c as byte)


Har även provat att skriva:
lcd_variabel2(dim value_c as byte, dim rs_bit_c as byte, dim var1_c as byte, dim var2_c as byte)

och samma princip med lcd_variabel.
Tyvärr utan någon skillnad.

Postat: 3 januari 2007, 14:14:11
av sodjan
Varför har inte rs_bit_c "dim" ??

Postat: 3 januari 2007, 14:16:27
av JimmyAndersson
Mest för att man enligt manualen och hjälpfilen kan skriva så. :)

Citat:

Here are a few examples:

dim i, j, k as byte
dim counter, temp as word
dim samples as longint[100]



Eller ser du något jag missat?

Postat: 3 januari 2007, 14:21:06
av sodjan
Aha, så första dim gäller för alla variabler i listan... OK, då är jag med.

Postat: 3 januari 2007, 14:50:16
av JimmyAndersson
Jepp. :)

Mitt absolut största frågetecken är hur displayen kan få alla pixlar ifyllda på första raden och den andra blir tom. lcd_variabel2 körs inte så länge jag inte trycker på en encoders knapp, men jag rör inte någonting och ändå blir det såhär. Om jag däremot tar bort raden lcd_variabel2(value_c, rs_bit_c, var1_c, var2_c) så kör resten av programmet utmärkt. Displayen visar det den ska när PIC'en är programmerad och gör även så efter reset. När jag trycker på encoderns knapp så står det "SET" på översta raden, vilket det ska göra.

Vad kan det bero på?



Hela koden är ganska lång. 577 rader närmare bestämt, så det är kanske inget man slänger upp i ett inlägg. Men jag kan förklara tanken med koden ändå.

Efter en programmering eller reset ska detta hända:

1) Lite info visas i displayen.

2) Programmet går in i en while-loop där det finns en if-rad som kollar om variabeln avbrott = 1. Om det inte är sant så går programmet bara runt i while-loopen. När någon av knapparna (t.ex encoderns knapp) genererar ett interrupt så blir avbrott = 1.

3) Då görs en koll av vilken knapp som trycktes ner. Om det var encoderns knapp så körs denna rutin:

Kod: Markera allt

sub procedure tid_set
   'Börjar med att skriva ut SET längst till höger på översta raden i LCD'n.
   lcd_skriv("S", 3, %1000, %0111)' S
   lcd_skriv(69, 3, %1000, %1000) ' E
   lcd_skriv("T", 3, %1000, %1001)' T
   lcd_skriv(" ", 3, %1000, %1010)
   lcd_skriv(" ", 3, %1000, %1011)

   disp_min = 59
   lcd_variabel2(disp_min, 3, %1000, %0010) ' *Ska* visa talet 59.

   'Här kommer det mer kod senare..
end sub
Det är alltså först *då* som programmet går in i lcd_variabel2-proceduren. Den proceduren används inte någon annanstans i koden. Det vågar jag sätta mina studios på. :)


Det knasiga är alltså att den proceduren verkar köras så fort man ger hela projektet (på labbplattan) spänning.

Jag fattar noll och har debuggat om och om igen sedan veckan innan jul. Tur att man är envis. :D

Bild


edit: Skrev lite fel i första stycket. Det ska vara "Om jag däremot tar bort raden lcd_variabel2(value_c, rs_bit_c, var1_c, var2_c)...", dvs ingen 'dim' där förstås.

Postat: 3 januari 2007, 15:28:42
av Kaggen
Du får prova hårdkoda lcd_skriv2 och testa vad som går fel. Minimera den till:

Kod: Markera allt

sub procedure lcd_variabel2(dim value_c, rs_bit_c, var1_c, var2_c as byte)
      lcd_skriv("H", 3, %1100, %0001)
end sub
och se om det funkar (borde komma fram ett "H" på LCDn enligt din egen definition i första inlägget). Om detta skulle funka är problemet antagligen hur du passar data till proceduren/funktionen.

Det som jag tycker verkar skumt är dim value_c, definierar du inte en ny variabel med dim? D.v.s. är du säker på att variabeln value_c i proceduren innehåller värdet du skickar till proceduren och inte är en ny tom variabel?

Postat: 3 januari 2007, 16:08:48
av JimmyAndersson
Första tipset gav en tom display. Stängde av och satte igång labbagget och fick då lite konstigt resultat.


Först en beskrivning av hur det *ska* vara när PIC'en får spänning:
Först visas "TuFvT" i mitten på översta raden. Sedan scrollas den texten till vänster. Understa raden är tom hela tiden tills man trycker på någon av knapparna.

Ett tryck på Knapp3 visar "UV" till vänster på nedersta raden. Nästa tryck på samma knapp plockar bort "UV" och skriver istället "TFT" i mitten på nedersta raden. Ett till tryck visar både "UV" och "TFT" på ovanstående positioner.

Ett tryck på Knapp4 visar "HOLD" längst till höger på nedersta raden. Nästa tryck på samma knapp plockar bort "HOLD".



Men, såhär ser det ut nu:
"TuFvT" visas där det ska, men efter att det scrollats till vänster så står det helt plötsligt "TuFvv".

Tryck på Knapp3 ger likadant resultat som tidigare, bortsett från att det inte bara står "TFT" i mitten, utan även längst till höger.

Trycker man på Knapp4 så visas ett "D" längst till höger på nedersta raden.


Så, ett märkligt resultat byttes mot ett annat.



Testade även att plocka bort "dim" ur sub-procedur-raden, men det gick inte alls. Det ska se ut så. :)

Postat: 3 januari 2007, 16:29:37
av sodjan
> hur displayen kan få alla pixlar ifyllda på första raden och den andra blir tom.

Är inte det samma resultat som efter en power-on ?

Postat: 3 januari 2007, 16:37:23
av JimmyAndersson
Jo precis.