自动喂鱼机

自动喂鱼机

自从上次成功驱动了报废光驱上拆下来的步进电机后,就一直想做一个能够自动定时喂鱼的装置,解决我周末或者长假回老家后鱼缸没人照料的窘境。一旦连续两天不喂食,那么必有最弱小的一条鱼会被啃得面目全非,所以我急需这样一个装置。
所有有志者事竟成,一切伟大的思想和行动都有一个微不足道的开始,最终还是让我把这样一个“产品”给做出来了,先不多说了,上一张图来看看。

下面详细讲解下实现的过程吧。

硬件

通过上面的动图,能够看出这个装置其实主要分为四个部分:

  1. 饲料仓库
  2. 电机模块
  3. 电机驱动
  4. 主控板

由主控板上的软件做好时间控制,在到达喂食时间点后,通过高低电平控制电机驱动板控制电机正转一定时长,使得饲料投放装置落下,饲料从出口落出,再控制电机反转,拉起饲料投放装置。

饲料存储

这个其实没有什么好说的,和整个装置的支撑架一样,都是手工制作的。

电机

电机是从报废了的光驱上拆下来的两相双极性步进电机,可以参考之前的文章 两相双极性步进电机驱动

电机驱动板

电机驱动板,是很久很久以前,大概12年的时候,做智能巡线小车的时候留下来的L293D驱动芯片,通过输入不同的电平组,可以驱动电压输出到不同的口以及方向。最多可以同时驱动两个直流电机,这里我直接拿来驱动这一个步进电机了。

主控板

主控板就更简单了,直接花了几块钱在淘宝淘的一个最小C51单片机系统。

软件

软件部分主要是使用了单片机的定时器来计时,然后到达指定时长后驱动电机正转反转,让饲料可以落下。

流程图:

代码

点击下载代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*****************************************************************
* File Name: stepper.c
* Description: This file is a stepper related function, includes
* time controller, stepper controller, task controller.
* Date: 2018.11.14
* Author: Bob, Zhang
* E-mail: 156500117@qq.coom
*****************************************************************/

#include <reg52.h>

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned char bool;
#define false ( 0 )
#define true ( !false )

// stepper pins
sbit steperA = P1^0;
sbit steperB = P1^1;
sbit steperA_ = P1^2;
sbit steperB_ = P1^3;

// count for 1 ms
#define TIMER_VAL_FOR_1MS (0xFC18)
int direction_change_flag = 0x00;

void delay(int aUs)
{
static int i;
static int us;

us = aUs;

while(us--)
{
i = 11;
while(--i);
}
}

// stepper left turn
void MotorLeft()
{
static int i = 3;

switch( i-- )
{
case 0:
steperA = 1;
steperA_ = 0;
steperB = 0;
steperB_ = 0;
break;
case 1:
steperA = 0;
steperA_ = 0;
steperB = 1;
steperB_ = 0;
break;
case 2:
steperA = 0;
steperA_ = 1;
steperB = 0;
steperB_ = 0;
break;
case 3:
steperA = 0;
steperA_ = 0;
steperB = 0;
steperB_ = 1;
break;
default:
break;
}

if( -1 >= i )
i = 3;
}

// stepper right turn
void MotorRight()
{
static int i = 0;

switch( i++ )
{
case 0:
steperA = 1;
steperA_ = 0;
steperB = 0;
steperB_ = 0;
break;
case 1:
steperA = 0;
steperA_ = 0;
steperB = 1;
steperB_ = 0;
break;
case 2:
steperA = 0;
steperA_ = 1;
steperB = 0;
steperB_ = 0;
break;
case 3:
steperA = 0;
steperA_ = 0;
steperB = 0;
steperB_ = 1;
break;
default:
break;
}

if( 4 <= i )
i = 0;
}

// init timer
void InitTimer()
{
TMOD = 0x01;
TH0 = TIMER_VAL_FOR_1MS >> 8; // 1 ms
TL0 = TIMER_VAL_FOR_1MS & 0xFF;
ET0 = 0x01;
EA = 0x01;
TR0 = 0x01;
}

// state machine
typedef uint8_t task_state_t; enum
{
TASK_STATE_INIT_TIMER_STATE=0,
TASK_STATE_FEED_FISH_MOTOR_LEFT_STATE,
TASK_STATE_FEED_FISH_MOTOR_RIGHT_STATE,
TASK_STATE_WAIT_STATE,
};

#define FEED_FISH_TIME_PERIOD 3 //( 8*60*60 ) // 8h
static const uint32_t feed_fish_period = FEED_FISH_TIME_PERIOD; // 8h
static const uint32_t feed_first_period = FEED_FISH_TIME_PERIOD + 4; // 4s
static const uint32_t feed_second_period = FEED_FISH_TIME_PERIOD + 4 + 4; // 4s

static task_state_t next_state = TASK_STATE_INIT_TIMER_STATE;

void TaskLoop()
{
switch(next_state)
{
case TASK_STATE_INIT_TIMER_STATE:
InitTimer();
next_state = TASK_STATE_WAIT_STATE;
break;
case TASK_STATE_FEED_FISH_MOTOR_LEFT_STATE:
MotorLeft();
break;
case TASK_STATE_FEED_FISH_MOTOR_RIGHT_STATE:
MotorRight();
break;
case TASK_STATE_WAIT_STATE:
break;
}
}

void StateLoop()
{
static uint32_t fedd_fish_time_count = FEED_FISH_TIME_PERIOD;

if( fedd_fish_time_count == feed_fish_period )
{
next_state = TASK_STATE_FEED_FISH_MOTOR_LEFT_STATE;
}
else if( fedd_fish_time_count == feed_first_period )
{
next_state = TASK_STATE_FEED_FISH_MOTOR_RIGHT_STATE;
}
else if( fedd_fish_time_count == feed_second_period )
{
next_state = TASK_STATE_WAIT_STATE;
fedd_fish_time_count = 0;
}

++fedd_fish_time_count;
}

// timer interrupt function
#define STATE_CHECK_TIME ( 1000 )
void TimerIrq( void ) interrupt 1 using 1
{
static long time_count = 0;

++time_count;

// every second run once state check
if( STATE_CHECK_TIME == time_count )
{
StateLoop();
time_count = 0;
}

TH0 = TIMER_VAL_FOR_1MS >> 8; // 1 ms
TL0 = TIMER_VAL_FOR_1MS & 0xFF;

}

void main()
{
do
{
TaskLoop();
delay(100);
} while( 1 );
}