STM32 Разные результаты при отладке

Я пытаюсь запрограммировать цифровой термометр DS18B20 на 1-Wire с использованием UART, и у меня возникают странные проблемы. Когда я отлаживаю эту программу, которая работает без точек останова (или просто запускает программу без отладки), я получаю значения около 100 ° C. Когда я устанавливаю точку останова перед получением информации о температуре, это дает мне около 50 ° C. И третий вариант, когда я просто открываю это окно, когда я вижу SFR и расширяю раздел UART4, он дает мне правильные показания около 25 ° C. У меня есть логический анализатор Saleae, и во всех этих трех случаях он отправляет мне достоверные данные (около 25 ° C). Я попытался установить некоторую задержку там, где находится точка останова (даже задержка в 2 секунды), и это не помогает. Он дает мне показания около 50 ° C (как с точками останова и не расширенным окном SFR). Вероятно, это ошибка программирования (я начинаю), но это действие с расширенным окном SFR выходит за рамки моих рассуждений. Я действительно не знаю, что происходит. Надеюсь, вы сможете пролить свет на эту ситуацию для меня.

Я использую оценочную плату STM32F4-Discovery и программирую ее на Atollic 4.1.0.

Мой "Библиотечный" файл:

#include "DS18B20_Lib.h"


void DS18B20_Init(void)
{
    //USART4 PA0
    GPIO_InitTypeDef GS;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_UART4);

    GS.GPIO_Mode = GPIO_Mode_AF;
    GS.GPIO_OType = GPIO_OType_PP;
    GS.GPIO_PuPd = GPIO_PuPd_UP;
    GS.GPIO_Speed = GPIO_Speed_50MHz;
    GS.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA,&GS);

    USART_InitTypeDef US;
    US.USART_BaudRate = 115200;
    US.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    US.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    US.USART_Parity = USART_Parity_No;
    US.USART_StopBits = USART_StopBits_1;
    US.USART_WordLength = USART_WordLength_8b;
    USART_Init(UART4,&US);
    USART_SetAddress(UART4,0x12);
    USART_Cmd(UART4,ENABLE);
    USART_HalfDuplexCmd(UART4,ENABLE);

    USART_ITConfig(UART4,USART_IT_TXE | USART_IT_RXNE | USART_IT_TC ,ENABLE);
    /*NVIC_InitTypeDef NS;
    NS.NVIC_IRQChannel = UART4_IRQn;
    NS.NVIC_IRQChannelCmd = ENABLE;
    NS.NVIC_IRQChannelPreemptionPriority = 1;
    NS.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NS);*/

}

uint16_t Reset_1Wire(void)
{
    uint16_t Present;
    while (USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);
    UART4->BRR = 0x1117;
    while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
    USART_SendData(UART4,0xF0);
    while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET);
    Present = USART_ReceiveData(UART4);
    while (USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);
    UART4->BRR = 0x016D;
    return Present;
}

char Read_1Wire(void)
{

    char Data=0;
    int i;
    for(i=0;i<8;i++)
    {
        while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
        USART_SendData(UART4,0xFF);
        while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET);
        if(USART_ReceiveData(UART4)==0xFF)
            Data|=0x80;
        else Data|=0;
        if (i!=7) Data=Data>>1;
    }
    return Data;
}

void Write_1Wire(char Data)
{
    char Mask=1;
    int i;
    for(i=0;i<8;i++)
    {
        while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
        if (Data & Mask)
            USART_SendData(UART4,0xFF);
        else
            USART_SendData(UART4,0x00);
        Mask=Mask<<1;
    }
}

uint16_t DS18B20_MeasTemp(void)
{
    uint16_t Data;
    uint16_t LSB;
    uint16_t MSB;
    Reset_1Wire();
    Write_1Wire(0xCC); //SkipRom only 1 device
    Write_1Wire(0x44);
    while(Read_1Wire()==0x00);
    Reset_1Wire();
    Write_1Wire(0xCC);
    Write_1Wire(0xBE);
   /*--------BRAKEPOINT HERE--------*/
    LSB=Read_1Wire();
    MSB=Read_1Wire();
    Data=MSB<<8|LSB;
    Reset_1Wire();
    return Data;
}

И моя основная функция:

int main(void)
{
  char strLine[25];
  uint16_t Temperature;

  LCD_Init();
  LCD_SetColors(GREEN, BLUE);
  LCD_Clear(BLUE);
  LCD_CharSize(16);

  DS18B20_Init();

  sprintf(strLine,"%s","Temp: ");
  LCD_StringLine(20,50,(uint8_t*) strLine);
  //GPIO_Config();
  while (1)
  {
    Presence1Wire();
    Temperature = DS18B20_MeasTemp();
    if (Temperature&0xF000)
        LCD_PutChar(60,50,'-');
    else LCD_PutChar(60,50,'+');
    LCD_PutInt(68,50,(Temperature&0x0FF0)>>4);
    LCD_PutInt(72,64,(Temperature&0xF)*625);
  }

}

person Dziat    schedule 05.03.2014    source источник
comment
Никогда раньше не использовал STM, но посмотрел их справочное руководство похоже, что GPIO нужно открыть + подтянуть; ваш код подразумевает, что он настроен на push-pull. Я думаю, вам нужен GPIO_OType_OD, но я не могу найти подходящий файл заголовка, чтобы быть уверенным. Возможно, дополнительное потребление энергии при запуске отладчика, когда 1-Wire замыкает ваш выход USART на землю, вызывает проблемы, которые вы наблюдаете?   -  person Rich Hendricks    schedule 06.03.2014
comment
Спасибо за ваш ответ. Сначала я установил открытый сток и подтянул его с помощью внешнего резистора 4,7 кОм, когда я пытался прочитать этот номер ПЗУ устройства, полученный с помощью лазера, и все работало хорошо, мои показания в отладчике были такими же, как и в saleae, поэтому мне было интересно, Я установил его pushpull и pull up изнутри, будет ли он работать, и он сработал, поэтому я просто оставил его там :). Сменить его на открытый сток и вытащить наружу не помогло. У меня точно такая же проблема.   -  person Dziat    schedule 06.03.2014
comment
Я обнаружил еще одну вещь, которая может помочь. Давайте назовем эти 3 возможных варианта для запуска этой программы FS для полной скорости, BP для параметра точки останова и SFR для просмотра SFR. Получил показания: FS - 0x5BE, BP - 0x2DE, SFR - 0x16E. 4 LSB являются дробной частью, и они всегда хороши. С частью мантиссы это 0x5B ›› 1 = 0x2D, ​​0x2D ›› 1 = 0x16. В качестве (полумера) быстрого исправления я просто ›› 2 моя мантисса, и она работает в FS, но все еще не работает в BP и SFR. Может быть, это будет ключом к разгадке.   -  person Dziat    schedule 06.03.2014
comment
Можно попробовать убрать вызов USART_ITConfig? Вам это не нужно, когда вы используете USART в режиме опроса (не с прерываниями).   -  person Étienne    schedule 06.03.2014
comment
Ваши переменные MSB и LSB должны быть типа uint8_t, а не uint16_t. В противном случае я не вижу проблемы в вашем коде. Я бы посоветовал вам запрограммировать его с использованием прерываний USART вместо опроса флагов и посмотреть, имеет ли это значение.   -  person Étienne    schedule 06.03.2014
comment
Спасибо за ответ, Этьен. Я закончил свой код этим быстрым исправлением, о котором писал, а также исправил эти 2 вещи, которые вы мне сказали. Программа работает хорошо на полной скорости, но с точкой останова и просмотром SFR все равно не работает. Я мог бы написать это о прерываниях, и проблема, вероятно, не возникла бы, но я написал и измерил то, что хотел, и мне было интересно, что вызывает эту проблему, чтобы я мог знать, как исправить это в будущем, если она появится.   -  person Dziat    schedule 09.03.2014


Ответы (2)


Write_1Wire(0xCC);
Write_1Wire(0xBE);
  • отправлять байты в UART и не читать. Получать данные в формате fifo.
Read_1Wire()
  • прочти старые эти данные в фифо.
uint16_t DS18B20_MeasTemp(void)
{
    uint16_t Data;
    uint16_t LSB;
    uint16_t MSB;
    Reset_1Wire();
    Write_1Wire(0xCC); //SkipRom only 1 device
    Write_1Wire(0x44);
    while(Read_1Wire() == 0x00);
    Reset_1Wire();
    Write_1Wire(0xCC);
    Write_1Wire(0xBE);
   /*--------BRAKEPOINT HERE--------*/
    // !!!!!!! Paste this
    while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) != RESET)
      USART_ReceiveData(UART4);
    // !!!!!!!
    LSB = Read_1Wire();
    MSB = Read_1Wire();
    Data = MSB << 8 | LSB;
    Reset_1Wire();
    return Data;
}
person Sergey B    schedule 20.09.2014

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

Я думаю, что проблема связана с архитектурой процессора, когда вы отлаживаете точку останова, он приостанавливает процессор, но не периферийные часы, а GPT не приостанавливается, что дает разные показания, поскольку мои измерения зависят от таймера.

Я говорю со своей точки зрения, поэтому в вашем случае этого может и не происходить, но это может дать вам другой взгляд на проблему.

person Robert Sabljo    schedule 30.04.2019