银杏科技有限公司旗下技术文档发布平台 |
技术支持电话 | 0379-69926675-801 |
技术支持邮件 | Gingko@vip.163.com |
版本 | 日期 | 作者 | 修改内容 |
V1.0 | 2020-11-18 | gingko | 初次建立 |
STM32CubeMX教程十二——DDS输出正弦波
实验十二:DDS实验——输出正弦波
一、实验目的与意义
了解STM32 DAC结构
了解STM32 DAC特征
掌握DDS原理
掌握STM32 HAL库中DAC属性的配置方法
掌握KEIL MDK 集成开发环境使用方法
二、实验设备及平台
iCore3L 双核心板
JLINK(或相同功能)仿真器
Micro USB线缆
Keil MDK 开发平台
STM32CubeMX开发平台
装有WIN XP(及更高版本)系统的计算机
三、实验原理
1.DAC简介
STM32F429IGH6的DAC模块主要特性:
DAC框图:
DAC 包含:
多达两条输出通道
DAC_OUTx 可与输出引脚断开连接并用作普通 GPIO
DAC_OUTx 可使用与片上外设(如比较器和 OPAMP)的内部引脚连接。
DAC 输出通道(缓冲/非缓冲)
使用 LSI 时钟源在停止模式下运行以实现静态转换的采样和保持模块及其寄存器
DAC 包含多达两条独立的输出通道。每条输出通道均可连接到片上外设,如 COMP、 OPAMP和 ADC。在这种情况下, DAC 输出通道可与 DAC_OUTx 输出引脚断开连接,相应的 GPIO可用于其他用途。
DAC 输出可缓冲、也可以不缓冲。采样和保持模块及其关联寄存器可在停止模式下使用 LSI时钟源运行。
图中VDDA和VSSA为DAC模块模拟部分的供电,而VREF+则是DAC模块的参考电压。(对应PA4引脚)。
从图中可以看出,DAC输出是受DORx(x=1/2,下同)寄存器直接控制的,但是我们不能直接往DORx寄存器写入数据,而是通过DHRx间接的传给DORx寄存器,实现对DAC输出的控制。前面我们提到,STM32F429IGH6的DAC支持8/12位模式,8位模式的时候是固定的右对齐的,而12位模式又可以设置左对齐/右对齐。单DAC通道x,总共有3种情况:
8位数据右对齐:用户将数据写入DAC_DHR8Rx[7:0]位(实际存入DHRx[11:4]位)。
12位数据左对齐:用户将数据写入DAC_DHR12Lx[15:4]位(实际存入DHRx[11:0]位)。
12位数据右对齐:用户将数据写入DAC_DHR12Rx[11:0]位(实际存入DHRx[11:0]位)。
关闭触发 (TEN = 0) 时的转换时序图:
DAC输入/输出引脚:
DAC内部输入/输出信号:
2.DAC输出电压公式
经过线性转换后,数字输入会转换为 0 到 VREF+ 之间的输出电压。
各 DAC 通道引脚的模拟输出电压通过以下公式确定:
DAC_output= V_REF × DOR/4096
3.DAC部分寄存器介绍
DAC_CR 的低 16 位用于控制通道 1,而高 16 位用于控制通道 2,我们这里仅列出比较本章需要设置的一些位:
EN1 位:用于 DAC 通道 1 的使能,我们需要用到 DAC 通道 1 的输出,该位必须设置为 1。
TEN1 位:用于 DAC 通道 1 的触发使能,我们设置该位为 0,不使用硬件触发。 写入 DHR1的值会在 1 个 APB1 周期后传送到 DOR1,然后输出到 PA4 口上。
TSEL[3:0]位,用于选择 DAC 通道 1 的触发方式,本章设置为 0,使用软件触发。
WAVE[1:0]位,用于控制 DAC 通道 1 的噪声/波形输出功能,默认设置为 0,不使能噪声/波形输出。
DMAEN1 位,用于控制 DAC 通道 1 的 DMA 使能,本章不使能,设置该位为 0 即可。CEN1 位,用于控制 DAC 通道 1 的输出缓冲校准使能,本章不使用校准功能(默认有一个出场校准值,我们使用默认的校准值即可),设置该位为 0 即可。
然后,我们介绍 DAC 模式控制寄存器( DAC1_MCR),该寄存器各位描述如图所示:
位 2:0 MODE1[2:0]: DAC 通道 1 模式 (DAC Channel 1 mode)
仅当 DAC 已禁止且不处于校准模式时( DACx_CR 寄存器中的位 EN1 = 0 且
位 CEN1 = 0),才可写入这些位。如果 EN1=1 或 CEN1 =1,则会忽略写操作。
这些位可由软件置 1 和清零,用于选择 DAC 通道 1 模式。
– DAC 通道 1 处于正常模式
000: DAC 通道 1 连接到外部引脚且使能了缓冲器
001: DAC 通道 1 连接到外部引脚以及片上外设且使能了缓冲器
010: DAC 通道 1 连接到外部引脚且禁止了缓冲器
011: DAC 通道 1 连接到片上外设且禁止了缓冲器
– DAC 通道 1 处于采样和保持模式
100: DAC 通道 1 连接到外部引脚且使能了缓冲器
101: DAC 通道 1 连接到外部引脚以及片上外设且使能了缓冲器
110: DAC 通道 1 连接到外部引脚以及片上外设且禁止了缓冲器
111: DAC 通道 1 连接到片上外设且禁止了缓冲器
注: 仅可在 EN1 = 0 时修改该寄存器。
4、DDS原理
4.1 什么是频率
频率是指单位时间内某事件重复的次数。在电子学中,信号的频率是指单位时间内信号的周期数,单位是赫兹(Hertz,简称Hz)。很多年前有一个著名的德国物理学家海因里希· 鲁道夫·赫兹,他首先证明了电磁波的存在,为了纪念他,频率的单位就用他的名字命名。频率是一个非常常用、也是一个非常重要的国际单位;日常生活中,我们收听的收音机、观看的电视机、交流市电、移动蜂窝电话等信号的传输过程,都利用了信号的频率特性。频率与信号的周期互为倒数关系,所以频率也可以表示为:
4.2 怎么得到任意频率的信号
既然信号的频率特性那么重要,我们怎么样才能得到自己想要的频率的信号呢?一般来说,我们通过下面三种方法得到想要的频率信号。
晶体或者晶体振荡器:晶体振荡器是利用石英晶体的压电效应,来产生我们想要的频率,他有精度高、稳定性强、温漂小等特点。晶体或者晶振是电路中常用的元器件,它能给我们的电路提供稳定的时钟源,但它也有它的局限性,晶体一旦切割完毕,他的固有频率也就固定了,所以晶体或者晶振不适用于要求频率时刻变化的场合。
RLC 振荡器:利用RC 振荡或者 LC 振荡的原理,通过改变其中的R、L或者C达到改变振荡频率的目的。这种振荡器电路简单、起振容易,所以也很常用。不过他频率稳定性一般,不适合在频率精度要求较高的场合使用。
频率合成技术:频率合成技术可以理解为我们通过某种方法,对固定的频率进行运算,来完成频率的变换。频率合成方法一般有锁相环(PLL)法和直接数字合成技术。PLL 是一种闭环系统,他通过对输入频率进行倍频、分频等过程,完成频率的变换。这种技术一般用于输出频点不多的场合(例如MCU中频率的倍频过程),它得天独厚的优势是可以产生比输入频率更高的频率。直接数字合成技术为本节讨论的重点,以下内容均讨论直接数字合成技术。
4.3 直接数字合成技术简介
4.4 DDS原理
4.4.1 相位累加器
相位累加器(ACCUMULATOR)是DDS的核心,它由一个加法器和一个D触发器组成。相位累加器由多位组成,典型的应用中,一般取 16~48位。相位累加器工作过程中,时钟每动作一次,累加器便累加一次调谐字(TUNING WORD);所以相位累加器输出一个以时间为序列的数字字,它线性增长,直到达到最大值2n(假设该累加器为n位),如果大于最大值,则舍弃溢出的高位,仍然保留n位。
为了形象的描述相位累加器的工作过程,我们可以把相位累加器看做一个圆周,如图三所示。其中,n表示相位累加器的位数,2n为相位累加器的模数,也就是圆周等分点数,每次的步进值为调谐字(TUNING WORD)。如果把相位累加器旋转一周作为一个周期的话,则最终频率输出可以用方程式(2)来描述。
4.4.2 角度-幅度转换
4.4.3 D/A 转换
四、实验程序
1.主函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DAC1_Init();
MX_SDMMC1_SD_Init();
MX_TIM3_Init();
MX_FATFS_Init();
res = f_mount(&fatfs,"0:",1);
if(res != RES_OK)
{
while(1)
{
LED_ON;
HAL_Delay(300);
LED_OFF;
HAL_Delay(300);
}
}
wave.waveform(WAVE_SINE,0);
wave.set_frequency(1000);
//计算频率为1K的波表数据
i = 0;
while(1)
{
wave.accumulator = wave.accumulator + wave.fword;
if(wave.accumulator > 4294967295)break;
temp = wave.accumulator >> 18;
f = wave.buffer[temp];
g = f / 16384.0;
g = g * 2.0 +0.05;
g = g * 4096 / 2.5;
wave.buffer[i ++] = g;
}
counter = i - 1;
HAL_TIM_Base_Start_IT(&htim3);
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
LED_ON;
while (1)
{
}
}
2.set_frequency函数
static int set_frequency(int freq)
{
//32位相位累加器 400K 采样率
wave.accumulator = 0;
wave.fword = (int)(freq * 4294.967296 * 2.5);
return 0;
}
3.HAL_DAC_SetValue函数
HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data)
//hdac:指向DAC_HandleTypeDef结构的指针
//Channel:选定DAC通道
//Alignment:数据对方方式
//Data:放入寄存器中的值
4.DAC初始化函数
void MX_DAC1_Init(void)
{
DAC_ChannelConfTypeDef sConfig = {0};
hdac1.Instance = DAC1;
if (HAL_DAC_Init(&hdac1) != HAL_OK)
{
Error_Handler();
}
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;//关闭
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;//关闭DAC触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;//使用输出缓存,提高驱动力
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;//关闭DAC芯片连接
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;//缓冲器偏移校准采用出厂修整
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
}
五、实验步骤
把仿真器与iCore3L的SWD调试口相连(直接相连或者通过转接器相连);
将iCore3L与扩展底板相连,为扩展板供电;
打开Keil MDK 开发环境,并打开本实验工程;
烧写程序到iCore3L上;
也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。
六、实验现象
用示波器测量iCore3L底板的DAC引脚(PA4)可以看到2Vpp 1KHz的正弦波,如下图。