Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Доброго всем времени суток. Прошу помочь с одной проблемой. Нужно получить оцифрованный сигнал с АЦП AD7730 на МК ATmega8. Когда использовал встроенный в МК АЦП проблем почти не было, но был большой минус - мало разрядов. Поэтому поставил 24-х разрядный AD7730. Развел согласно даташиту. Кварц 2,4576 МГц шкворчит. Сигнал с тензомоста (2 мВ/В при питании 12 В) усиливаю ОУ ОР275 примерно в 850 раз (если будет сильно шуметь, уменьшу усиление, пока не суть). На ноге CS АЦП, соединенной с PB2/SS МК логический 0. АЦП подключен к аппаратному SPI ATmega. Вся проблема в написании программы записи/чтения регистров АЦП и получению/отправке данных по SPI. В интернете, к сожалению, конкретного ответа или хотя бы совета не нашел. Даташиты перепрочитал, но вот как именно это реализуется в программной среде Си, где записываются регистры АЦП (в основной программе или в прерывании), как потом считать байт пришедший с DOUT, не знаю. Инициализирую SPI: SPCR=0xDB; //прерывание по SPI разрешено, активация SPI, первым передается старший разряд байта данных, //MSTR=1 - МК ведущий, импульсы отриц.полярности, выборка по спадающему фронту, //обработка данных по переднему фронту SCK, деление частоты на 128 SPSR=0x00; // Вызываю прерывание: interrupt [SPI_STC] void spi_isr(void) { data=SPDR; } Прошу помочь кодом (очень сильно желательно на Си) или советом.
функции инициализации МК ведомым и функция приема байта void SPI_SlaveInit() { DDR_SPI = (1<<DD_MISO); //настраиваем на выход MISO, остальные на вход SPCR = (1<<SPE); //включаем SPI } //функция приема байта char SPI_SlaveReceive() { while(!(SPSR & (1<<SPIF))); //ждем если занят return SPDR; //возвращаем байт данных }
После приема каждого байта измеренных данных лепим из восьмиразрядных переменных двадцатичетырехразрядную:
Код:
long int ADC_data; ADC_data=ADC_data<<8; ADC_data |= SPDR;
Все это дело повторяем три раза (можно в цикл встроить, тут уж разберетесь). После этого с данными уже можно будет работать. По поводу работы с регистрами АЦП. Все там делается через Communications register, доступ к которому получаем сразу же после подачи питания. Естественно, нам нужно полностью его инициализировать - выбрать режим, выбрать канал измерений, и т.д., и т.п. (все это подробно описано в даташите, повторяться не буду). Для получения доступа к тому или иному регистру мы должны передать определенные значения битов RS2,RS1,RS0. К примеру, настроим регистр Mode register, используя функции, приведенные выше:
Код:
SPI_MasterTransmit(0x02); //пишем 0b00000010 в Status register, получая доступ к Mode Register SPI_MasterTransmit(0x4F); //передаем старший байт настроек регистра SPI_MasterTransmit(0xB0); //передаем младший байт настроек регистра
Ну вот примерно как-то так, думается мне. Если не нужно постоянно менять каналы и настройки АЦП, то достаточно единожды произвести инициализацию АЦП, и спокойненько себе работать. Но в прерывание не стоит ничего подобного пихать. Прерывание должно быть максимально кратким.
_________________ pavel_cydenov: Вобще я праAVRославный человек. Но и про ислARM слышал много хорошего ) MrYuran: Самые ортодоксальные — это PICудеи ) Katz: Не, 51-ники. )
Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Что-то пока совсем не то, что нужно. В основной программе void main инициализирую передачу и получение даных в и из регистров: SPI_MasterInit(); SPI_MasterTransmit(0x02); //доступ в mode register SPI_MasterTransmit(0x31); //старший байт: непрерывное преобразование, //униполярный размах входн.напряж, передавать 24 бита данных,
SPI_MasterTransmit(0x90); //младший байт: опорное напр.=5В, диапазон вход.напр.=от 0 до 20мВ, //вкл.внеш.резонатор, выкл.перегорание контактов, канал AIN1(+) AIN1(-)
SPI_MasterTransmit(0x21); //непрерывное считывание из регистра DATA SPI_SlaveInit();
Прерыванием от таймера Т0 задаю тактирующие импульсы на ноге SCK:
В прерывании от SPI считываю из SPDR: interrupt [SPI_STC] void spi_isr(void) { SPI_SlaveReceive(); }
Прерыванием от Т1 мигаю светодиодом, считываю данные из SPDR и передаю на экран LCD: interrupt [TIM1_OVF] void timer1_ovf_isr(void) //процедура прерывания от таймера Т1 { TCNT1H=0xFC; //установить начальное //раз в 0,1 сек TCNT1L=0xF2; //состояние таймера Т1 PORTB^=(0x01); //мигает светодиод ADC_data = SPDR; //считываю из регистра данных lcd_clear(); lcd_gotoxy( 0,0 ); sprintf( lcd_buffer,"U= %u",ADC_data ); lcd_gotoxy( 0,0 ); lcd_puts( lcd_buffer );
delay_ms( 10 ); return; }
В итоге у меня на экране LCD чаще всего ноль, либо десятиричное 33 (это шестнадцитиричное 21, которое должно было задать непрерывное считывание) либо переполенный байт 255. Где ошибся в коде?
Chipselect - это раз, и еще что-то не вижу, как Вы обрабатываете принятые данные. Ведь у Вас переменная, приходящая от АЦП - 24-битная. То есть Вам нужно три раза принять восьмиразрядную посылку, приходящую от АЦП, и из этих посылок получить истинное число в двоичном виде. Может, в данной случае это и не столь критично, но все же внимание на это обратите.
_________________ pavel_cydenov: Вобще я праAVRославный человек. Но и про ислARM слышал много хорошего ) MrYuran: Самые ортодоксальные — это PICудеи ) Katz: Не, 51-ники. )
Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Всем спасибо за ответы. CS постоянно в логическом нуле. АЦП один и постоянно выбирать его нет смысла. Однажды его инициализировал CS в ноль и всё. По крайней мере так я понял из даташита. Немного изменил прием 24-х битного значения: interrupt [TIM1_OVF] void timer1_ovf_isr(void) //процедура прерывания от таймера Т1 { TCNT1H=0xFC; //установить начальное TCNT1L=0xF2; //состояние таймера Т1 PORTB^=(0x01); b++; //инкремент ADC_data=ADC_data<<8; //сразу сдвигаю на 8 разрядов влево ADC_data = SPDR; //в младшие записываю данные if (b==3) //проверяю условие трех отсчетов { lcd_clear(); lcd_gotoxy( 0,0 ); sprintf( lcd_buffer,"U= %u",ADC_data ); lcd_gotoxy( 0,0 ); lcd_puts( lcd_buffer ); b=0; } return; }
Громоздко конечно для прерывания, но пока ничего лучше не придумал. Теперь разбираюсь с тактирующим импульсом с ноги МК SCK на ногу АЦП SCLK. Может за 0,01 сек он отправлять не успевает. Пока результат тот же, т.е. на экране чушь.
CS постоянно в логическом нуле. АЦП один и постоянно выбирать его нет смысла. Однажды его инициализировал CS в ноль и всё.
Тогда есть смысл его вообще заземлить, но раз есть возможность управлять, лучше ее использовать.
Lotus13 писал(а):
Теперь разбираюсь с тактирующим импульсом с ноги МК SCK на ногу АЦП SCLK. Может за 0,01 сек он отправлять не успевает.
Если используется RC-генератор на 8 МГц, и делитель на 128, получается тактовая SPI: 8МГц/128=62500Гц, для передачи 4х байт (1 байт команда чтения+3байта данных) нужно: 62500^-1*8*4=0.0005с
Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Резонатор на МК внешний, 8МГц. С ним проблем нет. Выяснил, что сигналы с RDY от АЦП должны показывать микроконтроллеру, идет передача, калибровка или как раз передача завершена. У меня же на RDY постоянно 5В, т.е. лог.1, либо он так долго этот бит передает, либо калибруется. RDY не переводится в 0. На МК эта нога подходит к PD2/INT0, внеш прерывания разрешил, настроил на прерывание по пришедшему низкому уровню. Само собой они не срабатывают (проверил). Кто знаком с AD7730. Подскажите, почему RDY может не выдавать низкого уровня?
Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Всем спасибо. Всё заработало. Главной проблемой была инициализация АЦП. А именно правильно установить фронты тактирующих импульсов с ведущего МК, установить полярность и фазу этих импульсов и соответственно полярность считывания импульсов ведомым АЦП. Всего восемь вариантов получилось. Тут главное не методом подбора, а всё таки почитать. Регистры записываются, данные читаются.
Добрый день! Очень прошу вас помогите мне с запуском и конфигурацией. Написал функции для записи и чтения всех регистров. Работают хорошо. Но прочитать данные с регистра данных никак не получается. То отправляет FFFFFE, то выход AD7730 вовсе переходит в высокоимпедансное состояние. Подскажите какая должна быть последовательность действий? Код инициализации взял из datasheet
Код:
void AD7730_init() {
AD7730_CS=0; //Выбираю АЦП AD7730_write_8bit(0x03); //Собираюсь писать в регистр фильтра AD7730_write_24bit(0x800010); //Пишу в регистр фильтра AD7730_write_8bit(0x04); //Собираюсь писать в регистр АЦП AD7730_write_8bit(0x23); //Пишу в регистр АЦП AD7730_write_8bit(0x02); //Пишу в регистр MODE AD7730_write_16bit(0xB190); //Пишу while(AD7730_RDY ==1) //Жду когда на AD7730_RDY будет 0 { Delay_ms(200); } AD7730_write_8bit(0x02); AD7730_write_16bit(0x9190); //Internal Zero-Scale Calibration for 0 mV to +40 mV Input Range while(AD7730_RDY==1) //Жду когда на AD7730_RDY будет 0 { Delay_ms(200); } AD7730_write_8bit(0x02); AD7730_write_16bit(0x4190); //Starting Continuous Conversions for 0 mV to +40 mV Input Range AD7730_write_8bit(0x21); //Собираюсь читать 24 бит данных AD7730_SDO=0; //ошибки нет, опускаю выход МК(вход AD7730)
Зарегистрирован: Сб май 03, 2014 20:11:44 Сообщений: 1
Рейтинг сообщения:0
Помогите, не как ни получается адекватно заставить работать AD7730 и ATmeag32. При Аппаратном SPI постоянно получаем 65535 (т.е. FF), при Программном SPI значения получаем и даже меняются в зависимости от нажима на тензодатчик, но через пару секунд AD7730 перестает выдавать данные (срыв чтения данных), тоже самое при сильном нажатии на датчик, только быстрее. Как добиться стабильной работы. Так же не понятно как убирать вес тары и калибровать тензодатчик под вес. Буду очень благодарен за любую помощь.
Зарегистрирован: Вт окт 11, 2011 13:17:43 Сообщений: 7 Откуда: г. Томск
Рейтинг сообщения:0
Тут я, однако помочь увы не могу. С тех пор перевелся на ПЛИС и скоростные параллельные АЦП. Про тот проект забыл окончательно, хотя и получил тогда удовлетворительные результаты. Все равно уже код проекта утерян, разве что сама плата где-то еще валяется. Больше, чем описывал я и те, кто мне помогал, в этой теме я сказать не смогу. АЦП удалось запустить, точность измерений составляла около 0,1 %, не удалось обнулять вес тары, как выразился DJCooler сообщением выше, не удалось стабилизировать показания на LCD. Но это в первую очередь связано с ФНЧ фильтром, который я тогда считать не умел, во вторую с тензодатчиком, в третью с кривой программой. Удачи, да прибудет с вами сила.
Всем привет! Раз уж такая тема есть напишу здесь. Работаю с этим АЦП и на нем собрал амперметр. Запустил работает шустро но, в итоге при подаче тока на шунт через некоторое время он начинает плавать. Ноль стоит на месте. В качестве опорника стоит ref192. Напряжение с шунта подается на AIN1+ и AIN1-. Перед входом стоит RC фильтр. 2к2 резисторы и 5мкф кондеры. Может кто знает как мне его подключить чтоб он не плавал?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения