Правильно, выигрыш — в уменьшении частоты сигнала — переходом с завышенной на рабочую частоту и использовании обычных «однофазных (не дифференциальных)» проводов. Согласовать не всегда просто, особенно, с неизвестным волновым сопротивлением, в моем случае USB сигнал необходимо было пропустить через несигнальные четырех-метровые провода электроввода (2м снаружи, 2 м внутри) в камеру высокого давления.
Работу с LowSpeed не проверял.
Из руководства пользователя MPLAB (Google переводчик):
При добавлении файла вы можете выбрать, следует ли добавить его как:
…
• Относительный (Relative) — местоположение файла указывается по отношению к проекту (рекомендуется использовать этот вариант, например, для перемещения проекта на другой компьютер.)
• Абсолютный (Absolute) — Указывается абсолютный путь расположения файла,
Что почитать?
Рекомендую
— взять любой простейший пример на ассемблере
— набрать его в редакторе MPLAB
— открыть в MPLAB окна с отображением регистров и памяти виртуального контроллера и
— под отладчиком по шагам рассмотреть как программа изменяет содержимое регистров и памяти контроллера
MPLAB позволяет смоделировать и подачу внешних виртуальных сигналов на портах контроллера.
Подробное описание используемых команд программы лучше взять из первоисточника, например:
PIC12F6XX Однокристальные 8-разрядные FLASH CMOS микроконтроллеры компании Microchip Technology Incorporated
• PIC12F629
• PIC12F675
Перевод основывается на технической документации DS4 11 90A компании Microchip Technology Incorporated, USA.
Этими же средствами можно построить и вычислитель координат. Вот пример отслеживания координат объекта (26х36 пикселей) в кадре 320х240, практически, с частотой загрузки кадров (1/33 мс) оператором snapshot(cam).
clear all
load ('target_image_art'); % 36х26 uint8
% figure, imshow(target_image);
dX = size(target_image,2); 26 pixels
dY = size(target_image,1); 36 pixels
Img_eroding = 100; % average between screen and target intensity
cam = webcam(1);
cam.Resolution = '320x240';
for i = 1:1000
pct = snapshot(cam);
Img=rgb2gray(pct); % rgb in gray
Img_edge_enhacement=imsubtract(Img,Img_eroding); % negative result of subtract is replaced by zero
Img_lgc=logical(Img_edge_enhacement); % '0' if pixel = 0; '1' if pixel > 0
%figure, imshow(Img_lgc);
Img_inv_lgc = not(Img_lgc); % inversion
Img_inv_flt_lgc = bwareaopen(Img_inv_lgc,500); % remove 'island' being less than 500 pixels
Iprops=regionprops(Img_inv_flt_lgc,'BoundingBox','Image'); % find remained 'islands'
% format: Iprops(i).BoundingBox(:) = [X,Y,dX,dY]
obj_num = find(arrayfun(@(x)max(x.BoundingBox(3)),Iprops)< 50 & ... % max(dx)
arrayfun(@(x)min(x.BoundingBox(3)),Iprops)> 10 & ... % min(dx)
arrayfun(@(x)max(x.BoundingBox(4)),Iprops)< 60 & ... % max(dy)
arrayfun(@(x)min(x.BoundingBox(4)),Iprops)> 20); % min(dy)
% display target
if ~isempty(obj_num)
X = Iprops(obj_num(1)).BoundingBox(1);
Y = Iprops(obj_num(1)).BoundingBox(2)+11;
if X+dX < 320 && Y+dY < 240
% target iside the screen
target_area = [X,Y,dX-1,dY-1];
Imf = insertShape(pct, 'Rectangle', target_area, 'Color', 'green');
image(Imf);
else
% target in screen boarder
image(pct);
end
else
% no target found
image(pct);
end
end
clear cam;
Рис. Результаты отслеживания координат объекта при изменении черных зон и разворотах.
Увеличение точности в зоне меньшей кадра (с известными координатами) можно получить применением корреляционных методов.
При обмене данными через общую шину буфер является выходом передающего устройства, а регистр – входом принимающего устройства. Только одна пара передатчик-приёмник участвует в обмене.
Буфер действует как ключ, который подключает сигналы устройства к шине данных на время кратковременного цикла обращения к устройству, остальное время буфер отсоединен от шины данных открытыми коллекторами. Для простоты, можно рассматривать буфер как идеальный параллельный ключ, который замыкает или размыкает проводники по сигналу управления.
При помощи регистра устройство принимает и сохраняет кратковременные данные шины.
Спасибо за ссылку на datasheet.
Вариант канала контроллер – COM порт – модель МатЛАБ с сэмплированием на 66 кГц изложен в дополнении к основной работе: последнее “Задание 6”.
Спасибо за обстоятельный комментарий.
Вариант канала контроллер – COM порт – модель МатЛАБ с сэмплированием на 66 кГц изложен в дополнении к основной работе: последнее “Задание 6”.
void loop(){
unsigned long time_start = millis();
for (int i = 0; i < 256; i++) {
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA & (1 << ADIF)) == 0); // пока не будет выставлено флага об окончании преобразования
// u = (ADCL|ADCH << 8); // Считываем полученное значение
// adc_bytes[i] = ADCL; // Считываем полученное значение
}
unsigned long time_end = millis();
unsigned int dt = time_end — time_start;
Serial.println (dt);
}
Программа (без затрат на обработку прерываний) показала, что максимальная частота преобразований = 9.14 КГц (как 1/(28мс/256)), близка к 10 КГц, но далека от 50… 80 КГц.
На результат не влияют
— установка частоты преобразования 76 КГц и выше битами ADPS0… ADPS2
— добавление чтения: u = (ADCL|ADCH << 8)
— добавление копирования в массив adc_bytes[i] = ADCL
Вывод: максимальная частота преобразования АЦП Arduino UNO c процессором ATmega328 не превышает 10 кГц.
Буду рад узнать, что это ошибочное утверждение и существуют примеры, доказывающие возможность корректного АЦ Преобразования на более высоких частотах для контроллера Arduino UNO.
Что-то делаю не так. UDR0 имеет только нулевые значения.
Проверил использование ISR на следующем примере. Работает.
Не могли бы Вы показать вариант заполнения АЦП данными в память Arduino (например, размером 1024 байт) на максимальной частоте, передачи массива в COM порт (на любой частоте) и циклического повторения названных операций.
volatile int count = 0; // Переменная счётчика (volatile означает указание компилятору не оптимизировать код её чтения,
// поскольку её значение изменяется внутри обработчика прерывания)
ISR(INT0_vect)
{
count = 25; // Инициализировать счётчик
}
// Режимы вызова прерывания INT0
#define INT0_SENSE_LOW_LEVEL 0 // Прерывание при низком уровне на выводе
#define INT0_SENSE_LEVEL_CHANGE 1 // Прерывание при изменении уровня
#define INT0_SENSE_FALLING_EDGE 2 // Прерывание по фронту на спад (когда 1 переходит в 0)
#define INT0_SENSE_RISING_EDGE 3 // Прерывание по фронту на подъём (когда 0 переходит в 1)
// Управляющая функция для прерывания INT0
// mode — режим вызова прерывания
// enable — разрешить/запретить прерывание
void int0Control (uint8_t mode, bool enable){
EIMSK &= ~ (1 << INT0); // Запретить прерывание (так как следующая команда устанавливает режим INT0_SENSE_LOW_LEVEL)
EICRA &= ~ (1 << ISC00) | (1 << ISC01); // Обнуляем биты ISC00 и ISC01 в регистре EICRA
EICRA |= mode; // Устанавливаем режим вызова прерывания INT0
if (enable)
EIMSK |= (1 << INT0); // Разрешить прерывание
}
void setup(){
pinMode(LEDPIN, OUTPUT);
pinMode(BTNPIN, INPUT); // Вывод кнопки в режим ввода
int0Control(INT0_SENSE_RISING_EDGE, true); // Разрешить прерывание по фронту на подъём (в данном случае при нажатии на кнопку)
interrupts(); // Разрешить прерывания глобально
}
void loop(){
if(count==0) {
digitalWrite(LEDPIN, LOW); // Выключить светодиод, если счётчик равен 0…
}
else {
digitalWrite(LEDPIN, HIGH); //… иначе включить светодиод,
--count; // и уменьшить счётчик на 1.
}
delay(100); // Подумать 10 милисекунд.
}
Фантастика! Если покажете на рабочем примере как это сделать, думаю, многим бы пригодилась работа Arduino с АЦП на таких (или более высоких чем сейчас) частотах.
В режиме rtwin.tlc частота сэмплирования совпадает с частотой RT. Например, при частоте RT 2 КГц вычисления цикла в режиме rtwin.tlc не могут превышать 0.5 мсек…
В предлагаемом варианте период RT может заметно превышать период сэмплирования. Сэмплирование с частотой выше 2 КГц может выполняться в RT режиме с периодом в десятки и сотни мсек. Используя векторную обработку данных (а средства МатЛАБ и ориентированы на работу с матрицами) можно существенно (в десятки и более раз) увеличить вычислительную мощь алгоритмов ( в сравнении с 0.5 мс вариантом) и использовать недорогие популярные средства типа Arduino.
0.07 – время цикла (в секундах) — время построения одного кадра. Здесь построение кадра должно быть чуть дольше, чем суммарное время 256 преобразований АЦП (42 мс) и передачи (23 мс). При автономной работе Arduino время передачи используется для обработки данных по найденному в МатЛАБ алгоритму.
Для других задач время кадра можно уменьшить вместе с вектором нулевых констант модели так, чтобы эталонный сигнал, например, период сетевой 50 Гц наводки отображался правильно.
В этих примерах заголовок (header) может быть и другим. Только его нужно указать и в коде Arduino и в блоке “Serial Receive” модели.
Мой опыт работы с PCI (!!!) платами: Sensory 626 и NI-6014 (“узнаваемыми” МатЛАБ) говорит, что на 2 КГц в RT режиме (с rtwin.tlc) работа возможна с несложными моделями, которые накапливают данные в workspace не более одной минуты.
В отличии от LabWiew, МатЛАБ не будет компилировать модель для работы в режиме реального времени если не может гарантировать все необходимые вычисления внутри такта (и этим он тоже хорош).
Однако, интересно увидеть ваши примеры работы оборудования с МатЛАБ в контурных задачах в режиме реального времени на частотах 10… 20 кГц.
Планы? — выставлять работы в основном связанные с автоматизацией и управлением технических систем под “dr bob davidov”
Спасибо за дельный совет. Используя Вашу подсказку сделал следующее.
1. В файле ...\arduino-1.0.6\hardware\arduino\cores\arduino\ wiring_analog.c создал копию функции int analogRead(uint8_t pin): int analogRead8bit(uint8_t pin)
2. В копию внёс следующие изменения
2.1. Заменил “int analogRead8bit(uint8_t pin)” на “byte analogRead8bit(uint8_t pin)”
2.2. Убрал “low” из “uint8_t low, high;”
2.3. Заменил “ADMUX = (analog_reference << 6) | (pin & 0x07);” на “ADMUX = (analog_reference << 6) | (pin & 0x07) | (1<< ADLAR);”
2.4. Убрал строку “low = 0;”
2.5. Заменил “return (high << 8) | low;” на “return (high);”
3. Сделал изменения в программе сканирования АЦП без пропусков (см. пример в задании 5):
const int adc_5 = A5; // ADC port number
void setup() {
Serial.begin (115200); // bit/s
}
void loop(){
for (int i = 0; i < 2048; i++) {
if (i == 0) Serial.print(«A „); // “A» is header
byte adc_byte = analogRead8bit(adc_5);
Serial.write(adc_byte);
}
}
4. Уменьшил шаг времени моделирования c 375.5 мсек на 265 мсек в Simulink модели: “меню > Simulation > Configuration Parameters > Solver > Fixed-step size” и в блоке модели “Serial Receive > Block Sample Time”.
В РЕЗУЛЬТАТЕ частота сэмплирования непрерывно отображаемого сигнала увеличилась с 2.66 КГц до 7.73 КГц.
Работу с LowSpeed не проверял.
При добавлении файла вы можете выбрать, следует ли добавить его как:
…
• Относительный (Relative) — местоположение файла указывается по отношению к проекту (рекомендуется использовать этот вариант, например, для перемещения проекта на другой компьютер.)
• Абсолютный (Absolute) — Указывается абсолютный путь расположения файла,
Что почитать?
Рекомендую
— взять любой простейший пример на ассемблере
— набрать его в редакторе MPLAB
— открыть в MPLAB окна с отображением регистров и памяти виртуального контроллера и
— под отладчиком по шагам рассмотреть как программа изменяет содержимое регистров и памяти контроллера
MPLAB позволяет смоделировать и подачу внешних виртуальных сигналов на портах контроллера.
Подробное описание используемых команд программы лучше взять из первоисточника, например:
PIC12F6XX Однокристальные 8-разрядные FLASH CMOS микроконтроллеры компании Microchip Technology Incorporated
• PIC12F629
• PIC12F675
Перевод основывается на технической документации DS4 11 90A компании Microchip Technology Incorporated, USA.
Рис. Результаты отслеживания координат объекта при изменении черных зон и разворотах.
Увеличение точности в зоне меньшей кадра (с известными координатами) можно получить применением корреляционных методов.
Буфер действует как ключ, который подключает сигналы устройства к шине данных на время кратковременного цикла обращения к устройству, остальное время буфер отсоединен от шины данных открытыми коллекторами. Для простоты, можно рассматривать буфер как идеальный параллельный ключ, который замыкает или размыкает проводники по сигналу управления.
При помощи регистра устройство принимает и сохраняет кратковременные данные шины.
Вариант канала контроллер – COM порт – модель МатЛАБ с сэмплированием на 66 кГц изложен в дополнении к основной работе: последнее “Задание 6”.
Вариант канала контроллер – COM порт – модель МатЛАБ с сэмплированием на 66 кГц изложен в дополнении к основной работе: последнее “Задание 6”.
sites.google.com/site/100voltsamper/mikrokontroller-cto-da-kak/rabota-s-acp-na-primere-atmega328p-nastrojka-acp-primer-koda-ispolzovania-acp
и написал тестовую программу определения времени 256 преобразований:
void setup() {
Serial.begin (57600); // 9600, 19200, 38400, 57600 and 115200 bit/s
ADCSRA |= (1 << ADEN) // Включаем АЦП
|(1 << ADPS1)|(1 << ADPS0); // устанавливаем предделитель преобразователя на 8
ADMUX |= (0 << REFS1)|(1 << REFS0) //выставляем опорное напряжение, как внешний ИОН
|(0 << MUX0)|(0 << MUX1)|(0 << MUX2)|(0 << MUX3); // снимать сигнал будем с входа PC0
}
void loop(){
unsigned long time_start = millis();
for (int i = 0; i < 256; i++) {
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA & (1 << ADIF)) == 0); // пока не будет выставлено флага об окончании преобразования
// u = (ADCL|ADCH << 8); // Считываем полученное значение
// adc_bytes[i] = ADCL; // Считываем полученное значение
}
unsigned long time_end = millis();
unsigned int dt = time_end — time_start;
Serial.println (dt);
}
Программа (без затрат на обработку прерываний) показала, что максимальная частота преобразований = 9.14 КГц (как 1/(28мс/256)), близка к 10 КГц, но далека от 50… 80 КГц.
На результат не влияют
— установка частоты преобразования 76 КГц и выше битами ADPS0… ADPS2
— добавление чтения: u = (ADCL|ADCH << 8)
— добавление копирования в массив adc_bytes[i] = ADCL
Вывод: максимальная частота преобразования АЦП Arduino UNO c процессором ATmega328 не превышает 10 кГц.
Буду рад узнать, что это ошибочное утверждение и существуют примеры, доказывающие возможность корректного АЦ Преобразования на более высоких частотах для контроллера Arduino UNO.
Проверил использование ISR на следующем примере. Работает.
Не могли бы Вы показать вариант заполнения АЦП данными в память Arduino (например, размером 1024 байт) на максимальной частоте, передачи массива в COM порт (на любой частоте) и циклического повторения названных операций.
Рабочий пример с прерываниями из
“Использование прерываний Arduino
sites.google.com/site/vanyambauseslinux/arduino/ispolzovanie-preryvanij-arduino”
#define LEDPIN 13 // Вывод светодиода
#define BTNPIN 2 // Вывод кнопки
volatile int count = 0; // Переменная счётчика (volatile означает указание компилятору не оптимизировать код её чтения,
// поскольку её значение изменяется внутри обработчика прерывания)
ISR(INT0_vect)
{
count = 25; // Инициализировать счётчик
}
// Режимы вызова прерывания INT0
#define INT0_SENSE_LOW_LEVEL 0 // Прерывание при низком уровне на выводе
#define INT0_SENSE_LEVEL_CHANGE 1 // Прерывание при изменении уровня
#define INT0_SENSE_FALLING_EDGE 2 // Прерывание по фронту на спад (когда 1 переходит в 0)
#define INT0_SENSE_RISING_EDGE 3 // Прерывание по фронту на подъём (когда 0 переходит в 1)
// Управляющая функция для прерывания INT0
// mode — режим вызова прерывания
// enable — разрешить/запретить прерывание
void int0Control (uint8_t mode, bool enable){
EIMSK &= ~ (1 << INT0); // Запретить прерывание (так как следующая команда устанавливает режим INT0_SENSE_LOW_LEVEL)
EICRA &= ~ (1 << ISC00) | (1 << ISC01); // Обнуляем биты ISC00 и ISC01 в регистре EICRA
EICRA |= mode; // Устанавливаем режим вызова прерывания INT0
if (enable)
EIMSK |= (1 << INT0); // Разрешить прерывание
}
void setup(){
pinMode(LEDPIN, OUTPUT);
pinMode(BTNPIN, INPUT); // Вывод кнопки в режим ввода
int0Control(INT0_SENSE_RISING_EDGE, true); // Разрешить прерывание по фронту на подъём (в данном случае при нажатии на кнопку)
interrupts(); // Разрешить прерывания глобально
}
void loop(){
if(count==0) {
digitalWrite(LEDPIN, LOW); // Выключить светодиод, если счётчик равен 0…
}
else {
digitalWrite(LEDPIN, HIGH); //… иначе включить светодиод,
--count; // и уменьшить счётчик на 1.
}
delay(100); // Подумать 10 милисекунд.
}
В предлагаемом варианте период RT может заметно превышать период сэмплирования. Сэмплирование с частотой выше 2 КГц может выполняться в RT режиме с периодом в десятки и сотни мсек. Используя векторную обработку данных (а средства МатЛАБ и ориентированы на работу с матрицами) можно существенно (в десятки и более раз) увеличить вычислительную мощь алгоритмов ( в сравнении с 0.5 мс вариантом) и использовать недорогие популярные средства типа Arduino.
Для других задач время кадра можно уменьшить вместе с вектором нулевых констант модели так, чтобы эталонный сигнал, например, период сетевой 50 Гц наводки отображался правильно.
В этих примерах заголовок (header) может быть и другим. Только его нужно указать и в коде Arduino и в блоке “Serial Receive” модели.
В отличии от LabWiew, МатЛАБ не будет компилировать модель для работы в режиме реального времени если не может гарантировать все необходимые вычисления внутри такта (и этим он тоже хорош).
Однако, интересно увидеть ваши примеры работы оборудования с МатЛАБ в контурных задачах в режиме реального времени на частотах 10… 20 кГц.
Планы? — выставлять работы в основном связанные с автоматизацией и управлением технических систем под “dr bob davidov”
byte analogRead8bit(uint8_t);
в файл ...\arduino-1.0.6\hardware\arduino\cores\arduino\ Arduino.h
1. В файле ...\arduino-1.0.6\hardware\arduino\cores\arduino\ wiring_analog.c создал копию функции int analogRead(uint8_t pin): int analogRead8bit(uint8_t pin)
2. В копию внёс следующие изменения
2.1. Заменил “int analogRead8bit(uint8_t pin)” на “byte analogRead8bit(uint8_t pin)”
2.2. Убрал “low” из “uint8_t low, high;”
2.3. Заменил “ADMUX = (analog_reference << 6) | (pin & 0x07);” на “ADMUX = (analog_reference << 6) | (pin & 0x07) | (1<< ADLAR);”
2.4. Убрал строку “low = 0;”
2.5. Заменил “return (high << 8) | low;” на “return (high);”
3. Сделал изменения в программе сканирования АЦП без пропусков (см. пример в задании 5):
const int adc_5 = A5; // ADC port number
void setup() {
Serial.begin (115200); // bit/s
}
void loop(){
for (int i = 0; i < 2048; i++) {
if (i == 0) Serial.print(«A „); // “A» is header
byte adc_byte = analogRead8bit(adc_5);
Serial.write(adc_byte);
}
}
4. Уменьшил шаг времени моделирования c 375.5 мсек на 265 мсек в Simulink модели: “меню > Simulation > Configuration Parameters > Solver > Fixed-step size” и в блоке модели “Serial Receive > Block Sample Time”.
В РЕЗУЛЬТАТЕ частота сэмплирования непрерывно отображаемого сигнала увеличилась с 2.66 КГц до 7.73 КГц.
Еще раз спасибо radiolok.
Пожалуйста, поясните как это сделать.