реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Проблемы со встроенным датчиком температуры, MSP430F2013
Grigorij
сообщение Mar 11 2010, 08:17
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Здравствуйте.

Никак не получается добиться адекватной работы встроенного датчика температуры
в MSP430F2013. На комнатной температуре код АЦП 6-го канала (датчик температуры)
всегда находит в диапазоне от ~50000 до 65535, что несколько противоречит datasheet-у.
Ниже программа (код, реализующий UART приводить не стал, т.к. в нем сомнений нет),
которую я использовал для проверки работы датчика:
Код
#include <msp430x20x3.h>
#include <intrinsics.h>

#include "Types.h"
#include "UART.h"

volatile INT16U __ADCResult__;

void InitADC(void)
{
    SD16AE         = 0x00;

    //внутренний источник опорного напряжения
    //тактирование SMCLK / 48

    SD16CTL       = SD16SSEL_1 + SD16REFON + SD16DIV_3;

    // AIN6 - датчик температуры

    SD16INCTL0  = SD16INCH_6;

    //одиночно преобразование
    //униполярный режим
    //прерывания разрешены

    SD16CCTL0   = SD16SNGL + SD16UNI + SD16IE;
}

void StartSingleADC(void)
{
    SD16CCTL0 |= SD16SC;
}

void InitSFR(void)
{
    //VLOCLK

    BCSCTL3 = LFXT1S_2;
    BCSCTL2 = SELM_0;

    //DCO = 1 MHz, MCLK = SMCLK = 1 MHz

    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL  = CALDCO_1MHZ;

    //задержка для стабилизации генератора

    for (INT16U i = 0; i < 65535; i ++)
        __no_operation();

    P1SEL = 0X00;
    P2SEL = 0x00;
    P1DIR = 0xFF;
    P2DIR = 0xFF;

    InitADC();
    InitUART();
}

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;
    InitSFR();

    StartSingleADC();

    while (TRUE)
    {
        __bis_SR_register(CPUOFF + GIE);

        //отправка результата измерения на ПК

        SendUARTByte( (INT08U)(__ADCResult__ >> 8));
        SendUARTByte( (INT08U)(__ADCResult__ & 0x00FF));

        for (INT16U i = 0; i < 50000; i++)
            __no_operation();

        StartSingleADC();
    }
}

#pragma vector = SD16_VECTOR
__interrupt void SD16A_ISR(void)
{
    if (SD16CCTL0 & SD16IFG)
    {
        __ADCResult__ = SD16MEM0;
        __bic_SR_register_on_exit(CPUOFF);
    }
}

Пробовал:
- изменять источник тактирования АЦП - не помогло
- для проверки внутреннего источника опорного напряжения вывел его наружу - на Vref = 1.2 В
- проверил питание - Vcc = 3 В
- из-за отсутствия других идея впаял в плату новый МК - тоже не помогло

Чувствую, что где-то на ровном месте спотыкаюсь, но никак не могу понять где.
Go to the top of the page
 
+Quote Post
VVlad
сообщение Mar 11 2010, 15:07
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 67
Регистрация: 7-12-09
Пользователь №: 54 109



Здравствуйте, Григорий.
У меня была похожая неувязка, правда, диапазон прижимался не к верхнему краю (50000-65535), а к нижней четверти
(0-16383). Дело было именно в протоколе передачи. Думаю, стоит привести подпрограмму UART, тогда я с удовольствием помог бы. Лучше присылайте на vldu(cobak)itaec.ru
Go to the top of the page
 
+Quote Post
VVlad
сообщение Mar 15 2010, 10:08
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 67
Регистрация: 7-12-09
Пользователь №: 54 109



За долгое молчание прошу прощения, получил и
изучил Ваши программы, грубых ошибок пока не вижу, опробовал аналогичный алгоритм на Ассемблере.
Пробовали Вы, Григорий, тактировать от внешнего кварцевого резонатора? Нормально ли работает у Вас такой
код

Код
//******************************************************************************
//  MSP430F20x3 Demo - SD16, Using the Integrated Temperature Sensor
//
//                MSP430F20x3
//             ------------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |A6+              |
//            |A6-          P1.0|-->LED
//            |                 |
//
#include  <msp430x20x3.h>

#define ADCDeltaOn 31                       // ~0.5 Deg C delta
static unsigned int LastADCVal;             // holds ADC temperature result

void main(void)
{
  BCSCTL2 |= DIVS_3;                        // SMCLK/8
  WDTCTL = WDT_MDLY_32;                     // WDT Timer interval
  IE1 |= WDTIE;                             // Enable WDT interrupt
  P1DIR |= 0x01;                            // P1.0 to output direction
  SD16CTL = SD16REFON +SD16SSEL_1;          // 1.2V ref, SMCLK
  SD16INCTL0 = SD16INCH_6;                  // A6+/-
  SD16CCTL0 = SD16SNGL + SD16IE;           // Single conv, interrupt
    InitSFR();

    StartSingleADC();

    while (TRUE)
    {
        __bis_SR_register(CPUOFF + GIE);

        //отправка результата измерения на ПК

        SendUARTByte( (INT08U)(__ADCResult__ ));
        SendUARTByte( (INT08U)(__ADCResult__ ));

        for (INT16U i = 0; i < 50000; i++)
            __no_operation();

        StartSingleADC();
    }

  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 with interrupt
}

#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
  if (SD16CCTL0 & SD16IFG)
    {
        __ADCResult__ = SD16MEM0;
        __bic_SR_register_on_exit(CPUOFF);
    }
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  SD16CCTL0 |= SD16SC;                      // Start SD16 conversion
}
Go to the top of the page
 
+Quote Post
Grigorij
сообщение Mar 15 2010, 11:41
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Цитата(VVlad @ Mar 15 2010, 13:08) *
За долгое молчание прошу прощения, получил и
изучил Ваши программы, грубых ошибок пока не вижу, опробовал аналогичный алгоритм на Ассемблере.

Добрый день. Все равно спасибо.
Цитата(VVlad @ Mar 15 2010, 13:08) *
Пробовали Вы, Григорий, тактировать от внешнего кварцевого резонатора?

Первоначально был установлен часовой кварц. Потом решил эксперименты
ставить с внутренним генератором. Другого пока ничего не делал.
Цитата(VVlad @ Mar 15 2010, 13:08) *
Нормально ли работает у Вас такой код

Код немного подправил (надеюсь я не изменил ход Ваших мыслей):

Код
#include  <msp430x20x3.h>
#include ....

void main(void)
{
    BCSCTL3 = LFXT1S_2;
    BCSCTL2 = SELM_0 + DIVS_3;

    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL  = CALDCO_1MHZ;[

    //задержка для стабилизации генератора

    for (INT16U i = 0; i < 65535; i ++)
        __no_operation();

    P1SEL = 0x00;  P2SEL = 0x00;
    P1DIR = 0xFF;  P2DIR = 0xFF;

    P1SEL |= BIT3;

    WDTCTL = WDT_MDLY_32;                     // WDT Timer interval
    IE1 |= WDTIE;                                      // Enable WDT interrupt

   SD16CTL = SD16REFON +SD16SSEL_1;    // 1.2V ref, SMCLK
   SD16INCTL0 = SD16INCH_6;                  // A6+/-
   SD16CCTL0 = SD16SNGL + SD16IE;        // Single conv, interrupt

   InitUART();

   SD16CCTL0 |= SD16SC;   // Start SD16 conversion

    while (TRUE)
    {
        __bis_SR_register(CPUOFF + GIE);

        //отправка результата измерения на ПК

        SendUARTByte( (INT08U)(__ADCResult__ ));
        SendUARTByte( (INT08U)(__ADCResult__ ));
    }
}

#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
        if (SD16CCTL0 & SD16IFG)
    {
        __ADCResult__ = SD16MEM0;
        __bic_SR_register_on_exit(CPUOFF);
    }
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
       SD16CCTL0 |= SD16SC;   // Start SD16 conversion
}

На выходе при комнатной температуре наблюдаю код в диапазоне 0xD40A - 0xD40E (54282 - 54286).

Вернул предыдущие настройки АЦП (настройки системы тактирования оставил теже). Получил код
в диапазоне 0xA82C - 0xA82F (43052 - 43055).

Напряжение питание при этих экспериментах было 3,1 В. На выходе Vref 1,17 В. Снижение напряжение
питания до 2,95 В обоих случаях приводит к получение максимального АЦП по каналу.

В общем пока получается, что при напряжении питания 3 В все работает более или менее нормально
(по крайней мере при +60 гр. код АЦП максимального значения еще не достигает). При понижении
питания все идет вразнос, а как следствие этого от батареи CR2032 мой "термометр" пока не работает.
Go to the top of the page
 
+Quote Post
VVlad
сообщение Mar 16 2010, 07:11
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 67
Регистрация: 7-12-09
Пользователь №: 54 109



Спасибо, Григорий, за вежливость и терпимость. Я действительно сильно напутал в коде. На самом деле моя вина в не слишком хорошо сформулированной идее.
То, что запуск измерения инициируется сторожевым таймером, не обязательно должно влиять на передачу байтов.
Преобразование типов (INT08U)(__ADCResult__ )) выделяет один байт из двухбайтного слова,
но в обработчике прерываний от Timer A происходит 8 сдвигов вправо (UARTBuff=UARTBuff >> 1),
предлагаю организовать передачу слова целиком, без дробления на байты. Например - превратить функцию SendUARTByte(INT08U Data) в дважды вызываемую процедуру SendUARTByte(void), а пересылаемое слово загружать в глобальную переменную UARTBuff = _ADCResult_ перед двухкратным вызовом этой процедуры.
Что-то вроде
Код
UARTBuff = _ADCResult_;
SendUARTByte(void);
SendUARTByte(void);

Кстати, этот фрагмент может стать ещё короче, если его поместить в обработчик прерываний от SD16
Код
#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
        if (SD16CCTL0 & SD16IFG)
    {
UARTBuff = SD16MEM0;
SendUARTByte(void);
SendUARTByte(void);
__bic_SR_register_on_exit(CPUOFF);
    }
}

Единственное замечание - следует внимательно проследить, чтобы были разрешены оба типа прерываний (и TA, и SD16). Об их взаимном приоритете не беспокойтесь - он обеспечит правильность обработки.

Сообщение отредактировал VVlad - Mar 16 2010, 07:16
Go to the top of the page
 
+Quote Post
Grigorij
сообщение Mar 16 2010, 07:46
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Цитата(VVlad @ Mar 16 2010, 10:11) *
Преобразование типов (INT08U)(__ADCResult__ )) выделяет один байт из двухбайтного слова,
но в обработчике прерываний от Timer A происходит 8 сдвигов вправо (UARTBuff=UARTBuff >> 1),
предлагаю организовать передачу слова целиком, без дробления на байты. Например - превратить функцию SendUARTByte(INT08U Data) в дважды вызываемую процедуру SendUARTByte(void), а пересылаемое слово загружать в глобальную переменную UARTBuff = _ADCResult_ перед двухкратным вызовом этой процедуры. Что-то вроде ...

Обязательно попробую, как только переделаю плату в ближайшие пару дней, хотя и сомневаюсь что в этом дело.
Цитата(VVlad @ Mar 16 2010, 10:11) *
Кстати, этот фрагмент может стать ещё короче, если его поместить в обработчик прерываний от SD16
Код
#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
   if (SD16CCTL0 & SD16IFG)
   {
        UARTBuff = SD16MEM0;
        SendUARTByte(void);
        SendUARTByte(void);
        __bic_SR_register_on_exit(CPUOFF);
   }
}

Единственное замечание - следует внимательно проследить, чтобы были разрешены оба типа прерываний (и TA, и SD16). Об их взаимном приоритете не беспокойтесь - он обеспечит правильность обработки.

Ну и в обработчике прерываний SD16ISR думаю надо добавить установку бита GIE, т.е.
Код
#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
   //в этом месте, если я не ошибаюсь, все прерывания запрещены,
   //т.е. бит GIE = 0

   if (SD16CCTL0 & SD16IFG)
   {
        UARTBuff = SD16MEM0;
       __enable_interrupt();
       ...
   }
}


Вчера попробовал считывать данные с 5 канала (AVCC / 11) со следующими настройками:
Код
SD16CTL      = SD16REFON +SD16SSEL_1;    // 1.2V ref, SMCLK
SD16INCTL0 = SD16INCH_5;
SD16CCTL0  = SD16SNGL + SD16IE;           // Single conv, interrupt

Все работает превосходно. Получаемый код почти не отличается от расчетных значений
(разница 50-60 единиц думаю вполне приемлема). Напряжение питания от 2.7 до 3.3 В
(на других значения не пробовал).

С настройками:
Код
SD16CTL       = SD16SSEL_1 + SD16REFON + SD16DIV_3;
SD16INCTL0  = SD16INCH_5;
SD16CCTL0   = SD16SNGL + SD16UNI + SD16IE;

Все не так гладко. Адекватное значение получаю только при напряжении питания 3 и выше.

В новой схеме (благо это только для тестирования, да и ЛУТ наш лучший друг) выкину все лишнее,
т.е. будет только МК, преобразователь UART/USB, кварц. И на разъемы выведу все каналы АЦП,
которые доступны. Посмотрим, что из этого получиться.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 21:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01436 секунд с 7
ELECTRONIX ©2004-2016