Добрый день! Обращался уже с неделю назад по вопросу неправильного напряжения на выходе цап, мне указали на ошибку в инициализации CS, все заработало, но макет был ужасный, приходилось припаивать смд SOT8 на обычную макетную плату с отверстиями 2,54. Купил специальных переходников с смд на 2,54, сделал на той же макетке поприличнее и все перестало работать: с цапа выходит ерунда, на первой схеме лабораторный блок питания стабильно показывал 10мА, на новой ток получился нестабильный (иногда постепенно растет до 150мА и колеблется ± 50мА, иногда сразу колеблется на высоких значениях и напряжение скачет), при прозвонке земли и питания мультиметр может показывать и разрыв, и ±700, и 400 в прямом направлении и 150-400 (иногда вообще звенит) в обратном
После безуспешных попыток диагностики проблемы пересобрал схему уже на пластиковой макетке - точно так же, вытравил плату - точно так же
При том, что схема сборки не отличается от той, которая была изначально
Конечно, качество пайки все еще не лучшее, потому что разные элементы менялись/выпаивались и так далее
Первая была на нано, вторую тестил и на нано, и на уно
Из еще минимальных отличий в схемах: разные места пайки (паяльники, флюсы, припои) и разные ноутбуки, с которых произвожу прошивку (ноут на винде изменился на мак)
Сейчас параллельно с написанием поста сделал еще несколько тестов, в целом комбинаций результатов (ток потребления, напряжение на цап, сериал выход и тд) очень много, получил более менее понятный на зеленой макетке: ток потребления стабильные 10мА опять, но цап молчит и напряжение на выходе пару милливольт
Из-за чего такая проблема может наблюдаться и как ее решить?
Код
#include <SPI.h>
#define weight_of_standard 220 // Калибровочный вес
#define power_down() \
bitSet(_SFR_IO8(_Write), _clkPin); \
delayMicroseconds(64)
#define power_up() bitClear(_SFR_IO8(_Write), _clkPin) // Макрос для включения питания АЦП
#define GAIN64A 2 // Установка Коэффициента усиления
#define REF_GR_DAC 100.00 // Референсное значение для ЦАП в граммах (=максимум шкалы измерения)
#define SPI_CLK 13
#define SPI_SDI 11
class DAC {
public:
DAC(int i = 1) {
}
void begin(uint8_t CS_PIN, byte Regs[2]) { // Инициализация ЦАП, Pins - пины SPI
CLK_PIN = SPI_CLK; // Запись пинов SPI
SDI_PIN = SPI_SDI;
_Mode = Regs[0];
_Write = Regs[1];
bitSet(_SFR_IO8(_Mode), CS_PIN);
bitSet(_SFR_IO8(_Write), CS_PIN);
SPI.begin(); // Запуск интерфейса SPI
SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); // Начало транзакции, 20МГц, Старший байт первый, Мод0
}
void write(float value) { // Запись значения в ЦАП
if (value < 0) { // Если значение опускается меньше нуля, записывать ноль
_VAL = 0;
} else if (value > REF_GR_DAC) { // Если значение выше референсного, записывать максимальное
_VAL = 65535;
} else {
_VAL = uint16_t(65535 * value / REF_GR_DAC); // Расчет значения по пропорции
}
bitClear(_SFR_IO8(_Write), CS_PIN); // Запись в чипселект 0 для выбора ЦАП для передачи
SPI.transfer16(_VAL); // передача ЦАП
//delay(15);
bitSet(_SFR_IO8(_Write), CS_PIN); // Запись в чипселект 1 для окончания передачи
}
uint16_t get_value () {
return _VAL;
}
//MSBFIRST в настройке spi = избегаем разделения значений по двум байтам, выдача начинается со старшего байта
private:
uint16_t _VAL;
uint8_t CS_PIN, CLK_PIN, SDI_PIN;
int16_t REFERENCE_MV;
byte _Mode, _Write;
};
class SCALE {
public:
/*Порядок записи в массив: DR, DW, DM, CW, CM, DP, CP*/
SCALE(int i = 1) {
}
/*ИНИЦИАЛИЗАЦИЯ ДАТЧИКА*/
void begin(byte Regs[3], byte Pins[2]) { // Инициализация АЦП
_Read = Regs[0]; // Запись значений регистров и пинов
_Write = Regs[1];
_Mode = Regs[2];
_dataPin = Pins[0];
_clkPin = Pins[1];
bitSet(_SFR_IO8(_Mode), _clkPin); // Настройка регистров
bitClear(_SFR_IO8(_Mode), _dataPin);
bitClear(_SFR_IO8(_Write), _clkPin);
bitClear(_SFR_IO8(_Write), _dataPin);
power_down(); // Выключение и включение АЦП
power_up();
_chan = GAIN64A;
_weight = 0;
_value = 0;
_offset = 0;
_scale = 1;
}
/*УСТАНОВКА МАСШТАБА*/
void set_scale(float scale) {
_scale = 1.0 / scale;
}
/*КАЛИБРОВКА*/
void calibrate_scale(uint8_t weight) {
long read_av = 0;
for (uint8_t i = 0; i < 15; i++) { // Калибровка на 15 значениях среднее арифметическое
read_av += read();
}
read_av /= 15;
_scale = (1.0 * weight) / (read_av - _offset); // получаем масштаб
}
/*ВЕРНУТЬ МАСШТАБ*/
float get_scale() {
return 1 / _scale;
}
/*ТАРИРОВАНИЕ*/
void tare() {
for (uint8_t i = 0; i < 3; i++) { // тарируем на фильтрованном значении
_offset += filt();
}
_offset = (_offset / 3) / _scale;
}
/*ЧТЕНИЕ СЫРОГО ЗНАЧЕНИЯ*/
long read() {
while (bitRead(_SFR_IO8(_Read), _dataPin) == HIGH) yield();
_weight = 0;
for (uint8_t i = 0; i < 24; i++) { // посылка сигналов тактирования
bitSet(_SFR_IO8(_Write), _clkPin); //digitalWrite(_clock, HIGH);
delayMicroseconds(1);
_weight <<= 1;
if (bitRead(_SFR_IO8(_Read), _dataPin)) _weight |= 1;
bitClear(_SFR_IO8(_Write), _clkPin); //digitalWrite(_clock, LOW);
delayMicroseconds(1);
}
for (uint8_t i = 0; i < _chan + 1; i++) {
bitSet(_SFR_IO8(_Write), _clkPin); //digitalWrite(_clock, 1);
delayMicroseconds(1);
bitClear(_SFR_IO8(_Write), _clkPin); //digitalWrite(_clock, 0);
delayMicroseconds(1);
}
if (_weight & 0x800000) _weight |= 0xFF000000; // отрицательные
return _weight;
}
/*ПЕРЕВОД СЫРОГО ЗНАЧЕНИЯ В ГРАММЫ*/
float value() {
read();
_value = (_weight - _offset) * _scale;
return _value;
}
/*ВЕРНУТЬ ЗНАЧЕНИЕ В ГРАММАХ*/
float get_value() {
return _value;
}
/*ФИЛЬТРАЦИЯ ЗНАЧЕНИЯ В ГРАММАХ*/
float filt() {
float newVal = value();
byte k = 5;
static float filt = newVal;
if (abs(newVal - filt) <= 0.5) k = 30; // Выбор коэффициента для бегущего среднего в зависимости от величины изменения
else if (abs(newVal - filt) >= 0.51 && abs(newVal - filt) < 2.7) k = 4;
else if (abs(newVal - filt) >= 2.7 && abs(newVal - filt) < 3.5) k = 2;
else if (abs(newVal - filt) >= 3.5 && abs(newVal - filt) < 5) k = 6;
else if (abs(newVal - filt) >= 5 && abs(newVal - filt) < 7) k = 10;
else if (abs(newVal - filt) >= 7) k = 20;
filt += (newVal - filt) / k; // фильтрация по бегущему среднему
return filt;
}
// float filt_raw() {
// float newVal = read();
// byte k = 7;
// static float filt = newVal;
// // if (abs(newVal - filt) <=0.5) k = 30;
// // else if(abs(newVal-filt) >= 0.51 && abs(newVal-filt)<=15) k = 3;
// // else if (abs(newVal-filt) > 10) k = 10;
// filt += (newVal - filt) / k;
// return filt;
// }
private:
byte _Read, _Write, _Mode;
byte _dataPin, _clkPin, _chan;
long _weight, _offset;
float _scale, _value;
};
// Инициализация глобальных переменных
float values[4] = {0, 0, 0, 0};
bool tare_sig = false;
long timer = 0;
uint32_t t = 0;
/*Адресса регистров HX PIND, PORTD, DDRD PORTB DDRB*/
byte D_Adresses[3] = { 0x09, 0x0B, 0x0A /*, 0x05, 0x04*/ };
// DDRC PORTC
byte DAC_C_Regs[2] = {0x07, 0x08};
// Пины CS для DAC CS0 CS1 CS2 CS3
byte SPI_Adresses[4] = {0, 1, 2, 3};
// Пины данных и тактирования для HX711
byte D_Pins[4][2] = {
{ 1, 0 },
{ 2, 3 },
{ 4, 5 },
{ 6, 7 },
};
SCALE scale[4]; // создание объектов АЦП
DAC dac[4]; // Создание объектов ЦАП
// ISR(PCINT1_vect) { // Обработчик прерывания на пине А4
// scale[1].begin(D_Adresses, D_Pins[1]); // инициализация АЦП
// scale[1].set_scale(386.54); // установка масштаба
// scale[1].tare(); // тарирование
// scale[1].set_scale(386.54); // Вызов функции тарирование
// tare_sig = true; // Установка флага
// }
void setup() {
Serial.begin(9600);
// PCICR |= 1 << 1;
// PCMSK1 |= 1 << 4; // НАСТРОЙКА ПРЕРЫВАНИЯ НА ПИНЕ А4
// SREG |= 1 << SREG_I;
// КОД ДЛЯ 4 ДАТЧИКОВ
// for (int i = 0; i < 4; i++) {
// scale[i].begin(D_Adresses, D_Pins[i]); // инициализация АЦП
// scale[i].set_scale(386.54); // установка масштаба
// scale[i].tare(); // тарирование
// scale[i].set_scale(386.54);
// dac[i].begin(SPI_Adresses); // инициализация ЦАП
// }
scale[1].begin(D_Adresses, D_Pins[1]); // инициализация АЦП
scale[1].set_scale(386.54); // установка масштаба
scale[1].tare(); // тарирование
scale[1].set_scale(386.54);
dac[1].begin(SPI_Adresses[1], DAC_C_Regs); // инициализация ЦАП
}
void loop() {
tare_sig = false; // Сброс флага
while (tare_sig == false) { // Выполнение при активном флаге
values[1] = scale[1].filt(); //запись фильтрованного значения
//Serial.println(values[1]);
// исполняемый код для передачи на плк
dac[1].write(values[1]); // запись в ЦАП
uint16_t value = dac[1].get_value();
Serial.print("DAC: ");
Serial.print(value);
Serial.print(" ; ");
Serial.print("ACD: ");
Serial.println(values[1]);
}
}