ilkz 0 21 июня, 2016 Опубликовано 21 июня, 2016 · Жалоба Привет. Читаю AD7799 в униполярном режиме и получаю какую-то ересь, ну либо не понимаю как правильно преобразовать цифры. Для начала, пытаюсь читать AVDD. Вот код, которым настраиваю и читаю АЦП: ad7799_set_channel(AD7799_CH_AVDD_MONITOR); ad7799_set_burnout(0); ad7799_set_unipolar(1); ad7799_set_gain(AD7799_GAIN_1); ad7799_set_ref_det(0); ad7799_set_buffered(1); ad7799_set_psw(0); ad7799_set_rate(AD7799_RATE_4_17_HZ); ad7799_set_offset(0x000000); ad7799_set_fullscale(0xFFFFFF); ad7799_set_mode(AD7799_MODE_CONT); while(1) { if(ad7799_ready()) { ad7799_dump_regs(); printf(" offset = %f\n", ad7799_to_volts(ad7799_get_offset())); printf(" fullscale = %f\n", ad7799_to_volts(ad7799_get_fullscale())); printf("\n"); adc_raw = ad7799_read_data_raw(); printf("%06x %2.6fv\n", adc_raw, ad7799_to_volts(adc_raw)); for(i=0; i<20000000; i++); } } Вот так преобразую в вольты: uint32_t ad7799_read_data_raw(void) { return ad7799_get_register(AD7799_REG_DATA, 3); } #define VREF 2.5 #define SPAN 0xFFFFFF #define GAIN 1 float ad7799_to_volts(uint32_t value) { return (float)(value * (VREF / SPAN * GAIN)); } float ad7799_read_data_volts(void) { return ad7799_to_volts(ad7799_read_data_raw()); } Вот что выводит принтф: STAT = 0f MODE = 000f CONF = 1017 DATA = aeff0c ID = 49 IO = 00 OFFSET = 800000 FULLSCALE = 555500 offset = 1.250000 fullscale = 0.833321 aeff0c 1.708948v На ноге AVDD при этом сидит реальных 4.85В. Всю голову уже сломал, помогите разобраться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
skripach 6 21 июня, 2016 Опубликовано 21 июня, 2016 · Жалоба Привет. Очевидно проблема в функции чтения дынных из АЦП, а не в функции преобразония этих данных в напряжение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 21 июня, 2016 Опубликовано 21 июня, 2016 · Жалоба АЦП читается нормально - я это вижу по значениям регистров, вычитываемых после сброса: они соответствуют даташиту. Я вот что подумал: в даташите написано, что при измерении в канале AVDD само значение AVDD сначала ослабляется в 6 раз, потом выносится на подствку 1.17В (типа, чтобы лучше видеть пульсации напряжения). Означает ли это, что вместо сидящих на входе 5В я должен прочитать: (5/6)+1.17=2.003333 Вольта? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 205 21 июня, 2016 Опубликовано 21 июня, 2016 · Жалоба 2^24 · AVDD / (INTVREF · 6) = 16777216 · 5 В / (1,17 В · 6) = $B65610 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 60 22 июня, 2016 Опубликовано 22 июня, 2016 · Жалоба Я вот что подумал: в даташите написано, что при измерении в канале AVDD само значение AVDD сначала ослабляется в 6 раз, потом выносится на подствку 1.17В (типа, чтобы лучше видеть пульсации напряжения). Означает ли это, что вместо сидящих на входе 5В я должен прочитать: (5/6)+1.17=2.003333 Вольта? Это всего лишь для контроля напряжения AVDD. На оцифровку каналов это не влияет. Вы окончание преобразования как контролируете ? По ножке или чтением регистра статуса ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 22 июня, 2016 Опубликовано 22 июня, 2016 (изменено) · Жалоба Чтением регистра статуса: uint8_t ad7799_ready(void) { unsigned char rdy = 0; rdy = ad7799_get_register(AD7799_REG_STAT, 1) & 0x80; return(!rdy); } uint32_t ad7799_read_data_raw(void) { return ad7799_get_register(AD7799_REG_DATA, 3); } void main(void) { ... ad7799_set_mode(AD7799_MODE_CONT); while(1) { if(ad7799_ready()) { adc_raw = ad7799_read_data_raw(); printf("%06x %2.6fv\n", adc_raw, ad7799_to_volts(adc_raw)); } } } Еще вопрос: если АЦП подключен по униполярной схеме, то как правильно задавать значения FULLSCALE и OFFSET? Судя по даташиту (When the ADC is configured for unipolar operation, the output code is natural (straight) binary with a zero differential input voltage resulting in a code of 00...00, a midscale voltage resulting in a code of 100...000, and a full-scale input voltage resulting in a code of 111...111.), их надо задать как OFFSET=0, FULLSCALE=FFFFFF (нулевое смещение и размах во всю шкалу). Но если я так сделаю, то из АЦП всегда читается FFFFFF при напряжении на входе, например, 0.7В. Изменено 22 июня, 2016 пользователем ilkz Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 60 22 июня, 2016 Опубликовано 22 июня, 2016 · Жалоба ilkz сказал: Еще вопрос: если АЦП подключен по униполярной схеме, то как правильно задавать значения FULLSCALE и OFFSET? Судя по даташиту (When the ADC is configured for unipolar operation, the output code is natural (straight) binary with a zero differential input voltage resulting in a code of 00...00, a midscale voltage resulting in a code of 100...000, and a full-scale input voltage resulting in a code of 111...111.), их надо задать как OFFSET=0, FULLSCALE=FFFFFF (нулевое смещение и размах во всю шкалу). Но если я так сделаю, то из АЦП всегда читается FFFFFF при напряжении на входе, например, 0.7В. Их вообще не надо трогать. Вы сначала так запустите. Вот вам рабочий пример. void Init_ADC(void) { uint16_t snd; adc_proc = ST_IDLE; InitSPI(); // reset SPI interface SPI_CS_ASSERT(); SPI_rcvr_byte(0xFF); SPI_rcvr_byte(0xFF); SPI_rcvr_byte(0xFF); SPI_rcvr_byte(0xFF); SPI_CS_DEASSERT(); _delay_ms(750); // set Idle mode and 50 Hz update rate SPI_CS_ASSERT(); snd = WEN | RW_W | CREAD_OFF | MODE_REG; SPI_rcvr_byte(snd); snd = IDLE_MOD | FS_RATE_16_1; SPI_rcvr_byte(snd >> 8); SPI_rcvr_byte(snd); SPI_CS_DEASSERT(); adc_tim = 500UL; adc_ch_num = 0; } uint8_t ADC_Process(void) { uint8_t ret_val = 0; uint16_t snd; switch(adc_proc) { case ST_IDLE: if(adc_tim) break; // set gain = 4, unipolar, buffered SPI_CS_ASSERT(); snd = WEN | RW_W | CREAD_OFF | CONF_REG; SPI_rcvr_byte(snd); switch(adc_ch_num) { case PP_CHAN: snd = BO_DIS | UB_B | GAIN_4 | REF_DET_DIS | BUF_ENA | CHAN_AIN2; //snd = BO_DIS | UB_U | GAIN_1 | REF_DET_DIS | BUF_ENA | CHAN_AIN2; break; case PT_CHAN: snd = BO_DIS | UB_U | GAIN_2 | REF_DET_DIS | BUF_ENA | CHAN_AIN1; break; case TT_CHAN: snd = BO_DIS | UB_U | GAIN_1 | REF_DET_DIS | BUF_DIS | CHAN_AIN3; adc_tim = 1000UL; break; }; SPI_rcvr_byte(snd >> 8); SPI_rcvr_byte(snd); SPI_CS_DEASSERT(); // start single conversion SPI_CS_ASSERT(); snd = WEN | RW_W | CREAD_OFF | MODE_REG; SPI_rcvr_byte(snd); snd = SINGLE_MOD | FS_RATE_16_1 | PSW_ON; SPI_rcvr_byte(snd >> 8); SPI_rcvr_byte(snd); SPI_CS_DEASSERT(); adc_proc = ST_WAIT_DATA; break; case ST_WAIT_DATA: SPI_CS_ASSERT(); snd = WEN | RW_R | CREAD_OFF | STATUS_REG; SPI_rcvr_byte(snd); snd = SPI_rcvr_byte(0); SPI_CS_DEASSERT(); if((snd & RDY) == 0) adc_proc = ST_DATA_RDY; break; case ST_DATA_RDY: // read data reg SPI_CS_ASSERT(); snd = WEN | RW_R | CREAD_ON | DATA_REG; SPI_rcvr_byte(snd); adc_val[adc_ch_num] = 0; adc_val[adc_ch_num] = SPI_rcvr_byte(0); adc_val[adc_ch_num] <<= 8; adc_val[adc_ch_num] |= SPI_rcvr_byte(0); adc_val[adc_ch_num] <<= 8; snd = WEN | RW_R | CREAD_OFF | DATA_REG; adc_val[adc_ch_num] |= SPI_rcvr_byte(snd); SPI_CS_DEASSERT(); adc_proc = ST_IDLE; ++adc_ch_num; if(adc_ch_num > TT_CHAN) { adc_ch_num = 0; ret_val = 1; } break; } return ret_val; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 22 июня, 2016 Опубликовано 22 июня, 2016 (изменено) · Жалоба Ребята, все нормально: обнаружилась ошибка в разводке - вход не был подключен. :) Спасибо всем за помощь! Изменено 22 июня, 2016 пользователем ilkz Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 60 22 июня, 2016 Опубликовано 22 июня, 2016 · Жалоба Ребята, все нормально: обнаружилась ошибка в разводке - вход не был подключен. :) Спасибо всем за помощь! Электроника - наука о контактах ;-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 205 22 июня, 2016 Опубликовано 22 июня, 2016 · Жалоба пытаюсь читать AVDD DATA = aeff0c aeff0c 1.708948v На ноге AVDD при этом сидит реальных 4.85В. Всю голову уже сломал, помогите разобраться. По вышеприведённой формуле: $AEFF0C · 1,17 В · 6 / 2^24 = 4,79872603 В Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Reystlin 0 14 января, 2019 Опубликовано 14 января, 2019 (изменено) · Жалоба Доброго времени суток ув. форумчане Столкнулся я тут с задачей на AD7799, имеется 3 таких ацп на общей шине с раздельными CS ессно. К двум каналам каждого АЦП подключены свои мостовые тензодатчики. Устройство занимается дозированием, посему требуется достаточно быстрый опрос значений с ацп с приемлимой точностью. Столкнулся вот с какими проблемами: 1. Не совсем понятно как себя ведет внутренний фильтр. youtu.be/sv3gs0dkyPo На видео показана проблема. 5 число сверху - вход к которому подключен датчик. результаты измерения ацп иногда замирают, причем на разное время. так-же время замирания зависит от частоты фильтра. чем выше частота фильтра тем короче эти задержки режим работы ацп - непрерывный. данные считываю по флагу в регистре статуса. 2. Если часто переключать каналы то возникает проникание сигнала одного канала в другой. я подозреваю, что это связано с наличием фильтра после преобразователя а каналы там муксом на входе преобразователя выбираются... есть ли лайфхаки обойти сею проблему? код инициализации: void AD7799_Config(unsigned char chip) { AD7799_Init(chip); AD7799_SetUnipolar(chip,1); AD7799_SetGain(chip,AD7799_GAIN_1); AD7799_SetFilterMode(chip,AD7799_Filter_16_7_50hz); AD7799_SetChannel(chip,AD7799_CH_AIN2P_AIN2M); AD7799_SetMode(chip,AD7799_MODE_CAL_INT_ZERO); while(AD7799_Ready(chip)); AD7799_SetMode(chip,AD7799_MODE_CAL_INT_FULL); while(AD7799_Ready(chip)); AD7799_SetChannel(chip,AD7799_CH_AIN1P_AIN1M); AD7799_SetMode(chip,AD7799_MODE_CAL_INT_ZERO); while(AD7799_Ready(chip)); AD7799_SetMode(chip,AD7799_MODE_CAL_INT_FULL); while(AD7799_Ready(chip)); AD7799_SetFilterMode(chip,AD7799_Filter_10); AD7799_SetMode(chip,AD7799_MODE_CONT); } код опроса регистра статуса unsigned char AD7799_Ready(unsigned char CS) { unsigned char rdy = 0; unsigned long reg_stat= AD7799_GetRegisterValue( CS,AD7799_REG_STAT,1); rdy = (reg_stat & 0x80); if((rdy==0x80)&&((reg_stat& 0x07)==0x00)) rdy=1; if((rdy==0x80)&&((reg_stat& 0x07)==0x01)) rdy=2; if((rdy==0x80)&&((reg_stat& 0x07)==0x02)) rdy=3; return(rdy); } код опроса ацп switch(AD7799_Ready(AD7799_CHIP2)) { case 1: weigt[2] = AD7799_GetRegisterValue(AD7799_CHIP2, AD7799_REG_DATA,3); AD7799_SetChannel(AD7799_CHIP2,AD7799_CH_AIN2P_AIN2M); break; case 2: weigt[3] = AD7799_GetRegisterValue(AD7799_CHIP2, AD7799_REG_DATA,3); AD7799_SetChannel(AD7799_CHIP2,AD7799_CH_AIN1P_AIN1M); break; } Изменено 14 января, 2019 пользователем Reystlin Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Reystlin 0 15 января, 2019 Опубликовано 15 января, 2019 · Жалоба вывел все регистры на экран. считываю их в цикле измерений. 1 - STATUS 2 - MODE 3 - CONFIGURATION 4 - OFFSET 5 - FULLSALE 6- значение ацп. по видео видны странности: 1. в моменты пауз в регистре статуса биты ready и error = 0 положительное усилие на датчик не влияет на эту ситуацию но отрицательное усилие поднимает бит error сразу при его появлении(что в принципе нормально, на входе ацп отрицательное значение становится). 2. очень большая задержка между повышением показаний на выходе ацп и моментом приложения положительного усилия. так-же после снятия положительного усилия с датчика с очень большой задержкой он возвращается в нулевое положение по показаниям. куда копать? всю голову сломал, не могу понять природу происходящей магии Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexunder 4 15 января, 2019 Опубликовано 15 января, 2019 · Жалоба On 1/14/2019 at 3:54 PM, Reystlin said: 2. Если часто переключать каналы то возникает проникание сигнала одного канала в другой. я подозреваю, что это связано с наличием фильтра после преобразователя а каналы там муксом на входе преобразователя выбираются... есть ли лайфхаки обойти сею проблему? Встречал такое у АЦП с мултиплексором на входе, вроде у AD7949. Канал с низким напряжением на входе хорошо чувствовал своего соседа (опрошенного перед ним), у которого на входе был потенциал заметно выше (в режиме по умолчанию эта ИМС перебирала каналы последовательно от 0 до N). Проблема решилась отключением режима последовательного перебора канала и двух- трехкратным чтением каждого канала. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Reystlin 0 15 января, 2019 Опубликовано 15 января, 2019 (изменено) · Жалоба 11 minutes ago, alexunder said: Встречал такое у АЦП с мултиплексором на входе, вроде у AD7949. Канал с низким напряжением на входе хорошо чувствовал своего соседа (опрошенного перед ним), у которого на входе был потенциал заметно выше (в режиме по умолчанию эта ИМС перебирала каналы последовательно от 0 до N). Проблема решилась отключением режима последовательного перебора канала и двух- трехкратным чтением каждого канала. Пробовал делать переключение каналов на каждое 10ое измерение, все-равно каналы друг в друга проникают. после переключения один канал плавно подбирается к уровню второго было решено отказаться от использования вторых каналов. Изменено 15 января, 2019 пользователем Reystlin Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 17 16 января, 2019 Опубликовано 16 января, 2019 · Жалоба 12 hours ago, Reystlin said: Пробовал делать переключение каналов на каждое 10ое измерение, все-равно каналы друг в друга проникают. после переключения один канал плавно подбирается к уровню второго Это несколько интересных эффектов: 1. перезаряд всех имеющихся в схеме емкостей на входе АЦП (и внешних реальных-паразитных и внутренней) от неизвестного уровня предыдущего входа к новому измеряемому уровню током нового подключенного измеряемого входа, с учетом входного сопротивления АЦП и других токов утечки. 2. перегрузка фильтр АЦП новыми данными. Процесс и технология обычно описаны в даташите АЦП. Но следует понимать, что сеачала должно произойти (1) и тольео потом начаться (2). У меня был случай, когда, паразитные емкости электронных коммутаторов мешали. Вводил даже специальный вход, перезаряжающий все емкости измерителя до среднего уровня, от которого уже можно было посчитать максимальное время перезаряда до измеряемого уровня. То есть In1-Ref-In2-Пауза-Измерение_In2. Это все считается (ну или хоть симулируется в симуляторе как набор цепочек R-C), подбирать тут опасно- будет на одном входе -Vmax, а на другом входе +Vmax, и окажется что емкости недоперезарядились. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться