找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 7731|回復(fù): 4
打印 上一主題 下一主題
收起左側(cè)

基于stm32的單片機(jī)的數(shù)字頻率計(jì)設(shè)計(jì)

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
  1.簡(jiǎn)介:數(shù)字頻率計(jì)主要由四個(gè)部分組成:時(shí)基電路,整形電路,控制電路和顯示電路組成。在一個(gè)測(cè)量周期過(guò)程中,由時(shí)基電路產(chǎn)生一標(biāo)準(zhǔn)時(shí)間信號(hào)控制閥門(mén),調(diào)節(jié)時(shí)基電路中的電阻可產(chǎn)生需要的標(biāo)準(zhǔn)時(shí)間信號(hào)。信號(hào)輸入整形電路中,經(jīng)過(guò)整形,輸出一方波,通過(guò)閥門(mén)后,計(jì)時(shí)器對(duì)其計(jì)數(shù)。當(dāng)計(jì)數(shù)完畢,時(shí)基電路輸出一個(gè)上升沿,使鎖存器打開(kāi),計(jì)數(shù)器計(jì)數(shù)結(jié)果輸入譯碼器,從而讓顯示器顯示,達(dá)到測(cè)量頻率的目的。文件包括設(shè)計(jì)電路圖,設(shè)計(jì)源代碼與設(shè)計(jì)報(bào)
2.目標(biāo):本設(shè)計(jì)主要完成以下目標(biāo):
  1.測(cè)量信號(hào)輸入幅度1V~5V方波,頻率為1kHz~10kHz,測(cè)量精度1%,信號(hào)輸入幅度1V~5V三角波,頻率為1kHz~10kHz,測(cè)量精度1%,信號(hào)輸入幅度2V~5V正弦波,頻率為1kHz~10kHz,測(cè)量精度1%;
2.當(dāng)輸入信號(hào)幅度大于15V時(shí),具有報(bào)警功能,測(cè)量結(jié)果為數(shù)字顯示;
3.測(cè)量具有串口通信功能;
4.信號(hào)輸入幅度為1V~10V脈沖,頻率為20Hz~1kHz時(shí),測(cè)量并計(jì)算占空比。
3.硬件設(shè)計(jì):
3.硬件設(shè)計(jì)原理
硬件電路圖:

1.測(cè)頻部分:先對(duì)輸入信號(hào)進(jìn)行波形轉(zhuǎn)換,通過(guò)一個(gè)過(guò)零比較器將三角波、正弦波轉(zhuǎn)化為方波,之后將將方波輸入單片機(jī) 口進(jìn)行波形測(cè)試。
2.限幅報(bào)警部分:輸入信號(hào)經(jīng)過(guò)D1變成半波信號(hào),之后經(jīng)過(guò)C3C4,C5,C6C7進(jìn)行整流成為幅值直流信號(hào),之后將信號(hào)輸入電位器進(jìn)行分壓,保證15v電壓經(jīng)過(guò)電位器后剩余3.3v電壓。最后輸出到端口上與3.3v電壓進(jìn)行比較,將比較結(jié)果輸入單片機(jī) 口。
3.單片機(jī)供電部分:通過(guò)供電模塊輸出3.3v電壓供給stm32單片機(jī)。
4.軟件設(shè)計(jì)原理:
硬件部分會(huì)將所有波形統(tǒng)一成方波輸入。使用TIM3TIM4計(jì)時(shí)器。TIM3進(jìn)行波形捕捉。TIM3捕捉波形的上升沿或者下降沿。開(kāi)始計(jì)數(shù),知道捕捉到相對(duì)應(yīng)的上升沿或者下降沿。根據(jù)所計(jì)數(shù)的多少即可計(jì)算出波形的占空比。每次捕捉到上升沿且之前為低電平,頻率計(jì)數(shù)加一。TIM4計(jì)數(shù)器用來(lái)計(jì)數(shù)一秒,當(dāng)TIM4計(jì)數(shù)滿一秒時(shí),發(fā)生TIM4中斷,根據(jù)TIM3的頻率計(jì)數(shù),即可計(jì)算出輸入波形的頻率。
5.源代碼:(帶有詳細(xì)注釋)Main函數(shù):
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "oled.h"
#include "timer.h"
#include "led.h"
#include "key.h"

extern uint16_t  counter;                         //記錄捕獲狀態(tài)
extern uint8_t   flag;                                  //記錄計(jì)時(shí)是否滿一秒
extern uint32_t  rising_time;                  //高電平持續(xù)時(shí)間
extern uint32_t  falling_time;                 //低電平持續(xù)時(shí)間

int main(void)
{        
         delay_init();                                                                                 //延時(shí)函數(shù)初始化                    
         uart_init(115200);                                                                    //串口一初始化,設(shè)置波特率為115200
         LED_Init();                                                                                            //報(bào)警LED初始化
         KEY_Init();                                                                                            //比較器輸入初始化
         OLED_Init();                                                                                //OLED顯示屏初始化
         OLED_Clear();                                                                            //清空顯示屏
         OLED_ShowString(30,0, "Cymometer");                           //在屏幕上顯示Cymometer
         OLED_ShowString(20,4, "Fre:");
         OLED_ShowString(93,4, "Hz");
         OLED_ShowString(20,6, "Dut:");
         OLED_ShowString(87,6, "%");
         TIM3_Cap_Init(0xffff,72-1);                                         //TIM3初始化 時(shí)鐘設(shè)為1M Hz用于輸入捕獲
         TIM4_Int_Init(10000-1,72-1);                                               //TIM4初始化 時(shí)鐘設(shè)為1M Hz用于計(jì)時(shí)1s

         while(1)
         {                 
                   if(flag== 1)                //檢測(cè)計(jì)時(shí)是否滿1s                                          
                   {
                            flag= 0;
                            if((rising_time!= 0) && (falling_time != 0))     //有信號(hào)輸入
                            {
                                     printf("Fre:%dHz,     Dut:%1.2f\r\n", counter,(float)rising_time/(rising_time + falling_time));
                                     OLED_ShowNum(53,4, counter, 5, 16);
                                     OLED_ShowNum(71,6, (float)rising_time/(rising_time + falling_time)*100, 2, 16);
                            }
                            else
                            {
                                     printf("Fre:%d           Dut:0\r\n", counter);       //無(wú)信號(hào)輸入
                                     OLED_ShowNum(53,4, counter, 5, 16);
                                     OLED_ShowNum(71,6, 0, 2, 16);
                            }
                            counter= 0;
                            rising_time= 0;
                            falling_time= 0;
                   }
                   if(KEY== 1)                //檢測(cè)比較器輸入是否為高電平
                            LED= 0;             //報(bào)警燈亮
                   elseLED = 1;              //報(bào)警燈不亮
         }
}
計(jì)時(shí)器函數(shù):
#include "sys.h"
#include "timer.h"
#include "usart.h"

void TIM3_Cap_Init(uint16_t arr, uint16_tpsc)                                  //TIM3用于輸入捕獲
{
         GPIO_InitTypeDefGPIO_InitStructure;
         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
         TIM_ICInitTypeDef  TIM3_ICInitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;

         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);     //使能TIM3時(shí)鐘
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);          //使能GPIOA時(shí)鐘

         GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;                      //選擇6號(hào)引腳
         GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD;                      //輸入下拉
         GPIO_Init(GPIOA,&GPIO_InitStructure);                                             //初始化PA6
         GPIO_ResetBits(GPIOA,GPIO_Pin_0);                                                    //PA6下拉

         //初始化定時(shí)器3 TIM3  
         TIM_TimeBaseStructure.TIM_Period= arr;                               //設(shè)定計(jì)數(shù)器自動(dòng)重裝值
         TIM_TimeBaseStructure.TIM_Prescaler=psc;                                    //預(yù)分頻器
         TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
         TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;  //TIM向上計(jì)數(shù)模式
         TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);

         //初始化TIM3輸入捕獲參數(shù)
         TIM3_ICInitStructure.TIM_Channel= TIM_Channel_1;                   //CC1S=01選擇輸入端 IC1映射到TI1
       TIM3_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;      //上升沿捕獲
       TIM3_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //映射到TI1
       TIM3_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1;   //配置輸入分頻,不分頻
       TIM3_ICInitStructure.TIM_ICFilter = 0x00;                                  //IC1F=0000 配置輸入濾波器 不濾波
       TIM_ICInit(TIM3,&TIM3_ICInitStructure);

         //中斷分組初始化
         NVIC_InitStructure.NVIC_IRQChannel= TIM3_IRQn;            //TIM3中斷
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;  //先占優(yōu)先級(jí)0級(jí)
         NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;          //從優(yōu)先級(jí)0級(jí)
         NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;           //IRQ通道被使能
         NVIC_Init(&NVIC_InitStructure);

         TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);

     TIM_Cmd(TIM3,ENABLE );     //使能定時(shí)器3
}

uint8_t  TIM3CH1_CAPTURE_STA;                                           //輸入捕獲狀態(tài)
uint16_t counter = 0;                                                           //記錄捕獲上升沿次數(shù)
uint8_t  sec_cnt = 0;                                                           //毫秒計(jì)時(shí)
uint8_t       flag = 0;                                                                          //計(jì)時(shí)1s完成標(biāo)志
uint32_t rising_time;                                                            //高電平時(shí)間
uint32_t falling_time;                                                          //低電平時(shí)間

//定時(shí)器3中斷服務(wù)程序      
void TIM3_IRQHandler(void)
{
         if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)                            //發(fā)生捕獲事件
         {        
                   if(TIM3CH1_CAPTURE_STA& 0x80)                                                                 //捕獲下降沿(已經(jīng)捕獲到上升沿)
                   {
                            rising_time= TIM_GetCapture1(TIM3);                             //讀取高電平時(shí)間(us)

                            TIM3CH1_CAPTURE_STA= 0;                                                         //清空
                            TIM_SetCounter(TIM3,0);
                            TIM3CH1_CAPTURE_STA|= 0x40;                                                //標(biāo)記捕獲到了下降沿
                            TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Rising);   //設(shè)置為上升沿觸發(fā)
                   }
                   else                                                                                                                  //捕獲上升沿
                   {
                            falling_time= TIM_GetCapture1(TIM3);                                     //低電平時(shí)間

                            TIM3CH1_CAPTURE_STA= 0;                                                         //清零
                            TIM_SetCounter(TIM3,0);
                            TIM3CH1_CAPTURE_STA|=0X80;                                                            //標(biāo)記捕獲到了上升沿
                            TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);  //開(kāi)始捕獲下降沿
                            counter++;                                                                                                     //頻率計(jì)數(shù)加一
                   }
         }

         TIM_ClearITPendingBit(TIM3,TIM_IT_CC1); //清除中斷標(biāo)志位
}



void TIM4_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
         NVIC_InitTypeDefNVIC_InitStructure;

         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //時(shí)鐘使能

         TIM_TimeBaseStructure.TIM_Period= arr; //設(shè)置在下一個(gè)更新事件裝入活動(dòng)的自動(dòng)重裝載寄存器周期的值
         TIM_TimeBaseStructure.TIM_Prescaler=psc; //設(shè)置用來(lái)作為TIMx時(shí)鐘頻率除數(shù)的預(yù)分頻值
         TIM_TimeBaseStructure.TIM_ClockDivision= 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
         TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;  //TIM向上計(jì)數(shù)模式
         TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位

         TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);

         NVIC_InitStructure.NVIC_IRQChannel= TIM4_IRQn;
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1;  //先占優(yōu)先級(jí)1級(jí)
         NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;  //從優(yōu)先級(jí)0級(jí)
         NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; //IRQ通道被使能
         NVIC_Init(&NVIC_InitStructure);  //根據(jù)NVIC_InitStruct中指定的參數(shù)初始化外設(shè)NVIC寄存器

         TIM_Cmd(TIM4,ENABLE);  

}

void TIM4_IRQHandler(void)                                                               //TIM3中斷,10000us中斷一次
{
         if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)  //檢查指定的TIM中斷發(fā)生與否:TIM 中斷源
         {
                   sec_cnt++;                                                                                            
                   if(sec_cnt== 100)                                                                     //計(jì)時(shí)滿1
                   {
                            sec_cnt= 0;
                            flag= 1;
                   }
                   TIM_ClearITPendingBit(TIM4,TIM_IT_Update);           //清除TIMx的中斷待處理位:TIM 中斷源
         }
}
       LED初始化:
#include "led.h"
#include "sys.h"

void LED_Init(void)
{
         GPIO_InitTypeDef  GPIO_InitStructure;

         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);    //使能GPIOC端口時(shí)鐘

         GPIO_InitStructure.GPIO_Pin= GPIO_Pin_13;                                    //LED-->PC13 端口配置
         GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;                //推挽輸出
         GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;                 //IO口速度為50MHz
         GPIO_Init(GPIOC,&GPIO_InitStructure);                                             //根據(jù)設(shè)定參數(shù)初始化GPIOB.5
         GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
幅值報(bào)警初始化:
#include "key.h"
#include "sys.h"

void KEY_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA時(shí)鐘

         GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;
         GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; //設(shè)置成下拉輸入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA5

}


全部資料51hei下載地址:
簡(jiǎn)易頻率計(jì).rar (663.26 KB, 下載次數(shù): 188)


評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏10 分享淘帖 頂1 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:91165 發(fā)表于 2020-4-26 19:39 | 只看該作者
好東東,頂樓主,謝謝分享
回復(fù)

使用道具 舉報(bào)

板凳
ID:473907 發(fā)表于 2020-4-27 16:24 | 只看該作者
感覺(jué)稍微復(fù)雜了些~  新手理解困難
回復(fù)

使用道具 舉報(bào)

地板
ID:942534 發(fā)表于 2021-6-22 15:49 | 只看該作者
感謝分享,先拿著學(xué)一下看看
回復(fù)

使用道具 舉報(bào)

5#
ID:1108903 發(fā)表于 2024-1-11 10:19 | 只看該作者
電路圖就那么一點(diǎn)啊
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表