C для 16f628, счетчик программ выходит из строя

У меня тут новая проблема. Я все еще изучаю C для PIC (компилятор xc8), и в качестве начинающего проекта я делаю термометр с популярным 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;
}

c pic
person zakkos    schedule 30.04.2013    source источник
comment
Не уверен, что stackoverflow — лучшее место для публикации. У вас может быть больше шансов здесь: electronics.stackexchange.com   -  person joce    schedule 01.05.2013
comment
Спасибо, попробую!   -  person zakkos    schedule 01.05.2013
comment
Также попробуйте microchip.com/forums, хотя здесь есть многообещающие ответы.   -  person Peter L.    schedule 01.05.2013
comment
Спасибо, я тоже там спрошу   -  person zakkos    schedule 01.05.2013


Ответы (4)


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

...будет работать от 0-9 (10 символов), а...

char scratchpad[9];

... резервирует место только для 9. Это может перезаписать стек (т.е. адрес возврата)

person Joachim Isaksson    schedule 30.04.2013
comment
Благодарю вас! Не заметил, сразу исправлю. Но, к сожалению, программа работала хорошо до того, как я попытался использовать struct (а затем union, чтобы увидеть, изменило ли это что-то) для передачи значений из read_temp(); на главную(); Я даже не знаю, правильно ли я сделал это, и если это лучший способ сделать это, это только узнать, как все работает! - person zakkos; 01.05.2013

Этот:

        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 имеет немного больше смысла.

И вы получаете доступ к 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. Это в основном установка temp на 0, если temps.eratura меньше 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);  

или мы можем полностью избавиться от конвертера децимов с помощью:

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

По сути, все эти изменения позволяют компилятору немного поработать за вас и упрощают работу с кодом.

person Michael Dorgan    schedule 30.04.2013
comment
Я пробовал структуру перед использованием union, но у меня возникла та же проблема. Код должен выполнять дополнение до 2 для обоих членов temps (дополнение до 1 плюс один), оба имеют длину 8 бит. Перед добавлением десятичных знаков (поэтому мне нужно передать 2 значения вне read_temp(); одно для всей температуры и одно для цифр после точки) он работал хорошо, значения, которые он получает от датчика, оцениваются правильно, затем я добавил структура и все пошло не так... - person zakkos; 01.05.2013
comment
union означает, что оба члена занимают одну и ту же ячейку памяти. Я уверен, это не то, чего ты хочешь. Так как изменение его с struct на union все равно не помогло, я предлагаю изменить его обратно на struct и продолжить оттуда. - person Keith Thompson; 01.05.2013
comment
Точно так же эти две строки не имеют смысла с вашим объединением, вы назначаете его и сразу же заменяете содержимое в следующей строке: temps.decimali = блокнот[0] & 0x0F; temps.eratura = (блокнот[1] ‹‹ 4)|(блокнот[0] ›› 4); - person Étienne; 01.05.2013
comment
спасибо за понимание, Кейт, я думал, что «объединение» означает другое (два члена были помещены в последовательные адреса в одном и том же блоке памяти, на одной и той же странице в структуре памяти pic), я изменяю код, как вы предлагаете. Извините, Этьен, но я не понимаю, что вы имеете в виду, я даю «temps.decimali» и «temps.eratura» два разных значения. Конечно, это то, что я ДУМАЛ, что сделал, прежде чем узнал, как работает «союз»! - person zakkos; 01.05.2013
comment
Спасибо, Майкл! Я все еще много думаю об ассемблере, поэтому мне трудно позволить компилятору делать работу за меня (как бы странно это ни звучало!). Имею дело с подписанными номерами! - person zakkos; 01.05.2013
comment
Я тоже работаю на ассемблере, поэтому я точно понимаю, откуда вы. :) - person Michael Dorgan; 01.05.2013
comment
@MichaelDorgan Ваши улучшения кода прекрасно работают при работе с положительными числами (они также требуют меньше ресурсов!), Но как только я устанавливаю отрицательную температуру, программа начинает вести себя как раньше ... я задал тот же вопрос на форуме по микрочипам. , надеясь, что они знают, в чем проблема. Теперь я подозреваю, что это что-то с компилятором, потому что ПК прыгает туда-сюда, когда программа выполняет определенные операции, поэтому я думаю, что компилятор переводит мой код в странные инструкции или вызывает некоторые функции, которые плохо возвращаются. - person zakkos; 01.05.2013
comment
Можете ли вы опубликовать вывод вашего устройства - что программа получает в первых 2 байтах буфера вашего блокнота? Возможно, он возвращает не истинное отрицательное число, а что-то еще. Если бы я мог увидеть пример, скажем, -1,0, -1,5, -2,75 и, скажем, -100, я мог бы увидеть, является ли это проблемой. Я предполагаю, что может быть проблема с отрицанием десятичной части вашего ввода. И просто для подтверждения, ПК здесь означает счетчик программ, верно? - person Michael Dorgan; 01.05.2013
comment
НМ, только что увидел твой пост. Хотя, кажется, я угадал правильно :) - person Michael Dorgan; 01.05.2013

На микрочиповом форуме нашли недоработку в коде. Оказывается, проблема была во мне, я не учел отрицательный индекс в массиве 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('-'); 
 } 

Спасибо всем за ответы, вы действительно очень помогли мне понять, как все работает!

person zakkos    schedule 01.05.2013

Это может быть компилятор C, оптимизирующий код, что может создать видимость нелинейного выполнения кода... Попробуйте пошаговое выполнение с отключенным оптимизатором.

person Anonymouse    schedule 30.04.2013