本帖最后由 1五湖四海1 于 2015-4-18 10:49 編輯 0 q* W, j: m* }% q& L y
; a5 U$ S+ A) x; @; C
我這小項目是為了解決運動的活塞是否被卡住而設計的。在實際中汽車剎車系統出現故障容易造成重大事故發生。我們的礦車有兩個加力器,如果一個加力器出現問題能及時發現是可以避免事故的發生。所以制作這個運動部件卡住報警器對安全是很有必要的。 實現原理上用一個能夠檢測距離的模擬量傳感器。控制器先判斷運動部件是否受人為控制開始運動,如果部件開始運動,控制器的模數轉換器每隔一段時間采集一次距離,控制器計算前后兩次采集距離值是否一樣,就可以判斷運動部件是否被卡住不動了。下面介紹下用到的器件和具體設計細節。 距離傳感器用的是光電模擬量輸出傳感器,檢測范圍在10mm——100mm。如下圖中兩個圓柱形的便是距離傳感器。 控制器用的是ARM cortek M3 STM32f103,有人會問為什么要用這個高性能的處理器呢?我認為現在已經不是51單片機是世界了,51單片機沒有AD轉換器,需要外接AD轉換器,代碼需要從零開始寫。而ARM cortek M3 里面有10bit AD轉換器,有大量的寫好的庫函數可以調用,可以縮短開發時間。他們的價格差不多為什么不選STM32f10。這次用的是現成的STM32f103最小系統板。如上圖 代碼設計上用到了兩個定時器中斷,一個定時器每隔200ms采集一次距離值,另一個發生故障時每隔500ms報警一次,用到的算法有AD軟件濾波,采集500次距離值后,用冒泡排序法去掉最大值和最小值后,再求平均數算出距離值,這時采集的距離值很準。剩下的就是用if else編寫的邏輯判斷了。調試時用到了printf()庫函數,結合電腦串口調試助手調試代碼。調試代碼如下圖,部分程序代碼在最下面 完成的控制器如上圖,正常工作時指示燈和蜂鳴器不亮也不響,如果活塞被卡住時聲光報警。 上圖是加力器,它是用氣頂動油完成輸出二倍力的器件。如果活塞卡死這個報警就會報警提示故障。 下面是代碼是主函數代碼 最下面有全部代碼如果有問題可以和我交流,QQ:835358518 微信:hm15041303104
2 k! f9 X; E0 Y( a4 }8 N0 Q% [: z# o#include <stm32f10x_lib.h> #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "key.h" #include "exti.h" #include "wdg.h" #include "timer.h" #include "adc.h" #include "alarm.h"
6 `5 s, `) E! `$ @; q0 r#define LIM 5 //卡住判斷參數 #define TREAD 2 //踩剎車 #define LOOSEN 1 //松剎車 #define CLEAR 3 //清除 #define DIFFERENCE 50 //回差
) s) g( c: g7 V# }( Z+ F: Q% U) Q y' s5 Z
u16 lim_value = 1800; //極限報警值 u16 max_value_l = 1000, max_value_r = 1000; //踩剎車標志值 u16 min_value_l = 3000, min_value_r = 3000; //松剎車標志值 6 D: @3 k7 T6 i2 t
u8 count = 0; //設置剎車標志防干擾計數 u8 lock_count; //卡住時計數防干擾處理 ' I% G! |; V1 T5 g. _' _/ N
u16 distance_l[2] = {0,0}; //卡住比較數組 u16 distance_r[2] = {0,0}; u8 i = 0; //采集數據計數變量
7 E( E' P( @7 Q, u2 Vbool brake_state_l, brake_state_r; //剎車狀態標志位 bool lock_alarm_l, lock_alarm_r, lock_alarm; //卡住報警標志位
. A* Y) |! I& gu16 value_buf[N]; //濾波求平均緩存 u32 sum; //濾波求平均總和緩存 u16 temp; //濾波求排序緩存
8 m! ?0 g0 P- i9 m, R; u //判斷是否活塞卡住 bool is_stuck(u16 distance_zero, u16 distance_one, bool brake_state, u16 *max_value, u16 *min_value); void data_collection(void); //數據采集 /** 主函數 */ int main(void) { bool lim_alarm_l, lim_alarm_r; //超限警報標志位
7 Z6 a. p; y! p Stm32_Clock_Init(9); //系統時鐘設置 delay_init(72); //延時初始化 uart_init(72,9600); //串口1初始化 LED_Init(); Adc_Init(); Timer2_Init(5000,7199); //定時報警 Timer3_Init(2000,7199); //定時采集ADC // Timer4_Init(5000,7199); //定時打印 8 B% V& N2 L' X) G$ u9 A1 [
while(1) { lim_alarm_l = isOverrun(distance_l[0]); //返回超限標志 lim_alarm_r = isOverrun(distance_r[0]); //返回剎車中標志 brake_state_l = isBrake_state(distance_l[0], max_value_l, min_value_l); brake_state_r = isBrake_state(distance_r[0], max_value_r, min_value_r); //報警處理函數 Alarm_dispose(lim_alarm_l, lim_alarm_r, lock_alarm); } } /** 定時器2中斷服務程序 功能:發生定時中斷控制蜂鳴器報警 */ void TIM2_IRQHandler(void) {
5 ]; d" J! R+ Y. E' H% q( D if(TIM2->SR&0X0001) //溢出中斷 { BUZZER = 0; delay_ms(100); BUZZER = 1; } TIM2->SR&=~(1<<0); //清除中斷標志位 } /** 定時器3中斷服務程序 功能:發生定時中斷時采集ADC數據,并根據判斷活塞是否卡住 */ void TIM3_IRQHandler(void) { if(TIM3->SR&0X0001)//溢出中斷 { if( ( lock_alarm_l && brake_state_l) || ( lock_alarm_r && brake_state_r) ) lock_alarm = 1; else lock_alarm = 0; & n! ^2 j4 v: o9 Z1 i
data_collection(); //數據采集后判斷是否活塞卡住 " K, U" D7 |# j/ _. U+ y+ O
} TIM3->SR&=~(1<<0); //清除中斷標志位 } /** 功能:1.判斷左活塞是否卡住 2.設置剎車標志 */ bool is_stuck(u16 distance_zero, u16 distance_one, bool brake_state, u16 *max_value, u16 *min_value) { u8 motion; % B P. ^' f9 n' X* {
if( (distance_one-distance_zero) > 5) //松剎車標志 motion = LOOSEN; 0 u" v; S3 F2 D1 v5 U6 Q1 |2 ?
if( (distance_one-distance_zero) < -5) //踩剎車標志 motion = TREAD;
: l3 n8 [- O8 T5 N) k: F! E- H if( ( (distance_one-distance_zero) < LIM) && ( (distance_zero-distance_one) < LIM) ) { /* 踩剎車時動態設置最小值剎車標志*/ if(motion == TREAD) /* 如果這次值比上次設置的標志值小說明上次是卡住值,更新最小值標志*/ if(distance_zero+DIFFERENCE < *min_value ) *min_value = distance_zero+DIFFERENCE;
2 I4 Q# a, }7 S/ P4 X6 V/ K/* 松剎車時動態設置最大值剎車標志*/ if(motion == LOOSEN) /* 如果這次值比上次設置的標志值大說明上次是卡住值,更新新的標志*/ if(distance_zero-DIFFERENCE > *max_value ) count++; //防干擾計數 if(count > 1) { *max_value = distance_zero-DIFFERENCE; count = 0; }
) [5 ~6 N5 w; m6 @% V motion = CLEAR; //清除剎車標志
; h L. X- u5 p. C0 N# Z if( brake_state ) //剎車時如果卡住開始計數 lock_count++; 5 _( ^* J6 p) Y7 h. l1 P
if( lock_count >= 5 ) //計數五次后報警位置位 { lock_count = 5; return TRUE; } } else { // lock_alarm = 0; lock_count = 0; return FALSE; } } /** 功能:判斷活塞是否卡住數據采集函數 */ void data_collection(void) { 7 H" G" p" C# z0 z. k+ n+ k4 S* [* d
u16 distance_zero, distance_one; : \: i, H+ j" h. w4 g+ T8 g7 E2 Y
filter(ADC_CH0); distance_l = sum;
2 y5 H- l4 O/ q0 {: E0 N! n1 ? delay_ms(20);
8 d! B; H3 p1 \ filter(ADC_CH1); distance_r = sum; i++; if(i > 1) //采集了兩組數據后判斷一次是否卡住 { i = 0; distance_zero = distance_l[0]; distance_one = distance_l[1]; lock_alarm_l = is_stuck(distance_zero, distance_one, brake_state_l, &max_value_l, &min_value_l); distance_zero = distance_r[0]; distance_one = distance_r[1]; lock_alarm_r = is_stuck(distance_zero, distance_one, brake_state_r, &max_value_r, &min_value_r); // d_value = distance_l[1]-distance_l[0]; // printf("%d,%d\n", motion_l, motion_r); printf("%d,%d,%d,%d\n",max_value_l,min_value_l,max_value_r,min_value_r); // printf("%d,%d,%d,%d\n",lock_alarm_l, lock_alarm_r ,lock_count_l, lock_count_r); // printf("%d,%d,%d,%d\n",distance_l[0],distance_l[1],distance_r[0],distance_r[1]); // printf("%d,%d\n",distance_l[1]-distance_l[0],distance_r[1]-distance_r[0]); // printf("%d\n",distance_r[1]-distance_r[0]); } }
" ?5 r0 e' I" m. z
7 c% Y- a0 q t
5 V2 e' n6 b2 r2 ~, `" _( i, |5 u
9 H1 o! d: w5 W% \' E! ^+ y- X( H* G2 o+ X: r
& {% B8 D1 O) H# z* C T4 B# n2 g0 L
+ } d: c/ ^( Z, a/ z4 l/ N
5 ?4 D7 o" I' N, H/ ~( o; c- K, h7 y, F k
5 o. x/ G/ O! X0 _2 n1 R: C$ g9 P5 @+ n3 o3 q$ d5 K& `: `
% ]9 p6 x1 e8 l# K
9 d) U( J( F# d N
3 g1 r8 x( v, v% I/ P1 I- d4 K" }# u) ]; {! _: ~
: j0 _/ S, a. }5 ?! m
6 O8 I2 q8 b8 _& A3 [
# O5 a4 w& [: A# o8 x$ N; Y4 }; V9 a9 v
# U8 F! A/ }; {" m. ^! J |