繁体   English   中英

对于16f628的C,程序计数器变得混乱

[英]C for 16f628, Program Counter goes haywire

我这里有一个新问题。 我还在学习PIC for PIC(xc8编译器),作为一个初学者项目,我正在使用流行的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;
}
for(char k=0;k<10;k++){
    scratchpad[k] = ow_read_byte();
}

...将从0-9(10个字符)运行,而...

char scratchpad[9];

...只保留9的空间。这可能会覆盖堆栈(即返回地址)

这个:

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

因为临时是一个union而不是一个struct ,所以是一个很大的小问题。 你想在这做什么? 为什么不:

temps.eratura = -temps.eratura;

也许你的意思是union的第二个成员是一个int 在这种情况下,它仍然会失败,但在read_temp中使用它会更有意义

你正在访问其他人提到的9个字符串的10个字符。

更多基于评论的信息:

你肯定想要为你的临时使用一个结构,因为你想在内存中有2个distict值。 另外,虽然我不确定你的编译器允许什么,

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

看起来有点直接 - 允许编译器为你处理2s恭维。

下一个:

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

因为值只能达到128,所以工作空间很小。如果temps.eratura小于100则基本上将temp设置为0,如果更大则设置为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)); 

基本上,所有这些更改都允许编译器为您做一些工作并使代码更容易遵循。

在微芯片论坛上,他们发现了代码中的一个缺陷。 结果问题是我,我没有在decims[];考虑负面指数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('-'); 
 } 

谢谢大家的答案,你们在理解工作原理方面给了我很多帮助!

它可能是C编译器优化代码,可以给出非线性代码执行的外观......尝试关闭优化器的单步执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM