Тед
Пн 25 декабря 2017 г., 20:17
Я только что наткнулся на интересный проект детектора металлов CD42, ссылка ниже
Это может быть значительно улучшено, используя аудио -усилитель для энергии TX -катушки, TDA2030 увеличивается в 20 раз превышает интенсивность электромагнитного поля, используя последовательный резонанс CT и TX Coil.
Больше улучшений может быть сделано с помощью модификаций программы, я знаю, что электроника не программирование.
Есть ли кто -то, кто заинтересован, присоединился ко мне в этом улучшении ?
https: // github.com/dc42/arduino/blob/ma ... эматический.JPG
TDA2030; https: // m.aliexpress.com/item/32814901629.HTML
Это может быть значительно улучшено, используя аудио -усилитель для энергии TX -катушки, TDA2030 увеличивается в 20 раз превышает интенсивность электромагнитного поля, используя последовательный резонанс CT и TX Coil.
Больше улучшений может быть сделано с помощью модификаций программы, я знаю, что электроника не программирование.
Есть ли кто -то, кто заинтересован, присоединился ко мне в этом улучшении ?
https: // github.com/dc42/arduino/blob/ma ... эматический.JPG
TDA2030; https: // m.aliexpress.com/item/32814901629.HTML
Ахулл
Вт 26 декабря 2017 г. 8:50 утра
У меня не было много времени, чтобы посмотреть на обнаружение металлов с помощью чертеже Детектор металлов индукции импульсного индукции.
На тему усилителей звука для управления катушкой, индукционного детектора баланса, я задавался вопросом, может ли одна из этих маленьких досок усилителей класса D сделать уловку. Класс D теоретически более эффективен, что является большим соображением, если они работают из батарей. Они также представляют собой отдельные управляющие устройства, которые упрощают источник питания.
Ищите eBay для "DC 5V PAM8403 Class D" (также PAM8406, который может водить 5 Вт в 2 Ом при 5V) для той вещи, о которой я говорю.
Проектирование подходящих катушек, возможно, будет самой проблемной частью процесса.
На форуме есть несколько других тем о детекторах металлов, не уверен, как далеко эти люди удалось получить.
Мне интересно посмотреть, как твоя идея выходит.
На тему усилителей звука для управления катушкой, индукционного детектора баланса, я задавался вопросом, может ли одна из этих маленьких досок усилителей класса D сделать уловку. Класс D теоретически более эффективен, что является большим соображением, если они работают из батарей. Они также представляют собой отдельные управляющие устройства, которые упрощают источник питания.
Ищите eBay для "DC 5V PAM8403 Class D" (также PAM8406, который может водить 5 Вт в 2 Ом при 5V) для той вещи, о которой я говорю.
Проектирование подходящих катушек, возможно, будет самой проблемной частью процесса.
На форуме есть несколько других тем о детекторах металлов, не уверен, как далеко эти люди удалось получить.
Мне интересно посмотреть, как твоя идея выходит.
Тед
Вторник 26 декабря 2017 г. 15:51
Результаты не теория, а фактические испытания, катушки могут быть такими же, как в оригинальном дизайне.
Я жду прибытия доски Arduino, так же, как DC42, однако, STM32103 даст лучшие результаты, это намного быстрее.
Я жду прибытия доски Arduino, так же, как DC42, однако, STM32103 даст лучшие результаты, это намного быстрее.
Тед
Вт 26 декабря 2017 г., 18:27
- DC42B.JPG (222.98 киб) просмотрено 1216 раз
Тед
Вт 23 января 2018 г. 11:59
Просто генератор сигналов +TDA2030 +осциллограф = 70 см.
Помощь в программе приветствуется.
Помощь в программе приветствуется.
Дэнниф
Вт 23 января 2018 г. 13:05
это зависит от диапазона желаемого обнаружения.
Для меня этот подход слишком сложный: поскольку он опирается на связь между двумя катушками для обнаружения. Более простой подход заключается в использовании катушки в рамках генератора, частота которой изменяется с наличием металла (хорошо, большинство металлов) вблизи катушки. Таким образом, если вы обнаружите частоту осциллятора катушки + металла, ...
Это обнаружение может быть сделано путем сравнения частоты против. внутренний генератор, или Xtal, .... Наиболее интересным случаем является настройка катушки + металл в качестве основного генератора и использовать другие осцилляторы на борту, например, время -аут, чтобы обнаружить сдвиг частоты....
Смиренного аттини здесь более чем достаточно.
Для меня этот подход слишком сложный: поскольку он опирается на связь между двумя катушками для обнаружения. Более простой подход заключается в использовании катушки в рамках генератора, частота которой изменяется с наличием металла (хорошо, большинство металлов) вблизи катушки. Таким образом, если вы обнаружите частоту осциллятора катушки + металла, ...
Это обнаружение может быть сделано путем сравнения частоты против. внутренний генератор, или Xtal, .... Наиболее интересным случаем является настройка катушки + металл в качестве основного генератора и использовать другие осцилляторы на борту, например, время -аут, чтобы обнаружить сдвиг частоты....
Смиренного аттини здесь более чем достаточно.
Тед
Вт 23 января 2018 г. 13:42
Моя цель - обнаружить Cola Can с расстояния 1m+, нет проблем с катушкой
нулевая. Упомянутый метод измерение сдвига частоты намного чувствителен к LES, чем детекторы TX-RX.
нулевая. Упомянутый метод измерение сдвига частоты намного чувствителен к LES, чем детекторы TX-RX.
Дэнниф
Вторник 23 января 2018 г. 15:27
Кола может с расстояния 1M+
Вы можете помочь себе, установив реалистичные цели по дизайну и понимая, как обнаружение металла работает на некоторых металлах, таких как алюминий.
Пито
Вторник 23 января 2018 г., 17:15
Это зависит от того, поступает ли банка от нас или из Европы.. Два разных сплава, я думаю..
Тед
Вторник 23 января 2018 г. 18:09
Привет, пито, приятно видеть тебя здесь
На банке это говорит - Канада. Я заказал atmega328p на Aliexpress с ним, я ожидаю 1 м, всего на 30 см больше. С STM32 было бы лучше, но необходимо преобразовать код из AVR в ARM.
На банке это говорит - Канада. Я заказал atmega328p на Aliexpress с ним, я ожидаю 1 м, всего на 30 см больше. С STM32 было бы лучше, но необходимо преобразовать код из AVR в ARM.
Тед
Вторник 30 января 2018 г. 14:00
Итак, я получил UNO, но у меня есть проблема с LCD 128x64 7920.
http: // hobbycomponents.com/изображения/форум ... 00_600.JPG
#1 код
http: // hobbycomponents.com/изображения/форум ... 00_600.JPG
#1 код
This is what I an using and Have nathing on LCD.
#include // recommended by author DC42
// Digital pin definitions
// Digital pin 0 not used, however if we are using the serial port for debugging then it's serial input
const int debugTxPin = 1; // transmit pin reserved for debugging
const int encoderButtonPin = 2; // encoder button, also IN0 for waking up from sleep mode
const int earpiecePin = 3; // earpiece, aka OCR2B for tone generation
const int T0InputPin = 4;
const int coilDrivePin = 5;
const int LcdRsPin = 6;
const int LcdEnPin = 7;
const int LcdRWPin = 0;[b] // added by me for testing
[/b][color=#FF0000][/color]
const int LcdPowerPin = 8; // LCD power and backlight enable
const int T0OutputPin = 9;
const int lcdD0Pin = 10;
const int lcdD1Pin = 11; // pins 11-13 also used for ICSP
const int LcdD2Pin = 12;
const int LcdD3Pin = 13;
Беннебой
Вторник 30 января 2018 г. 14:55
Я думаю, что вам нужен штифт GPIO для ЖК -R/W. PIN 0 на Arduino Uno - серийный RX.
Чтобы упростить жизнь, я использую драйвер I2C LCD, меньше требуемых контактов, а библиотека - это падение замены, см. ЖК -код в этом репо -> https: // github.com/bennehboy/td5ecuemulator
Чтобы упростить жизнь, я использую драйвер I2C LCD, меньше требуемых контактов, а библиотека - это падение замены, см. ЖК -код в этом репо -> https: // github.com/bennehboy/td5ecuemulator
Тед
Вторник 30 января 2018 г. 15:37
Я сделал это до без успеха const int lcdrwpin = 0; // добавлено мной для тестирования
Беннебой
Вторник 30 января 2018 г. 16:13
[Тед - Вторник 30 января 2018 г. 15:37] - Я сделал это до без успеха const int lcdrwpin = 0; // добавлено мной для тестирования
Сделал то, что раньше?
Я говорю, не используй PIN -код 0.
Тед
Вторник 30 января 2018 г. 16:37
Я пытаюсь использовать 0 пин, я попробую другие.
Тед
Ср 31 января 2018 12:49
Я думаю, что проблема описана ниже
У меня есть программа, которая имеет описание и сообщение с ЖК -плана. Итак, я добавляю жидкий лицистал.H Библиотека.
Я думаю, что я должен объявить тип использованного ЖК -дисплея и добавить команду для запуска ЖК -программы.
Что мне следует с булавками R/W и PBS ?
У меня есть программа, которая имеет описание и сообщение с ЖК -плана. Итак, я добавляю жидкий лицистал.H Библиотека.
Я думаю, что я должен объявить тип использованного ЖК -дисплея и добавить команду для запуска ЖК -программы.
Что мне следует с булавками R/W и PBS ?
Ахулл
Ср 31 января 2018 г. 14:41
Я абсолютно ничего не знаю об этом конкретном дисплее, но из шелковидного экрана я предлагаю вам вытащить R/W Высокий, чтобы читать с дисплея, и низко, чтобы написать на него (поскольку стержень над W). Теперь, какая булавка вы выбрали, чтобы использовать это, я оставлю вас полностью.
Беннебой
Ср 31 января 2018 г. 15:07
Тед
Ср 31 января 2018 г. 15:23
я был там
Так что я тестирую свой ЖК -дисплей с традиционным «Hello World», работает ОК, эта программа использует различную ЖК -библиотеку и булавки.
#2 код
Код: выберите все
#include "u8glib.час"
// PINS ИСПОЛЬЗОВАНИЕ_ E, R/W, RS, PSB.
Так что я тестирую свой ЖК -дисплей с традиционным «Hello World», работает ОК, эта программа использует различную ЖК -библиотеку и булавки.
#2 код
Код: выберите все
#include "u8glib.час"
// PINS ИСПОЛЬЗОВАНИЕ_ E, R/W, RS, PSB.
Беннебой
Ср 31 января 2018 г., 19:15
Последний пост от меня здесь....
Прочитайте ссылку, которую я опубликовал.... Установите UNO только с помощью LCD, подключенного с использованием контактов, описанных в ссылке. Скомпилируйте и загрузите тестовый эскиз, который они предоставляют.
Прочитайте ссылку, которую я опубликовал.... Установите UNO только с помощью LCD, подключенного с использованием контактов, описанных в ссылке. Скомпилируйте и загрузите тестовый эскиз, который они предоставляют.
Тед
Чт, 01 февраля 2018 г. 2:09
Я использовал последнюю ссылку, у меня есть «компоненты хобби» в кадрах. Как внедрить его в эту программу DC42 ?
#define TIMER1_TOP (249) // can adjust this to fine-tune the frequency to get the coil tuned (see above)
#define USE_3V3_AREF (1) // set to 1 of running on an Arduino with USB power, 0 for an embedded atmega28p with no 3.3V supply available
// Digital pin definitions
// Digital pin 0 not used, however if we are using the serial port for debugging then it's serial input
const int debugTxPin = 1; // transmit pin reserved for debugging
const int encoderButtonPin = 2; // encoder button, also IN0 for waking up from sleep mode
const int earpiecePin = 3; // earpiece, aka OCR2B for tone generation
const int T0InputPin = 4;
const int coilDrivePin = 5;
const int LcdRsPin = 6;
const int LcdEnPin = 7;
const int LcdPowerPin = 8; // LCD power and backlight enable
const int T0OutputPin = 9;
const int lcdD0Pin = 10;
const int lcdD1Pin = 11; // pins 11-13 also used for ICSP
const int LcdD2Pin = 12;
const int LcdD3Pin = 13;
// Analog pin definitions
const int receiverInputPin = 0;
const int encoderAPin = A1;
const int encoderBpin = A2;
// Analog pins 3-5 not used
// Variables used only by the ISR
int16_t bins[4]; // bins used to accumulate ADC readings, one for each of the 4 phases
uint16_t numSamples = 0;
const uint16_t numSamplesToAverage = 1024;
// Variables used by the ISR and outside it
volatile int16_t averages[4]; // when we've accumulated enough readings in the bins, the ISR copies them to here and starts again
volatile uint32_t ticks = 0; // system tick counter for timekeeping
volatile bool sampleReady = false; // indicates that the averages array has been updated
// Variables used only outside the ISR
int16_t calib[4]; // values (set during calibration) that we subtract from the averages
volatile uint8_t lastctr;
volatile uint16_t misses = 0; // this counts how many times the ISR has been executed too late. Should remain at zero if everything is working properly.
const double halfRoot2 = sqrt(0.5);
const double quarterPi = 3.1415927/4.0;
const double radiansToDegrees = 180.0/3.1415927;
// The ADC sample and hold occurs 2 ADC clocks (= 32 system clocks) after the timer 1 overflow flag is set.
// This introduces a slight phase error, which we adjust for in the calculations.
const float phaseAdjust = (45.0 * 32.0)/(float)(TIMER1_TOP + 1);
float threshold = 10.0; // lower = greater sensitivity. 10 is just about usable with a well-balanced coil.
// The user will be able to adjust this via a pot or rotary encoder.
void setup()
{
pinMode(encoderButtonPin, INPUT_PULLUP);
digitalWrite(T0OutputPin, LOW);
pinMode(T0OutputPin, OUTPUT); // pulse pin from timer 1 used to feed timer 0
digitalWrite(coilDrivePin, LOW);
pinMode(coilDrivePin, OUTPUT); // timer 0 output, square wave to drive transmit coil
cli();
// Stop timer 0 which was set up by the Arduino core
TCCR0B = 0; // stop the timer
TIMSK0 = 0; // disable interrupt
TIFR0 = 0x07; // clear any pending interrupt
// Set up ADC to trigger and read channel 0 on timer 1 overflow
#if USE_3V3_AREF
ADMUX = (1 << ADLAR); // use AREF pin (connected to 3.3V) as voltage reference, read pin A0, left-adjust result
#else
ADMUX = (1 << REFS0) | (1 << ADLAR); // use Avcc as voltage reference, read pin A0, left-adjust result
#endif
ADCSRB = (1 << ADTS2) | (1 << ADTS1); // auto-trigger ADC on timer/counter 1 overflow
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2); // enable adc, enable auto-trigger, prescaler = 16 (1MHz ADC clock)
DIDR0 = 1;
// Set up timer 1.
// Prescaler = 1, phase correct PWM mode, TOP = ICR1A
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10); // CTC mode, prescaler = 1
TCCR1C = 0;
OCR1AH = (TIMER1_TOP/2 >> 8);
OCR1AL = (TIMER1_TOP/2 & 0xFF);
ICR1H = (TIMER1_TOP >> 8);
ICR1L = (TIMER1_TOP & 0xFF);
TCNT1H = 0;
TCNT1L = 0;
TIFR1 = 0x07; // clear any pending interrupt
TIMSK1 = (1 << TOIE1);
// Set up timer 0
// Clock source = T0, fast PWM mode, TOP (OCR0A) = 7, PWM output on OC0B
TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00) | (1 << CS01) | (1 << CS02) | (1 << WGM02);
OCR0A = 7;
OCR0B = 3;
TCNT0 = 0;
sei();
while (!sampleReady) {} // discard the first sample
misses = 0;
sampleReady = false;
Serial.begin(19200);
}
// Timer 0 overflow interrupt. This serves 2 purposes:
// 1. It clears the timer 0 overflow flag. If we don't do this, the ADC will not see any more Timer 0 overflows and we will not get any more conversions.
// 2. It increments the tick counter, allowing is to do timekeeping. We get 62500 ticks/second.
// We now read the ADC in the timer interrupt routine instead of having a separate comversion complete interrupt.
ISR(TIMER1_OVF_vect)
{
++ticks;
uint8_t ctr = TCNT0;
int16_t val = (int16_t)(uint16_t)ADCH; // only need to read most significant 8 bits
if (ctr != ((lastctr + 1) & 7))
{
++misses;
}
lastctr = ctr;
int16_t *p = &bins[ctr & 3];
if (ctr < 4)
{
*p += (val);
if (*p > 15000) *p = 15000;
}
else
{
*p -= val;
if (*p < -15000) *p = -15000;
}
if (ctr == 7)
{
++numSamples;
if (numSamples == numSamplesToAverage)
{
numSamples = 0;
if (!sampleReady) // if previous sample has been consumed
{
memcpy((void*)averages, bins, sizeof(averages));
sampleReady = true;
}
memset(bins, 0, sizeof(bins));
}
}
}
void loop()
{
while (!sampleReady) {}
uint32_t oldTicks = ticks;
if (digitalRead(encoderButtonPin) == LOW)
{
// Calibrate button pressed. We save the current phase detector outputs and subtract them from future results.
// This lets us use the detector if the coil is slightly off-balance.
// It would be better to everage several samples instead of taking just one.
for (int i = 0; i < 4; ++i)
{
calib[i] = averages[i];
}
sampleReady = false;
Serial.print("Calibrated: ");
for (int i = 0; i < 4; ++i)
{
Serial.write(' ');
Serial.print(calib[i]);
}
Serial.println();
}
else
{
for (int i = 0; i < 4; ++i)
{
averages[i] -= calib[i];
}
const double f = 200.0;
// Massage the results to eliminate sensitivity to the 3rd harmonic, and divide by 200
double bin0 = (averages[0] + halfRoot2 * (averages[1] - averages[3]))/f;
double bin1 = (averages[1] + halfRoot2 * (averages[0] + averages[2]))/f;
double bin2 = (averages[2] + halfRoot2 * (averages[1] + averages[3]))/f;
double bin3 = (averages[3] + halfRoot2 * (averages[2] - averages[0]))/f;
sampleReady = false; // we've finished reading the averages, so the ISR is free to overwrite them again
double amp1 = sqrt((bin0 * bin0) + (bin2 * bin2));
double amp2 = sqrt((bin1 * bin1) + (bin3 * bin3));
double ampAverage = (amp1 + amp2)/2.0;
// The ADC sample/hold takes place 2 clocks after the timer overflow
double phase1 = atan2(bin0, bin2) * radiansToDegrees + 45.0;
double phase2 = atan2(bin1, bin3) * radiansToDegrees;
if (phase1 > phase2)
{
double temp = phase1;
phase1 = phase2;
phase2 = temp;
}
double phaseAverage = ((phase1 + phase2)/2.0) - phaseAdjust;
if (phase2 - phase1 > 180.0)
{
if (phaseAverage < 0.0)
{
phaseAverage += 180.0;
}
else
{
phaseAverage -= 180.0;
}
}
// For diagnostic purposes, print the individual bin counts and the 2 indepedently-calculated gains and phases
Serial.print(misses);
Serial.write(' ');
if (bin0 >= 0.0) Serial.write(' ');
Serial.print(bin0, 2);
Serial.write(' ');
if (bin1 >= 0.0) Serial.write(' ');
Serial.print(bin1, 2);
Serial.write(' ');
if (bin2 >= 0.0) Serial.write(' ');
Serial.print(bin2, 2);
Serial.write(' ');
if (bin3 >= 0.0) Serial.write(' ');
Serial.print(bin3, 2);
Serial.print(" ");
Serial.print(amp1, 2);
Serial.write(' ');
Serial.print(amp2, 2);
Serial.write(' ');
if (phase1 >= 0.0) Serial.write(' ');
Serial.print(phase1, 2);
Serial.write(' ');
if (phase2 >= 0.0) Serial.write(' ');
Serial.print(phase2, 2);
Serial.print(" ");
// Print the final amplitude and phase, which we use to decide what (if anything) we have found)
if (ampAverage >= 0.0) Serial.write(' ');
Serial.print(ampAverage, 1);
Serial.write(' ');
if (phaseAverage >= 0.0) Serial.write(' ');
Serial.print((int)phaseAverage);
// Decide what we have found and tell the user
if (ampAverage >= threshold)
{
// When held in line with the centre of the coil:
// - non-ferrous metals give a negative phase shift, e.g. -90deg for thick copper or aluminium, a copper olive, -30deg for thin alumimium.
// Ferrous metals give zero phase shift or a small positive phase shift.
// So we'll say that anything with a phase shift below -20deg is non-ferrous.
if (phaseAverage < -20.0)
{
Serial.print(" Non-ferrous");
}
else
{
Serial.print(" Ferrous");
}
float temp = ampAverage;
while (temp > threshold)
{
Serial.write('!');
temp -= (threshold/2);
}
}
Serial.println();
}
while (ticks - oldTicks < 16000)
{
}
}
Тед
Чт, 01 февраля 2018 г., 3:27
Я сделал две реализации, экран черный для программы DC42, и для программы «Hello World» работает.
Поэтому мне нужно изменить черный экран, чтобы отобразить сообщение программы DC42, которые находятся на своем конце = активировать последовательный.печать
#1
Поэтому мне нужно изменить черный экран, чтобы отобразить сообщение программы DC42, которые находятся на своем конце = активировать последовательный.печать
#1
// include the library code:
//#include
/* Include the U8glib library */
#include "U8glib.h"
/* Define the SPI Chip Select pin */
#define CS_PIN 10
/* Create an instance of the library for the 12864 LCD in SPI mode */
U8GLIB_ST7920_128X64_1X u8g(CS_PIN);
Беннебой
Чт 01 февраля 2018 г. 8:09
Я подозреваю, что вам может быть лучше, задавая ваши вопросы об arduino.Форум CC, который имеет гораздо более активное USRE, со временем, чтобы помочь новичкам в кодировании AVR/MCU - в соответствии с вопросами, которые вы задаете, действительно не связаны с STM32, в то время как вы выясняете, как получить основы вашего проекта, работая над UNO.
Тед
Чт 01 февраля 2018 г., 20:47
ЖК -дисплей отображает то, что находится под прямой линией № 1, мне нужно изменить это на информацию ниже.
// Induction balance metal detector
// We run the CPU at 16MHz and the ADC clock at 1MHz. ADC resolution is reduced to 8 bits at this speed.
// Timer 1 is used to divide the system clock by about 256 to produce a 62.5kHz square wave.
// This is used to drive timer 0 and also to trigger ADC conversions.
// Timer 0 is used to divide the output of timer 1 by 8, giving a 7.8125kHz signal for driving the transmit coil.
// This gives us 16 ADC clock cycles for each ADC conversion (it actually takes 13.5 cycles), and we take 8 samples per cycle of the coil drive voltage.
// The ADC implements four phase-sensitive detectors at 45 degree intervals. Using 4 instead of just 2 allows us to cancel the third harmonic of the
// coil frequency.
// Timer 2 will be used to generate a tone for the earpiece or headset.
// Other division ratios for timer 1 are possible, from about 235 upwards.
// Wiring:
// Connect digital pin 4 (alias T0) to digital pin 9
// Connect digital pin 5 through resistor to primary coil and tuning capacitor
// Connect output from receive amplifier to analog pin 0. Output of receive amplifier should be biased to about half of the analog reference.
// When using USB power, change analog reference to the 3.3V pin, because there is too much noise on the +5V rail to get good sensitivity.
#define TIMER1_TOP (249) // can adjust this to fine-tune the frequency to get the coil tuned (see above)
#define USE_3V3_AREF (1) // set to 1 of running on an Arduino with USB power, 0 for an embedded atmega28p with no 3.3V supply available
// include the library code:
//#include
/* Include the U8glib library */
#include "U8glib.h"
/* Define the SPI Chip Select pin */
#define CS_PIN 10
/* Create an instance of the library for the 12864 LCD in SPI mode */
U8GLIB_ST7920_128X64_1X u8g(CS_PIN);
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
//const int rs = 6, en = 7, d4 = 10, d5 = 11, d6 = 12, d7 = 13;
//LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// Digital pin definitions
// Digital pin 0 not used, however if we are using the serial port for debugging then it's serial input
const int debugTxPin = 1; // transmit pin reserved for debugging
const int encoderButtonPin = 2; // encoder button, also IN0 for waking up from sleep mode
const int earpiecePin = 3; // earpiece, aka OCR2B for tone generation
const int T0InputPin = 4;
const int coilDrivePin = 5;
const int LcdEPin = 13;
const int LcdRWPin = 11;
const int LcdRsPin = 10;
//const int LcdRsPin = 6;
//const int LcdEnPin = 7;
const int LcdPowerPin = 8; // LCD power and backlight enable
const int T0OutputPin = 9;
/*
const int lcdD0Pin = 10;
const int lcdD1Pin = 11; // pins 11-13 also used for ICSP
const int LcdD2Pin = 12;
const int LcdD3Pin = 13;
*/
// Analog pin definitions
const int receiverInputPin = 0;
const int encoderAPin = A1;
const int encoderBpin = A2;
// Analog pins 3-5 not used
// Variables used only by the ISR
int16_t bins[4]; // bins used to accumulate ADC readings, one for each of the 4 phases
uint16_t numSamples = 0;
const uint16_t numSamplesToAverage = 1024;
// Variables used by the ISR and outside it
volatile int16_t averages[4]; // when we've accumulated enough readings in the bins, the ISR copies them to here and starts again
volatile uint32_t ticks = 0; // system tick counter for timekeeping
volatile bool sampleReady = false; // indicates that the averages array has been updated
// Variables used only outside the ISR
int16_t calib[4]; // values (set during calibration) that we subtract from the averages
volatile uint8_t lastctr;
volatile uint16_t misses = 0; // this counts how many times the ISR has been executed too late. Should remain at zero if everything is working properly.
const double halfRoot2 = sqrt(0.5);
const double quarterPi = 3.1415927/4.0;
const double radiansToDegrees = 180.0/3.1415927;
// The ADC sample and hold occurs 2 ADC clocks (= 32 system clocks) after the timer 1 overflow flag is set.
// This introduces a slight phase error, which we adjust for in the calculations.
const float phaseAdjust = (45.0 * 32.0)/(float)(TIMER1_TOP + 1);
float threshold = 10.0; // lower = greater sensitivity. 10 is just about usable with a well-balanced coil.
// The user will be able to adjust this via a pot or rotary encoder.
void setup()
{
// set up the LCD's number of columns and rows:
// lcd.begin(16, 2);
// Print a message to the LCD.
//lcd.print("hello, world!");
///////////////////////////////////////////////////////////////
{
/* Start of a picture loop */
u8g.firstPage();
/* Keep looping until finished drawing screen */
do
{
/* Set the font */
u8g.setFont(u8g_font_courB14);
// #1
///////////////////////////////////////////////////////////
/* Display some text */
u8g.drawStr( 35, 26, "HOBBY");
u8g.drawStr( 8, 46, "COMPONENTS");
/* Draw a simple border */
u8g.drawFrame(5,5,117,54);
u8g.drawFrame(3,3,121,58);
}while(u8g.nextPage());
}
pinMode(encoderButtonPin, INPUT_PULLUP);
digitalWrite(T0OutputPin, LOW);
pinMode(T0OutputPin, OUTPUT); // pulse pin from timer 1 used to feed timer 0
digitalWrite(coilDrivePin, LOW);
pinMode(coilDrivePin, OUTPUT); // timer 0 output, square wave to drive transmit coil
cli();
// Stop timer 0 which was set up by the Arduino core
TCCR0B = 0; // stop the timer
TIMSK0 = 0; // disable interrupt
TIFR0 = 0x07; // clear any pending interrupt
// Set up ADC to trigger and read channel 0 on timer 1 overflow
#if USE_3V3_AREF
ADMUX = (1 << ADLAR); // use AREF pin (connected to 3.3V) as voltage reference, read pin A0, left-adjust result
#else
ADMUX = (1 << REFS0) | (1 << ADLAR); // use Avcc as voltage reference, read pin A0, left-adjust result
#endif
ADCSRB = (1 << ADTS2) | (1 << ADTS1); // auto-trigger ADC on timer/counter 1 overflow
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2); // enable adc, enable auto-trigger, prescaler = 16 (1MHz ADC clock)
DIDR0 = 1;
// Set up timer 1.
// Prescaler = 1, phase correct PWM mode, TOP = ICR1A
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10); // CTC mode, prescaler = 1
TCCR1C = 0;
OCR1AH = (TIMER1_TOP/2 >> 8);
OCR1AL = (TIMER1_TOP/2 & 0xFF);
ICR1H = (TIMER1_TOP >> 8);
ICR1L = (TIMER1_TOP & 0xFF);
TCNT1H = 0;
TCNT1L = 0;
TIFR1 = 0x07; // clear any pending interrupt
TIMSK1 = (1 << TOIE1);
// Set up timer 0
// Clock source = T0, fast PWM mode, TOP (OCR0A) = 7, PWM output on OC0B
TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00) | (1 << CS01) | (1 << CS02) | (1 << WGM02);
OCR0A = 7;
OCR0B = 3;
TCNT0 = 0;
sei();
while (!sampleReady) {} // discard the first sample
misses = 0;
sampleReady = false;
Serial.begin(19200);
}
// Timer 0 overflow interrupt. This serves 2 purposes:
// 1. It clears the timer 0 overflow flag. If we don't do this, the ADC will not see any more Timer 0 overflows and we will not get any more conversions.
// 2. It increments the tick counter, allowing is to do timekeeping. We get 62500 ticks/second.
// We now read the ADC in the timer interrupt routine instead of having a separate comversion complete interrupt.
ISR(TIMER1_OVF_vect)
{
++ticks;
uint8_t ctr = TCNT0;
int16_t val = (int16_t)(uint16_t)ADCH; // only need to read most significant 8 bits
if (ctr != ((lastctr + 1) & 7))
{
++misses;
}
lastctr = ctr;
int16_t *p = &bins[ctr & 3];
if (ctr < 4)
{
*p += (val);
if (*p > 15000) *p = 15000;
}
else
{
*p -= val;
if (*p < -15000) *p = -15000;
}
if (ctr == 7)
{
++numSamples;
if (numSamples == numSamplesToAverage)
{
numSamples = 0;
if (!sampleReady) // if previous sample has been consumed
{
memcpy((void*)averages, bins, sizeof(averages));
sampleReady = true;
}
memset(bins, 0, sizeof(bins));
}
}
}
void loop()
{
while (!sampleReady) {}
uint32_t oldTicks = ticks;
if (digitalRead(encoderButtonPin) == LOW)
{
// Calibrate button pressed. We save the current phase detector outputs and subtract them from future results.
// This lets us use the detector if the coil is slightly off-balance.
// It would be better to everage several samples instead of taking just one.
for (int i = 0; i < 4; ++i)
{
calib[i] = averages[i];
}
sampleReady = false;
Serial.print("Calibrated: ");
for (int i = 0; i < 4; ++i)
{
Serial.write(' ');
Serial.print(calib[i]);
}
Serial.println();
}
else
{
for (int i = 0; i < 4; ++i)
{
averages[i] -= calib[i];
}
const double f = 200.0;
// Massage the results to eliminate sensitivity to the 3rd harmonic, and divide by 200
double bin0 = (averages[0] + halfRoot2 * (averages[1] - averages[3]))/f;
double bin1 = (averages[1] + halfRoot2 * (averages[0] + averages[2]))/f;
double bin2 = (averages[2] + halfRoot2 * (averages[1] + averages[3]))/f;
double bin3 = (averages[3] + halfRoot2 * (averages[2] - averages[0]))/f;
sampleReady = false; // we've finished reading the averages, so the ISR is free to overwrite them again
double amp1 = sqrt((bin0 * bin0) + (bin2 * bin2));
double amp2 = sqrt((bin1 * bin1) + (bin3 * bin3));
double ampAverage = (amp1 + amp2)/2.0;
// The ADC sample/hold takes place 2 clocks after the timer overflow
double phase1 = atan2(bin0, bin2) * radiansToDegrees + 45.0;
double phase2 = atan2(bin1, bin3) * radiansToDegrees;
if (phase1 > phase2)
{
double temp = phase1;
phase1 = phase2;
phase2 = temp;
}
double phaseAverage = ((phase1 + phase2)/2.0) - phaseAdjust;
if (phase2 - phase1 > 180.0)
{
if (phaseAverage < 0.0)
{
phaseAverage += 180.0;
}
else
{
phaseAverage -= 180.0;
}
}
//#2
//////////////////////////////////////////////////////////////////////////////
// For diagnostic purposes, print the individual bin counts and the 2 indepedently-calculated gains and phases
Serial.print(misses);
Serial.write(' ');
if (bin0 >= 0.0) Serial.write(' ');
Serial.print(bin0, 2);
Serial.write(' ');
if (bin1 >= 0.0) Serial.write(' ');
Serial.print(bin1, 2);
Serial.write(' ');
if (bin2 >= 0.0) Serial.write(' ');
Serial.print(bin2, 2);
Serial.write(' ');
if (bin3 >= 0.0) Serial.write(' ');
Serial.print(bin3, 2);
Serial.print(" ");
Serial.print(amp1, 2);
Serial.write(' ');
Serial.print(amp2, 2);
Serial.write(' ');
if (phase1 >= 0.0) Serial.write(' ');
Serial.print(phase1, 2);
Serial.write(' ');
if (phase2 >= 0.0) Serial.write(' ');
Serial.print(phase2, 2);
Serial.print(" ");
// Print the final amplitude and phase, which we use to decide what (if anything) we have found)
if (ampAverage >= 0.0) Serial.write(' ');
Serial.print(ampAverage, 1);
Serial.write(' ');
if (phaseAverage >= 0.0) Serial.write(' ');
Serial.print((int)phaseAverage);
// Decide what we have found and tell the user
if (ampAverage >= threshold)
{
// When held in line with the centre of the coil:
// - non-ferrous metals give a negative phase shift, e.g. -90deg for thick copper or aluminium, a copper olive, -30deg for thin alumimium.
// Ferrous metals give zero phase shift or a small positive phase shift.
// So we'll say that anything with a phase shift below -20deg is non-ferrous.
if (phaseAverage < -20.0)
{
Serial.print(" Non-ferrous");
}
else
{
Serial.print(" Ferrous");
}
float temp = ampAverage;
while (temp > threshold)
{
Serial.write('!');
temp -= (threshold/2);
}
}
Serial.println();
}
while (ticks - oldTicks < 16000)
{
}
}
Mrburnette
Чт, 01 февраля 2018 г., 22:41
[Беннебой - Чт 01 февраля 2018 г. 8:09 утра] - Я подозреваю ...Я думаю, что Тед просто держит нас в курсе своего прогресса .. Как журнал проекта.
Луча
Тед
Пт, 02 февраля 2018 г., 15:44
Тед изучает программирование.
Он показывает, с какими проблемами он сталкивается, и ищет на них ответы.
Он показывает, с какими проблемами он сталкивается, и ищет на них ответы.
Tfried
Сб 03 февраля 2018 г. 20:06
Тед изучает программирование.
Он показывает, с какими проблемами он сталкивается, и ищет на них ответы. Нет проблем, Тед. Мы все были там, C ++ не является чем -то родным языком, в конце концов.
Но при поиске ответов примите, когда ответ: «Вам нужно сделать шаг назад и начать базовый". Действительно, вы пытаетесь решить конкретные проблемы, и, конечно, найти решение этих проблем, именно поэтому вы смотрите на программирование в первую очередь. Но даже если вы можете чувствовать себя очень близко к решению этих проблем с вашим текущим методом копирования и вставки, вы, кажется, полностью недооценивают, это ваше отсутствие понимания справедливого как Любое из того, что на самом деле работает ваше копирование (на уровне программирования). Извините, но в этом не хватает является фундаментальным И вы нигде не пытаетесь игнорировать это. Лучшее понимание будет нет Приходите автоматически, просто потратив больше времени на свой подход. Вместо этого, что вам нужно сделать, это вернуться и проработать некоторые основные учебные пособия. Сосредоточившись на "Hello World!"Может выглядеть как огромный шаг назад, но вы ни разу Собираюсь достичь ваших реальных целей, если вы не потратите время на понимание каждая линия таких основных примеров. Да, многое из этого уже будет вам знакомо. Не позволяй этому обмануть тебя. Вам все еще нужно понять основы, полностью.
Поскольку вы говорите, что у вас есть твердое сцепление со стороны электроники, и вам не нужна помощь с такими основными задачами, как установка или загрузка, попробуйте эти учебники, сосредоточенные на основе программирования: https: // startelectronics.org/softwar ... Am-Course/. Все они, пожалуйста. И опять же, вам нужно понять каждую линию кода в этих учебниках. Это займет некоторое время (хотя не навсегда) и усилия (не усилие супергероя), но нет ярлыка Чтобы изучить основы.
Ваше здоровье!
Он показывает, с какими проблемами он сталкивается, и ищет на них ответы. Нет проблем, Тед. Мы все были там, C ++ не является чем -то родным языком, в конце концов.
Но при поиске ответов примите, когда ответ: «Вам нужно сделать шаг назад и начать базовый". Действительно, вы пытаетесь решить конкретные проблемы, и, конечно, найти решение этих проблем, именно поэтому вы смотрите на программирование в первую очередь. Но даже если вы можете чувствовать себя очень близко к решению этих проблем с вашим текущим методом копирования и вставки, вы, кажется, полностью недооценивают, это ваше отсутствие понимания справедливого как Любое из того, что на самом деле работает ваше копирование (на уровне программирования). Извините, но в этом не хватает является фундаментальным И вы нигде не пытаетесь игнорировать это. Лучшее понимание будет нет Приходите автоматически, просто потратив больше времени на свой подход. Вместо этого, что вам нужно сделать, это вернуться и проработать некоторые основные учебные пособия. Сосредоточившись на "Hello World!"Может выглядеть как огромный шаг назад, но вы ни разу Собираюсь достичь ваших реальных целей, если вы не потратите время на понимание каждая линия таких основных примеров. Да, многое из этого уже будет вам знакомо. Не позволяй этому обмануть тебя. Вам все еще нужно понять основы, полностью.
Поскольку вы говорите, что у вас есть твердое сцепление со стороны электроники, и вам не нужна помощь с такими основными задачами, как установка или загрузка, попробуйте эти учебники, сосредоточенные на основе программирования: https: // startelectronics.org/softwar ... Am-Course/. Все они, пожалуйста. И опять же, вам нужно понять каждую линию кода в этих учебниках. Это займет некоторое время (хотя не навсегда) и усилия (не усилие супергероя), но нет ярлыка Чтобы изучить основы.
Ваше здоровье!
Тед
Сб 03 февраля 2018 г., 20:29
Я мечтаю понять каждую строку, спасибо за отличную ссылку, я близок, чтобы решить проблему, просто заменить сериал на ЖК -дисплей и больше копать.
Тед
Чт, 08 февраля 2018 г. 14:43
Я следил за тем, чтобы добраться до кока -колы - 95 см. Не нужен фильтр наемка 60 Гц
Программа любой информации ценится.
Программа любой информации ценится.
Ахулл
Сб 10 февраля 2018 г. 12:29
Насколько хороша ваша тригонометрия Foo?
https: // www.Researchgate.net/post/how_t ... tch_filter
Я предполагаю, что вы пытаетесь удалить Главные гули, Но вы не полностью описали свою проблему. Вам может быть проще сделать фильтрацию с одним или несколькими электронными фильтрами R/C или L/C. Это займет часть нагрузки с вашего процессора. Иногда проще бросить несколько операционных усилий и некоторых пассива в задачу, чем попытаться вычислить решение в режиме реального времени. Тем более.
https: // en.Википедия.org/wiki/band-stop_filter
https: // www.Researchgate.net/post/how_t ... tch_filter
Я предполагаю, что вы пытаетесь удалить Главные гули, Но вы не полностью описали свою проблему. Вам может быть проще сделать фильтрацию с одним или несколькими электронными фильтрами R/C или L/C. Это займет часть нагрузки с вашего процессора. Иногда проще бросить несколько операционных усилий и некоторых пассива в задачу, чем попытаться вычислить решение в режиме реального времени. Тем более.
https: // en.Википедия.org/wiki/band-stop_filter
Ахулл
Сб 10 февраля 2018 г. 11:30
Связанный (своего рода) -> https: // chackaday.com/2018/02/10/all- ... id-to-ask/
Связано в том смысле, что эта серия видео сообщает вам в относительно усваиваемом формате * Как * удаление определенной частоты из кучи частот на самом деле работает.
Для тех из вас, кто считает вашу математику, немного ржаво, вы можете сначала пройти через материал «Единый круг» в следующей серии видео, чтобы получить захват основных концепций триг.
Также прочитание этого связанного потока... -> ViewTopic.PHP?t = 1145&начало = 30#p14677
... И видео здесь ...
Может быть, тоже стоит время.
Связано в том смысле, что эта серия видео сообщает вам в относительно усваиваемом формате * Как * удаление определенной частоты из кучи частот на самом деле работает.
Для тех из вас, кто считает вашу математику, немного ржаво, вы можете сначала пройти через материал «Единый круг» в следующей серии видео, чтобы получить захват основных концепций триг.
Также прочитание этого связанного потока... -> ViewTopic.PHP?t = 1145&начало = 30#p14677
... И видео здесь ...
Может быть, тоже стоит время.
Пито
Сб 10 февраля 2018 г. 13:53
60 Гц Band Stop:
С помощью фильтра FIR вы можете получить, например, (нажмите «Исходный код», выберите IE. Формат числа: целое число и 32 -битный int precision и скопировать/вставить источник) - ссылка находится на рисунке ниже:
С помощью фильтра FIR вы можете получить, например, (нажмите «Исходный код», выберите IE. Формат числа: целое число и 32 -битный int precision и скопировать/вставить источник) - ссылка находится на рисунке ниже:
- 60 Гц bandstop_minus 90db.JPG (85.54 киб) просмотрено 309 раз
Ахулл
Сб 10 февраля 2018 г. 14:13
Очень аккуратно. Мне это нравится. (Ссылка на вышеупомянутый сайт -> здесь <- )
Пито
Сб 10 февраля 2018 г. 15:22
..
#include "SampleFilter.c"
..
int32_t signal; // the actual ADC signal sample
int32_t fsig; // internal FIR filter variable
setup() {
..
SampleFilter_init(&fsig); // you have to init the FIR filter
..
}
HERE IS A 400Hz SAMPLING LOOP >>>>>
signal = readAnalog(PA4); // get 12bit signal sample
SampleFilter_put(&fsig, signal); // pass the signal into the FIR filter
signal = SampleFilter_get(&fsig); // read the signal from the FIR filter
..
DO SOMETHING WITH THE FILTERED signal
..
<<<<< END OF THE 400Hz SAMPLING LOOP
Тед
Сб 10 февраля 2018 г. 16:02
Спасибо за вашу поддержку, я читаю всю информацию, я могу сгенерировать исходный код для фильтров, но я еще не знаю, как их реализовать, я имею в виду добавить функции для выводов ввода и вывода.
Вот код, который работал раньше, но когда я его сохранил и снова открыл, ШИМ на PIN PB1 больше нет. В этой программе также Notch Filter.
Вот код, который работал раньше, но когда я его сохранил и снова открыл, ШИМ на PIN PB1 больше нет. В этой программе также Notch Filter.
#include
#include
const float ECG_samplefreq = 360;
const uint8_t ECG_pin = PB0;
const int16_t DC_offset = 511;
//const uint8_t ECG_pin = PB1; //output pin
int outputPin = PB1; //output pin
//int outputPin = PA6; //output pin
// 50 Hz notch
//const float b_notch[] = { 1.39972748302835, -1.79945496605670, 1.39972748302835 };
/*
// 35 Hz Butterworth low-pass
const float b_lp[] = { 0.00113722762905776, 0.00568613814528881, 0.0113722762905776, 0.0113722762905776, 0.00568613814528881, 0.00113722762905776 };
const float a_lp[] = { 1, -3.03124451613593, 3.92924380774061, -2.65660499035499, 0.928185738776705, -0.133188755896548 };
*/
const float a_coefficients[] = {1, 3.610968072739773, 5.096060175734044, 3.317095275389235, 0.844114606367055};
const float b_coefficients[] = {0.003306153133358, 0, -0.006612306266715, 0, 0.003306153133358};
/*
// 0.3 Hz high-pass
const float b_hp[] = { 1, -1 };
const float a_hp[] = { 1, -0.995 };
FIRFilter notch(b_notch);
//IIRFilter lp(b_lp, a_lp);
IIRFilter hp(b_hp, a_hp);
*/
void setup() {
Serial.begin(115200);
}
unsigned long ECG_prevmicros = micros();
void loop() {
const static unsigned long ECG_interval = round(1e6 / ECG_samplefreq);
if (!Serial) {
ECG_prevmicros = micros();
} else if (micros() - ECG_prevmicros >= ECG_interval) {
measureECGAndSend();
ECG_prevmicros += ECG_interval;
}
}
void measureECGAndSend() {
int16_t value = analogRead(ECG_pin);
float filtered = //notch.filter(
//lp.filter(
// hp.filter(value - DC_offset));
value = round((filtered) + DC_offset);
Serial.println(value);
//Serial.print(value); // PWM on PB1
value = map(value, 0, 1023, 0, 255);
value = constrain(value, 0, 255);
analogWrite(outputPin, value); // output pin
}
Тед
Сб 10 февраля 2018 г. 20:05
Спасибо, Пито
Я прочитал все, включая ссылку, но со своими знаниями по программированию я не могу собрать все вместе.
Я прочитал все, включая ссылку, но со своими знаниями по программированию я не могу собрать все вместе.