内容介绍
内容介绍
项目要求;
使用串行DAC AD5626设计一款任意波形发生器
搭配单片机或FPGA或其它方式的控制逻辑能够产生10Hz到20KHz范围内的正弦波信号
输出信号幅度要达到3Vpp,直流偏移可调1.5V到3.5V
使用套件中的Micro USB适配器通过USB给面包板供电,供电电压为5V
使用ADALP2000套件中的运算放大器搭建一个Sallen-Key滤波器,滤除40KHz以上的混叠信号
整体设计思路
本项目中采用WeDesign中设计的开发板MM32F0140来产生驱动串行DAC模块所需要的时序逻辑,来驱动DAC模块产生10Hz到20KHz的正弦信号数据, 使用AD8542搭建一个Sallen-Key低通滤波器,滤除40KHz以上的混叠信号。通过AD8542搭建同向求和运算电路来实现输出信号的幅度的放大以及直流偏移的可调。
串行DAC AD5626驱动
AD5626的驱动时序图图如下,如图可以驱动该芯片需要按照CPOL = 1, CPHA = 1 12bit的SPI通讯模式给AD5626内部的数据寄存器传输数据,然后还需要通过控制LDAC引脚给一个低电平完成一次模拟量的转换。
这部分是采用MM32F0140单片机的SPI外设进行驱动,根据AD5626的是时序要求进行相关驱动引脚的初始化。
/* Setup SPI. */
void app_spi_init(void)
{
/* Setup SPI module. */
SPI_Master_Init_Type spi_init;
spi_init.ClockFreqHz = BOARD_LOOP_SPI_FREQ;
spi_init.BaudRate = BOARD_LOOP_SPI_BAUDRATE;
spi_init.XferMode = SPI_XferMode_TxRx;
spi_init.PolPha = SPI_PolPha_Alt2;
spi_init.DataWidth = SPI_DataWidth_12b;
spi_init.LSB = false;
spi_init.AutoCS = true;
SPI_InitMaster(BOARD_LOOP_SPI_PORT, &spi_init);
/* Enable SPI. */
SPI_Enable(BOARD_LOOP_SPI_PORT, true);
}
GPIO_Init_Type gpio_init;
gpio_init.Pins = AD5635_LDAC_PIN | AD5635_CLR_PIN ;
gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
具体的驱动接口函数实现如下
/* SPI tx. */
void ad5626_update(uint32_t c)
{
/* Polling for tx empty. */
// while ( SPI_STATUS_TX_FULL & SPI_GetStatus(BOARD_LOOP_SPI_PORT) )
// {}
SPI_PutData(BOARD_LOOP_SPI_PORT, c);
while ( !(SPI_STATUS_TX_EMPTY & SPI_GetStatus(BOARD_LOOP_SPI_PORT)) )
{}
GPIO_ClearBits(GPIOB, AD5635_LDAC_PIN);
GPIO_SetBits(GPIOB, AD5635_LDAC_PIN);
}
MM32F0140单片机SPI的工作频率为20MHz的情况下实际的时序如下图所示,更新一次数据的时间大约为1.7us左右。
为了提高在单片机上的更新显示效率,正弦波显示上首先是通过波表初始化函数在内存上生成所需的正弦波数值查找表。
然后循环将数据输出给DAC模块。
#define SIN_TABLE_LEN 256
uint32_t g_sintable_len = SIN_TABLE_LEN;
uint16_t sin_table[SIN_TABLE_LEN] = {0};
uint16_t sin_table1[SIN_TABLE_LEN] = {0};
uint16_t sin_table2[SIN_TABLE_LEN] = {0};
uint16_t sin_table3[SIN_TABLE_LEN] = {0};
uint16_t sin_table4[SIN_TABLE_LEN] = {0};
void sin_table_init(){
uint16_t temp_value;
for(uint16_t i=0; i< g_sintable_len; i++){
sin_table[i] = sin(3.14/2.0/(float)(g_sintable_len)*i)*2048;
printf("sin_table[%d];%d \r\n", i, sin_table[i]);
}
for(uint16_t i=0; i< g_sintable_len; i++){
sin_table1[i] = 2048+sin_table[i];
sin_table2[i] = 2048+sin_table[g_sintable_len-i-1];
sin_table3[i] = 2048-sin_table[i];
sin_table4[i] = 2048-sin_table[g_sintable_len-i-1];
}
}
while (1)
{
for(uint16_t i=0; i< g_sintable_len; i++){
for(uint16_t ki=0; ki< g_keepconut; ki++)
{
ad5626_update(sin_table1[i]);
}
}
for(uint16_t i=0; i< g_sintable_len; i++){
for(uint16_t ki=0; ki< g_keepconut; ki++)
{
ad5626_update(sin_table2[i]);
}
}
for(uint16_t i=0; i< g_sintable_len; i++){
for(uint16_t ki=0; ki< g_keepconut; ki++)
{
ad5626_update(sin_table3[i]);
}
}
for(uint16_t i=0; i< g_sintable_len; i++){
for(uint16_t ki=0; ki< g_keepconut; ki++)
{
ad5626_update(sin_table4[i]);
}
}
}
频率计算是根据波表位数g_sintable_len和保持次数g_keepconut共同决定的。
void set_sin_frequency(uint32_t freq){
// Fsin-clk = 1/(Tsingle_tranfer*SIN_TABLE_LEN*4*g_keepconut)
// Tsingle_tranfer = 1.71us
uint32_t min_freq = 571;//1/(Tsingle_tranfer*SIN_TABLE_LEN*4*g_keepconut
if(freq >= min_freq && freq<=20000){
g_keepconut = 1;
g_sintable_len = 1/(0.00000684*freq);
}
if(freq < min_freq){
g_sintable_len = 256;
g_keepconut = 1/(0.00000684*freq*g_sintable_len);
}
printf("g_sintable_len:%d g_keepconut:%d\r\n", g_sintable_len, g_keepconut);
}
频率的的控制是通过UART接口来是实现的,串口接收中断接收到频率控制字符后进行解析,解析完成后对波表重新进行初始化。
void app_uart_rx_isr_hook(void)
{
if ( (0u != (UART_INT_RX_DONE & UART_GetEnabledInterrupts(BOARD_DEBUG_UART_PORT)))
&& (0u != (UART_INT_RX_DONE & UART_GetInterruptStatus(BOARD_DEBUG_UART_PORT))) )
{
uint8_t data = UART_GetData(BOARD_DEBUG_UART_PORT); /* read data to clear rx interrupt bits. */
if(receive_status == 1){
cmd_string[cmd_string_index++] = data;
if(cmd_string_index >10){
receive_status = 0;
}
}
if(data == 'f'){
memset(cmd_string, 0, 10);
cmd_string_index = 0;
receive_status = 1;
}
if(data == '\r' && receive_status ==1){
receive_status = 0;
flag_setfreq = 1;
}
}
}
if(flag_setfreq == 1){
uint32_t target_freq = atoi(cmd_string);
printf("Frequency :%d \r\n", target_freq);
if(target_freq>20000 || target_freq<10){
printf("Frequency out of range \r\n");
}
else{
set_sin_frequency(target_freq);
}
flag_setfreq =0 ;
}
Sallen-Key滤波器
sallen-key低通滤波器的实现是通过ADI的Filter Wizard工具实现的,如下是根据题目要求以及所选器件等限定条件利用Analog Filter Wizard工具进行的设置。
在LTSpice中的仿真结果如下所示
偏置电路设计
直流偏置电路为基于ad8542运放的同相比例相加电路。先用一个电压跟随器将滤波后的直流偏置电压进行阻抗变换,通过改变滑动变阻器的阻值来调整偏置电压的范围。
效果展示:
生成频率为20kHz信号时的波形,此时的波表长度为32。
生成频率为10Hz信号时的波形,此时的波表长度为1024,保持次数为。
未加入保持逻辑时的timing测试
参考链接
软硬件
附件下载
pokt-f0140_mdk_dds.zip
DCbias.asc
Sk-LTspice.zip
团队介绍
1
团队成员
maskmoo
评论
0 / 100
查看更多
猜你喜欢
模拟电路前端工程化设计 -使用串行DAC AD5626设计一款任意波形发生器使用串行DAC AD5626设计任意波形发生器
使用FPGA产生10Hz到20KHz范围内的正弦波信号
输出信号幅度要达到3Vpp,直流偏移可调1.5V到3.5V
wyk
1225
模拟电路设计课程——使用串行DAC AD5626 设计一款任意波形发生器使用AD5626数字模拟转换器和ADALP2000模拟学习套件设计一款任意波形发生器。
cjmf
1132
使用串行DAC AD5626设计一款任意波形发生器使用串行DAC AD5626设计一款任意波形发生器搭配FPGA控制逻辑能够产生10Hz到20KHz范围内的正弦波信号
输出信号幅度要达到3Vpp,直流偏移可调1.5V到3.5V
红军啊
795