3

ここで新たな問題が発生しました。私はまだPIC(xc8コンパイラ)のCを学んでおり、初心者プロジェクトとして、人気のあるds18b20と横になっていたpic16f628を使って温度計を作っています。私のプログラムは、実行が許可されている場合は正常に動作しますが、関数で複数の値を返すためにポインター、構造体、配列などを操作しているときに、何かがうまくいかないことに気付き、今では PC が行ったり来たりして、プログラムを許可していません順番に実行するには、少なくとも mplabx でシ​​ミュレーターを使用すると、それが表示されます。プログラムやメモリの場所について何か忘れていることは確かですが、何が原因か、理由がわかりません。誰かが私を助けることができますか?ここにメインコードを貼り付けます。他に何が必要ですか?

/*
 * File:   termometro.c
 * Author: zakkos 
 * Created on April 18, 2013, 2:20 PM
 *
 * /
/*ESSENTIAL DEFINITIONS*/
#define _XTAL_FREQ 4000000
/*INCLUSIONS*/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <lcd.h>
#include <1-wire.h>
/*CONFIG PRAGMA*/
#pragma config BOREN = OFF, CPD = OFF, FOSC = INTOSCIO, MCLRE = OFF, WDTE = OFF, CP = OFF, LVP = OFF, PWRTE = ON

//typedef unsigned char uint8_t;

void read_temp(void);

union {
    char eratura;
    char decimali;
}temps;

int main(void) {

    INTCON = 0x00;
    PIE1 = 0x00;

    CMCON = 0x07; //disabilito i comparatori - disable comparators

    TRISA = 0x00;
    PORTA = 0x00;

    TRISB = 0x00;
    PORTB = 0x00;

    const char decims[16] = {0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9};
    char temp;

    lcd_init();
    lcd_send_cmd(LCD_CLR);
    lcd_send_cmd(LCD_HOME);
    writeString("Hello,");
    lcd_send_cmd(LCD_LN2);
    writeString("World!");
    __delay_ms(1000);
    while(1)
    {
        read_temp();
        lcd_send_cmd(LCD_CLR);
        lcd_send_cmd(LCD_HOME);
        writeString("Temp:");
        lcd_send_cmd(LCD_LN2);
        if((temps.eratura & 0x80)){                             //if sign bit is set
                temps.eratura = ~temps.eratura;                 //2's complement
                temps.eratura += 1;                             
                temps.decimali = ~temps.decimali;               //2's complement
                temps.decimali += 1;
                lcd_send_dat(0x2D);                             //minus
        }
        temp = (temps.eratura/100)& 0x0F;                       //centinaia 157/100=1 (hundreds)
        if(temp){
            lcd_send_dat(0x30 | temp);
            temp = ((temps.eratura/10)%10) & 0x0F;              //decine    157/10=15%10=5 (tens if hundreds is set, meaning it will display also a 0)
            lcd_send_dat(0x30 | temp);
        } else {
            temp = ((temps.eratura/10)%10) & 0x0F;              //decine    157/10=15%10=5 (tens if hundreds is no set, meaning it will not display if 0)
            if(temp){lcd_send_dat(0x30 | temp);
            }
        }
        lcd_send_dat(0x30 | (temps.eratura%10)& 0x0F);          //unita     157%10=7 (ones)
        lcd_send_dat(0x2E);                                     //dot
        lcd_send_dat(0x30 | decims[temps.decimali] & 0x0F);     //decimals
        lcd_send_dat(0xDF);                                     //degrees
 }
}

void read_temp(void){
    char scratchpad[9];
    while(ow_reset());
    ow_write_byte(0xCC);
    ow_write_byte(0x44);
    while(ow_read_bit()==0);
    __delay_ms(1);
    while(ow_reset());
    ow_write_byte(0xCC);
    ow_write_byte(0xBE);
    for(char k=0;k<10;k++){
        scratchpad[k] = ow_read_byte();
    }
    temps.decimali = scratchpad[0] & 0x0F;
    temps.eratura = (scratchpad[1] << 4)|(scratchpad[0] >> 4);
    return;
}
4

4 に答える 4

3

これ:

        temps.eratura = ~temps.eratura;                 //2's complement
        temps.eratura += 1;                             
        temps.decimali = ~temps.decimali;               //2's complement
        temps.decimali += 1;

temps は aunionではなく であるため、大きな問題structです。ここで何をしようとしていますか?なぜだめですか:

temps.eratura = -temps.eratura;

おそらく、 の 2 番目のメンバーを?にするつもりでしunionた。intその場合でも失敗しますが、read_temp

他の人が述べたように、9文字の配列に対して10文字にアクセスしています。

コメントに基づく詳細情報:

メモリ内に2つの個別の値が必要なため、間違いなく一時に構造体を使用したいと考えています。また、コンパイラで何が許可されているかはわかりませんが、

    if(temps.eratura < 0){              
            temps.eratura = -temps.eratura;
            temps.decimali = -temps.decimali;
            lcd_send_dat('-'); 
    }

少し単純に思えます-コンパイラーが2の補数を処理できるようにします。

次:

temp = (temps.eratura/100)& 0x0F;

値は 128 までしか上げられないため、機能するスペースがほとんどありません。これは基本的に、temps.eratura が 100 未満の場合は temp を 0 に設定し、100 より大きい場合は 1 に設定します。ここは必要ありません&。ああ、あなたは数字を送信しています。Ok。

temp = temps.eratura;

if(temp >= 100)
{
    temp -= 100;  
    lcd_send_dat('1');
}

if(temps.eratura >= 10)
{
    lcd_send_dat('0' + (temp / 10));
}

lcd_send_dat('0' + (temp % 10));

次に、小数について:

const char decims[16] =
   {'0', '0', '1', '1', '2', '3', '3', '4', '5', '5', '6', '6', '7', '8', '8', '9'};

lcd_send_dat('.');  
lcd_send_dat(decims[temps.decimali]); 
lcd_send_dat(0xDF);  

または、次の方法で 10 進数コンバーターを完全に取り除くことができます。

lcd_send_dat('0' + ((temps.decimali * 10) / 16)); 

基本的に、これらすべての変更により、コンパイラが少し作業を実行できるようになり、コードを追跡しやすくなります。

于 2013-04-30T20:50:49.473 に答える
1

マイクロチップ フォーラムで、彼らはコードの欠陥を発見しました。問題は私にあるdecims[];ことがわかりました。負の温度の場合に評価されたときに、配列内の負のインデックスを考慮していませんでした

if(temps.eratura < 0){ 
 temps.eratura = -temps.eratura; 
 temps.decimali = -temps.decimali; 
 lcd_send_dat('-'); 
 } 

次に使用される

lcd_send_dat(decims[temps.decimali]); //decimals

下位ニブル (0x0F) のみを含むバイトの 2 の補数には、最上位ニブル セット (0xF1) があります。これが私のすべての問題の原因でした!バイトを補完した後に下位ニブルにマスクを追加すると、問題が解決しました。

if(temps.eratura < 0){ 
 temps.eratura = -temps.eratura; 
 temps.decimali = -temps.decimali & 0x0F; 
 lcd_send_dat('-'); 
 } 

答えてくれてありがとう、物事がどのように機能するかを理解するのに本当に役立ちました!

于 2013-05-01T15:07:07.117 に答える