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

 
 
> Проблемы со встроенным датчиком температуры, 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
 
Start new topic
Ответов
VVlad
сообщение Mar 16 2010, 07:11
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 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
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 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 Текстовая версия Сейчас: 24th July 2025 - 06:18
Рейтинг@Mail.ru


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