Адрес 0x0164 в микроконтроллерах MSP430

Разбираем загадочный адрес 0x0164 в MSP430! Узнайте, какие функции он выполняет, как работает карта памяти и как использовать его в своих проектах.

Бесплатная консультация юриста

+7 (800) -02-87-29

Реклама jurik.ru

В микроконтроллерах семейства MSP430 (от Texas Instruments) каждый регистр, область памяти и периферийный модуль имеет фиксированный адрес в 16‑битовом адресном пространстве. Один из часто упоминаемых адресов – 0x0164 (в десятичной системе – 164). В этой статье мы подробно разберём, к чему относится этот адрес, какие функции он выполняет и как правильно работать с ним в проектах.


Содержание

  1. Общая карта памяти микроконтроллера
  2. Адрес 0x0164: назначение и регистр
  3. Практическое использование
  4. Примеры кода
  5. Отладка и типичные ошибки
  6. FAQ

MSP430 – это 16‑битовый микроконтроллер с низким энергопотреблением, широко используемый в портативных устройствах, измерительных приборах и IoT‑решениях. Ключевые особенности:

  • 16‑битовый регистр‑счётчик (PC, SR, R0‑R15).
  • Плоская модель памяти: регистровая область, периферийные регистры, Flash и RAM.
  • Поддержка нескольких режимов сна (LPM0‑LPM4).
  • Разнообразные периферийные модули: таймеры, UART, SPI, I2C, ADC, сравниватель, компаратор и др.

Все регистры периферии находятся в диапазоне 0x0100–0x01FF. Именно сюда попадает наш интересующий адрес 0x0164.


Общая карта памяти микроконтроллера

Диапазон Назначение
0x0000‑0x00FF Регистры ядра (R0‑R15, SR, CG, …)
0x0100‑0x01FF Регистры периферийных модулей (Timer_A, USCI, ADC12, …)
0x0200‑0x02FF Дополнительные регистры (если присутствуют)
0x1100‑0xFFFF Flash‑память (программный код)
0x0200‑0x02FF RAM (внутренняя оперативная память)

Адрес 0x0164 находится в периферийной области. Точный регистр зависит от конкретного семейства (MSP430G2xx, MSP430F5xx, MSP430FR2xx и т.д.). Наиболее часто встречающийся вариант – это регистры таймера Timer_A или модуля USCI (UART/SPI/I2C).


Адрес 0x0164: назначение и регистр

Для большинства популярных микроконтроллеров семейства MSP430G2xx и MSP430F2xx адрес 0x0164 соответствует регистру TA0CCR2 – Capture/Compare Register 2 таймера Timer_A0. Ниже – детали:

  • Имя регистра: TA0CCR2
  • Адрес: 0x0164 (16‑битный, доступный как volatile unsigned int)
  • Назначение: хранит значение сравнения/захвата для канала 2 таймера A0.
  • Тип доступа: чтение/запись.
  • Биты: 0‑15 – значение счётчика, которое сравнивается с текущим значением таймера.

Если вы используете микроконтроллер из семейства MSP430FR5xx/FR6xx, то 0x0164 может относиться к регистру UCA0BR1 (второй байт делителя скорости UART). Поэтому всегда проверяйте техническую документацию (datasheet) конкретного устройства.


Практическое использование

Настройка таймера для PWM

Регистры TA0CCR0, TA0CCR1 и TA0CCR2 часто используют для генерации ШИМ‑сигналов. Пример настройки канала 2 (адрес 0x0164) под 1 kHz PWM с 50 % скважностью:

// Предполагаем, что тактовая частота SMCLK = 1 MHz
TA0CCR0 = 1000 ― 1; // Период 1 ms (1 kHz)
TA0CCTL2 = OUTMOD_7; // Reset/Set – классический PWM
TA0CCR2 = 500; // 50 % скважность
TA0CTL = TASSEL_2 | MC_1; // SMCLK, Up‑mode

Захват входного импульса

Если таймер работает в режиме захвата, регистр TA0CCR2 будет автоматически заполняться временем появления фронта на соответствующем входе (TA0.2). Это удобно для измерения периода или ширины импульса.

Работа с UART (для FR5xx/FR6xx)

В микросхемах, где 0x0164 – это UCA0BR1, он задаёт старший байт делителя скорости UART. Пример установки скорости 9600 bd при SMCLK = 1 MHz:

UCA0BR0 = 104; // младший байт (0x68)
UCA0BR1 = 0; // старший байт (0x00) – адрес 0x0164
UCA0MCTL = UCBRS_1; // модуляция
UCA0CTL1 &= ~UCSWRST; // включаем UART

Полные примеры кода

Пример генерации PWM на канале 2

#include <ti/devices/msp430/driverlib/driverlib.h>

void main(void)
{

 WDT_A_hold(WDT_A_BASE); // Отключаем watchdog

 // Настройка тактовой частоты (SMCLK = 1 MHz)
 CS_setDCOFreq(CS_DCO_FREQUENCY_1MHZ);
 CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);

 // Конфигурация таймера A0
 Timer_A_initUpModeParam upParam = {0};
 upParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
 upParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
 upParam.timerPeriod = 1000 ⎻ 1; // 1 kHz
 upParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
 upParam.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_DISABLE;
 upParam.timerClear = TIMER_A_DO_CLEAR;
 Timer_A_initUpMode(TIMER_A0_BASE, &upParam);

 // Конфигурация канала 2 (CCR2) – PWM, Reset/Set
 Timer_A_initCompareModeParam compParam = {0};
 compParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;
 compParam.compareInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
 compParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
 compParam.compareValue = 500; // 50 %
 Timer_A_initCompareMode(TIMER_A0_BASE, &compParam);

 // Запуск таймера
 Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);
 while (1) {
 __no_operation; // Пустой цикл, PWM работает в фоне
 }
}

Пример измерения периода импульса (захват)

#include <ti/devices/msp430/driverlib/driverlib.h>

volatile unsigned int lastCapture = 0;
volatile unsigned int period = 0;

void TA0_ISR(void)
{
 unsigned int now = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,
 TIMER_A_CAPTURECOMPARE_REGISTER_2);
 period = now ― lastCapture;
 lastCapture = now;
 Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
 TIMER_A_CAPTURECOMPARE_REGISTER_2);
}
int main(void)
{
 WDT_A_hold(WDT_A_BASE);
 CS_setDCOFreq(CS_DCO_FREQUENCY_1MHZ);
 CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
 // Таймер в режиме захвата, положительный фронт
 Timer_A_initCaptureModeParam capParam = {0};
 capParam.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;
 capParam.captureMode = TIMER_A_CAPTUREMODE_RISING_EDGE;
 capParam.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
 capParam.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
 capParam.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
 capParam.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
 Timer_A_initCaptureMode(TIMER_A0_BASE, &capParam);

 // Разрешаем прерывание
 Interrupt_enableInterrupt(INT_TA0_2);
 __enable_interrupt;

 while (1) {
 // Здесь можно использовать переменную period
 }}

Отладка и типичные ошибки

  • Неправильный адрес в datasheet – убедитесь, что ваш микроконтроллер действительно использует 0x0164 для нужного регистра. В разных семействах адрес может относиться к разным модулям.
  • Неинициализированный таймер – перед записью в TA0CCR2 необходимо включить таймер (регистры TA0CTL) и задать период в TA0CCR0. Иначе запись будет игнорироваться.
  • Конфликт прерываний – если используете захват, не забудьте очистить флаг прерывания в ISR, иначе ISR будет вызываться бесконечно.
  • Неправильный делитель частоты – при работе с UART убедитесь, что UCA0BR0 и UCA0BR1 (0x0164) рассчитаны правильно, иначе получаете неверную скорость передачи.
  • Энергосбережение – при переходе в режим LPM убедитесь, что таймер/UART не отключаются, иначе регистр 0x0164 перестанет работать.

Диагностический чек‑лист

  1. Проверьте, что #include <driverlib.h> соответствует вашему устройству.
  2. Сверьте адрес 0x0164 в регистровой таблице вашего datasheet.
  3. Убедитесь, что тактовая частота SMCLK настроена правильно.
  4. Инициализируйте соответствующий модуль (Timer_A, USCI) до записи в регистр.
  5. Если используете прерывания – включите их в NVIC и очистите флаги.

Часто задаваемые вопросы (FAQ)

Что делать, если в datasheet указано, что 0x0164 – это UCA0STAT?

Это значит, что вы работаете с микросхемой, где UCA0STAT (статусный регистр UART) находится по этому адресу. В таком случае запись в 0x0164 будет менять статус, а не значение делителя. Перепроверьте семейство (например, MSP430FR5994) и используйте правильный регистр.

Можно ли использовать 0x0164 как обычную переменную в RAM?

Нет. Адрес 0x0164 относится к периферийному регистру, а не к RAM. Попытка использовать его как обычную переменную может привести к непредсказуемому поведению и конфликту с периферией.

Как быстро проверить, какой модуль занимает адрес 0x0164?

Откройте Technical Reference Manual (TRM) для вашего микроконтроллера, найдите раздел Memory Map и найдите строку с адресом 0x0164. Там будет указано имя регистра и модуль.

Почему при работе с PWM на канале 2 наблюдаю «мигание» LED?

Возможные причины:

  • Неправильный режим OUTMOD (должен быть OUTMOD_7 – Reset/Set).
  • Слишком маленькое значение TA0CCR0 (частота выше 20 kHz может быть не видна глазу, но LED может мерцать из‑за инерции).
  • Отсутствие подтягивающего резистора на выводе, если он открыт (floating).

Как изменить частоту PWM без перепрограммирования?

Можно изменить только регистр TA0CCR0 в рантайме:

TA0CCR0 = newPeriod ⎻ 1; // newPeriod – желаемый период в тактах SMCLK

Это не требует пересборки кода, но требует, чтобы таймер был уже запущен.


Адрес 0x0164 в микроконтроллерах MSP430 – это ключевой регистр, который может относиться к TA0CCR2 (таймер) или к UCA0BR1 (UART) в зависимости от семейства. Понимание его назначения, правильная инициализация и корректный доступ к регистру позволяют реализовать такие задачи, как генерация ШИМ‑сигналов, измерение импульсов и настройка скорости последовательного порта.

Всегда проверяйте техническую документацию конкретного устройства, используйте драйверную библиотеку DriverLib или CMSIS‑MSP430 для упрощения работы с регистрами, и не забывайте о тестировании в отладчике.

Удачной разработки!