АЦП AD7730
АЦП AD7730
Доброго всем времени суток.
Прошу помочь с одной проблемой. Нужно получить оцифрованный сигнал с АЦП 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;
}
Прошу помочь кодом (очень сильно желательно на Си) или советом.
Прошу помочь с одной проблемой. Нужно получить оцифрованный сигнал с АЦП 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;
}
Прошу помочь кодом (очень сильно желательно на Си) или советом.
- Реклама
- SubDia
- Держит паяльник хвостом
- Сообщения: 995
- Зарегистрирован: Сб апр 02, 2011 17:59:22
- Откуда: Город-герой Севастополь
Re: АЦП AD7730
Все, по идее, достаточно несложно.
Для работы используем описанные в Атмеловском аппноуте151 (кажется) функции работы с SPI:
После приема каждого байта измеренных данных лепим из восьмиразрядных переменных двадцатичетырехразрядную:
Все это дело повторяем три раза (можно в цикл встроить, тут уж разберетесь).
После этого с данными уже можно будет работать.
По поводу работы с регистрами АЦП. Все там делается через Communications register, доступ к которому получаем сразу же после подачи питания. Естественно, нам нужно полностью его инициализировать - выбрать режим, выбрать канал измерений, и т.д., и т.п. (все это подробно описано в даташите, повторяться не буду).
Для получения доступа к тому или иному регистру мы должны передать определенные значения битов RS2,RS1,RS0. К примеру, настроим регистр Mode register, используя функции, приведенные выше:
Ну вот примерно как-то так, думается мне.
Если не нужно постоянно менять каналы и настройки АЦП, то достаточно единожды произвести инициализацию АЦП, и спокойненько себе работать. Но в прерывание не стоит ничего подобного пихать. Прерывание должно быть максимально кратким.
Для работы используем описанные в Атмеловском аппноуте151 (кажется) функции работы с SPI:
Код: Выделить всё
#define DDR_SPI DDRB
#define DD_MOSI 3
#define DD_MISO 4
#define DD_SCK 5
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7
//функция передачи байта
void SPI_MasterTransmit(char cData)
{
SPDR = cData; //начинаем передачу
while(!(SPSR & (1<<SPIF))); //ждем пока передача завершится
return;
}
функции инициализации МК ведомым и функция приема байта
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-ники. )

MrYuran: Самые ортодоксальные — это PICудеи )
Katz: Не, 51-ники. )

Re: АЦП AD7730
SubDia, спасибо. Буду пробовать.
Re: АЦП AD7730
Что-то пока совсем не то, что нужно.
В основной программе 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:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0xB2; //раз в 0,01 сек
PORTB^=(0x1<<5);
delay_ms ( 5 );
}
В прерывании от 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.
Где ошибся в коде?
В основной программе 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:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0xB2; //раз в 0,01 сек
PORTB^=(0x1<<5);
delay_ms ( 5 );
}
В прерывании от 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.
Где ошибся в коде?
- Engineer_Keen
- Друг Кота
- Сообщения: 3872
- Зарегистрирован: Пт янв 29, 2010 10:27:40
- Откуда: Москва
Re: АЦП AD7730
Линия CS опускается в 0 во время передачи данных по SPI?
- Реклама
- SubDia
- Держит паяльник хвостом
- Сообщения: 995
- Зарегистрирован: Сб апр 02, 2011 17:59:22
- Откуда: Город-герой Севастополь
Re: АЦП AD7730
Chipselect - это раз, и еще что-то не вижу, как Вы обрабатываете принятые данные.
Ведь у Вас переменная, приходящая от АЦП - 24-битная. То есть Вам нужно три раза принять восьмиразрядную посылку, приходящую от АЦП, и из этих посылок получить истинное число в двоичном виде. Может, в данной случае это и не столь критично, но все же внимание на это обратите.
Ведь у Вас переменная, приходящая от АЦП - 24-битная. То есть Вам нужно три раза принять восьмиразрядную посылку, приходящую от АЦП, и из этих посылок получить истинное число в двоичном виде. Может, в данной случае это и не столь критично, но все же внимание на это обратите.
pavel_cydenov: Вобще я праAVRославный человек. Но и про ислARM слышал много хорошего )
MrYuran: Самые ортодоксальные — это PICудеи )
Katz: Не, 51-ники. )

MrYuran: Самые ортодоксальные — это PICудеи )
Katz: Не, 51-ники. )

Re: АЦП AD7730
Всем спасибо за ответы.
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 в ноль и всё. По крайней мере так я понял из даташита.
Немного изменил прием 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 сек он отправлять не успевает.
Пока результат тот же, т.е. на экране чушь.
- Engineer_Keen
- Друг Кота
- Сообщения: 3872
- Зарегистрирован: Пт янв 29, 2010 10:27:40
- Откуда: Москва
Re: АЦП AD7730
Тогда есть смысл его вообще заземлить, но раз есть возможность управлять, лучше ее использовать.Lotus13 писал(а):CS постоянно в логическом нуле. АЦП один и постоянно выбирать его нет смысла. Однажды его инициализировал CS в ноль и всё.
Если используется RC-генератор на 8 МГц, и делитель на 128, получается тактовая SPI: 8МГц/128=62500Гц, для передачи 4х байт (1 байт команда чтения+3байта данных) нужно: 62500^-1*8*4=0.0005сLotus13 писал(а):Теперь разбираюсь с тактирующим импульсом с ноги МК SCK на ногу АЦП SCLK. Может за 0,01 сек он отправлять не успевает.
Re: АЦП AD7730
Резонатор на МК внешний, 8МГц. С ним проблем нет. Выяснил, что сигналы с RDY от АЦП должны показывать микроконтроллеру, идет передача, калибровка или как раз передача завершена. У меня же на RDY постоянно 5В, т.е. лог.1, либо он так долго этот бит передает, либо калибруется. RDY не переводится в 0. На МК эта нога подходит к PD2/INT0, внеш прерывания разрешил, настроил на прерывание по пришедшему низкому уровню. Само собой они не срабатывают (проверил).
Кто знаком с AD7730. Подскажите, почему RDY может не выдавать низкого уровня?
Кто знаком с AD7730. Подскажите, почему RDY может не выдавать низкого уровня?
Re: АЦП AD7730
Всем спасибо. Всё заработало. Главной проблемой была инициализация АЦП. А именно правильно установить фронты тактирующих импульсов с ведущего МК, установить полярность и фазу этих импульсов и соответственно полярность считывания импульсов ведомым АЦП. Всего восемь вариантов получилось. Тут главное не методом подбора, а всё таки почитать. Регистры записываются, данные читаются.
Re: АЦП AD7730
Добрый день! Очень прошу вас помогите мне с запуском и конфигурацией.
Написал функции для записи и чтения всех регистров. Работают хорошо. Но прочитать данные с регистра данных никак не получается.
То отправляет FFFFFE, то выход AD7730 вовсе переходит в высокоимпедансное состояние.
Подскажите какая должна быть последовательность действий?
Код инициализации взял из datasheet
Дальше жду когда будет 0 на RDY и читаю
Если видно явный баг то подскажите где он.
Написал функции для записи и чтения всех регистров. Работают хорошо. Но прочитать данные с регистра данных никак не получается.
То отправляет 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)
}Дальше жду когда будет 0 на RDY и читаю
Код: Выделить всё
RX_24bit=AD7730_read_24bit();Re: АЦП AD7730
Помогите, не как ни получается адекватно заставить работать AD7730 и ATmeag32.
При Аппаратном SPI постоянно получаем 65535 (т.е. FF), при Программном SPI значения получаем и даже меняются в зависимости от нажима на тензодатчик, но через пару секунд AD7730 перестает выдавать данные (срыв чтения данных), тоже самое при сильном нажатии на датчик, только быстрее. Как добиться стабильной работы. Так же не понятно как убирать вес тары и калибровать тензодатчик под вес.
Буду очень благодарен за любую помощь.
При Аппаратном SPI постоянно получаем 65535 (т.е. FF), при Программном SPI значения получаем и даже меняются в зависимости от нажима на тензодатчик, но через пару секунд AD7730 перестает выдавать данные (срыв чтения данных), тоже самое при сильном нажатии на датчик, только быстрее. Как добиться стабильной работы. Так же не понятно как убирать вес тары и калибровать тензодатчик под вес.
Буду очень благодарен за любую помощь.
Андрей (UB6AFB).
Re: АЦП AD7730
Как найти топикстартера?
Re: АЦП AD7730
Тут я, однако помочь увы не могу. С тех пор перевелся на ПЛИС и скоростные параллельные АЦП. Про тот проект забыл окончательно, хотя и получил тогда удовлетворительные результаты. Все равно уже код проекта утерян, разве что сама плата где-то еще валяется. Больше, чем описывал я и те, кто мне помогал, в этой теме я сказать не смогу. АЦП удалось запустить, точность измерений составляла около 0,1 %, не удалось обнулять вес тары, как выразился DJCooler сообщением выше, не удалось стабилизировать показания на LCD. Но это в первую очередь связано с ФНЧ фильтром, который я тогда считать не умел, во вторую с тензодатчиком, в третью с кривой программой. Удачи, да прибудет с вами сила.
Re: АЦП AD7730
Всем привет! Раз уж такая тема есть напишу здесь. Работаю с этим АЦП и на нем собрал амперметр. Запустил работает шустро но, в итоге при подаче тока на шунт через некоторое время он начинает плавать. Ноль стоит на месте. В качестве опорника стоит ref192. Напряжение с шунта подается на AIN1+ и AIN1-. Перед входом стоит RC фильтр. 2к2 резисторы и 5мкф кондеры. Может кто знает как мне его подключить чтоб он не плавал?
- Вложения
-
- 0.png
- (3.04 КБ) 811 скачиваний


