1.簡介:數字頻率計主要由四個部分組成:時基電路,整形電路,控制電路和顯示電路組成。在一個測量周期過程中,由時基電路產生一標準時間信號控制閥門,調節時基電路中的電阻可產生需要的標準時間信號。信號輸入整形電路中,經過整形,輸出一方波,通過閥門后,計時器對其計數。當計數完畢,時基電路輸出一個上升沿,使鎖存器打開,計數器計數結果輸入譯碼器,從而讓顯示器顯示,達到測量頻率的目的。文件包括設計電路圖,設計源代碼與設計報
1.測量信號輸入幅度1V~5V方波,頻率為1kHz~10kHz,測量精度1%,信號輸入幅度1V~5V三角波,頻率為1kHz~10kHz,測量精度1%,信號輸入幅度2V~5V正弦波,頻率為1kHz~10kHz,測量精度1%;
1.測頻部分:先對輸入信號進行波形轉換,通過一個過零比較器將三角波、正弦波轉化為方波,之后將將方波輸入單片機 口進行波形測試。
2.限幅報警部分:輸入信號經過D1變成半波信號,之后經過C3,C4,C5,C6,C7進行整流成為幅值直流信號,之后將信號輸入電位器進行分壓,保證15v電壓經過電位器后剩余3.3v電壓。最后輸出到端口上與3.3v電壓進行比較,將比較結果輸入單片機 口。
3.單片機供電部分:通過供電模塊輸出3.3v電壓供給stm32單片機。
4.軟件設計原理:硬件部分會將所有波形統一成方波輸入。使用TIM3與TIM4計時器。TIM3進行波形捕捉。TIM3捕捉波形的上升沿或者下降沿。開始計數,知道捕捉到相對應的上升沿或者下降沿。根據所計數的多少即可計算出波形的占空比。每次捕捉到上升沿且之前為低電平,頻率計數加一。TIM4計數器用來計數一秒,當TIM4計數滿一秒時,發生TIM4中斷,根據TIM3的頻率計數,即可計算出輸入波形的頻率。
5.源代碼:(帶有詳細注釋)Main函數:#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; //記錄捕獲狀態
extern uint8_t flag; //記錄計時是否滿一秒
extern uint32_t rising_time; //高電平持續時間
extern uint32_t falling_time; //低電平持續時間
int main(void)
{
delay_init(); //延時函數初始化
uart_init(115200); //串口一初始化,設置波特率為115200
LED_Init(); //報警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初始化 時鐘設為1M Hz用于輸入捕獲
TIM4_Int_Init(10000-1,72-1); //TIM4初始化 時鐘設為1M Hz用于計時1s
while(1)
{
if(flag== 1) //檢測計時是否滿1s
{
flag= 0;
if((rising_time!= 0) && (falling_time != 0)) //有信號輸入
{
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); //無信號輸入
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) //檢測比較器輸入是否為高電平
LED= 0; //報警燈亮
elseLED = 1; //報警燈不亮
}
}
計時器函數:#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時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //選擇6號引腳
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; //輸入下拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA6
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA6下拉
//初始化定時器3 TIM3
TIM_TimeBaseStructure.TIM_Period= arr; //設定計數器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler=psc; //預分頻器
TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1; //設置時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
//初始化TIM3輸入捕獲參數
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; //先占優先級0級
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //從優先級0級
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
TIM_Cmd(TIM3,ENABLE ); //使能定時器3
}
uint8_t TIM3CH1_CAPTURE_STA; //輸入捕獲狀態
uint16_t counter = 0; //記錄捕獲上升沿次數
uint8_t sec_cnt = 0; //毫秒計時
uint8_t flag = 0; //計時1s完成標志
uint32_t rising_time; //高電平時間
uint32_t falling_time; //低電平時間
//定時器3中斷服務程序
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) //發生捕獲事件
{
if(TIM3CH1_CAPTURE_STA& 0x80) //捕獲下降沿(已經捕獲到上升沿)
{
rising_time= TIM_GetCapture1(TIM3); //讀取高電平時間(us)
TIM3CH1_CAPTURE_STA= 0; //清空
TIM_SetCounter(TIM3,0);
TIM3CH1_CAPTURE_STA|= 0x40; //標記捕獲到了下降沿
TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Rising); //設置為上升沿觸發
}
else //捕獲上升沿
{
falling_time= TIM_GetCapture1(TIM3); //低電平時間
TIM3CH1_CAPTURE_STA= 0; //清零
TIM_SetCounter(TIM3,0);
TIM3CH1_CAPTURE_STA|=0X80; //標記捕獲到了上升沿
TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling); //開始捕獲下降沿
counter++; //頻率計數加一
}
}
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1); //清除中斷標志位
}
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDefNVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //時鐘使能
TIM_TimeBaseStructure.TIM_Period= arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler=psc; //設置用來作為TIMx時鐘頻率除數的預分頻值
TIM_TimeBaseStructure.TIM_ClockDivision= 0; //設置時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel= TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1; //先占優先級1級
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //從優先級0級
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器
TIM_Cmd(TIM4,ENABLE);
}
void TIM4_IRQHandler(void) //TIM3中斷,10000us中斷一次
{
if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //檢查指定的TIM中斷發生與否:TIM 中斷源
{
sec_cnt++;
if(sec_cnt== 100) //計時滿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端口時鐘
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); //根據設定參數初始化GPIOB.5
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
幅值報警初始化:#include "key.h"
#include "sys.h"
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; //設置成下拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA5
}