Регулировка частоты с помощью ЦАП STM32

Я использовал STM32F407VG для создания синусоидальной волны 30 кГц. Настройки таймера есть; Предделитель = 2-1, ARR = 1, также частота составляет 84 МГц (часы, на которых работает ЦАП).

Я написал функцию под названием generate_sin ();

#define SINE_ARY_SIZE (360)
const int MAX_SINE_DEGERI = 4095; // max_sine_value
const double BASLANGIC_NOKTASI = 2047.5; //starting point
uint32_t sine_ary[SINE_ARY_SIZE];
void generate_sine(){
    for (int i = 0; i < SINE_ARY_SIZE; i++){
        double deger = (sin(i*M_PI*360/180/SINE_ARY_SIZE) * BASLANGIC_NOKTASI) + BASLANGIC_NOKTASI; //double value
        sine_ary[i] = (uint32_t)deger; // value
}

Это функция, которая создает синусоидальную волну. Я использовал HAL DMA для отправки выходных переменных ЦАП.

HAL_TIM_Base_Start(&htim2);
generate_sine();
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, SINE_ARY_SIZE, DAC_ALIGN_12B_R);

Это коды, которые я использовал, чтобы делать то, что хочу. Но у меня возникли проблемы с изменением частоты без изменения предделителя или ARR.

Вот мой вопрос. Могу ли я изменить частоту, не меняя настроек таймера? Например, я хочу использовать кнопки, и всякий раз, когда я нажимаю кнопку, я хочу, чтобы моя частота менялась.


person Kırambor    schedule 07.04.2021    source источник
comment
Всё нормально кроме смены частоты? Кстати, я не вижу настроек частоты в вашем коде.   -  person Tagli    schedule 07.04.2021
comment
@Tagli Да, он действительно хорошо работает. Я меняю частоту, изменяя SINE_ARY_SIZE, что является моей частотой дискретизации. Остальные настройки неизменны.   -  person Kırambor    schedule 08.04.2021
comment
Почему вы не хотите менять частоту TIM? Изменение частоты TIM намного лучше, чем пересчет синусоидальной справочной таблицы.   -  person Tagli    schedule 09.04.2021


Ответы (1)


Функция generate_sine даст вам один период синусоидальной волны, который имеет SINE_ARY_SIZE отсчетов.

Чтобы увеличить частоту, вам нужно сделать период короче (для двукратной частоты у вас будет половина количества выборок за период). Таким образом, вы должны вычислить массив для меньшего SINE_ARY_SIZE (который заполнит только часть исходного буфера более короткой синусоидой), а также поместить это меньшее значение в функцию HAL_DAC_Start_DMA.

Уменьшение частоты потребует увеличения длины массива.

Вы должны объявить sine_ary с максимальной длиной, которая вам понадобится (для самой низкой частоты). Убедитесь, что он умещается в ОЗУ.

#define MAXIMUM_ARRAY_LENGTH 360

uint32_t usedArrayLength = 180;

const double amplitude = 2047.5;

uint32_t sine_ary[MAXIMUM_ARRAY_LENGTH];

void generate_sine(){
    for (int i = 0; i < usedArrayLength; i++){
        double value = (sin(i*M_PI*2/usedArrayLength) * amplitude) + amplitude;
        sine_ary[i] = (uint32_t)value; // value
}

Это будет иметь в два раза более высокую частоту, чем исходный код, потому что он имеет только 180 выборок за период по сравнению с 360.

Запустите его, используя

HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, usedArrayLength, DAC_ALIGN_12B_R);

Чтобы изменить частоту, остановите DAC, измените значение usedArrayLength (меньшее значение означает более высокую частоту, должно быть меньше или равно MAXIMUM_ARRAY_LENGTH). Затем вызовите функцию generate_sine и снова запустите DAC с помощью той же функции (которая теперь использует новый usedArrayLength).

Частота будет: Clock / prescaler / ARR / usedArrayLength.

Кроме того, вы должны использовать uint16_t для массива (значения от 0 до 4095, DAC, я полагаю, 12-битный), а DMA должен быть установлен на полуслове (2 байта на значение).

person Jiří Maier    schedule 08.04.2021
comment
To change the frequency, stop DAC .... крайне наивно и плохо. В большинстве случаев вы не можете остановить генерацию, и вам нужно избегать джиттера или искажения сигнала. - person 0___________; 09.04.2021
comment
@ Jiří Maier Спасибо за ваши усилия. Так могу ли я сделать это с помощью кнопки? Я имею в виду, что могу создать переменную, которая называется buttonState, и когда buttonState перейдет в 1, нужно применить другие настройки для изменения частоты. Как вы думаете, возможно ли это? - person Kırambor; 09.04.2021
comment
@ 0 ___________ Да, в моем случае я не должен останавливать генерацию. Каждый раз при нажатии кнопки частота должна быть изменена без остановки генерации. Иржи, кстати, спасибо за уделенное время. Я подумаю над этим и постараюсь придумать решение. - person Kırambor; 09.04.2021
comment
@ Kırambor, почему бы вам не изменить настройку таймера, а не менять частоту путем пересчета отсчетов? Один раз вычислить выборки, а затем изменить частоту таймера, кажется проще, чем пересчитывать массив каждый раз, когда вы меняете частоту. - person Jiří Maier; 09.04.2021
comment
Потому что я не знаю, как применить новые настройки таймера. Я имею в виду, что настройки таймера находятся в функции, например, под названием void TimerSettings () ;. Когда я нажимаю кнопку, я изменяю предварительный делитель с 2 на 4. Но возможно ли это сделать с помощью состояния кнопки? - person Kırambor; 09.04.2021
comment
Вы можете изменить период таймера, используя __HAL_TIM_SET_AUTOREALOAD (& htim2, newValue); или __HAL_TIM_SET_PRESCALER для предварительного делителя. (эти функции - всего лишь макрос для установки ARR или PSC) - person Jiří Maier; 09.04.2021
comment
Чтобы изменить частоту с помощью кнопки, просто проверьте вход (либо опросите его в цикле while, либо с помощью прерывания) и установите новую частоту при изменении состояния кнопки. - person Jiří Maier; 09.04.2021
comment
@ JiříMaier Большое спасибо за вашу помощь. Я попробую. - person Kırambor; 14.04.2021