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

 
 
 
Reply to this topicStart new topic
> AD7476 и ATmega32, Подключение ADC по SPI интерфейсу
B_Sergey_N
сообщение Aug 21 2008, 21:23
Сообщение #1


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



Всем привет.
Подключил АЦП 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 ( 942.18 килобайт ) Кол-во скачиваний: 59
 
Go to the top of the page
 
+Quote Post
aesok
сообщение Aug 21 2008, 21:35
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(B_Sergey_N @ Aug 22 2008, 01:23) *
Знаю, что не правильно, поэтому спрашиваю. Буду очень признателен за помощь, а то уже не знаю сколько перечитал всего, так и не разобрался.
Было бы совсем не плохо, если бы выложили код.


Порочтите "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

Анатолий.
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Aug 22 2008, 13:08
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



попробуйте, для начала, поуправлять АЦП "в ручную" - подёргать битики 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;
}
Go to the top of the page
 
+Quote Post
GDI
сообщение Aug 22 2008, 14:16
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



Цитата
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;


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
B_Sergey_N
сообщение Aug 23 2008, 00:39
Сообщение #5


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



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

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

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

Спасибо, Сергей.
Go to the top of the page
 
+Quote Post
SysRq
сообщение Aug 23 2008, 18:23
Сообщение #6


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(GDI @ Aug 22 2008, 18:16) *
Примерно так:
Код
//...
adc_in = (short)SPDR << 8;
//...
adc_in |= SPDR;


А почему бы не вот так?
Код
//...
*(((unsigned char *) &adc_in) + 1) = SPDR;
//...
*((unsigned char *) &adc_in) = SPDR;
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Aug 24 2008, 08:12
Сообщение #7


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(SysRq @ Aug 23 2008, 22:23) *
А почему бы не вот так?
Код
//...
*(((unsigned char *) &adc_in) + 1) = SPDR;
//...
*((unsigned char *) &adc_in) = SPDR;

Потому что контроллеры и процессоры бывают как Little-Endian, так и Big-Endian,
а Ваш вариант этого совсем не учитывает - следовательно это unsafe:).
Посмотрите для самообразования: Порядок байтов — Википедия


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
SysRq
сообщение Aug 24 2008, 11:55
Сообщение #8


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(demiurg_spb @ Aug 24 2008, 12:12) *
Потому что контроллеры и процессоры бывают как Little-Endian, так и Big-Endian,
а Ваш вариант этого совсем не учитывает...

Ну само собой! При попытке чего-то оптимизировать теряем в универсальности.. sad.gif
Go to the top of the page
 
+Quote Post
GDI
сообщение Aug 25 2008, 06:33
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



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

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


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Aug 25 2008, 06:47
Сообщение #10


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(SysRq @ Aug 24 2008, 15:55) *
Ну само собой! При попытке чего-то оптимизировать теряем в универсальности.. sad.gif

Что называется, почувствуйте разницу.
Я не думал что будет ТАКОЕ:
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


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
B_Sergey_N
сообщение Aug 25 2008, 08:51
Сообщение #11


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



Цитата(GDI @ Aug 25 2008, 10:33) *
МК у вас выступает как мастер, значит именно он должен генерировать клоки, а чтобы он начал это делать на до что то поместить в регистр данных SPI, т.е. в SPDR. Клоки при этом генерируются аппаратно и все времянки определяются настройками SPI. А если вы сами будете дергать ногой CLK то это будет уже программный SPI и вам самому надо будет организовывать считывание битов с MISO и размещение их в какой то переменной, что работает намного медленнее аппаратной реализации.


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

С Уважением, Сергей.
Go to the top of the page
 
+Quote Post
SysRq
сообщение Aug 25 2008, 17:24
Сообщение #12


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(demiurg_spb @ Aug 25 2008, 10:47) *
Я не думал что будет ТАКОЕ...

Вот и я как-то посмотрел какое там чудовисче генерится, и решил что как-то не позволительно делать такое. Ну а об неуниверсальности должен помнить программер, иначе зачем он вообще нужен?..
Go to the top of the page
 
+Quote Post
B_Sergey_N
сообщение Aug 31 2008, 10:47
Сообщение #13


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



Хорошо, спасибо большое за подсказки.
Возник теперь такой вопрос:
Как передать 16-ти разрядное число по USARTу, можно так настроить USART, что бы он понимал что передается одно число 2-мя байтами?
Это для того что бы на приемной стороне не надо было самому склеивать два полученных байта в одно число.
По USARTу подключен Bluetooth к атмеге, передача происходит фактически по беспроводному COM порту на комп.
Go to the top of the page
 
+Quote Post
Dmitry_Od
сообщение Aug 31 2008, 11:32
Сообщение #14


Участник
*

Группа: Свой
Сообщений: 58
Регистрация: 17-01-07
Из: Одесса
Пользователь №: 24 523



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


--------------------
http://odessa-intern.myminicity.com/ - эдакий муравейник
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 19th July 2025 - 23:55
Рейтинг@Mail.ru


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