利用STM32开发板制作一个简单的信号发生器,能输出三角波、方波以及正弦波。
这里选用到的芯片型号是STM32F103ZET6,先利用CUBE对其进行配置吧~
先配置RCC:
然后打开SYS,调整相应的Debug,我这里是用ST_LINK,所以用到Serial Wire。
配置时钟树,HCLK直接拉满:
然后打开DAC,任意选择通道1或2,并进行基础配置(如果只是想生成三角波,那么在Wave generation mode中可以直接选择Triangle wave generation,程序中只需要打开DAC输出就能自行生成三角波):
将Trigger(触发方式)选择为定时器2事件触发,再配置其DMA:
值得一提的是,DMA请求设置中,我们需选用Circular(循环)模式,因为只有如此配置才能产生一条可以持续的波形。
由于DAC触发方式为定时器2触发,所以我们需要打开定时器2,时钟源为内部时钟,再配置PSC与ARR:
该处配置会影响到你的波形频率。同时我们需将它的触发事件调整为Update Event,这很重要,如果遗漏,你就无法控制DAC输出了。
打开串口一,并开启中断,让我们可以使用串口的功能来实现波形的切换:
配置到这里就基本结束了,那么可以生成程序进KEIL5来进行程序的编译。
先在串口的头文件中重定向printf,具体细节可以参考我之前的随笔。
然后编写用于输出波形的数组,可将其置于主函数内:
for(i=0;i<1000;i++)
{
if(i<500)
Sine12bit[i]=1500*sin(i*2*3.1415926/100)+2000;
else
Sine12bit[i]=1500*sin((i-500)*2*3.1415926/100)+2000;
}
for(i=0;i<1000;i++)
{
if(i<250)
fangbo[i]=500;
else if(i>=250&&i<500)
fangbo[i]=2000;
else if(i>=500&&i<750)
fangbo[i]=500;
else if(i>=750&&i<1000)
fangbo[i]=2000;
}
for(i=0;i<1000;i++)
{
if(i<250)
sjbo[i]=10*i+1000;
else if(i>=250&&i<500)
sjbo[i]=10*250+1000-10*(i-250);
else if(i>=500&&i<750)
sjbo[i]=10*(i-500)+1000;
else if(i>=750&&i<1000)
sjbo[i]=10*250+1000-10*(i-750);
}
由于可写入寄存器的最大值为2^12即4096,那么DAC输出的可调范围也就在0~4095之间,所以写波形计算公式的时候需要注意数值会不会溢出。也许你们注意到我每个数组中都有一千个数据,而用于输出的数据实质上只有五百个,我以每五百个数据为一个波形周期,设置两个周期是为了方便调整相位差。而波形的噪音大小、平滑程度则与显示一个周期所给出的数据个数有关,个数越多,波形越好看。
如果运用Sin函数会报错,那一定是没有添加math.h,将它加在include中即可。
至此,三种波形的输出数组已经给值完成,打开定时器和接收中断就可以开始输出了:
printf("please tell me : (S输出正弦波,F输出方波,P输出三角波)\r\n");
HAL_TIM_Base_Start(&htim2);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)
Sine12bit,500,DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)
(Sine12bit+k),500,DAC_ALIGN_12B_R);
UART_Start_Receive_IT(&huart1,&Receive_date,1);
运用HAL_DAC_Start_DMA(),两个通道都给出初始波形(正弦波),而其中的k则是我设置的相位差,理论范围可以是0~500,我给出的初始值是80,调整k的值可以实现调整相位差。
while(1)里面什么都不用放,将页面拉到末尾来编写串口中断回调:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
if(Receive_date=='S')
{
printf("输出正弦波");
ki=1;
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)Sine12bit,500,DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(Sine12bit+k),500,DAC_ALIGN_12B_R);
}
else if(Receive_date=='F')
{
printf("输出方波");
ki=2;
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)fangbo,500,DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(fangbo+k),500,DAC_ALIGN_12B_R);
}
else if(Receive_date=='P')
{
printf("输出三角波");
ki=3;
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)sjbo,500,DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(sjbo+k),500,DAC_ALIGN_12B_R);
}
}
UART_Start_Receive_IT(&huart1,&Receive_date,1);
}
串口中断结束时务必重新打开串口接收中断,不然你的串口接收中断就只能用一次了~
编程结束,上电来试试三种波形的输出吧~
分别能输出720Hz的方波与三角波,和3600Hz的正弦波。当然这里生成的波形都是用于显示,交交作业还可以,切不可作为稳定信号源。