社团作业=_=
任务一:波形生成。
1.使用STM32的DAC功能,生成0~10kHz的方波,频率精确到1%以内;
2.能够生成三角波、正弦波;
3.实现频率设置,可以实现一定步进数的调节,最高为100Hz
一、相关内容简介
1.DAC
DAC指数模转换器,指的是将数字量转为模拟量的一类元件。以此项目中的DAC为例,通过向DAC的寄存器写入0 ~ 4095之间的一个值,就能输出0 ~ 3.3V的一个电压。
2.STM32的内置DAC
此次使用的STM32F103ZET6芯片自带一个12位数字输入,电压输出的数模转换器。这个DAC模块具有两个支持独立转换的通道,还可以配置成两个通道同时转换。DAC可以配置为12位(4096档)或者8位(256档)。
3.定时器
定时器的功能挺多的,这里主要是利用定时器在每个计数周期计数器溢出产生中断/触发输出来达到定时输出波形的目的
4.DMA
DMA的中文名是直接存储器访问,相比于通过CPU来控制传输数据,DMA的速度更快,并且可以节省CPU资源。
二、用定时器中断+DAC实现
这是最容易想到的办法。因为波形可以看作是电压关于时间的函数,而涉及到在指定时刻(指定周期内)进行操作时,很容易就会想到用定时器,所以只需要在定时器的中断函数当中计算此时的电压值并写入DAC寄存器,就能达到输出波形的目的。
具体实现思路:用一个全局变量mode来存储当前需要输出的波形类型,主函数中用while循环扫描板载按键是否被按下,从而对应改变mode的值。而定时器中断函数中根据当前mode的值进行对应波形的计算,将计算出来的值写入DAC寄存器。
1.配置DAC
查开发手册得知DAC的两个通道分别对应PA4和PA5,在作为DAC输出使用时需要先将端口配置为模拟输入模式以避免干扰。
这里直接用了开发板例程的代码,以使用DAC通道1,PA4作为模拟输出为例,代码如下:
void Dac1_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitType;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); // DAC时钟使能
DAC_DeInit(); // 初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 配置为模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
DAC_StructInit(&DAC_InitType); // 初始化
DAC_InitType.DAC_Trigger = DAC_Trigger_None; // 不使用触发功能,对应寄存器中TEN1=0,TSEL1[2:0] = 000
DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None; // 不使用自带的波形生成功能
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0; // 通过线性反馈移位寄存器生成伪噪声,仅当DAC_WaveGeneration配置为DAC_WaveGeneration_Noise时有效
DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable; // 禁用输出缓存
DAC_Init(DAC_Channel_1, &DAC_InitType); // 初始化DAC
DAC_Cmd(DAC_Channel_1, ENABLE); // 使能DAC
DAC_SetChannel1Data(DAC_Align_12b_R, 0); // 输出0V
}
以通道1为例,查阅开发手册可得以8位右对齐,12位左对齐,12位右对齐三种模式操作的时候其实是在写入DHR8R1,DHR12L1,DHR12R1三个不同位置的寄存器,这些值经过自动移位写入内部的DHR1寄存器,之后被转存至DOR1寄存器。从DHRx转存到DORx所需要的时钟周期取决于触发功能的配置,详见数据手册。
2.配置定时器
2.1.初始化
因为这里只是使用定时器的中断,所以随便用哪个定时器都可以
以配置TIM3为例,代码如下:
void TIM_Config()
{
u16 arr = 1; // 自动重装载寄存器(Auto Reload Register)
u16 psc = 0; // 预分频器(Prescaler)
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // TIM3时钟使能
TIM_DeInit(TIM3); // 初始化
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); // 初始化
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 似乎是在数字滤波器当中才会用到,平时一般设为0(TIM_CKD_DIV1)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 允许更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPrio