Sari la conținut
ELFORUM - Forumul electronistilor

Înmulțire În MikroC Pro for PIC


UDAR

Postări Recomandate

Vă salut.

M-am lovit de următoarea problemă :

În linia de cod de mai jos durata este unsigned long iar celelalte sunt char.

durata=(TMR1OF*65536)+(CPHfin*256)+CPLfin;

Rezultatul este greșit pentru că la transformarea lui TMR1OF din char în unsigned - ca sa aducă la tipul dat de 65536 - în loc să pună 0 în octetul superior, compilatorul  pune valoarea din adresa superioară a lui TMR1OF . 

Am rezolvat problema declarând și pe TMR1OF unsigned deși nu era nevoie. 

Unde greșesc ?

Editat de UDAR
Link spre comentariu
  • Răspunsuri 14
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • Liviu M

    7

  • UDAR

    6

  • djvas

    1

  • Bandi Szasz

    1

Zile populare

Top autori în acest subiect

Imagini postate

Scuze că nu am menționat . Toate sunt variabile - TMR1OF, CPHfin, CPLfin . Le-am denumit așa ca să știu ce conține fiecare - overflow la TMR1 respectiv octetii de la captură.

E un capacimetru . Durata totală e dată de numărul de depășiri a lui TMR1 + ce am în registrii de la captură .

Link spre comentariu

Cum adica transformi TMR1OF din char in unsigned? Ma uit acum la tipurile de date din MikroC si

(unsigned) char 	1 	0 .. 255

adica la mikroc char e deja unsigned.

Se comporta la fel si daca in loc de

TMR1OF*65536

faci

TMR1OF<<16

 

Link spre comentariu

Ce face compilatorul este corect si logic. Acolo tu faci o operatie matematica (TMR1OF*65536)" si cu parantezele ii zici sa le execute separat, din moment ce TMR1OF este "char" operatia de inmultire se va executa la nivel de char pe care il da peste cap la 256 respectiv 128 depinde daca e unsigned sau nu. Ori il declari si pe el unsigned long ori faci cast la operatia de inmultire " ((unsigned long)TMR1OF*65536)" si ii zici compilatorului ca in ciuda faptului ca tu acolo ai un char vrei ca operatia de inmultire sa se execute la nivel de unsigned long.

Link spre comentariu

gcc sub linux calculeaza corect. Program:

#include <stdio.h>

int main(void){
   unsigned char a;
   unsigned long b;
   
   a = 3;
   b = (a * 65536) + 2;
  
   printf("0x%x * 65536 + 2 = 0x%x\n", a, b);
}

rezultatul rularii:

0x3 * 65536 + 2 = 0x30002

 

Editat de Liviu M
Link spre comentariu

Cred că e mai elocvent dacă pun și segmentul de asm :

Inmultire.thumb.JPG.da362b250c1bc20d0df38c49bbd56665.JPG

 

Deci compilatorul transformă TMR1OF din char în int si îl deplasează cu 16 biți dar în loc să facă  :

 

CLRF                R8+3

MOVF              _TMR1OF, 0

MOVWF           R8+2

CLRF                R8+1

CLRF                R8 

 

cu alte cuvinte în octetul cel mai semnificativ al rezultatului ( R8+3) în loc să pună 0 pune valoarea găsită la adresa _TMR1OF + 1 care apartine unei alte variabile, oarecare. 

Declarând TMR1OF ca unsigned am fortat mentinerea libera a locatiei respective . 

 

În fine, am rezolvat cum am zis dar eram curios unde e greseala - sunt incepator in ale PIC-ului  ( și mai incepator in ale C-ului ) !

 

 

 

Editat de UDAR
Link spre comentariu

Si xc8 al lui microchip calculeaza corect.

Program (am inlocuit 2 cu o variabila unsigned char, ca sa evit vreo conversie ciudata a compilatorului)

#include <xc.h>

void main(void) {
  
   unsigned char a;
   unsigned char b;
   unsigned long c;
   
   a = 3;
   b = 2;
   c = (a * 65536) + b;

   a = 4; 
  
   return;
}

 

inmultireXc8.png

Link spre comentariu
Acum 6 minute, UDAR a spus:

Deci compilatorul transformă TMR1OF din char în int si îl deplasează cu 16 biți...

cu alte cuvinte în octetul cel mai semnificativ al rezultatului ( R8+3) în loc să pună 0 pune valoarea găsită la adresa _TMR1OF + 1 care apartine unei alte variabile, oarecare.

Daca compilatorul chiar transforma char in int, sunt sanse sa fie OK, ca facand compilatorul din 1 byte 2, eu ma astept ca adresa _TMR1OF + 1 sa fie MSB-ul noului int, care ar trebui sa fie 0.

Link spre comentariu

Așa și MikoC-ul face corect pentru că face calculele direct in compilator , nu le emuleaza cu adevarat.

Mult1.thumb.JPG.c05b3156d85da2919a1ececf3eaa11df.JPG

Dupa cum se vede el pune niște ”literale” ( MOVLW ) pe care le știe deja, nu citeste locațiile  de memorie ale variabilelor.

 

În fine , când o să am timp și chef o să mai încerc.

 

Acum 8 minute, Liviu M a spus:

Daca compilatorul chiar transforma char in int, sunt sanse sa fie OK, ca facand compilatorul din 1 byte 2, eu ma astept ca adresa _TMR1OF + 1 sa fie MSB-ul noului int, care ar trebui sa fie 0.

Așa am presupus și eu . Eu am înșelat cumva compilatorul ( fără să vreau ) dar mă așteptam ca el să se prindă că dacă faci dintr-un byte doi cel mai semnificativ e zero  - putem numi asta un bug ? 

Link spre comentariu

Daca esti sigur ca compilatorul "strica" alte variabile, clar e bug.

Sau, cu alte cuvinte, daca esti sigur ca rezultatul final e eronat (cum ziceam, la mine si gcc si xc8 par sa livreze rezultatul corect fara ajutor), atunci e clar, e bug.

Link spre comentariu

Nu strică alte variabile ci introduce conținutul variabilei respective in octetul mai semnificativ al variabilei mele . Nu pricepeam nicicum se se întâmplă - l-am pus să afișeze valoarea ”durata” și am văzut că e mult mai mare decât trebuie . El în loc să înmulțească 31( cât era TMR1OF ) cu 65536 înmulțea X31 ( adică X*256+31) cu 65536 . Noroc că mi-a picat fisa să mă uit în .lst. 

În fine, bine că am rezolvat și pot avansa cu proiectul. 

Mulțumesc pentru interes.

Link spre comentariu

Pai de unde pacatele mele il lua pe X?

Ca si daca ar fi facut vreo promotie, eu zic ca compilatorul ar fi trebuit sa puna 0 in MSB.

Acum ai rezolvat problema, da' altfel ai fi putut sa aplici o masca inainte de adunare:

durata=((TMR1OF*65536) & 0x00FF0000) + (CPHfin*256) + CPLfin;

In felul asta, stii sigur ca pastrezi doar ce-ti trebuie. Eventuel maschezi si ceilalti termeni ai adunarii.

Link spre comentariu

Da, excelentă ideea cu masca ! 

În ce-l privește pe X - să zicem că TMR1OF era la adresa 00B9 - compilatorul când citea TMR1OF+1 citea 00BA unde era conținutul altei variabile. 

Și eu zic la fel că trebuia să pună zero nu să citească .

 

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări