2013-04-30 53 views
3

我在這裏有一個新問題。 我仍然在學習用於PIC(xc8編譯器)的C語言,並且作爲一個初學者項目,我正在做一個帶有廣受歡迎的ds18b20和pic16f628的溫度計。 我的程序在允許運行時表現得很好,但是當我玩指針,結構體,數組等等時,我在一個函數中返回了多個值,我注意到有些東西變得不合時宜,現在PC來回移動,不允許程序順序運行,至少這就是我看到如果我在mplabx中使用模擬器。我很確定我忘記了有關程序和/或內存位置的信息,但我無法弄清楚什麼或爲什麼。有人能幫我嗎?我在這裏粘貼主代碼,你還需要什麼?C爲16f628,程序計數器出現故障

/* 
* 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; 
} 
+1

不確定是否stackoverflow是您發佈的最佳位置。您可能有更多的機會在這裏:http://electronics.stackexchange.com/ – joce 2013-04-30 20:45:11

+0

謝謝,我會試試看! – zakkos 2013-04-30 20:50:47

+0

也嘗試http://www.microchip.com/forums/,雖然這裏有一些有希望的答案。 – 2013-04-30 20:55:00

回答

1

在微芯片論壇上,他們發現代碼中存在缺陷。原來,問題是我,我也沒佔到decims[];陣列中的負指數,當它在一個負溫度

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

然後在

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

2的使用情況進行了評估只包含較低半字節(0x0F)的字節的補碼具有最重要的半字節集(0xF1)。這是我所有問題的根源! 添加的低四位口罩補充字節後解決了這個問題:

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

謝謝大家的答案,你真的幫了我很多理解是如何工作的!

6
for(char k=0;k<10;k++){ 
    scratchpad[k] = ow_read_byte(); 
} 

...將從0-9(10個字符),而運行...

char scratchpad[9]; 

...僅保留空間9。這可能會覆蓋堆(即返回地址)

+0

謝謝!沒有注意到,我會立即糾正它。但不幸的是,在我嘗試使用「struct」(然後「union」來查看它是否改變了某些內容)從read_temp()傳遞值之前,該程序運行良好。到main(); 我甚至不知道我是否做得對,如果這是做這件事的最佳方式,那只是要學習如何工作! – zakkos 2013-04-30 20:56:29

3

此:

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

是一個很大的作爲NOP臨時工是union而不是struct。你想在這裏做什麼?爲什麼不:

temps.eratura = -temps.eratura;

也許你的意思爲union的第二個成員是一個int?在這種情況下,它仍然失敗,但它使用更有意義read_temp

而你正在訪問10個字符作爲其他人提到的9個字符數組。根據意見

更多信息:

你肯定想,只要你想在內存2個DISTICT值以用於您的臨時工一個結構。此外,雖然我不知道你的編譯器允許什麼,

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

似乎有點爲直線前進 - 讓編譯器處理2S補你。

未來

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

具有非常小的空間裏工作的值只能上升到128這基本上是設定溫度爲0;如果temps.eratura低於100則爲1更大。這裏不需要&。啊,你正在發送數字。好。

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); 

,或者我們可以得到完全擺脫decims轉換器:

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

基本上,所有這些更改允許編譯r爲你做一些工作,使代碼更容易遵循。

+0

我在使用「union」之前試過了一個「struct」,但是我遇到了同樣的問題。那裏的代碼應該對temp的兩個成員(1的補碼加1)進行二進制補碼,這兩個補碼都是8位長。 在添加小數之前(這就是爲什麼我需要傳遞read_temp()之外的兩個值;一個用於整個溫度,一個用於點之後的數字)它運行良好,它從傳感器獲得的值得到正確評估,然後我添加了「結構」,一切都出錯...... – zakkos 2013-04-30 21:06:47

+2

「聯合」意味着兩個成員佔據相同的內存位置。我確定那不是你想要的。由於將其從'struct'改爲'union'並不能解決問題,所以我建議將它改回「struct」並從那裏繼續。 – 2013-04-30 21:13:55

+0

以同樣的方式,這兩行對你的工會沒有意義,你正在分配它並立即替換下一行的內容: temps.decimali = scratchpad [0] & 0x0F; temps.eratura =(scratchpad [1] << 4)|(scratchpad [0] >> 4); – 2013-04-30 21:16:34

0

它可能是優化代碼的C編譯器,可以給出非線性代碼執行的外觀......嘗試關閉優化器的單步執行。