Синус 10кГц
- Войдите на сайт для отправки комментариев
Вс, 18/03/2018 - 08:36
Здравствуйте. Подскажите пожалуйста, можно ли программно решить такую задачку на ардуино уно:
1. Синус 10 кГц
2. ШИМ с регулируемой скважностью (переменник) 500 Гц
3. Снятие синуса с внешней обмотки и сравнение с синусом генерируемым ардуинкой.
Зарание всем спасибо)
Protas, первые два однозначно можно, и примеры на форуме есть. (3) -это уже задача для осциллографа. В любом случае одновременно задачи (1) и (3) вряд ли могут сосуществовать на одном МК.
Да, форум я смотрел. Не пойму просто как частоты в 10 кГц достичь
Protas, Ардуино - это не конкретный контроллер, а целое семейство.
На данном форуме под Ардуино зачастую подразумевается семейство AVR. Строго говоря, аналоговые сигналы это семейство не способно генерить в принципе, поэтому задача 1 невыполнима.
Хотя, при наличии некоторого внешнего обвеса можно получить результат достаточно длизкий к желаемому. Например, генерить Ардуиной меандр 10 кГц, а в синус превращаать его узкополосным фильтром. И, кстати, для такой реализации увтерждение уважаемого dimax о невозможности совмещения 1 и 3 перестает быть истинным.
Что касается ввода аналоговых сигналов, то для указанного семейства максимальная частота дискретизации по умолчанию - 9 кГц. Если мы хотим уверенно отличать синус от прямоугольника, оцифровка должна ловить, минимум, 5-7 гармоник, для чего частота дискретизации должна быть не ниже 120-150 кГц.
Думаю, что единственный контроллер из семейства Ардуино, который способен выполнять задачи типа тех, что приведены Вами - это Arduino Due.
Спасибо. Уже заказал
Вот я причесал старый DDS для удобного использования.
Он на Bluepill STM32. Эта плата, в отличии от Due, стоит 100 р, а не 1000.
Замечу, что loop() - пустой и в нем можно делать, что захочется ;).
ДДС построен на ДМА и Таймере. ЦАП сделан за счет ШИМ и RC фильтра на выходе.
В примере использован RC фильтр из 180 Ом и 10 нФ.
Вот поясняющее видео на youtube.
Ниже - код. Он самодокументирован. Если нужны пояснения - пишите тут, я когда-нибудь отвечу ;). Если кто-то считает это правильным - можно перенести в проекты, Хоть это и смешно.
#include <libmaple/dma.h> //Задаем ФУНКЦИЮ DDS! Функция определена на 0..1 и приниммает значениея от 0 до 1! //ЗАДЕМ ЕЁ !!!!!!В_Н_И_М_А_Т_Е_Л_Ь_Н_О!!!!!!! //#define F(x) (0.5*(1+sin(2*3.1415926*x))) //это пример для синуса #define F(x) ( (x<0.5)?(x):(0.5-(x-0.5)) ) //Это пример для пилы //#define F(x) ( (x<0.7)?(x):(0.7-(x-0.7)*7/3) ) //Несимметричная пила #define Tperiod 100 //Задаем период в мкс #define SAMPLES 100 //Задаем число точек в периоде #define Prec (72*Tperiod/SAMPLES-1) //Тут вычисляем точность вычислений функции в точках по вертикальной оси // 72МГц - частота таймера. Остальное понятно, на высоких частотах нужно брать меньше самплов #define dt (1.0/SAMPLES) // Дельта т - шаг по времени dma_tube_config dma_cfg, dma_cfg2; int flag1 = 0; // это просто ни для чего - счетчик числа периодов int out1 = PB7; //номер вывода DDS СТМ32 - штука не простая, к выводам привязаны таймер и канал, к ним и свой ДМА привязан //если нет знаний о СТМ32, то сюда не нужно лезть int val1[SAMPLES]; // массив значений DDS float amp = 1.0; // амплитуда сигнала, глобальна потому, что была когда-то регулировка кнопками, ее можно добавить //уже служебные вещи, не нужно лезть, если нет знаний, тут определяем таймер и канал timer_dev *dev1 = PIN_MAP[out1].timer_device; uint8 cc_channel1 = PIN_MAP[out1].timer_channel; void fun() { //тут можно что-то делать забавное, каждый раз при окончании периода DDS flag1++; } void timer_conf() { timer_dma_set_base_addr(dev1, TIMER_DMA_BASE_CCR2); timer_dma_set_burst_len(dev1, 1); timer_dma_enable_req(dev1, cc_channel1); timer_set_reload(dev1, Prec); timer_set_prescaler(dev1, 0); } void dma_conf() { dma_init(DMA1); /* T4C2 DMA C4 */ dma_cfg.tube_dst = &(dev1->regs.gen->DMAR); dma_cfg.tube_dst_size = DMA_SIZE_32BITS; dma_cfg.tube_src = val1; dma_cfg.tube_src_size = DMA_SIZE_32BITS; dma_cfg.tube_nr_xfers = SAMPLES; dma_cfg.tube_flags = DMA_CFG_SRC_INC | DMA_CFG_CIRC | DMA_CFG_CMPLT_IE; dma_cfg.tube_req_src = DMA_REQ_SRC_TIM4_CH2; dma_cfg.target_data = 0; dma_tube_cfg(DMA1, DMA_CH4, &dma_cfg); } void dma_start() { dma_attach_interrupt(DMA1, DMA_CH4, fun); dma_enable(DMA1, DMA_CH4); timer_resume(dev1); } void init_wave() { float maxy=0; float y; int i; for(i=0;i<SAMPLES;i++) if ((y = F(dt * i)) > maxy) maxy=y; for(i=0;i<SAMPLES;i++) val1[i] = 1+amp*((Prec-1)/maxy)*F(dt * i); } void setup() { int i; pinMode(out1, PWM); // Serial.begin(57600); // ну это если управление по сериалу писать // можно даже интерпретатор сделать, чтобы функцию писать и разбирать ее "на лету"... если заняться больше нечем ;) timer_conf(); dma_conf(); dma_start(); init_wave(); } void loop() { // тут можно с сериала принимать параметры DDS, если есть желание и сами напишем ;) мне- не надо }Делал я генерацию синусов, причем сразу двух для DTMF, и ввод аналогового сигнала (собственно этого самого DTMF). Все это в прерывании таймера 1 на 62,5КГц. На нем же и ШИМ. Может можна и больше частоту, насколько помню выбиралась по возможностям ШИМа, его период равен 256 тактов и он 8-битный. Синус конечно таблично генерится, не как у wdrakula. Походу введеный сигнал еще на экран выводится, гдето на форуме даже ссылка на видео работы есть.
Добавлю еще функцию табличного синуса по четверти периода. А то есть любители целый период хранить.
signed char TabSin(unsigned char x) { const byte TabSin[64]={0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88, 90, 92, 94, 96, 98,100,102,104,106,107,109,111,112,113,115,116,117, 118,120,121,122,122,123,124,125,125,126,126,126,127,127,127}; signed char r=TabSin[((x&0x40)?-x-1:x)&0x3f]; if(x&0x80) return -r; return r; }Синус конечно таблично генерится, не как у wdrakula.
Стесняюсь спросить: а у меня как?
Я и строю таблицу при запуске в init_wave(). Строю для сигнала любой формы. Там первый for ишет максимум, а второй строит таблицу.
Если в контроллере дохрена памяти, то таблицу можно и нужно строить прямо в нем, нет?
Я люблю эффективное программирование, люблю "упихаить" а тиньку13 сложный код, но (!) для практической, не тренировочной, задачи - предпочту (в случае нехватки ресурсов) взять контроллер "потолще" ;).
А я обычно строю таблицы на ПК и объявляю const PEROGMEM. На практике более половины используемого объема flash уходит именно на таблицы.
Купил Due. Залил скетч, найденый в инте...
#define maxSamplesNum 120 static int sinwave[maxSamplesNum] = { 0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1, 0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4, 0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc, 0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f, 0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a, 0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a, 0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d, 0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a, 0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2, 0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf, 0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4, 0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794 }; int i = 0; void setup() { analogWriteResolution(12); } void loop() { i++; if(i == maxSamplesNum) i = 0; analogWrite(DAC1, sinwave[i]); }На цифровом осцилографе показывает синус, но частота постоянно скачет. Примерно 8кГц - 20 кГц. Подскажите плз, как стабилизировать частоту на 10 кГц.
Вот ссылка на автора http://arduino-er.blogspot.com.by/2014/12/generate-sin-wave-on-arduino-due.html
P.S. огромное спасибо всем кто откликнулся!
Protas, это пожалуй самый плохой генератор синуса из всех, что существуют =) Посмотрите в этой ветке программу от Волшебника. Там к слову есть и мой вариант для дуе, который даёт максимально качественный синус, но он занимает 100% вычислительной мощности, и делать что-то ещё во время генерации синуса невозможно. Вариант Волшебника с точностью до наоборот. Синус не выского качества, но вычислительная мощность почти вся свободна.
Все это в прерывании таймера 1 на 62,5КГц. На нем же и ШИМ.
А в примере wdrakula и прерывания не понадобились... и луп пустой... Прикинь!!!??? )))))))))
Может можна и больше частоту, насколько помню выбиралась по возможностям ШИМа, его период равен 256 тактов и он 8-битный.
Убогость налицо...
Синус конечно таблично генерится, не как у wdrakula.
А у него и таблично, и хардварно... )))))))))
Добавлю еще функцию табличного синуса по четверти периода. А то есть любители целый период хранить.
Нашёл чем удивить... И дельта Т меняется??? ))))))))
dimax, спасибо. Буду пробовать скетч от Волшебника!
030//уже служебные вещи, не нужно лезть, если нет знаний, тут определяем таймер и канал031timer_dev *dev1 = PIN_MAP[out1].timer_device;032uint8 cc_channel1 = PIN_MAP[out1].timer_channelА то не лез а уже заблудился. В МАПЛЕ не нашёл или не увидел.может зрение конечно не то.
Если от корня Arduino_STM32, то вот тут:
./STM32F1/variants/generic_stm32f103c/board.cpp
// Note. See the enum of pin names in board.h extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ };А зачет это тебе?
Если задал такой вопрос, значит не понимаешь в теме. Если не понимаешь - ничего не сумеешь изменить.
И конечно, такой файл есть и в мапл и в мапл-мини. Это часть пакета ардуино-стм32, то есть программирования плат СТМ в среде ардуино.
wdrakula.
Спасибо. А что всё так безнадёжно? :)
Пока я слежу за темой, можно попросить меня пояснить или изменить что либо. К сожалению мне лень было доделывать код так, что бы все параметры и таймера и канала дма сами опредеоялись по выходному пину.
Так что, если поменяешь пин, придется менять во могих местах руками. Это собственно все, что тут нужно знать про СТМ.
wdrakula. Буду весьма признателен. Поясните пожалуйста. PB7 это вроде 2 канал. тогда что значит 32 строка. так же непонятно назначение 17ст. и 55-66 в частности (dma_cfg.tube_). также инициализация таймеров например в http://arduino.ru/forum/programmirovanie/stm32-preryvanie-po-sravneniyu-v-taimere выглядит иначе.ещё не понятно с чего начинать если понадобится допусти режим шим захвата.честно говоря думал что с ардуино проще чем к примеру с кейлом или иаром.
Нужно уточнить, что я обещал пояснения по коду, а не лекции по программированию СТМ32 в среде Ардуино.
Итак:
1. в строке з2 определячется канал таймера по пину. Ссылку я уже давал, изучай STM32duino.
2. в 17 строке декларация переменной dma_cfg. вторая (dma_cfg2) - не нужна, наследство от версии для двух каналов.
3. 55-66 - конфигурация DMA канала, Таймер 4 канал 2 соответствуют 4ому каналу DMA.
ОЧЕНЬ ПОДРОБНО ИЗУЧАЕМ rm0008 от ST! Он ищется в яндексе просто первым в выдаче по rm0008 ;).
Там написано абсолютно все про контроллер и его настройки.
4. там же про таймеры. Замечу, что прерывания таймера в этом коде не используются совсем, используется DMA.
-------------------------------------
За сим благотворительность прекращаю. Изучайте даташиты и мануалы. СТМ это не ардуино и порог вхождения гораздо выше.
Учитесь пользоваться гуглом, а не форумом.
wdrakula. Спасибо.