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

 
 
 
Reply to this topicStart new topic
> MSP430 + Timer + Interrupt, Вопросы
Niketa
сообщение Feb 6 2014, 14:17
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



Читаю Student Guide and Lab Manual и Family User's Guide и стали мне непонятны некоторые строки из кода лабораторной.
В лабораторной 4 нашел пример кода.
Детально с ним разобрался,но некоторые вещи мне непонятны.


Код
#include <msp430g2553.h>

volatile unsigned int i;

void ConfigWDT(void);
void ConfigClocks(void);
void ConfigLEDs(void);
void ConfigTimerA2(void);

void main(void)
{
  ConfigWDT();
  ConfigClocks();
  ConfigLEDs();
  ConfigTimerA2();

  _BIS_SR(GIE);   // РАЗРЕШАЕМ ПРЕРЫВАНИЕ - ЭТО ПОНЯТНО

  while(1)
  {
   P1OUT |= BIT0;
   for (i = 100; i > 0; i--);
   P1OUT &= ~BIT0;
   for (i = 5000; i > 0; i--);
  }
}

void ConfigWDT(void)
{
WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog timer
}

void ConfigClocks(void)    // НЕПОНЯТНАЯ ЧАСТЬ,НО ОНА У ВСЕХ ПРИСУТСТВУЕТ,Я РЕШИЛ ОСТАВИТЬ
{
  BCSCTL1 = CALBC1_1MHZ;                     // Set range
  DCOCTL = CALDCO_1MHZ;                      // Set DCO step + modulation
}

void ConfigLEDs(void)
{
  P1DIR = BIT6 + BIT0;                      // P1.6 and P1.0 outputs
  P1OUT = 0;                                // LEDs off
}

void ConfigTimerA2(void)
  {
   TACCR0 = 62500 - 1;    // Период в 62,500 цикла, от 0 до 62,499.                    /// ПОЧЕМУ 62500 ОТСТЧЕТОВ ВСЕГО ????????
   TACCTL0 = CCIE;        // Разрешаем прерывание таймера по достижению значения CCR0.    // ЭТО ПОНЯТНО
   TACTL = TASSEL_2     // ПОНЯЛ ЧТО ЭТО ВЫБОР ИСТОЧНИКА ТАКТОВОГО СИГНАЛА, НО В ЧЕМ МЕЖДУ НИМИ РАЗНИЦА ? ГДЕ ПРОЧЕСТЬ ?
               + ID_3           // ЭТО ПОНЯТНО. НО КАКАЯ ИЗНАЧАЛЬНАЯ ЧАСТОТА КОТОРУЮ МЫ ДЕЛИМ ?
                + MC_1;     // ПОНЯТНО
  }

#pragma vector=TIMER0_A0_VECTOR          // НИ В ОДНОЙ ИЗ ВЫШЕ ОПИСАННЫХ КНИЖЕК НЕ НАПИСАНО ПОЧЕМУ ТАКОЙ СИНТАКСИС
__interrupt void Timer_A (void)                     // ПОЧЕМУ ТАКОЙ СИНТАКСИС ?
{
  P1OUT ^=BIT6;                                 
}



1. Если выше описано что в таймере 62500 отсчетов. А так же включен делитель частоты /8 - то изначальная частота была 8 *62500 = 500кГц ???
Т.е. SMCLK что в коде включен имеет такую частоту ?

2. Как мне реализовать 2 таймера ?
Мне нужно чтоб один обращался к прерыванию с частотой 48кГц , а второй 200 Гц.
Идея в том что 48кГц будет забираться данные с АЦП , потом еще и фильтроваться будет.
А 200гц - вывод на индикатор



Сообщение отредактировал Niketa - Feb 6 2014, 15:03
Go to the top of the page
 
+Quote Post
E.V.G.
сообщение Feb 6 2014, 20:23
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 31-01-10
Из: Арзамас
Пользователь №: 55 175



1. Частота прерываний от TACCR0=SMCLK/ID3/TACCR0=1000000/8/62500=2Гц. Т.к. в прерывании выполняется инверсия вывода P1.6, то на нём будет меандр с частотой импульсов 1Гц.
TASSEL_2 - выбор тактирования таймера от источника SMCLK. SMCLK вы отдельно не настраивали в модуле тактовых сигналов. Значит тактирование идёт по умолчанию после сброса от DCO ( настройка частоты DCO - в ConfigClocks).
Посмотрите файл msp430g2553.h - в нём есть определения битов и векторов прерываний. Можно посмотреть книжки по описанию модулей MSP430 по русски для других вариантов этого контроллера - они похожи. Раньше книжки были на сайте ф.КОМПЭЛ.

2. Данные с АЦП нужно не забирать, а настроить АЦП на оцифровку какого либо канала (или группы каналов) с частотой 48кГц. При тактовой частоте 1МГц вряд ли успеете потом обсчитать. Нужно поднимать частоту тактироания процессора MCLK. Запуск АЦП можно сделать по разному: либо настроить на запуск преобразований от таймера, либо сам АЦП будет работать от внутреннего таймера выборки/хранения с этой частотой после однократного запуска. Читайте режимы работы АЦП. Формирование частоты 200Гц можно сделать путём подсчёта в обработчике прерываний таймера. Делаете в таймере частоту прерываний от TACCR0 48кГц и вводите в обработчике прерываний переменную с инкрементом. Переменную сравниваете с числом (240 т.к. 48000/240=200Гц). Если больше или равно 240 - установить флаг (или выполнить вывод на индикатор) и сбросить в ноль переменную. Если нужны точные частоты и временные интервалы, то лучше поставить кварцевый резонатор.

Сообщение отредактировал E.V.G. - Feb 6 2014, 20:31
Go to the top of the page
 
+Quote Post
Niketa
сообщение Feb 7 2014, 13:15
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



Вот я написал Код.
С частотой 40кГц считывается АЦП.
На Индикатор выводится в основной программе под циклом While. Вывод на индикатор в данном случае не так важно.

Код
#include <msp430g2553.h>

unsigned int digit; /// переменная для значения 1 разряда
unsigned int pos = 1;    /// номер разряда
unsigned int value;   // переменная для значения выводимого числа
unsigned int buffer;   // переменная для значения ADC

unsigned int i;   // счетчик

void init_led(void)    // инициализация индикатора (описание смотрите в даташите)
{
    P1REN &= ~(BIT1+BIT2+BIT3+BIT4+BIT5+BIT6);
    P2REN &= ~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5);
    P2REN &= ~(BIT3+BIT4+BIT5);
    P1REN &= ~BIT6;
    P2DIR |= (BIT0+BIT1+BIT2);
    P1DIR |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2OUT |= (BIT0+BIT1+BIT2);
    P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2DIR |=(BIT3+BIT4+BIT5);
    P1DIR |=BIT6;
    P2OUT |=(BIT3+BIT4+BIT5);
    P1OUT |=BIT6;
}

void clear_led(void) {            // обнуление. выключаем все регистры и цифры.
    P2OUT |= (BIT0+BIT1+BIT2);
    P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2OUT |= (BIT3+BIT4+BIT5);
    P1OUT |= BIT6;
}

void show_number(number) {     // сопоставление ножек установки числа
    switch (number) {
        case 0 :
            P1OUT &=~(BIT1+BIT2+BIT3+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 1:
            P1OUT &=~(BIT3+BIT5);
            break;
        case 2:
            P1OUT &=~(BIT1+BIT3+BIT4);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 3:
            P1OUT &=~(BIT1+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
        case 4:
            P1OUT &=~(BIT2+BIT3+BIT4+BIT5);
            break;
        case 5:
            P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
        case 6:
            P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 7:
            P1OUT &=~(BIT1+BIT3+BIT5);
            break;
        case 8:
            P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 9:
            P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
    }
}

void show_registr(registr) {   // сопоставление ножек управления регистра
    switch (registr) {
        case 4:
            P1OUT &=~BIT6;
            break;
        case 3:
            P2OUT &=~BIT5;
            break;
        case 2:
            P2OUT &=~BIT4;
            break;
        case 1:
            P2OUT &=~BIT3;
            break;
    }

}

void init_ADC(void) {
    ADC10CTL1 |= CONSEQ_0;        // single channel, single conversion
    ADC10CTL1 |= INCH_0
               + SHS_0            // use ADC10SC bit to trigger sampling
               + ADC10DIV_3    // clock divider = 4
               + ADC10SSEL_3;    // clock source = SMCLK

    ADC10CTL0 |= SREF_0        // reference voltages are Vss and Vcc
               + ADC10SHT_3    // 64 ADC10 clocks for sample and hold time (slowest)
               + ADC10ON
               + ENC;

    ADC10AE0 = BIT0;      // Разрешаем вход АЦП на порту P1.0
}

void ConfigClocks(void)
{
    BCSCTL1 = CALBC1_16MHZ;                     // Set range
    DCOCTL = CALDCO_16MHZ;                      // Set DCO step + modulation
}

void ConfigTimerA(void)
  {
    TACCR0 = 50;    // Обеспечиваем обращение к прерыванию 16MHZ/ 8 / 50 = 40kHz
    TACCTL0 = CCIE;        // Разрешаем прерывание таймера по достижению значения CCR0.
    TACTL = TASSEL_2 + ID_3 + MC_1;
  }


int main(void) {
    WDTCTL = WDTPW | WDTHOLD;        // Stop watchdog timer
    ConfigClocks();
    ConfigTimerA();
    init_led();
    init_ADC();

    _BIS_SR(GIE);

    while (1)
    {
        if (value == 0) {
            value=buffer;  // присваиваем результат к АЦП
            pos = 1;
        }
        digit = value % 10;    /// взятие остатка от деления
        clear_led();
        show_number(digit);    // выбор числа
        show_registr(pos);     // выбор сегмента
        value /= 10;           // деление без остатка. отбпрасываем число которое показали
        pos++;
    }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_CC0 (void)
{
/////////////////////////////////////C Частотой 40кГц работает ADC///////////////////////
    ADC10CTL0 |= ADC10SC; // включаем считвание с ацп
    while (ADC10CTL1 & ADC10BUSY); // ждем пока все считает
    buffer = ADC10MEM;
/////////////////////////////////////////////////////////////////////////////////////////

}



Вопросы:

1.Что делаю неправильно ?

2.В дальнейшем я планирую сделать фильтрацию частоты 15кГц. Т.е. счиитывается с частотой 40кГц а я ППФ спроектирую которsй будет вырезать где то 15кГц +-300Гц. И собственно вопрос. Сколько у меня запас по отсчетам есть микропроконтроллера до следующего считывания АЦП и так чтоб мигание вело себя корректно.

3.
Цитата
Если нужны точные частоты и временные интервалы, то лучше поставить кварцевый резонатор.

Не совсем понял что это за резонатор. Исходя из мануала я вычитал что это какой то генератор. Но в чем он лучше ?

4.Как настроить второе прерывание с другой частотой ? По CC1 сравнивал чтоб в другом прерывании код выполнял. В описании g2553h есть такой пункт. Но что то он не работает.А в мануале не написано как настроить сравнение с CC1.
Сейчас while(1) выводит информацию на индикатор(с прерыванием на АЦП).
НО! Я хочу и не спрашивайте почему (для практики) сделать так чтоб :
-buffer - Значение АЦП меняется с частотой 40кГЦ
-value - то значение что выводится на индкатор (=buffer_2)
-buffer_2 - с частотой 20Гц(примерно) = buffer

пока реализовано это в том же прерывании
Код
    if (i==40000/10) {
        i=0;
        buffer_2=buffer;
    }
    i++;

Но хочу чтоб было в отдельном прерыании, просто для практики

Сообщение отредактировал Niketa - Feb 7 2014, 13:49
Go to the top of the page
 
+Quote Post
Mihey_K
сообщение Feb 7 2014, 14:52
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 156
Регистрация: 27-09-06
Из: Irkutsk
Пользователь №: 20 747



1. Смотрите внимательно юзер мануал

Пример реализации тут в файле msp430g2x33_adc10_13.c.
Запускайте измерения по таймеру и не надо никаких прерываний таймера, а просто по прерыванию АЦП читайте.
2. Тут уж как реализуете. Сложно оценить.
3. Это внешний кварцевый резонатор, имеет очень стабильную частоту, заданную на заводе. Частоты бывают разные до десятков МГц. Наверное слышали выражение "кварцевые часы". Так называют часы, секунды которых задает кварцевый резонатор частотой 32768 Гц. Например без кварца не сделать часы, будильник и прочие критичные ко времени выполнения задачи, чтобы время отсчета таймера не плыло.
4. Пример для справки. Вместо TA0 - TA, т.к. для msp430g2553 таймеры зовутся иначе.
Код
void Init_Timer0 (void){
    TA0CTL = TIMER0_SOURCE_CLK    |    /// Источник тактирования, подставьте своё
            TIMER0_SOURCE_DIV;            /// Предделитель частоты тактирования, подставьте своё
    /// Значение счетчика для сравнения, подставьте своё
    TA0CCR1 = (SMCLK_FREQUENCY_HZ /  TIMER0_DIV_VALUE) / TIMER0_CCR1_RATE_HZ;
    TA0CCR2 = (SMCLK_FREQUENCY_HZ /  TIMER0_DIV_VALUE) / TIMER0_CCR2_RATE_HZ;
    TA0CCTL1 = CCIE;            /// Разрешает прерывание от CCR1
    TA0CCTL2 = CCIE;            /// Разрешает прерывание от CCR2
    /// Сбрасывает флаг, задает режим бесконечного счета, т.е. запускает таймер
    TA0CTL |= TACLR | MC_2;// | TAIE; /// ВАЖНО, прерывание общее от таймера не включаем
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0_ISR( void ) {

    switch(__even_in_range(TA0IV,14))
    {
        case  0:                                     // No interrupt
            break;
        case  0x02:                                 // CCR1
        
                /** Код **/

        case  0x04:                                    // CCR2

                /** Код **/

        case  0x06:                                    // CCR3
            break;
        case  0x08:                                    // CCR4
            break;
        case 0x0A:                                    // CCR5
            break;
        case 0x0C:                                    // CCR6
            break;
        case 0x0E:                                     // overflow
            break;
        default:
            break;
    }
}


Допустимые источники прерываний для своего МК смотреть в юзер мануале в разделе 12.3.5 TAIV, Timer_A Interrupt Vector Register.

Сообщение отредактировал Mihey_K - Feb 7 2014, 14:54


--------------------
Блог о разработке на CC430, SIM900, GPS, ARM и не только...
Go to the top of the page
 
+Quote Post
Niketa
сообщение Feb 7 2014, 17:13
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



1. Я знаю что что неправильно АЦП включать в прерывании.
Но это сделано для того чтоб я в нем мог математические операции по фильтрации сделать
Вот тут сразу вопрос.
Как посчитать правильно сколько тактов работы проца у меня между прерываниями и сколько тактов работы проца занимает один проход мигания

2. ясно

3. Частота маловата. в комплекте есть такой генератор.

4. Огромное спасибо.
Go to the top of the page
 
+Quote Post
Mihey_K
сообщение Feb 8 2014, 03:39
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 156
Регистрация: 27-09-06
Из: Irkutsk
Пользователь №: 20 747



Цитата
3. Частота маловата. в комплекте есть такой генератор.
Наверное плохо объяснил - кварцы бывают разных частот, е не только 32768.
Чтобы посчитать кол-во тактов, надо открыть ассемблерный листинг и считать, сколько команд МК будет исполнять. Время выполнения одной команды фиксировано - 1 такт, кроме команд условий и перехода. 1 такт - это 1/Fosc. Лучше написать и потом оптимизировать, чем считать. 16 МГц это большая скорость, думаю не заметите, если конечно не брать тысячи отсчетов


--------------------
Блог о разработке на CC430, SIM900, GPS, ARM и не только...
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 8 2014, 11:46
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Mihey_K @ Feb 8 2014, 08:39) *
Чтобы посчитать кол-во тактов, надо открыть ассемблерный листинг и считать, сколько команд МК будет исполнять. Время выполнения одной команды фиксировано - 1 такт, кроме команд условий и перехода. 1 такт - это 1/Fosc.

Не вводите в заблуждение начинающего! 1111493779.gif Как мне кажется, упоминая об условных командах и переходах, вы путаете (или смешиваете) длину команды (количество слов, занимаемое командой в памяти) и количество машинных циклов ядра, необходимых для исполнения команды. Одноцикловых команд у MSP430 весьма немного - в основном это те команды, которые работают исключительно с регистрами. Большинство же команд (даже некоторые из тех, которые занимают в памяти всего одно слово) выполняются за 2-6 циклов. Таблицы с описанием команд, их длиной и количеством циклов, есть в User's manual. Поскольку у MSP430 две разновидности ядра - CPU, поддерживающее команды с 16-битной адресацией, и CPUX, поддерживающее команды с 20-битной адресацией, то для ознакомления можно почитать, например, MSP430x2xx Family User's Guide (Rev. J), поскольку там описаны обе разновидности. Узнать время выполнения куска программы можно и в симуляторе. У IAR C-Cpy, например, в составе CPU Registers для этого есть CYCLECOUNTER.
Go to the top of the page
 
+Quote Post
Mihey_K
сообщение Feb 8 2014, 13:17
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 156
Регистрация: 27-09-06
Из: Irkutsk
Пользователь №: 20 747



Rezident, хорошее пояснение. Скажу честно, не заморачивался количеством тактов на команду у MSP :-) это же RISC архитектура, длина команды фиксирована. Другое дело конвейер приходится выгружать при исполнении условных переходов


--------------------
Блог о разработке на CC430, SIM900, GPS, ARM и не только...
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 8 2014, 17:54
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Mihey_K @ Feb 8 2014, 18:17) *
Другое дело конвейер приходится выгружать при исполнении условных переходов

Какой конвейер? Вы опять MSP430 с чем-то (с ARM/Cortex?) путаете?
Go to the top of the page
 
+Quote Post
Niketa
сообщение Feb 9 2014, 22:27
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



АЦП считывает с частотой 40кГц по таймеру

Так же замутил фильтр полосо пропускающий на частоте 13.5кГц +-500Гц

Запрогал алгоритм (предварительно смоделировал его в Матлабе)

Но как оказалось слабый очень msp430g2553

У меня из обработчика прерывания не выходит. Только в нем крутится и поэтому данные на Индикатор не выводятся.

Вроде 16МГц.Я думал успеет посчитать. Всего то 40кГц таймер....

Код
#include <msp430g2553.h>

unsigned int digit; /// переменная для значения 1 разряда
unsigned int pos = 1;    /// номер разряда
unsigned int value;   // переменная для значения выводимого числа
unsigned int buffer;   // переменная для значения ADC
unsigned int buffer_2;   // переменная для значения ADC
unsigned int x1[3],x2[3],x3[3],x4[3],x5[3];
unsigned int y1[3],y2[3],y3[3],y4[3],y5[3];
unsigned int i;   // счетчик

void init_led(void)    // инициализация индикатора (описание смотрите в даташите)
{
    P1REN &= ~(BIT1+BIT2+BIT3+BIT4+BIT5+BIT6);
    P2REN &= ~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5);
    P2REN &= ~(BIT3+BIT4+BIT5);
    P1REN &= ~BIT6;
    P2DIR |= (BIT0+BIT1+BIT2);
    P1DIR |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2OUT |= (BIT0+BIT1+BIT2);
    P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2DIR |=(BIT3+BIT4+BIT5);
    P1DIR |=BIT6;
    P2OUT |=(BIT3+BIT4+BIT5);
    P1OUT |=BIT6;
}

void clear_led(void) {            // обнуление. выключаем все регистры и цифры.
    P2OUT |= (BIT0+BIT1+BIT2);
    P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
    P2OUT |= (BIT3+BIT4+BIT5);
    P1OUT |= BIT6;
}

void show_number(number) {     // сопоставление ножек установки числа
    switch (number) {
        case 0 :
            P1OUT &=~(BIT1+BIT2+BIT3+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 1:
            P1OUT &=~(BIT3+BIT5);
            break;
        case 2:
            P1OUT &=~(BIT1+BIT3+BIT4);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 3:
            P1OUT &=~(BIT1+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
        case 4:
            P1OUT &=~(BIT2+BIT3+BIT4+BIT5);
            break;
        case 5:
            P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
        case 6:
            P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 7:
            P1OUT &=~(BIT1+BIT3+BIT5);
            break;
        case 8:
            P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0+BIT2);
            break;
        case 9:
            P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
            P2OUT &=~(BIT0);
            break;
    }
}

void show_registr(registr) {   // сопоставление ножек управления регистра
    switch (registr) {
        case 4:
            P1OUT &=~BIT6;
            break;
        case 3:
            P2OUT &=~BIT5;
            break;
        case 2:
            P2OUT &=~BIT4;
            break;
        case 1:
            P2OUT &=~BIT3;
            break;
    }

}

void init_ADC(void) {
    ADC10CTL1 |= CONSEQ_0;        // single channel, single conversion
    ADC10CTL1 |= INCH_0
               + SHS_0            // use ADC10SC bit to trigger sampling
               + ADC10DIV_3    // clock divider = 4
               + ADC10SSEL_3;    // clock source = SMCLK

    ADC10CTL0 |= SREF_0        // reference voltages are Vss and Vcc
               + ADC10SHT_3    // 64 ADC10 clocks for sample and hold time (slowest)
               + ADC10ON
               + ENC;

    ADC10AE0 = BIT0;      // Разрешаем вход АЦП на порту P1.0
}

void ConfigClocks(void)
{
    BCSCTL1 = CALBC1_16MHZ;                     // Set range
    DCOCTL = CALDCO_16MHZ;                      // Set DCO step + modulation
}

void ConfigTimerA(void)
  {
    TACCR0 = 50;    // Обеспечиваем обращение к прерыванию 16MHZ/ 8 / 50 = 40kHz
    TACCTL0 = CCIE;        // Разрешаем прерывание таймера по достижению значения CCR0.
    TACTL = TASSEL_2 + ID_3 + MC_1;
  }


int main(void) {
    WDTCTL = WDTPW | WDTHOLD;        // Stop watchdog timer
    ConfigClocks();
    ConfigTimerA();
    init_led();
    init_ADC();

    _BIS_SR(GIE);

    while (1)
    {
        if (value == 0) {
            value=buffer_2;  // присваиваем результат к АЦП
            pos = 1;
        }
        digit = value % 10;    /// взятие остатка от деления
        clear_led();
        show_number(digit);    // выбор числа
        show_registr(pos);     // выбор сегмента
        value /= 10;           // деление без остатка. отбпрасываем число которое показали
        pos++;
    }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_CC0 (void)
{
/////////////////////////////////////C Частотой 40кГц работает ADC///////////////////////
    ADC10CTL0 |= ADC10SC; // включаем считвание с ацп
    while (ADC10CTL1 & ADC10BUSY); // ждем пока все считает
/////////////////////////////////////////////////////////////////////////////////////////

    x1[2]=x1[1];
    x1[1]=x1[0];
    x1[0]=ADC10MEM;

                   y1[0]=(5*x1[0]+6*x1[1]+5*x1[2]-10*y1[1]-8*y1[2])/8;
    x2[0]=y1[0];
    x2[1]=y1[1];
    x2[2]=y1[2];
    y1[2]=y1[1];
    y1[1]=y1[0];

                    y2[0]=(5*x2[0]+4*x2[1]+5*x2[2]-7*y2[1]-8*y2[2])/8;
    x3[0]=y2[0];
    x3[1]=y2[1];
    x3[2]=y2[2];
    y2[2]=y2[1];
    y2[1]=y2[0];


                    y3[0]=(3*x3[0]+5*x3[1]+3*x3[2]-9*y3[1]-7*y3[2])/8;
    x4[0]=y3[0];
    x4[1]=y3[1];
    x4[2]=y3[2];
    y3[2]=y3[1];
    y3[1]=y3[0];


                    y4[0]=(3*x4[0]+2*x4[1]+3*x4[2]-7*y4[1]-7*y4[2])/8;
    x5[0]=y4[0];
    x5[1]=y4[1];
    x5[2]=y4[2];
    y4[2]=y4[1];
    y4[1]=y4[0];

                    y5[0]=(1*x5[0]+0*x5[1]-1*x5[2]-8*y5[1]-6*y5[2])/8;
    y5[2]=y5[1];
    y5[1]=y5[0];

    buffer=y5[0];

    if (i==40000/10) {
        i=0;
        buffer_2=buffer;
    }
    i++;
}

Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 10 2014, 03:46
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Niketa @ Feb 10 2014, 03:27) *
АЦП считывает с частотой 40кГц по таймеру

Вы используете программный запуск преобразования АЦП. Если хотите, чтобы был аппаратный запуск по таймеру, то измените настройки АЦП. Вам Mihey_K уже указывал на этот способ в сообщении выше.
Цитата(Niketa @ Feb 10 2014, 03:27) *
Но как оказалось слабый очень msp430g2553

У меня из обработчика прерывания не выходит. Только в нем крутится и поэтому данные на Индикатор не выводятся.

Вроде 16МГц.Я думал успеет посчитать. Всего то 40кГц таймер....

Дык, а что вы ожидали? У вас же прямо в прерывании таймера ожидается готовность АЦП. Зачем??? Либо проверяйте готовность результата опросом флага ADC10IFG прямо в main-е, либо уберите проверку ADC10BUSY из обработчика прерывания таймера. Вообще функции обработки прерываний должны быть как можно короче. Вам весь функционал свободно можно перенести в main. А в прерывании от АЦП всего лишь считывать результат в буфер и устанавливать свой программый флаг о готовности этого результата. Раз нужна синхронизация от таймера, то настройте работу АЦП на запуск преобразования от этого таймера. Тогда результаты преобразований вы будете получать с частотой периода работы таймера, но в прерывании от АЦП.
Go to the top of the page
 
+Quote Post
Mihey_K
сообщение Feb 10 2014, 06:41
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 156
Регистрация: 27-09-06
Из: Irkutsk
Пользователь №: 20 747



Ёшкин кот, зачем математику-то всю в прерывание запихали. Делайте проходом: завести буфер, в него в прерывании класть измерения до тех пор, пока переменная счетчик не достигнет нужной выборки, выставляете переменную флаг готовности данных в прерывании. В программе опрашиваете все время этот флаг. Как только он установлен, обсчитываете, выдаете на экран, сбрасываете флаг и по новой накапливаете данные в прерывании. На время обсчета можно АЦП остановить. Или завести 2 буфера, в один класть данные АЦП, второй обсчитывать, потом менять их местами.


--------------------
Блог о разработке на CC430, SIM900, GPS, ARM и не только...
Go to the top of the page
 
+Quote Post
Niketa
сообщение Feb 15 2014, 20:43
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



Так.Не думал что вернусь в тему,но увы проблемы все такие есть.
После длительной паузы опять сел дорабаывать прогу.

И так что я имею.

Таймер - 40кГц
АЦП по прерыванию счиывает данные.
В обработчике эти данные я забираю. И с меньше частотой вывожу на Индикатор.
Программа работает.

CODE

#include <msp430g2553.h>

unsigned int digit; /// переменная для значения 1 разряда
unsigned int pos = 1; /// номер разряда
unsigned int value; // переменная для значения выводимого числа
unsigned int buffer; // переменная для значения ADC
unsigned int buffer_2; // переменная для значения ADC
unsigned int i; // счетчик
unsigned int x1[3]=0;
unsigned int y1[3]=0,y2[3]=0,y3[3]=0,y4[3]=0,y5[3]=0;

void init_led(void) // инициализация индикатора (описание смотрите в даташите)
{
P1REN &= ~(BIT1+BIT2+BIT3+BIT4+BIT5+BIT6);
P2REN &= ~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5);
P2REN &= ~(BIT3+BIT4+BIT5);
P1REN &= ~BIT6;
P2DIR |= (BIT0+BIT1+BIT2);
P1DIR |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2DIR |=(BIT3+BIT4+BIT5);
P1DIR |=BIT6;
P2OUT |=(BIT3+BIT4+BIT5);
P1OUT |=BIT6;
}

void clear_led(void) { // обнуление. выключаем все регистры и цифры.
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT3+BIT4+BIT5);
P1OUT |= BIT6;
}

void show_number(number) { // сопоставление ножек установки числа
switch (number) {
case 0 :
P1OUT &=~(BIT1+BIT2+BIT3+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 1:
P1OUT &=~(BIT3+BIT5);
break;
case 2:
P1OUT &=~(BIT1+BIT3+BIT4);
P2OUT &=~(BIT0+BIT2);
break;
case 3:
P1OUT &=~(BIT1+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 4:
P1OUT &=~(BIT2+BIT3+BIT4+BIT5);
break;
case 5:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 6:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 7:
P1OUT &=~(BIT1+BIT3+BIT5);
break;
case 8:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 9:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
}
}

void show_registr(registr) { // сопоставление ножек управления регистра
switch (registr) {
case 4:
P1OUT &=~BIT6;
break;
case 3:
P2OUT &=~BIT5;
break;
case 2:
P2OUT &=~BIT4;
break;
case 1:
P2OUT &=~BIT3;
break;
}

}

void init_ADC(void) {
ADC10CTL1 |= CONSEQ_2; // Циклический,одноканальный
ADC10CTL1 |= INCH_0 //A0
+ SHS_2; // Модуль вывода 0 Таймера А

ADC10CTL0 |= SREF_0 // Опорные Vcc Vss
+ ADC10SHT_3 // 64 такта ADC10CLK
+ ADC10ON //Модуль ADC10 включён
+ ENC //Работа ADC10 разрешена
+ ADC10IE; //Прерывание разрешено

ADC10AE0 = BIT0; // Разрешаем вход АЦП на порту P1.0
}

void ConfigClocks(void)
{
BCSCTL1 = CALBC1_16MHZ; // Set range
DCOCTL = CALDCO_16MHZ; // Set DCO step + modulation
}

void ConfigTimerA(void)
{
TA0CCR0 = 400; // Обеспечиваем обращение к прерыванию 16MHZ/ 400 = 40000 Hz
TA0CCTL0 = OUTMOD_2; // Режим работы модуля вывода. "Переключение"
TA0CTL = TASSEL_2 //SMCLK
+ MC_1 //Прямой счёт (таймер считает от 0000h до TACCR0)
+ ID_0; // и Делитель 1
}


int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ConfigClocks();
ConfigTimerA();
init_led();
init_ADC();

_BIS_SR(GIE); // Разрешаем прерывание

while (1)
{

//ТУТ ПОКА ПУСТО

}
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{

buffer=ADC10MEM; // с частотой 40000 гц берем значение с ацп

//C с частотой 200Гц выводим на экран каждую цифру
i++;
if (i==40000/200) {
i=0;
if (value == 0) {
value=buffer; // присваиваем результат к АЦП
pos = 1;
}
digit = value % 10; /// взятие остатка от деления
clear_led();
show_number(digit); // выбор числа
show_registr(pos); // выбор сегмента
value /= 10; // деление без остатка. отбпрасываем число которое показали
pos++;
}

}



Но вот куда добавить математику фильтрации?

Запихнул ее в While(1) в основную прогу с флагом.Если все правильно понял - как только данные считались - выполняется то что в цикле флага.

CODE
#include <msp430g2553.h>

unsigned int digit; /// переменная для значения 1 разряда
unsigned int pos = 1; /// номер разряда
unsigned int value; // переменная для значения выводимого числа
unsigned int buffer; // переменная для значения ADC
unsigned int buffer_2; // переменная для значения ADC
unsigned int i; // счетчик
unsigned int x1[3]=0;
unsigned int y1[3]=0,y2[3]=0,y3[3]=0,y4[3]=0,y5[3]=0;

void init_led(void) // инициализация индикатора (описание смотрите в даташите)
{
P1REN &= ~(BIT1+BIT2+BIT3+BIT4+BIT5+BIT6);
P2REN &= ~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5);
P2REN &= ~(BIT3+BIT4+BIT5);
P1REN &= ~BIT6;
P2DIR |= (BIT0+BIT1+BIT2);
P1DIR |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2DIR |=(BIT3+BIT4+BIT5);
P1DIR |=BIT6;
P2OUT |=(BIT3+BIT4+BIT5);
P1OUT |=BIT6;
}

void clear_led(void) { // обнуление. выключаем все регистры и цифры.
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT3+BIT4+BIT5);
P1OUT |= BIT6;
}

void show_number(number) { // сопоставление ножек установки числа
switch (number) {
case 0 :
P1OUT &=~(BIT1+BIT2+BIT3+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 1:
P1OUT &=~(BIT3+BIT5);
break;
case 2:
P1OUT &=~(BIT1+BIT3+BIT4);
P2OUT &=~(BIT0+BIT2);
break;
case 3:
P1OUT &=~(BIT1+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 4:
P1OUT &=~(BIT2+BIT3+BIT4+BIT5);
break;
case 5:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 6:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 7:
P1OUT &=~(BIT1+BIT3+BIT5);
break;
case 8:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 9:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
}
}

void show_registr(registr) { // сопоставление ножек управления регистра
switch (registr) {
case 4:
P1OUT &=~BIT6;
break;
case 3:
P2OUT &=~BIT5;
break;
case 2:
P2OUT &=~BIT4;
break;
case 1:
P2OUT &=~BIT3;
break;
}

}

void init_ADC(void) {
ADC10CTL1 |= CONSEQ_2; // Циклический,одноканальный
ADC10CTL1 |= INCH_0 //A0
+ SHS_2; // Модуль вывода 0 Таймера А

ADC10CTL0 |= SREF_0 // Опорные Vcc Vss
+ ADC10SHT_3 // 64 такта ADC10CLK
+ ADC10ON //Модуль ADC10 включён
+ ENC //Работа ADC10 разрешена
+ ADC10IE; //Прерывание разрешено

ADC10AE0 = BIT0; // Разрешаем вход АЦП на порту P1.0
}

void ConfigClocks(void)
{
BCSCTL1 = CALBC1_16MHZ; // Set range
DCOCTL = CALDCO_16MHZ; // Set DCO step + modulation
}

void ConfigTimerA(void)
{
TA0CCR0 = 400; // Обеспечиваем обращение к прерыванию 16MHZ/ 400 = 40000 Hz
TA0CCTL0 = OUTMOD_2; // Режим работы модуля вывода. "Переключение"
TA0CTL = TASSEL_2 //SMCLK
+ MC_1 //Прямой счёт (таймер считает от 0000h до TACCR0)
+ ID_0; // и Делитель 1
}


int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ConfigClocks();
ConfigTimerA();
init_led();
init_ADC();

_BIS_SR(GIE); // Разрешаем прерывание

while (1)
{
while ((ADC10CTL0 & ADC10IFG))
{
x1[0]=buffer; // входные данные с АЦП

y1[0]=(9*x1[0]+13*x1[1]+9*x1[2]-20*y1[1]-15*y1[2])/16;
y2[0]=(9*y1[0]+8*y1[1]+9*y1[2]-15*y2[1]-15*y2[2])/16;
y3[0]=(6*y2[0]+9*y2[1]+6*y2[2]-18*y3[1]-14*y3[2])/16;
y4[0]=(6*y3[0]+4*y3[1]+6*y3[2]-15*y4[1]-14*y4[2])/16;
y5[0]=(2*y4[0]+0*y4[1]-2*y4[2]-16*y5[1]-13*y5[2])/16;

buffer_2=y5[0];//

x1[2]=x1[1];
x1[1]=x1[0];
y1[2]=y1[1];
y1[1]=y1[0];
y2[2]=y2[1];
y2[1]=y2[0];
y3[2]=y3[1];
y3[1]=y3[0];
y4[2]=y4[1];
y4[1]=y4[0];
y5[2]=y5[1];
y5[1]=y5[0];

}

}
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{

buffer=ADC10MEM; // с частотой 40000 гц берем значение с ацп

//C с частотой 200Гц выводим на экран каждую цифру
i++;
if (i==40000/200) {
i=0;
if (value == 0) {
value=buffer_2; // присваиваем результат к АЦП
pos = 1;
}
digit = value % 10; /// взятие остатка от деления
clear_led();
show_number(digit); // выбор числа
show_registr(pos); // выбор сегмента
value /= 10; // деление без остатка. отбпрасываем число которое показали
pos++;
}

}



Но вот загвостка.
Я подаю на АЦП постоянный сигнал. АЧХ постоянного сигнала очевидна.Если я фильтрую частоту 13700 - то мне на выходе должен падать 0.
А вместо этого я получаю число 1456 +- небольшие помехи из за того что АЦП сам снимает с небольшими флуктуациями...

Фильтр в МАТЛАБЕ проектировал и там все тип топ.


Может с типами проблема. Или с тем что беззнаковые переменные использую....
А то мне кажется у меня в минус значения уходят....или нет....

Если меня с UNSIGNET INT на INT - то вроде похоже на правду , но проходит цикла 5-6 и больше в цикл математики не заходит...
В дебагере вижу что ацп считывает, но в математику не заходит.


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Короче решил математику в обработчик запихнуть.вроде успевает считать.все тип топ.

ВОПРОС - Когда выполняется код из обоаботчика - таймер пересает считать ? нет ли из за этого сбивки по частоте ?

CODE
#include <msp430g2553.h>

int digit; /// переменная для значения 1 разряда
unsigned int pos = 1; /// номер разряда
int value; // переменная для значения выводимого числа
int buffer; // переменная для значения ADC
int buffer_2; // переменная для значения ADC
unsigned int i; // счетчик
int x1[3]=0;
int y1[3]=0,y2[3]=0,y3[3]=0,y4[3]=0,y5[3]=0;

void init_led(void) // инициализация индикатора (описание смотрите в даташите)
{
P1REN &= ~(BIT1+BIT2+BIT3+BIT4+BIT5+BIT6);
P2REN &= ~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5);
P2REN &= ~(BIT3+BIT4+BIT5);
P1REN &= ~BIT6;
P2DIR |= (BIT0+BIT1+BIT2);
P1DIR |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2DIR |=(BIT3+BIT4+BIT5);
P1DIR |=BIT6;
P2OUT |=(BIT3+BIT4+BIT5);
P1OUT |=BIT6;
}

void clear_led(void) { // обнуление. выключаем все регистры и цифры.
P2OUT |= (BIT0+BIT1+BIT2);
P1OUT |= (BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT |= (BIT3+BIT4+BIT5);
P1OUT |= BIT6;
}

void show_number(number) { // сопоставление ножек установки числа
switch (number) {
case 0 :
P1OUT &=~(BIT1+BIT2+BIT3+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 1:
P1OUT &=~(BIT3+BIT5);
break;
case 2:
P1OUT &=~(BIT1+BIT3+BIT4);
P2OUT &=~(BIT0+BIT2);
break;
case 3:
P1OUT &=~(BIT1+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 4:
P1OUT &=~(BIT2+BIT3+BIT4+BIT5);
break;
case 5:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
case 6:
P1OUT &=~(BIT1+BIT2+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 7:
P1OUT &=~(BIT1+BIT3+BIT5);
break;
case 8:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0+BIT2);
break;
case 9:
P1OUT &=~(BIT1+BIT2+BIT3+BIT4+BIT5);
P2OUT &=~(BIT0);
break;
}
}

void show_registr(registr) { // сопоставление ножек управления регистра
switch (registr) {
case 4:
P1OUT &=~BIT6;
break;
case 3:
P2OUT &=~BIT5;
break;
case 2:
P2OUT &=~BIT4;
break;
case 1:
P2OUT &=~BIT3;
break;
}

}

void init_ADC(void) {
ADC10CTL1 |= CONSEQ_2; // Циклический,одноканальный
ADC10CTL1 |= INCH_0 //A0
+ SHS_2; // Модуль вывода 0 Таймера А

ADC10CTL0 |= SREF_0 // Опорные Vcc Vss
+ ADC10SHT_0 // 64 такта ADC10CLK
+ ADC10ON //Модуль ADC10 включён
+ ENC //Работа ADC10 разрешена
+ ADC10IE; //Прерывание разрешено

ADC10AE0 = BIT0; // Разрешаем вход АЦП на порту P1.0
}

void ConfigClocks(void)
{
BCSCTL1 = CALBC1_16MHZ; // Set range
DCOCTL = CALDCO_16MHZ; // Set DCO step + modulation
}

void ConfigTimerA(void)
{
TA0CCR0 = 400; // Обеспечиваем обращение к прерыванию 16MHZ/ 400 = 40000 Hz
TA0CCTL0 = OUTMOD_2; // Режим работы модуля вывода. "Переключение"
TA0CTL = TASSEL_2 //SMCLK
+ MC_1 //Прямой счёт (таймер считает от 0000h до TACCR0)
+ ID_0; // и Делитель 1
}


int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ConfigClocks();
ConfigTimerA();
init_led();
init_ADC();

_BIS_SR(GIE); // Разрешаем прерывание

while (1)
{
//while (!(ADC10CTL0 & ADC10IFG));
}
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{

buffer=ADC10MEM; // с частотой 40000 гц берем значение с ацп

x1[0]=buffer; // входные данные с АЦП

y1[0]=(5*x1[0]+6*x1[1]+5*x1[2]-10*y1[1]-8*y1[2])/8;
y2[0]=(5*y1[0]+4*y1[1]+5*y1[2]-7*y2[1]-8*y2[2])/8;
y3[0]=(3*y2[0]+5*y2[1]+3*y2[2]-9*y3[1]-7*y3[2])/8;
y4[0]=(3*y3[0]+2*y3[1]+3*y3[2]-7*y4[1]-7*y4[2])/8;
y5[0]=(1*y4[0]+0*y4[1]-1*y4[2]-8*y5[1]-6*y5[2])/8;

buffer_2=y5[0];//

x1[2]=x1[1];
x1[1]=x1[0];
y1[2]=y1[1];
y1[1]=y1[0];
y2[2]=y2[1];
y2[1]=y2[0];
y3[2]=y3[1];
y3[1]=y3[0];
y4[2]=y4[1];
y4[1]=y4[0];
y5[2]=y5[1];
y5[1]=y5[0];

//C с частотой 200Гц выводим на экран каждую цифру
i++;
if (i==40000/200) {
i=0;
if (value == 0) {
value=abs(buffer_2); // присваиваем результат к АЦП
pos = 1;
}
digit = value % 10; /// взятие остатка от деления
clear_led();
show_number(digit); // выбор числа
show_registr(pos); // выбор сегмента
value /= 10; // деление без остатка. отбпрасываем число которое показали
pos++;
}

}


Сообщение отредактировал Niketa - Feb 16 2014, 12:53
Go to the top of the page
 
+Quote Post
Niketa
сообщение Feb 16 2014, 13:13
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 1-02-14
Пользователь №: 80 290



///////////////////////////////////////////////////////////
еще как сюда уарт прикрутить ? чтоб на комп еще слать значения
В уже существующее прерывание от АЦП засунуть ?
или новое прерывание написать для уарта ?
Есть хоть один урок или пример нормальный ?

Сообщение отредактировал Niketa - Feb 16 2014, 20:12
Go to the top of the page
 
+Quote Post
PRidon
сообщение Feb 17 2014, 07:22
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 8-10-12
Пользователь №: 73 855



Куча примеров на сайте TI. Прям под твой МК. И уарт настраивать весьма просто.
А по работа с ним: есть 2 прерывания. Одно на прием, срабатывает когда пришел байт, считать можно в RXBUF. Другое на передачу, срабатывает когда передающий буфер TXBUF пустой.
И да, один момент, если по приему все просто, то передача организована след. образом: Есть сдвиговый регистр, откуда твой байт выдается на ножки МК, а в этот сдвиговый регистр байт попадает из TXBUF. Т.е. ты просто кидаешь байт в TXBUF, а дальше он сам переправляет его в сдвиговый регистр и выдает в UART.
Передача по уарту медленная штука, так что в прерывании просто закидываешь байт, и если это последний для передачи - выключаешь прерывание.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 3rd August 2025 - 10:26
Рейтинг@Mail.ru


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