Как избежать переполнения стека в моем проекте PIC16f877A с преобразованием числа с плавающей запятой в строку?

В настоящее время я работаю над системой мониторинга трафика, которая требует, чтобы геологические координаты (в виде поплавка) отправлялись в виде строки через модуль GSM/GPRS в виде текстового сообщения. Я использовал следующий код для преобразования этих значений с плавающей запятой в строки, но при компиляции появляется «предупреждение: (1393) возможное переполнение аппаратного стека; расчетная глубина стека: 10». Я использую PIC 16f877A, и что я могу сделать, чтобы избежать этого, кроме замены MCU?

void reverse(char *str, int len)
{
int i=0, j=len-1, temp;
    while (i<j)
    {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++; j--;
    }
}

int intToStr(int x, char str[], int d)
{
    int i = 0;
    while (x)
    {
        str[i++] = (x%10) + '0';
        x = x/10;
    }
    while (i < d)
        str[i++] = '0';

    reverse(str, i);
    str[i] = '\0';
    return i;
}

void ftoa(float n, char *res, int afterpoint)
{
    int ipart = (int)n;
    float fpart = n - (float)ipart;
    int i = intToStr(ipart, res, 0);
    if (afterpoint != 0)
    {
        res[i] = '.';
        fpart = fpart * pow(10, afterpoint);
        intToStr((int)fpart, res + i + 1, afterpoint);
    }
}

person TheShark    schedule 27.03.2016    source источник
comment
Трудно сказать без остальной части кода, но вы, вероятно, звоните слишком глубоко. На этой картинке всего 8 уровней стека. Перестройте всю свою программу так, чтобы она вызывала менее глубоко, не используйте рекурсию и не вызывайте подпрограммы из процедуры обработки прерывания (если вы используете прерывания).   -  person Unimportant    schedule 27.03.2016
comment
Мы не видим требований к вызову pow, что может быть ограничивающим фактором (если это библиотечная функция). В противном случае есть ли причина, по которой очень простая функция reverse не может быть частью intToStr? Это сэкономит 1 уровень стека. Но у вас нет глубины стека 10 в показанном коде: поэтому сделайте его более эффективным дальше.   -  person Weather Vane    schedule 27.03.2016


Ответы (2)


вы можете использовать встроенную функцию "sprintf", что-то вроде этого (компилируется нормально с pic16f1705 и должно быть таким же, как у вас):

char array[64];
float myvalue=2.0f;
sprintf(array, "%f", myvalue);

посмотрите файл справки для компилятора XC8, help-> XC8 Toolchain-> MPLAB XC8 Compiler-> библиотечные функции-> sprintf

Также вы можете печатать напрямую в USART1, используя printf:

printf("my message to GSM transitter %f", myvalue); 
person Vladimir Tsykunov    schedule 28.03.2016
comment
Большой ! Это действительно работало и с pic16f887a. Большое спасибо за поддержку! - person TheShark; 29.03.2016

Вот фрагмент кода, который я использовал для печати значений АЦП в PICF16F877A.

// CONFIG
#pragma config FOSC  = HS      // Oscillator Selection bits (HS oscillator)
#pragma config WDTE  = OFF     // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF    // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON    // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP   = OFF      // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD   = OFF      // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT   = OFF      // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP    = OFF       // Flash Program Memory Code Protection bit (Code protection off)

#include <xc.h>
#include <pic16f877a.h>
#include <stdio.h>
#include <string.h>

#define _XTAL_FREQ 20000000

/////////////////////////Code to print debug print//////////////////////////////
//#define FREQ 8000000
#define FREQ _XTAL_FREQ
#define baud 9600
#define spbrg_value (((FREQ/64)/baud)-1)    //312500 spbrg=32
unsigned char data1;
char *str1;
void serial_init()
{
    SPBRG=spbrg_value;
    //SPBRG=31;
    //  TXSTAbits.TXEN = 1;
    //CSRC: Clock Source Select bit            0
    //TX9 : 9-bit Transmit Enable bit          0
    //TXEN: Transmit Enable                    0  
    //SYNC: EUSART Mode Select bit             0
    //SENDB: Send Break Character bit          0
    //BRGH: High Baud Rate Select bit          0
    //TRMT: Transmit Shift Register Status bit 1
    //TX9D: Ninth bit of Transmit Data         0
    TXSTA=0x20;

    //  RCSTAbits.SPEN = 1;
    //  RCSTAbits.CREN = 1;

    //bit 7 SPEN: Serial Port Enable bit        1
    //bit 6 RX9: 9-bit Receive Enable bit       0
    //bit 5 SREN: Single Receive Enable bit     0
    //bit 4 CREN: Continuous Receive Enable bit 1
    //bit 3 ADDEN: Address Detect Enable bit    0
    //bit 2 FERR: Framing Error bit             0
    //bit 1 OERR: Overrun Error bit             0
    //bit 0 RX9D: 9th bit of Received Data      0
    RCSTA=0x90;
    //Setting 
    TRISCbits.TRISC6=0;
    TRISCbits.TRISC7=1;
}
void tx(unsigned char temp)
{
    TXREG=temp;
    while(PIR1bits.TXIF == 0);
    while(TXSTAbits.TRMT == 0);

}

void tx_str(char *senpoint)
{
    str1=senpoint;
    while(*str1 != '\0')
    {
        tx(*str1);
        str1++;

    }
}

//In main function, you can write,

unsigned char ADCBuf[40]; 
void main()
{
  serial_init();
//  unsigned int a;
  TRISA = 0xFF;                 //Analog pins as Input
//  TRISB = 0x00;                 //Port B as Output
//  TRISC = 0x00;                 //Port C as Output
  ADC_Init();                   //Initialize ADC
  unsigned int a;
  float V;
  a = 10;
  unsigned char str_1[]="P";
   tx_str("ADC TEST \n\r");
  while(1)
  {

    a = ADC_Read(0);            //Read Analog Channel 
//    a = a + 1;            //Read Analog Channel 0
    sprintf(ADCBuf,"Adc Val = %d \n\r",a);
    tx_str(ADCBuf);
    __delay_ms(1000);            //Delay
    V = a*(5000.0/1023.0);
    sprintf(ADCBuf,"Voltage = %f \n\r",V);
    tx_str(ADCBuf);
    __delay_ms(1000);


  }                    
}
person Pravin.2087    schedule 27.01.2020