Для чистоты эксперимента все параметры (значения сопротивлений) нашего апериодического звена второго порядка произвольны, конденсаторы через джампера подключаются 0,1 мкФ и 1 мкФ. Напряжение Uref выставлено произвольно, значения PR1 и PR2 также имеют произвольное положение. Сигнал снимается slowpoke USB осциллографом.
1. Сигнал STEP, выход с ЦАП-а (рисунок 1)
Рисунок 1 — Сигнал STEP, выход ЦАП (1 В/дел., 5 us/дел.)
Нарастание фронта примерно 968 ns (валенком измерено)
2. Сигнал STEP, после RC(рисунок 2) цепи фильтра (рисунок 3)
Рисунок 3 — Сигнал STEP после RC цепи (1 В/дел., 10 us/дел.)
3. Замкнута перемычка (см. рисунок 4) J1 — введен конденсатор 0,1 мкФ (рисунок 5)
Рисунок 4 — Схема апериодического звена второго порядка
Рисунок 5 — Сигнал STEP после первой (PR1 + C1) RC цепи (1 В/дел., 500 us/дел.)
4. Замкнута перемычка (см. рисунок 4) J1 и J3 — введены конденсаторы 0,1 мкФ (рисунок 6)
Рисунок 6 — Сигнал STEP после первой (PR1+PR2 + C1 + С3) RC цепи (1 В/дел., 1000 us/дел.)
5. Замкнута перемычка (см. рисунок 4) J1, J2 и J3 — введены конденсаторы 0,1 мкФ и один 1 мкФ (рисунок 7)
Рисунок 7 — Сигнал STEP после первой (PR1+PR2 + C1+C2 + С3) RC цепи (1 В/дел., 1000 us/дел.)
6. Замкнута перемычка (см. рисунок 4) J1, J2, J3 и J4 — введены конденсаторы 0,1 мкФ и один 1 мкФ (рисунок 8)
Рисунок 8 — Сигнал STEP после первой (PR1+PR2 + C1 + С3 + c2 + c4) RC цепи (1 В/дел., 10 ms/дел.)
7. Чистый синус (рисунок 9)
8. RAMP (рисунок 10)
Код работы с ЦАП-ом, main.c:
#include "stm32f0xx.h" #include "stm32f0xx_adc.h" #include "stm32f0xx_gpio.h" #include "stm32f0xx_rcc.h" #include "main.h" #include "delay_tim17.h" GPIO_InitTypeDef DACIO_Setup; GPIO_InitTypeDef DACCTR_Setup; int main(void) { GPIO_config();//Настройка портов InitDelayTIM17();//Настройка таймера uint8_t tt = 0x00;//дополнительная переменная Write_Data(0x00, 0x00); //Write_Data(0xFF, 0x00); // STEP while(1) { Write_Data(sin_table[tt++], 0x00);//SIN _delay_ms(50);//delay of TIM17 время не совпадает(( // Write_Data(tt, 0x00);//RAMP } } void GPIO_config(void) { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); DACIO_Setup.GPIO_Pin = DAC_PINS_DATA; DACIO_Setup.GPIO_Mode = GPIO_Mode_OUT; DACIO_Setup.GPIO_OType = GPIO_OType_PP; DACIO_Setup.GPIO_Speed = GPIO_Speed_50MHz; DACIO_Setup.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(DAC_D_PORT, &DACIO_Setup); GPIO_ResetBits(DAC_D_PORT, DAC_PINS_DATA); DACCTR_Setup.GPIO_Pin = DAC_PINS_CONTROL; DACCTR_Setup.GPIO_Mode = GPIO_Mode_OUT; DACCTR_Setup.GPIO_OType = GPIO_OType_PP; DACCTR_Setup.GPIO_Speed = GPIO_Speed_50MHz; DACCTR_Setup.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(DAC_C_PORT, &DACCTR_Setup); GPIO_ResetBits(DAC_C_PORT, DAC_PINS_CONTROL); } void Write_Data(uint8_t data, uint8_t adr) { //setadr Set_adr(adr); //setdata DAC_Push_Data(data); //setwr DAC_WR_LOW; //nop asm("NOP"); DAC_WR_HIGH; //desetwr } void Set_adr(uint8_t adr) { DAC_C_PORT->ODR |= adr & 0x03; } void DAC_Push_Data(uint8_t data) { DAC_D_PORT->ODR = data; }
main.h:
#ifndef MAIN_H_ #define MAIN_H_ #include "stdint.h" const uint8_t sin_table[256] = {//Таблица синуса 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76, 79, 81, 84, 87, 90, 93, 96, 99, 103,106,109,112,115,118,121,124, 128,131,134,137,140,143,146,149,152,156,159,162,165,168,171,174, 176,179,182,185,188,191,193,196,199,201,204,206,209,211,213,216, 218,220,222,224,226,228,230,232,234,236,237,239,240,242,243,245, 246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255, 255,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247, 246,245,243,242,240,239,237,236,234,232,230,228,226,224,222,220, 218,216,213,211,209,206,204,201,199,196,193,191,188,185,182,179, 176,174,171,168,165,162,159,156,152,149,146,143,140,137,134,131, 128,124,121,118,115,112,109,106,103,99, 96, 93, 90, 87, 84, 81, 79, 76, 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 18, 16, 15, 13, 12, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0 }; //define data pins #define DAC_D_PORT GPIOA #define DAC_C_PORT GPIOB #define DAC_D0 GPIO_Pin_0 #define DAC_D1 GPIO_Pin_1 #define DAC_D2 GPIO_Pin_2 #define DAC_D3 GPIO_Pin_3 #define DAC_D4 GPIO_Pin_4 #define DAC_D5 GPIO_Pin_5 #define DAC_D6 GPIO_Pin_6 #define DAC_D7 GPIO_Pin_7 //======================== #define DAC_PINS_DATA (DAC_D0 | DAC_D1 | DAC_D2 | DAC_D3 | DAC_D4 | DAC_D5 | DAC_D6 | DAC_D7) //======================== #define DAC_A0 GPIO_Pin_0 #define DAC_A1 GPIO_Pin_1 #define DAC_WR GPIO_Pin_3 //======================== #define DAC_PINS_CONTROL (DAC_WR | DAC_A0 | DAC_A1) //======================== #define DAC_WR_LOW DAC_C_PORT->BRR = DAC_WR; #define DAC_A0_LOW DAC_C_PORT->BRR = DAC_A0; #define DAC_A1_LOW DAC_C_PORT->BRR = DAC_A1; //======================== #define DAC_WR_HIGH DAC_C_PORT->BSRR = DAC_WR; #define DAC_A0_HIGH DAC_C_PORT->BSRR = DAC_A0; #define DAC_A1_HIGH DAC_C_PORT->BSRR = DAC_A1; //======================== void GPIO_config(void); void Write_Data(uint8_t data, uint8_t adr); void Set_adr(uint8_t adr); void DAC_Push_Data(uint8_t data); #endif /* MAIN_H_ */
Алгоритм работы с ЦАП-ом очень прост, данные передаются по параллельной шине данных (D0 — D7), адрес канала выставляется ножками А0 и А1 (канал А — 00, канал B — 01, канал C — 10, канал D — 11), запись в ЦАП происходит по низкому ровню сигнала WR.
1) Выставляем адрес:
Set_adr(adr);
2) Отправляем данные в порт:
DAC_Push_Data(data);
3) Сигнал WR в низкий уровень;
DAC_WR_LOW;
4) Сигнал WR в высокий уровень;
DAC_WR_HIGH;
А можно последние два графика наложить друг на друга в одном масштабе, для большей наглядности?
Думаю что да, но они совсем в разных временных масштабах (в 25 раз почти). Будет свободное время — сделаю