本帖最后由 1五湖四海1 于 2015-4-18 10:49 编辑 7 J7 H; z2 r2 p0 [% w% ]
& P9 o8 _! ]9 n, i
我这小项目是为了解决运动的活塞是否被卡住而设计的。在实际中汽车刹车系统出现故障容易造成重大事故发生。我们的矿车有两个加力器,如果一个加力器出现问题能及时发现是可以避免事故的发生。所以制作这个运动部件卡住报警器对安全是很有必要的。 实现原理上用一个能够检测距离的模拟量传感器。控制器先判断运动部件是否受人为控制开始运动,如果部件开始运动,控制器的模数转换器每隔一段时间采集一次距离,控制器计算前后两次采集距离值是否一样,就可以判断运动部件是否被卡住不动了。下面介绍下用到的器件和具体设计细节。 距离传感器用的是光电模拟量输出传感器,检测范围在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
% T* W( @0 I. G2 l" F#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" ) C- Z# [/ A! \
#define LIM 5 //卡住判断参数 #define TREAD 2 //踩刹车 #define LOOSEN 1 //松刹车 #define CLEAR 3 //清除 #define DIFFERENCE 50 //回差 ' ~+ A: e4 y3 j
8 Z+ E$ s* ~, w& j* I! U! P& w% vu16 lim_value = 1800; //极限报警值 u16 max_value_l = 1000, max_value_r = 1000; //踩刹车标志值 u16 min_value_l = 3000, min_value_r = 3000; //松刹车标志值 - G+ o5 c- z# y; T) T6 p" s" |
u8 count = 0; //设置刹车标志防干扰计数 u8 lock_count; //卡住时计数防干扰处理 - H. N' q. T, V" v$ ~1 B, m
u16 distance_l[2] = {0,0}; //卡住比较数组 u16 distance_r[2] = {0,0}; u8 i = 0; //采集数据计数变量 3 I+ M! G2 k! `& S6 Y
bool brake_state_l, brake_state_r; //刹车状态标志位 bool lock_alarm_l, lock_alarm_r, lock_alarm; //卡住报警标志位
+ \/ Q x: |0 e( {7 O# k7 N t4 Wu16 value_buf[N]; //滤波求平均缓存 u32 sum; //滤波求平均总和缓存 u16 temp; //滤波求排序缓存
' {7 @' G3 C- N. d3 f* T { //判断是否活塞卡住 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; //超限警报标志位
# I4 Q4 v) O1 u9 u* \ 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); //定时打印 ! \0 c1 F/ [) m. }: \! H( q& E
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) { / V4 s& V$ r1 E9 |# y
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; & G8 c5 {& t. O) k: W& X
data_collection(); //数据采集后判断是否活塞卡住
) l- H! O- ~: r0 }) n( ^/ h& S) w } 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;
% U' P- N! \( `/ p1 K7 y; I' ? if( (distance_one-distance_zero) > 5) //松刹车标志 motion = LOOSEN;
F+ h" ~: z$ C+ D0 k6 @: ]% C( A, z; Z. P if( (distance_one-distance_zero) < -5) //踩刹车标志 motion = TREAD;
2 k: n1 F& ~: \! l6 L 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; 1 v+ [; D1 _ n6 N
/* 松刹车时动态设置最大值刹车标志*/ if(motion == LOOSEN) /* 如果这次值比上次设置的标志值大说明上次是卡住值,更新新的标志*/ if(distance_zero-DIFFERENCE > *max_value ) count++; //防干扰计数 if(count > 1) { *max_value = distance_zero-DIFFERENCE; count = 0; } : v5 w* a9 N8 A4 T
motion = CLEAR; //清除刹车标志
9 }% s8 L$ D/ C if( brake_state ) //刹车时如果卡住开始计数 lock_count++; S! P; h: D$ B: ^6 V H$ K
if( lock_count >= 5 ) //计数五次后报警位置位 { lock_count = 5; return TRUE; } } else { // lock_alarm = 0; lock_count = 0; return FALSE; } } /** 功能:判断活塞是否卡住数据采集函数 */ void data_collection(void) {
4 |9 I! E, t( G. x. w5 a2 k$ e7 ~( f u16 distance_zero, distance_one; 2 c+ l+ o1 h1 \7 p
filter(ADC_CH0); distance_l = sum; & L9 j' A' U6 [1 A
delay_ms(20);
8 O, J2 H8 H5 ^+ }3 g 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]); } }
, _+ ` s/ Q8 j$ N, i$ }: M5 A * i. {% D0 u1 o! R2 B' R) S
' p% I) f2 W, f( j+ t+ \5 A/ X
9 X ]0 F+ n. k' s
" p+ C( I; G/ t6 @. }2 ?
, Z: k O- W' |% @: S$ t8 W9 I+ @# l4 J
' v8 c: `# w8 x/ n
; [: Y% M' A8 c) r5 S F" f6 P9 [( c
5 a5 P# H- a0 `. [5 U9 ?! K( h8 S+ A. X+ a6 V5 v
1 R' L( Z1 S; g k
2 Q; i& a7 q9 \7 r5 W' s' D$ X# |4 R w
K- `7 a& _; G) u2 S
' g3 Y& F/ Y; q0 `) N. G# S
7 r# ^/ ^" J$ F7 U
+ g$ ?" M3 c! o, ^, G" z
+ y" f) s9 o# i% \+ m9 N
- w5 C$ o+ X4 C. v
7 j# d! J5 ~" {! F. `- Y( r3 N$ e8 x. [% }, \ |