利用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的正弦波。當然這里生成的波形都是用於顯示,交交作業還可以,切不可作為穩定信號源。