我这里有一个新问题。 我仍在学习 PIC(xc8 编译器)的 C 语言,作为一个初学者项目,我正在使用流行的 ds18b20 和我手边的 pic16f628 制作温度计。 当我的程序被允许运行时,它的表现确实很好,但是当我使用指针、结构、数组等在函数中返回多个值时,我注意到有些东西出了问题,现在电脑来回不允许程序运行按顺序运行,至少这是我在 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;
是一个很大的问题,因为 temps 是
union
而不是 struct
。你想在这里做什么?为什么不:
temps.eratura = -temps.eratura;
也许您的意思是
union
的第二个成员是int
?在这种情况下,它仍然会失败,但在 read_temp
中使用它更有意义
正如其他人提到的,您正在访问 9 字符数组的 10 个字符。
基于评论的更多信息:
您肯定想使用一个结构体来存储临时值,因为您希望内存中存在 2 个不同的值。另外,虽然我不确定你的编译器允许什么,
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,如果大于 100,则将 temp 设置为 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);
或者我们可以完全摆脱十进制转换器:
lcd_send_dat('0' + ((temps.decimali * 10) / 16));
基本上,所有这些更改都允许编译器为您做一些工作,并使代码更易于理解。
在微芯片论坛上,他们发现了代码中的一个缺陷。原来问题出在我身上,在负温度情况下评估时,我没有考虑到
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编译器优化了代码,它可以给出非线性代码执行的外观。尝试在关闭优化器的情况下单步执行。