STM32-正弦波可調(50HZ~20KHZ可調、峰峰值0~3.3V可調)

来源:https://www.cnblogs.com/lifexy/archive/2018/04/13/8820281.html
-Advertisement-
Play Games

1.原理: 通過定時器每隔一段時間觸發一次DAC轉換,然後通過DMA發送正玄波碼表值給DAC. 當需要改變頻率HZ時,只需要修改定時器頻率即可(最高只能達到20KHz) 當需要改變正玄波的正峰峰值/負峰峰值時,只需要修改正玄波碼表即可 2.實現 代碼如下所示(採用的是定時器2,DAC引腳是PA4) ...


1.原理:

通過定時器每隔一段時間觸發一次DAC轉換,然後通過DMA發送正玄波碼表值給DAC.

  • 當需要改變頻率HZ時,只需要修改定時器頻率即可(最高只能達到20KHz)
  • 當需要改變正玄波的正峰峰值/負峰峰值時,只需要修改正玄波碼表即可

 

2.實現

代碼如下所示(採用的是定時器2,DAC引腳是PA4)

#define HZ(x) (u16)(72000000/sizeof(Sine12bit)*2/x)     //計算Hz

#define DAC_DHR12R1 0x40007408 //外設DAC通道1的基地址


u16 Sine12bit[256] = { //正弦波描點
 2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496,
 2545, 2594, 2642, 2690, 2737, 2785, 2831, 2877, 2923, 2968,
 3013, 3057, 3100, 3143, 3185, 3227, 3267, 3307, 3347, 3385,
 3423, 3460, 3496, 3531, 3565, 3598, 3631, 3662, 3692, 3722,
 3750, 3778, 3804, 3829, 3854, 3877, 3899, 3920, 3940, 3958,
 3976, 3992, 4007, 4021, 4034, 4046, 4056, 4065, 4073, 4080,
 4086, 4090, 4093, 4095, 4095, 4095, 4093, 4090, 4086, 4080,
 4073, 4065, 4056, 4046, 4034, 4021, 4007, 3992, 3976, 3958,
 3940, 3920, 3899, 3877, 3854, 3829, 3804, 3778, 3750, 3722,
 3692, 3662, 3631, 3598, 3565, 3531, 3496, 3460, 3423, 3385,
 3347, 3307, 3267, 3227, 3185, 3143, 3100, 3057, 3013, 2968,
 2923, 2877, 2831, 2785, 2737, 2690, 2642, 2594, 2545, 2496,
 2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098, 2047, 1997,
 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1501,
 1453, 1405, 1358, 1310, 1264, 1218, 1172, 1127, 1082, 1038,
 995, 952, 910, 868, 828, 788, 748, 710, 672, 635,
 599, 564, 530, 497, 464, 433, 403, 373, 345, 317,
 291, 266, 241, 218, 196, 175, 155, 137, 119, 103,
 88, 74, 61, 49, 39, 30, 22, 15, 9, 5,
 2, 0, 0, 0, 2, 5, 9, 15, 22, 30,
 39, 49, 61, 74, 88, 103, 119, 137, 155, 175,
 196, 218, 241, 266, 291, 317, 345, 373, 403, 433,
 464, 497, 530, 564, 599, 635, 672, 710, 748, 788,
 828, 868, 910, 952, 995, 1038, 1082, 1127, 1172, 1218,
 1264, 1310, 1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697,
 1747, 1797, 1847, 1897, 1947, 1997 };


 /*************************************************************
Function  :  set_Sine12bit
Description : 設置正玄波碼表
Input  :   MAX(正峰峰值) MIN(負峰峰值)
return  :  none
*************************************************************/ 
 void Set_Sine12bit(float MAX,float MIN)
{
         int i;
         float  jiaodu=0;

float MID=(MAX+MIN)/2.0;                        //中間峰值

if(MAX>3.3) MAX=3.3;

else if(MAX<=MIN) MIN=0;
for(i=0;i<256;i++)
         {
             jiaodu=i*0.0247369;      //當i =127時,表示為180度,由於sin()是弧度制,所以需要轉換
             Sine12bit[i]=  ((float)sin(jiaodu)*(MAX-MID)+MID)*1241.212;     //1241.212是比例,等於4096/3.3            
         }  
}

/*************************************************************
Function  :   Set_Period
Description : 設置頻率hz
Input  :   value(需要設置的頻率hz值)
return :  none
*************************************************************/ 
void  Set_Period(u32 value)
{
     TIM_ARRPreloadConfig(TIM2,DISABLE);
     TIM2->ARR=HZ(value);                //更新預裝載值 
     TIM_ARRPreloadConfig(TIM2,ENABLE);

}

/*************************************************************
Function : TIM2_Int_Init
Description: 初始化定時器2
Input :  Hz (需要初始化的頻率hz值)
return :  none
*************************************************************/ 
void TIM2_Int_Init(u32 Hz)
{

      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//初始化定時器2與6的時鐘

      TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
      TIM_TimeBaseStructure.TIM_Period = HZ(Hz);                        //正弦波頻率設置
      TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                   //沒有預分頻
      TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;  //時鐘不分頻  72M
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //增計數
      TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

      TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//更新TIM2輸出觸發    
}

/*************************************************************
Function : DAC_DMA_Config
Description: 初始化DAC和DMA
Input :   none
return :  none
*************************************************************/ 
void DAC_DMA_Config(void)
{  
     DAC_InitTypeDef DAC_InitStructure;
     DMA_InitTypeDef DMA_InitStructure;
     GPIO_InitTypeDef GPIO_InitStructure;

     RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

     RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//初始化DAC的時鐘

     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//初始化DMA2的時鐘

     /*初始化GPIO*/
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;//DAC channel1和channel2對應的引腳
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推輓輸出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOA, &GPIO_InitStructure);

    /*初始化DAC寄存器*/
     DAC_StructInit(&DAC_InitStructure);
     DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//指定DAC1的觸發定時器TIM2
     DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//無波形產生
     DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //不是能DAC輸出緩衝
     DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化DAC channel1
     DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC channel1
     DAC_DMACmd(DAC_Channel_1, ENABLE); //使能DAC Channel1的DMA
/*初始化DMA寄存器*/ DMA_DeInit(DMA2_Channel3); //將DMA配置成預設值 DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//指定DMA2通道3的目標地址為DAC1_DHR12R1 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;//指定DMA的源地址為數組Sine12bit DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設作為數據傳輸的目的地 DMA_InitStructure.DMA_BufferSize = sizeof(Sine12bit)/2;//DMA緩衝區大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設機地址存器不變 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //記憶體地址寄存器遞增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外設數據寬度為半字 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//記憶體數據寬度為半字 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在迴圈緩存模式,數據傳輸數為0時,自動恢復配置初值 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//非常高優先順序 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被設置成記憶體到記憶體模式,與迴圈模式相對 DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化DMA DMA_Cmd(DMA2_Channel3, ENABLE); //使能DMA的channel3 TIM_Cmd(TIM2, ENABLE); //最後開啟TIM2轉換 }

 

然後在main()函數里,調用上面函數初始化,並判斷串口處理:

  int main(void)
 {    
       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 設置中斷優先順序分組2
       uart_init(115200);
       delay_init();               //延時函數初始化         
    TIM2_Int_Init(50);          //50HZ 
    DAC_DMA_Config();  

     while(1)
    {
       USART_handler();          //處理串口輸入,實現頻率,峰峰值可調
       delay_ms(20);
    }

}

其中USART_handler()函數實現如下:

void USART_handler()
{  
       u8 len;
       u32 hz;                //獲取HZ頻率
       float dac_max,dac_min; //獲取DAC峰值     

       if(USART_RX_STA&0x8000)
       { 
              len=USART_RX_STA&0x2F;
              USART_RX_BUF[len]=0;
              sscanf((char *)USART_RX_BUF,"%d,%f,%f",&hz,&dac_max,&dac_min);
              printf("SET  HZ = %d, MAX = %f,MIN = %f\r\n", hz,dac_max,dac_min);

              Set_Sine12bit(dac_max,dac_min);        //更改峰值
              Set_Period( hz);                       //更改頻率

              USART_RX_STA=0;
       }
}

 

3.進入串口試驗

1)設置頻率=50hz,正峰值=3.3V,負峰值=0V,串口則發送50,3.3,0.0,如下圖所示:

 

示波器測量:

 

 

2)設置頻率=100hz,正峰值=3V,負峰值=0V, 串口則發送100,3,0.0:

 

 

3)設置頻率=100hz,正峰值=2V,負峰值=1V, 串口則發送100,2,1:

 

 

4)設置頻率=1khz,正峰值=3.3V,負峰值=0V, 串口則發送1000,3.3,0

 

 

5)設置頻率=20khz,正峰值=3.3V,負峰值=0V,串口則發送20000,3.3,0:    

 

 

 是不是很簡單~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...