大家好,本人在校老菜雞一個,最近抽空接手了一個項目,其中一個關鍵點在于“通過輸入捕獲檢測任意引腳、任意順序高低電平的持續時間”。
咱們直入主題,stm32的具有豐富的外設資源,小編選擇用stm32f1系列單片機作為核心控制器,來完成這個項目。
方案有兩種:
方案一:采用中斷,例如外部引腳中斷等,直接在檢測到指定電平時,發生跳變進入中斷函數,然后進行計時。
方案二:采用定時器輸入捕獲,在上升沿、下降沿時發生跳變,然后進行計時。
優缺點分析:方案一實行難度較小,但是需要引腳資源較多(一個檢測高電平,一個檢測低電平),時間精度稍微弱一點。
方案二擁有現成的歷程,直接調用即可,通過定時器輸入捕獲模式,中斷里進行計數。
看似使用方案二是最佳的選擇,但是,如果這樣的話,小編就不用寫這篇博客了 .
至于方案一、小弟也還沒有嘗試過,不清楚具體效果如何。
背景介紹(大牛不喜勿噴)
輸入捕獲模式:輸入捕獲模式可以用來測量脈沖寬度或者測量頻率,Stm32定時器除了定時器6和定時器7,其他定時器都有輸入捕獲功能,簡單來說,就是在邊沿信號發生跳變的時候(上升沿、下降沿),將當前定時器的值存放到對應通道的捕獲/比寄存器中,完成一次捕獲,同時,可以再配置捕獲到相應跳變時,是否觸發中斷/DMA等等。
一、測量高電平脈沖寬度:采用正點原子的代碼思路。先將引腳設定為下拉輸入,然后設置輸入捕獲為“上升沿觸發”,將當前定時器中的時間存儲起來,然后再中斷里將觸發方式設置為“下降沿觸發”,再記錄一下觸發時間,二者相減,即可得出高電平持續時間。
二、測量低電平脈沖寬度:與測量高電平脈沖寬度正好相反,不過應該如何設置呢?小編找了很久,也沒有答案,所以只能自己動手,豐衣足食咯。
先看檢測高電平脈沖的代碼:
//定時器2中斷服務程序
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)// 這里采用了兩個變量作為臨時判斷條件,這兩個變量最初值都為0
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//如果是發生了中斷,那么向下執行
{
if(TIM2CH1_CAPTURE_STA&0X40)//如果已經捕獲到高電平那么就進一步執行程序。
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//
{
TIM2CH1_CAPTURE_STA|=0X80;/
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//
{
if(TIM2CH1_CAPTURE_STA&0X40) /
{
TIM2CH1_CAPTURE_STA|=0X80; /
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); /
}else //
{
TIM2CH1_CAPTURE_STA=0;
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); /
}//////(小小吐槽一下,網站上傳圖片功能個人感覺有點雞肋。這一段很重要,必須要認真去揣摩TIM2CH1_CAPTURE_STA的賦值關系。不要做拿來主義,這樣只能是拔苗助長,得不償失。)
通過兩個變量的“與”、“賦值”等操作,對高電平進行不同的操作。在輸入捕獲通道中,設置為上升沿觸發。過來一個上升沿,進入中斷,檢查是否標記位被賦值,如果沒有,代表是是第一次檢測到高電平,記錄當前定時器的值,然后設置為下降沿........
測量低電平脈沖時長的代碼:簡述一下思路,就是同樣定義兩個變量,按照上述代碼的格式,照貓畫虎一次,幾乎沒有大的改變。
具體情況,請在代碼文件中進行查看。
備注:有一個語句 TIM_SetCounter(TIM2,0);具體作用我在代碼中也有標注,時間所限,就不再多說了,一切盡在代碼中。有空再來補全相關內容。
單片機源程序如下:
- #include "sys.h"
- #include "usart.h"
- #include "delay.h"
- #include "led.h"
- #include "stm32f10x.h"
- #include "usart1.1.h"
- #include "oled.h"
- #include "timer.h"
- //MPU6050
- //串口1發送1個字符
- //c:要發送的字符
- float x,y=0;
- u8 xy[20];//用于接收坐標?
- u8 len;
- u16 led0pwmval=1;
- int main(void)
- {
- int i=0;
- u8 t;
- u16 times=0;
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- delay_init(); //延時函數初始化
- usart_init(19200); //串口初始化為9600
- OLED_Init();
- LED_Init();
- TIM2_Cap_Init(0XFFFF,7199); //以1Mhz的頻率計數 0XFFFF----1111 1111 1111 1111(2進制)//10khz計數頻率,每計數一下是1ms
- TIM1_PWM_Init(9999,7199);//1MHZ頻率輸出。
- TIM3_PWM_Init(9999,7199);//10kHZ技術頻率。
- while(1)
- {
- //OLED_show();
- //show1_all();這兩個暫時取消
- //delay_ms(300);不清楚會造成什么樣的后果
- TIM_SetCompare3(TIM3,led0pwmval);
- TIM_SetCompare4(TIM3,led0pwmval);
- // TIM_SetCompare4(TIM1,led0pwmval);
-
- if(USART_RX_STA&0x8000)//判斷接收數組的最高位是否為一,本次接收是否完成
- {
- len=USART_RX_STA&0x3fff;//取出u16中的低16 位,得到此次接收到的數據長度
- USART_RX_STA=0;//對數組清零,方便下一次接收
-
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==0)
- {
- delay_ms(1000);
- LED=0;
- printf("1");
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
- {
- delay_ms(1000);
- LED=1;
- printf("2");
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==0)
- {
- delay_ms(1000);
- printf("3");
- }
- convey();
- }
- }
復制代碼
目前代碼還存在很多問題,求大神指導如何修改:
交替檢測高低電平.7z
(215.35 KB, 下載次數: 149)
2019-7-16 16:55 上傳
點擊文件名下載附件
|