背景
本人主要考虑AT32F437 GPIO的翻转速度为72M,那么用来产生任意波形,频率应该挺高的,但是没有考虑到需要更新电压值,因此波形频率不高。
一、DAC R2R介绍
1、原理
1)等效电阻
如图所示,从D0-D7端口,看过去,左边的电阻值一直是R(1K);也就是说,整个输出阻抗为R;
2)推导公式
a、假如只有R38 R39 两个电阻,那么Vout = 1/2Vd0;
b、假如只有R38 R39 R40 R47,根据戴维南定理,R38和R39 等效为一个1/2的VCC电压源和一个电阻R串联;
那么从Vd1的电压=1/2(Vd1+1/2Vd0) = 1/4Vd0 + 1/2 Vd1
最后得出来的公式如下:
D0*Vcc/256+D1*Vcc/128+D2*Vcc/64+D3*Vcc/32+D4*Vcc/16+D5*Vcc/8+D6*Vcc/4+D7*Vcc/2; 就可以利用这个公式来产生信号;
参考文章:R2R DAC 梯形数到模拟教程 |泰克 (tek.com)
2、硬件原理图
二、程序编写
1、使用定时器中断更新电压值
定时器程序
uint16_t dac_out[32] = {128, 154, 178, 201, 221, 237, 248, 255,
255, 252, 243, 229, 211, 190, 166, 141,
115, 90, 66, 45, 27, 13, 4, 0,
1, 8, 19, 35, 55, 78, 102, 128};
uint16_t dac_out_BIG[32] = {
32768, 39424, 45568, 51456, 56576, 60672, 63488, 65280,
65535, 64512, 62208, 58624, 54016, 48640, 42496, 36096,
29440, 23040, 16896, 11520, 6912, 3328, 1024, 0,
256, 2048, 4864, 8960, 14080, 19968, 26112, 32768};
uint8_t g_speed = FAST;
void button_exint_init(void);
void button_isr(void);
crm_clocks_freq_type crm_clocks_freq_struct = {0};
void dac_init(void) {
gpio_init_type gpio_init_struct;
crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
/* configure the uart tx pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10 | GPIO_PINS_11 | GPIO_PINS_12| GPIO_PINS_13| GPIO_PINS_14| GPIO_PINS_15;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOE, &gpio_init_struct);
gpio_bits_reset(GPIOE,0xff00);
}
void timer_init(uint32_t counter) {
/* get system clock */
crm_clocks_freq_get(&crm_clocks_freq_struct);
/* turn led2/led3/led4 on */
/* enable tmr1 clock */
crm_periph_clock_enable(CRM_TMR5_PERIPH_CLOCK, TRUE);
/* tmr1 configuration */
/* time base configuration */
tmr_base_init(TMR5, counter,1);
tmr_cnt_dir_set(TMR5, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR5, TMR_OVF_INT, TRUE);
/* tmr1 hall interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR5_GLOBAL_IRQn, 1, 0);
/* enable tmr1 */
tmr_counter_enable(TMR5, TRUE);
}
2、直接更新法
int main(void)
{
system_clock_config();
at32_board_init();
button_exint_init();
dac_init();
// timer_init(1);
while(1)
{
GPIOE->odt = dac_out_BIG[0];
GPIOE->odt = dac_out_BIG[1];
GPIOE->odt = dac_out_BIG[2];
GPIOE->odt = dac_out_BIG[3];
GPIOE->odt = dac_out_BIG[4];
GPIOE->odt = dac_out_BIG[5];
GPIOE->odt = dac_out_BIG[6];
GPIOE->odt = dac_out_BIG[7];
GPIOE->odt = dac_out_BIG[8];
GPIOE->odt = dac_out_BIG[9];
GPIOE->odt = dac_out_BIG[10];
GPIOE->odt = dac_out_BIG[11];
GPIOE->odt = dac_out_BIG[12];
GPIOE->odt = dac_out_BIG[13];
GPIOE->odt = dac_out_BIG[14];
GPIOE->odt = dac_out_BIG[15];
GPIOE->odt = dac_out_BIG[16];
GPIOE->odt = dac_out_BIG[17];
GPIOE->odt = dac_out_BIG[18];
GPIOE->odt = dac_out_BIG[19];
GPIOE->odt = dac_out_BIG[20];
GPIOE->odt = dac_out_BIG[21];
GPIOE->odt = dac_out_BIG[22];
GPIOE->odt = dac_out_BIG[23];
GPIOE->odt = dac_out_BIG[24];
GPIOE->odt = dac_out_BIG[25];
GPIOE->odt = dac_out_BIG[26];
GPIOE->odt = dac_out_BIG[27];
GPIOE->odt = dac_out_BIG[28];
GPIOE->odt = dac_out_BIG[29];
GPIOE->odt = dac_out_BIG[30];
GPIOE->odt = dac_out_BIG[31];
// at32_led_toggle(LED2);
// delay_ms(1000);
// gpio_bits_write(GPIOE,GPIO_PINS_15,TRUE);
//gpio_port_write(GPIOE,(0x80 << 8) & 0xff00);
}
}
三、验证
1、定时器方式
1)定时器预装载值为999;分频值为239;
频率为37.5Hz
2)定时器预装载值为1;分频值为239;
频率为18.8KHz
3)定时器预装载值为1;分频值为2;
频率为93.5Khz;
2、直接更新主程序
总结:使用32个点来模拟SIN信号,根据实测,最大频率只有1M;因此使用GPIO口来驱动R2R产生比较高频率的信号,不可行。看来还是需要使用FPGA来进行驱动R2R,进行提高信号输出频率。
工程文件: