Современная электроника №6/2023

ИНЖЕНЕРНЫЕ РЕШЕНИЯ 35 WWW.SOEL.RU СОВРЕМЕННАЯ ЭЛЕКТРОНИКА • № 6 / 2023 в регистре SPI0CFG переключить бит полярности с « дисплейного » ( задан - ного в начальной конфигурации – рис . 5 д ) на «DDS- й », а после оконча - ния вывода восстановить первоначаль - ное его ( бита ) значение , иначе дисплей работать не будет . Подпрограмма вывода двухбайтно - го числа в DDS по SPI с учётом выше - указанного совмещения , переключе - ния бита полярности и вышеописан - ной подпрограммы вывода байта по SPI outspi() приведена ниже . Теперь о том , как вывести в DDS само значение частоты . Как указано в спра - вочном листке (datasheet) на AD9837, численное значение частоты представ - ляется 28- разрядным кодом и вводит - ся в DDS двумя двухбайтными (16- раз - рядными ) словами . В первом слове в 14 его младших битах содержится 14 млад - ших бит 28- разрядного кода , во втором , в его 14 младших битах , – 14 старших бит кода . А в двух старших битах обоих слов содержится управляющий код . Если , например , этот управляющий код равен 01b (01 2 ), то DDS будет воспринимать его следующим образом . Во - первых , будет выводиться синусоида , во - вторых , чис - ленное значение частоты будет вводить - ся в нулевой регистр частоты (FREG0), а численное значение фазы ( как пра - вило , нулевое значение ) – в нулевой регистр фазы (PHASE0). Есть ещё FREG1 и PHASE1, но их использования не тре - буется . Пусть задано 32- разрядное (uint32_t) значение частоты F. Каким образом сформировать из этого числа два двух - байтных слова с указанным управляю - щим кодом для ввода в DDS? Сделать это достаточно просто . Во - первых , определим это число F как 32- разрядное : uint32_t F; // частота в Гц Во - вторых , сделаем ещё одно совме - щение : В этом совмещении 4- байтное (uint32_t) число FR.FRL и два двух - байтных (uint16_t) числа FR.FRS[0] и FR.FRS[1] двухэлементного массива FRS[1] также перераспределяют одно и то же место в памяти МК и являют - ся соответственно старшим и младшим словами числа FR.FRL. Теперь , как указывалось выше ( см . формулу (3)), заданное число F умно - жим на 16, а результат запишем в 4- байтное число FR.FRL вышеуказан - ного совмещения , т . е . FR.FRL = F × 16. Если теперь сдвинуть 32- разрядное чис - ло FR.FRL влево на 2 бита , то в млад - шем слове FR.FRS[1] получим 14 млад - ших бит 28- разрядного кода , только сдвинутых влево на 2 бита , а в стар - шем слове FR.FRS[0] – полностью 14 старших бит этого кода . Если сдвинуть младшее слово FR.FRS[1] вправо на 2 бита ( т . е . восстановить сдвинутое вле - во значение ), то в его 14 младших битах как раз и будет содержаться 14 младших бит 28- разрядного кода . Таким образом , оба слова FR.FRS[0] и FR.FRS[1] для вывода теперь подготовлены и оста - ётся только добавить к ним 2 старших управляющих бита 01b ( или 0x4000). Эту « добавку » можно , например , про - сто прибавить , но проще каждое из слов логически сложить ( | ) с числом 0x4000. Для вывода нулевого значения фазы в нулевой регистр фазы (PHASE0) тре - буется подать команду 0xC000 ( см . справочный листок AD9837). Но прежде чем выводить в регистр частоты (FREG0) эти два двухбайт - ных слова и нулевое значение фазы в нулевой регистр фазы (PHASE0), DDS нужно сбросить ( т . е . установить бит RESET’ а , подав команду 0x2108 – см . справочный листок на AD9837), а после вывода частоты и фазы – запу - стить , т . е . обнулить бит сброса , подав команду 0x2008. Несмотря на такое пространное объяснение , подпрограмма вывода в DDS заданной частоты занимает все - го 9 строчек кода на C51: Таким образом , программирование DDS примитивно просто , а приведённая выше подпрограмма занимает ничтож - ное место в программной памяти МК . Подпрограмма для измерения напря - жения аккумулятора и вывода на дисплей состояния его разряженности также проста . Она десятикратно изме - ряет напряжение , поступающее на вход ADC0.1 (P0.1) МК , осредняет его , срав - нивает с порогами (3,2 В ; 3,5 В и 3,8 В ) и в зависимости от этого напряжения выводит на дисплей рисунок аккумуля - тора с тем или иным количеством сег - ментов . С необходимыми комментари - ями эта подпрограмма приведена ниже . Поскольку подпрограмма взята из одно - го из примеров работы АЦП , приведён - ных в среде Simplicity Studio, и адаптиро - вана под настоящую задачу , некоторые комментарии оставленыв оригинальном виде . Вывод на дисплей опущен , посколь - ку , как указывалось выше , более подроб - но о таком выводе написано в [3]. Учиты - вая заданнуюконфигурацию ( см . рис . 5 ж и рис . 5 з ), её достаточно просто понять : //Вывод 16-разрядного слова в DDS void outspi16(uint16_t wor) { U.US = wor; SPI0CFG = SPI0CFG | 0x10; // IDLE_HIGN для AD9837 CSAD = 0; // CSAD=0. outspi (U.UB[ 0]); // Ст.б. outspi (U.UB[ 1]); // Мл.б. CSAD = 1; // CSAD=1. SPI0CFG = SPI0CFG & 0xef; // IDLE_LOW - Для дисплея } union { uint32_t FRL; // FR.FRS[0]- Ст. uint16_t слово. uint16_t FRS[1]; // FR.FRS[1]- Мл. uint16_t слово. } FR; // FR.FRL - 4-байтное uint32_t число. //Вывод частоты в DDS FR.FRL = F * 16; FR.FRL = FR.FRL << 2; // Сдвиг всего числа uint32_t влево на 2 бита FR.FRS[0] = (FR.FRS[0]) | 0x4000; //Добавка 2-х ст.бит 01b к ст. слову для Freq 0 FR.FRS[1] = ((FR.FRS[1]) >> 2) | 0x4000;//Сдвиг мл. слова вправо на 2 бита (восст.) //и добавка 2-х ст.бит 01b к мл. слову outspi16(0x2108); // Сброс DDS (стоп) outspi16(FR.FRS[1]); // вывод мл. слова частоты в FREG_0 outspi16(FR.FRS[0]); // вывод ст. слова частоты в FREG_0 outspi16(0xC000); // WRITE_TO_PHASE0_REG 0xC000 outspi16(0x2008); // Выход из сброса (запуск) void BAT() { uint32_t accumulator = 0; // accumulator for averaging uint8_t measurements; // = 10; // measurement counter uint32_t result = 0; uint32_t mV; // measured voltage in mV for (measurements = 0; measurements < 10; measurements++) { // clear ADC0 conv. complete flag ADC0CN0_ADINT = 0; // Start a conversion by setting ADBUSY ADC0CN0_ADBUSY = 1; while (!ADC0CN0_ADINT); //wait conversionComplete accumulator += ADC0; // ADC0 } result = accumulator / 10; // Vref (mV) // measurement (mV) = --------- ------ * result (bits) // (2^10)-1 (bits) mV = result * 6600 / 1023; //2*1650=3300 и *2 = 6600, так как 2 резистора // и повторитель на OPA333;0.5x gain => 2*1650 if (mV < 3200) { //вывод пустого аккумулятора } if ((mV >= 3200) & (mV <= 3500)) { //вывод одного сегмента } if ((mV > 3500) & (mV <= 3800)) { //вывод двух сегментов } if (mV > 3800) { //вывод трех сегментов } }

RkJQdWJsaXNoZXIy MTQ4NjUy