Перейти к содержанию
    

AD7476 и ATmega32

Всем привет.

Подключил АЦП 12 битовый к ATmega32 по SPI. Но никак не могу понять как принимать данные с АЦП.

У SPI есть 8-разрядный сдвиговый регистр, мне же надо принять сразу 12 (точнее 16, но первые 4 бита нули). Каким образом? Как двигать и записывать эти биты. Прикрепляю datasheet АЦП, может кто захочет взглянуть.

 

Инициализация SPI вроде правильна:

// Установить PB5(MOSI), PB7(SCK) как выходы
DDRB    = (1<<PB5)|(1<<PB7)|(1<<PB4);
PORTB   = 0xFF;    

DDRC    = (1 << PC0);   // PС0(/СS) выход
PORTC  |= (1 << PC0);
        
// Включаю SPI в режиме мастер с SCK = CK/4 = 4МГц
        SPCR    = (1<<SPE)|(1<<MSTR)|(1<<CPOL);
        SPSR    = (1<<SPI2X);  // Удваиваю скорость до 8МГц

 

После этого написал так, светодиоды использ. для проверки.

 

       
                while(1)
    {
    PORTC &= ~(1 << 0); // Включаю АЦП
    
    _delay_ms(1);
    
                //while(PINB6 == 0);
    
                while (!(SPSR & (1<<SPIF))); 

    PORTC |= (1 << 0); // Отключил АЦП
                
                if (SPDR <= 256)
            {
                // Мигаю светодиодом
                
                _delay_ms(50);

                PORTA |= (1 << 1);
        
                _delay_ms(500);
        
                PORTA &= ~(1 << 1); 
            }
            else
            {
                 // Подмигиваю
                 
                _delay_ms(50);

                PORTA |= (1 << 2);
        
                _delay_ms(50);
        
                PORTA &= ~(1 << 2); 
            }
                }

 

 

Знаю, что не правильно, поэтому спрашиваю. Буду очень признателен за помощь, а то уже не знаю сколько перечитал всего, так и не разобрался.

Было бы совсем не плохо, если бы выложили код.

 

А и еще, программатор подключен тоже по SPI. Могут ли возникнуть с этим проблемы? На всякий случай отрубаю его от схемы перед подачей сигнала на АЦП.

 

Спасибо, Сергей.

___AD7476_7477_7478.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Знаю, что не правильно, поэтому спрашиваю. Буду очень признателен за помощь, а то уже не знаю сколько перечитал всего, так и не разобрался.

Было бы совсем не плохо, если бы выложили код.

 

Порочтите "AVR151: Setup and use of the SPI"

http://www.atmel.com/dyn/resources/prod_do...nts/doc2585.pdf

И код:

http://www.atmel.com/dyn/resources/prod_documents/AVR151.zip

 

Анатолий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

попробуйте, для начала, поуправлять АЦП "в ручную" - подёргать битики SPI программно.

 

Вот пара моих кусочков кода для разных АЦП - по аналогии попробуйте...

 

 

Для ad7276:

unsigned long BoardReadADC()
{    
    unsigned long val = 0;
    prog_select(targetadc1, 1);

    SCLK_SET();
    SCLK_CLR();

    for (int i = 0; i < 12; ++ i)
    {
        SCLK_SET();
        SCLK_CLR();

        unsigned v = (lpt_readb_status() & 0x08) == 0;
        val = (val << 1) | v;
    }

    prog_select(targetadc1, 0);
    return val;
}

 

Для ad7810

 

void sclk_pulse(void)
{
    SCLK_CLR();
    SCLK_SET();
}

// ADC conversion start signal
void convstart_pulse(void)
{
    prog_select(targetadc1, 1);
    prog_select(targetadc1, 0);
}

unsigned ad7810_read(
    void //unsigned char target    /* addressing to chip */
    )
{    
    unsigned val = 0;
    // ADC conversion start signal
    convstart_pulse();
    //
    for (int i = 0; i < 10; ++ i)
    {
        unsigned v;
        sclk_pulse();
        //
        //v = (PIND & 0x08) != 0;
        v = (lpt_readb_status() & 0x08) == 0;
        val = (val * 2) | v;

    }
    //
    sclk_pulse();
    sclk_pulse();


    return val;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

if (SPDR <= 256)

Это условие никогда не выполнится, потому что SPDR 8и разрядный и максимальное его значение 255 или 0xFF.

 

Вам надо Во первых сперва записать в SPDR любое число(обычно 0xff) чтобы SPI начал передавать клоки подчиненному, после передачи в регистре SPDR вы получите то что вам передал подчиненный, затем содержимое SPDR надо где то сохранить, и повторить передачу(записью в SPDR=255), чтобы получить второй байт от подчиненного, вот теперь вы имеете 2 байта от АЦП(тот что вы сохранили ранее и тот что лежит в SPDR теперь.

 

Примерно так:

short adc_in;
SPDR = 255;
while (!(SPSR & (1<<SPIF)));
adc_in = (short)SPDR << 8;
SPDR = 255;
while (!(SPSR & (1<<SPIF)));
adc_in |= SPDR;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Заработало!!! Всем спасибо, особенно GDI.

 

Но я так и не могу понять, зачем перед тем как что-то принять, надо каждый раз чем-то забивать SPDR?

Неужели только из-за подачи клоков? А я не могу разве просто дергать ногой SCLK и следить за спадом и поднятием фронтов?

 

А и еще, читал что задержки всякие надо делать, между клоками и еще чем-то, хотя они настолько малы, там всего ns какие-то. Вроде без задержек всяких работает.

 

Спасибо, Сергей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Примерно так:

//...
adc_in = (short)SPDR << 8;
//...
adc_in |= SPDR;

 

А почему бы не вот так?

//...
*(((unsigned char *) &adc_in) + 1) = SPDR;
//...
*((unsigned char *) &adc_in) = SPDR;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему бы не вот так?

//...
*(((unsigned char *) &adc_in) + 1) = SPDR;
//...
*((unsigned char *) &adc_in) = SPDR;

Потому что контроллеры и процессоры бывают как Little-Endian, так и Big-Endian,

а Ваш вариант этого совсем не учитывает - следовательно это unsafe:).

Посмотрите для самообразования: Порядок байтов — Википедия

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Потому что контроллеры и процессоры бывают как Little-Endian, так и Big-Endian,

а Ваш вариант этого совсем не учитывает...

Ну само собой! При попытке чего-то оптимизировать теряем в универсальности.. :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но я так и не могу понять, зачем перед тем как что-то принять, надо каждый раз чем-то забивать SPDR?

Неужели только из-за подачи клоков? А я не могу разве просто дергать ногой SCLK и следить за спадом и поднятием фронтов?

МК у вас выступает как мастер, значит именно он должен генерировать клоки, а чтобы он начал это делать на до что то поместить в регистр данных SPI, т.е. в SPDR. Клоки при этом генерируются аппаратно и все времянки определяются настройками SPI. А если вы сами будете дергать ногой CLK то это будет уже программный SPI и вам самому надо будет организовывать считывание битов с MISO и размещение их в какой то переменной, что работает намного медленнее аппаратной реализации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну само собой! При попытке чего-то оптимизировать теряем в универсальности.. :(

Что называется, почувствуйте разницу.

Я не думал что будет ТАКОЕ:

gcc 4.1.2 Os

volatile unsigned short a;
volatile unsigned short b;
volatile unsigned short с;

    a  = (unsigned short)SPDR<<8;  // Hi
  b6:    8f b1           in    r24, 0x0f; 15
  b8:    99 27           eor    r25, r25
  ba:    98 2f           mov    r25, r24
  bc:    88 27           eor    r24, r24
  be:    9e 83           std    Y+6, r25; 0x06
  c0:    8d 83           std    Y+5, r24; 0x05
    a |=  SPDR;                    // Low
  c2:    2d 81           ldd    r18, Y+5; 0x05
  c4:    3e 81           ldd    r19, Y+6; 0x06
  c6:    8f b1           in    r24, 0x0f; 15
  c8:    99 27           eor    r25, r25
  ca:    28 2b           or    r18, r24
  cc:    39 2b           or    r19, r25
  ce:    3e 83           std    Y+6, r19; 0x06
  d0:    2d 83           std    Y+5, r18; 0x05

    *((unsigned char*)&b + 1) = SPDR;  // Hi
  d2:    8f b1           in    r24, 0x0f; 15
  d4:    8a 83           std    Y+2, r24; 0x02
    *((unsigned char*)&b + 0) = SPDR;  // Low
  d6:    8f b1           in    r24, 0x0f; 15
  d8:    89 83           std    Y+1, r24; 0x01

    c = a+b;
  da:    8d 81           ldd    r24, Y+5; 0x05
  dc:    9e 81           ldd    r25, Y+6; 0x06
  de:    29 81           ldd    r18, Y+1; 0x01
  e0:    3a 81           ldd    r19, Y+2; 0x02
  e2:    82 0f           add    r24, r18
  e4:    93 1f           adc    r25, r19
  e6:    9c 83           std    Y+4, r25; 0x04
  e8:    8b 83           std    Y+3, r24; 0x03

 

Так будет лучше, но....

gcc 4.3.0 Os

    a  = (unsigned short)SPDR<<8;  // Hi
  b0:    2f b1           in    r18, 0x0f; 15
  b2:    92 2f           mov    r25, r18
  b4:    80 e0           ldi    r24, 0x00; 0
  b6:    9a 83           std    Y+2, r25; 0x02
  b8:    89 83           std    Y+1, r24; 0x01
    a |=  SPDR;                    // Low
  ba:    29 81           ldd    r18, Y+1; 0x01
  bc:    3a 81           ldd    r19, Y+2; 0x02
  be:    8f b1           in    r24, 0x0f; 15
  c0:    90 e0           ldi    r25, 0x00; 0
  c2:    82 2b           or    r24, r18
  c4:    93 2b           or    r25, r19
  c6:    9a 83           std    Y+2, r25; 0x02
  c8:    89 83           std    Y+1, r24; 0x01

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

МК у вас выступает как мастер, значит именно он должен генерировать клоки, а чтобы он начал это делать на до что то поместить в регистр данных SPI, т.е. в SPDR. Клоки при этом генерируются аппаратно и все времянки определяются настройками SPI. А если вы сами будете дергать ногой CLK то это будет уже программный SPI и вам самому надо будет организовывать считывание битов с MISO и размещение их в какой то переменной, что работает намного медленнее аппаратной реализации.

 

Аа..Все, вот теперь понял, Огромное спасибо!

 

С Уважением, Сергей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не думал что будет ТАКОЕ...

Вот и я как-то посмотрел какое там чудовисче генерится, и решил что как-то не позволительно делать такое. Ну а об неуниверсальности должен помнить программер, иначе зачем он вообще нужен?..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо, спасибо большое за подсказки.

Возник теперь такой вопрос:

Как передать 16-ти разрядное число по USARTу, можно так настроить USART, что бы он понимал что передается одно число 2-мя байтами?

Это для того что бы на приемной стороне не надо было самому склеивать два полученных байта в одно число.

По USARTу подключен Bluetooth к атмеге, передача происходит фактически по беспроводному COM порту на комп.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понадобится самому организовывать протокол передачи данных (2 байта, цепочку байтов...), поскольку usart передает или получает за один кадр до 8 битов информации (без учеты старт-стоповых)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...