洗衣机模拟_基本驱动模块开发(Arm2410,Linux,自制简易洗衣机电路板)
——2012年6月1日
一、任务和要求
1、 课程设计任务:
2、 分组完成一个课题制作。
3、 按要求完成可提供能。
4、 进行元器件的焊接、装配、并进行硬件测试。
5、 进行软件、硬件联机调试。
本设计通过理论学习,资料查阅,软、硬件设计,系统调试等环节,巩固和提高所学的知识和应用水平,进一步学习和领会嵌入式电子产品开发方法和技巧,提高自己的分析问题和解决问题的能力,提高学生的实际动手能力。学会提出问题,观察和分析问题,得到最终的科学方法。培养团队合作精神,严谨的工作作风,务实的工作态度,为今后的毕业设计,及从事嵌入式产品的设计与维护奠定坚实的基础。
二、内容和结果
1、(1)设计意义:
- 控制系统指通过一个设备或者一套设备来对其他设备或系统的行为进行管理、控制、引导、调整。
- 控制系统从不同角度可以归为两大类:逻辑控制(顺序控制)、带反馈的控制(线性控制)。目前的各种控制方法往往是上面这些方法的变换或者结合来达到特定的控制目的。比如模糊控制是结合了逻辑控制和线性控制。
- 顺序控制(sequential control):通过按照正确的顺序来触发一系列的机械装置来完成一个任务。比较清晰的例子比如产品装瓶、装箱任务,比如灌装啤酒等。
- 逻辑控制:逻辑控制主要涉及到一个开关量或者多个开关量的逻辑运算,逻辑控制往往用来控制机械的操作次序(如开关、光线传感器、压力开关)
- 带反馈控制/闭环控制(feedback control、closed-loop):这种系统带有一个控制回路(control loop),回路包括传感器、控制逻辑和驱动装置,通过这些装置来将一个变化量调整到我们希望的值(参考值、设置值)。比如空调控制系统、烤箱等等。PID、Bang-bang(on-off)是常用的反馈控制系统。
- 线性控制:通过使用相关的变化量的数学运算后产生一个负反馈信号到控制系统中,从而将控制过程维持在可接受的操作范围。线性控制最后一般输出一个变化的控制信息加入到控制系统中,比如阀门的张开度(0~100%),在计算机进行控制时往往通过PWM来对开闭进行占空比控制
(2)完成的功能:
普通洗衣机内部控制系统是种顺序控制系统(没有反馈控制)。洗衣过程包括一系列按照固定顺序的机械控制过程,例如浸泡->洗涤->漂洗->脱水,中间还包括进出水控制。
2、设计方案以及思路
分别给LED数码管、电机、蜂鸣器和拨码开关四个模块各写一个驱动并写出相应的测试应用程序,所有模块独立测试通过了之后再按照事先拟定的控制流程将所有功能整合到一个完整的洗衣机应用程序。
控制流程和使用说明:
State LED beep Motor
进水 1 beep1
浸泡 2 beep2
洗涤 正转正计时10秒
倒转倒计时10秒
出水 4 beep4
甩干 正转正计时 10秒
结束 6 beep6
3、电路组成及硬件原理图(洗衣机控制模拟系统硬件组成):
(1)LED模块:
缓冲器分为两种,常规缓冲器和三态缓冲器。常规缓冲器总是将值直接输出,用在推进电流到高一级的电路系统。三态缓冲器除了常规缓冲器的功能外,还设置有使能输入端,这里对应的是74HC240的第1脚和第19脚。从图4的真值表中可以看出当使能端电平不同时缓冲器有不同的输出值。当Enable A,Enable B=0时,芯片选通,缓冲器工作;当Enable A, EnableB=1,缓冲器被阻止,无论输入什么值,输出的总是高阻抗状态,用Z表示。高阻抗状态能使电流降到足够低,以致于类似缓冲器的输出没有与任何电路相连。
C |
B |
A |
LED亮的段 |
0 |
0 |
0 |
e |
0 |
0 |
1 |
d |
0 |
1 |
0 |
h |
0 |
1 |
1 |
c |
1 |
0 |
0 |
g |
1 |
0 |
1 |
b |
1 |
1 |
0 |
a |
1 |
1 |
1 |
f |
由上表可知LED共阴极段码表(与74HC138的序号对应):
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 全灭 |
0xeb |
0x28 |
0x73 |
0x7a |
0xb8 |
0xda |
0xdb |
0x68 |
0xfb |
0xfa |
0x00 |
原理:电路部分使用一个三八译码器(74HC138)将三路信号转成8个单路信号,在通过74HC240线驱(line driver)来驱动7段管。7段管为共阴极,这里由于I/O口有限,4位7段管只用两位,选通处使用使用两个三极管(Q6、7)做开关。
完成功能:用7段管模拟显示,显示当前信息。
4、原器件清单
硬件需求:一个三八译码器(74hc138)、一个4位7段管、一个74HC240线驱、1k电阻(15个)、10k电阻(2个)、一个HD74LS04P反相器、NPN三级管c9013(5个)、PNP三级管c9012(2个)、一个直流电机、两个开关、一个蜂鸣器、一块电路板、导线若干。
5、产品样图
三、课程设计体会
这次课程设计的亮点在于LED数码管的控制方式,按照一般思路是用table[8][3]去定义一个数码,固定位选再通过该段选表去控制某段亮灭,在老师的提示下,换一种角度去思考,用位选去决定当前段的亮灭,使得代码的实现简洁多了,效率上也会高一些,这个方法也算一个小技巧吧。
此外,由于没有传感器的反馈这里我们并没有实现进出水的自动化以及用PID去实时精确地控制电机的转速(压力传感器、编码器-速度传感器)。
总结:关于Linux下的驱动开发,我们现在写的东西还不够,各实验模块也只是在原有模版的基础上实现其基本功能,特别是在多线程、保护机制、通信、协议等方面还有待实验。
四、软件模块(驱动及应用程序主要代码)
//IO口说明:
//{GPIO_B4,GPIO_B5,GPIO_B7,PIO_B9,GPIO_E11,GPIO_E12,GPIO_E13, GPIO_F0,GPIO_F1};
// cs1 beep cs0 与pwm配合 A B C 输入模式:进水 出水
//LED端口初始化 :
for (i = 0; i < LED_IO_NUM; i++)
{ set_gpio_ctrl (led_io_table[i] | GPIO_MODE_OUT); // | GPIO_PULLUP_EN
write_gpio_bit(led_io_table[i], 0);
}
//Motor端口初始化:
set_gpio_ctrl (GPIO_B9 | GPIO_MODE_OUT);
write_gpio_bit(GPIO_B9, 0);
//Beep端口初始化:
set_gpio_ctrl (GPIO_B5 | GPIO_MODE_OUT); // | GPIO_PULLUP_EN
write_gpio_bit(GPIO_B5, 0);
//Switch端口初始化:
set_gpio_ctrl (GPIO_F0 | GPIO_MODE_IN | GPIO_PULLUP_EN );
set_gpio_ctrl (GPIO_F1 | GPIO_MODE_IN | GPIO_PULLUP_EN );
/* LED显示 ***************************************************************/
void led_show()
{
unsigned char num,sta,ds;
static unsigned char i=0,j=0;
if(led_status==SHOW_LEDBUF)
num=led_buf[i]; // printk("num:%d,",num);
else if(led_status==SHOW_SEC)
{
if(i==0) num=sec/10;
else if(i==1) num=sec%10;
}
ds=led_table[num];
//不管亮灭 都给当前段置1
write_gpio_bit(GPIO_E11,j&0x01);
write_gpio_bit(GPIO_E12,(j&0x2)>>1);
write_gpio_bit(GPIO_E13,j>>2);
// printk("A:%d,",j&0x01);
// printk("B:%d,",(j&0x02)>>1);
// printk("C:%d,",j>>2);
//通过对cs赋值决定8位段码的亮灭
sta=(ds & (0x1<<j)) >>j; //printk("ds:0x%0x,",ds);
//printk("sta:%d,",sta);
if(i==0)
{ write_gpio_bit(GPIO_B7,sta);
write_gpio_bit(GPIO_B4,0);
}
else if(i==1)
{write_gpio_bit(GPIO_B4,sta);
write_gpio_bit(GPIO_B7,0);
}
// printk("i:%d,",i); printk("j:%d\n",j);
j++;
if(j>=8)
{
j=0;
i++;
if(i>=2) i=0;
}
}
/* 中断计时器初始化 for LED动态刷新 */
/*
1)定时器输入时钟频率f tclk (即计数时钟频率) :
f tclk=[f pclk∕(Prescaler+1)] ×分频值
式中:Prescaler为预分频值,0---255;分频值为1/2、1/4、1/8、1/16。(实验板上fpclk=50.7MHz)
2)PWM输出时钟频率 :
PWM输出时钟频率= ftclk ∕TCNTBn
3)PWM输出信号占空比(即高电平持续时间所占信号周期的比例):
PWM输出信号占空比 = TCMPBn∕ TCNTBn
*/
static int led_timer0_init(void)
{
TCFG1 &=~(0x0f);
TCFG1 |= 0x03; // 0011
// 50.7MHz/16=X; 10ms/16/(1/X)=1980.46875 其中10ms为视觉停留
TCNTB0 = 1980;
TCMPB0 = 0;
TCON |=0x02;//TIMER0 TUP0=1 手动立即更新TCNTBn和TCMPBn
TCON &=~(0x02); //**** **0* 清TIMER0手动更新位
TCON |= 0x09; //TIMER0自动重装初值连续计数 并 启动计数
return 0;
}
// led_ioctl ////////////////////////////////////////////////////////////////////
//顺便以此向应用程序提供计时器接口,传出当前秒数给用户
static int led_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, int *arg) {
// printk("ioctl runing\n");
switch(cmd)
{
case SHOW_LEDBUF:
led_status=SHOW_LEDBUF;
break;
case TIME_ADD:
led_status=SHOW_SEC;
sec=0;
dif=1;
break;
case TIME_DEC:
led_status=SHOW_SEC;
sec=(*arg);
dif=-1;
break;
case READ_SEC:
(*arg)=sec;
break;
}
return 0;
}
/* 中断子函数 for LED动态刷新 */
static void isr_timer0(int irq, void *dev_id, struct pt_regs *reg)
{
static int count=0;
led_show();
count++;
if(count>=100*16)
{
count=0;
sec+=dif;
if(sec<0 || sec>60) sec=0;
}
}
/* PWM初始化 for MOTOR *************************************************/
static int motor_timer2_init(void)
{
TCFG0 &= ~(0x00ff0000);
TCFG0 |= (MOTOR_TCFG0<<8); //预分频值Prescaler1_timer234=MOTOR_TCFG0=2
TCFG1 &= ~(0xf00); /* timer2分频值取1/2 */
TCNTB2 = MOTOR_TCNTB; /*timer2初值*/
TCMPB2 = MOTOR_TCNTB-1; /*初始占空比为0*/
TCON &=~(0xf000);
TCON |= (0x2000); //TIMER2 TUP2=1 手动立即更新TCNTBn和TCMPBn
TCON &=~(0x2000); // 清TIMER2手动更新位
TCON &= ~(0x8000); //TIMER2自动重装初值连续计数 未启动计数
return 0;
}
#define tout2_enable() ({ GPBCON &=~ 0x30; GPBCON |= 0x20; })
//GPB2:10 - TOUT2
#define motor_start_timer2() ({ TCON |= 0x9000; }) /*启动timer2*/
#define tout2_disable() ({ GPBCON &=~ 0x30; GPBCON |= 0x10; GPBUP &=~0x4; })
//GPB2:01 - 输出 上拉电阻
#define motor_stop_timer2() ({ TCON &= ~0x9000; }) /*停止timer2*/
static int motor_setpwm2(int v)
{ return (TCMPB2 = MOTOR_TCNTB - v); }
// motor_ioctl ////////////////////////////////////////////////////////////////////
static int motor_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg) {
switch(cmd){
case MOTOR_IOCTRL_STARTPWM:
tout2_enable();
motor_start_timer2();
motor_status=(int)arg;
if(motor_status ==1) /* 正转 */
write_gpio_bit(GPIO_B9, 1);
else if(motor_status==2) /*反转*/
write_gpio_bit(GPIO_B9, 0);
else
return -EINVAL;
break;
case MOTOR_IOCTRL_SETPWM:
motor_setpwm2((int)arg);
break;
case MOTOR_IOCTRL_STOPPWM:
write_gpio_bit(GPIO_B9, 0);
break;
}
return 0;
}
/* beep_ioctl *************************************************************/
static int beep_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg) {
// printk("ioctl runing\n");
if(arg==0 | arg==1)
return( write_gpio_bit(GPIO_B5, (int)arg) );
else
return -EINVAL;
}
/* switch_ioctl*************************************************************/
static int switch_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long *arg) {
// printk("ioctl runing\n");
switch(cmd)
{
case 0: *arg=read_gpio_bit(GPIO_F0);break;
case 1: *arg=read_gpio_bit(GPIO_F1);break;
}
return 0;
}
//洗衣机应用程序
int main(int argc, char **argv)
{ //int i,j;
led_fd=open(LED_DEV,O_WRONLY);
motor_fd=open(MOTOR_DEV,O_WRONLY);
beep_fd=open(BEEP_DEV,O_WRONLY);
switch_fd=open(SWITCH_DEV,O_WRONLY);
if (led_fd<0 || motor_fd<0 || beep_fd<0 || switch_fd<0)
{ perror("open device");exit(1); }
water_in();
jinpao();
washing();
water_out();
drying();
end();
close(led_fd);
close(motor_fd);
close(beep_fd);
close(switch_fd);
return 0;
}
/* 进水 1 beep1 */
void water_in(void)
{
int s0,i;
led_buf[0]=10;
led_buf[1]=1;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
ioctl(switch_fd,0,&s0);
while(s0==1)
ioctl(switch_fd,0,&s0);
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}
/* 浸泡 2 beep2 */
void jinpao(void)
{
int sec=0,sec_temp,cmpsec,i;
ioctl(led_fd,READ_TIME,&sec_temp);
ioctl(led_fd,READ_TIME,&cmpsec);
while(sec<10)
{
while(sec_temp==cmpsec)
{
ioctl(led_fd,READ_TIME,&cmpsec);
}
sec++;
led_buf[0]=sec/10;
led_buf[1]=sec%10;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
sec_temp=cmpsec;
}
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}
/* 洗涤 正转正计时10秒 倒转倒计时10秒 cs0.亮 */
void washing(void)
{
int sec=0,sec_temp,cmpsec,i,setpwm;
static int j=0;
ioctl(led_fd,READ_TIME,&sec_temp);
ioctl(led_fd,READ_TIME,&cmpsec);
ioctl(motor_fd,MOTOR_IOCTRL_STARTPWM, 1); //正转加速
while(sec<10)
{
while(sec_temp==cmpsec)
ioctl(led_fd,READ_TIME,&cmpsec);
setpwm=sec * 100;
ioctl(motor_fd, MOTOR_IOCTRL_SETPWM, setpwm * MOTOR_FACTOR);
sec++;
led_buf[0]=sec/10;
led_buf[1]=sec%10;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
sec_temp=cmpsec;
}
ioctl(motor_fd,MOTOR_IOCTRL_STARTPWM, 2); //反转减速
while(sec>=0)
{
while(sec_temp==cmpsec)
ioctl(led_fd,READ_TIME,&cmpsec);
setpwm=sec * 100;
ioctl(motor_fd, MOTOR_IOCTRL_SETPWM, setpwm * MOTOR_FACTOR);
sec--;
led_buf[0]=sec/10;
led_buf[1]=sec%10;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
sec_temp=cmpsec;
}
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}
/* 出水 4 beep4 */
void water_out(void)
{
int s1,i;
led_buf[0]=10;
led_buf[1]=4;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
ioctl(switch_fd,1,&s1);
while(s1==1)
ioctl(switch_fd,1,&s1);
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}
/* 甩干 正转正计时 10秒 cs1.亮 */
void drying(void)
{
int sec=0,sec_temp,cmpsec,i,setpwm;
static int j=0;
ioctl(led_fd,READ_TIME,&sec_temp);
ioctl(led_fd,READ_TIME,&cmpsec);
ioctl(motor_fd,MOTOR_IOCTRL_STARTPWM, 1); //正转全速
// setpwm=1024;
// ioctl(motor_fd, MOTOR_IOCTRL_SETPWM, setpwm * MOTOR_FACTOR);
while(sec<10)
{
while(sec_temp==cmpsec)
ioctl(led_fd,READ_TIME,&cmpsec);
sec++;
led_buf[0]=sec/10;
led_buf[1]=sec%10;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
sec_temp=cmpsec;
}
ioctl(motor_fd, MOTOR_IOCTRL_STOPPWM, 0);//stop
printf("PAUSE!\n");
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}
/* 结束 6 beep6 */
void end(void)
{
int i;
led_buf[0]=10;
led_buf[1]=6;
ioctl(led_fd,SHOW_LEDBUF,NULL);
write(led_fd, led_buf, sizeof(led_buf));
ioctl(beep_fd,NULL,1);
for(i=0;i<=2;i++) delay(30000);
ioctl(beep_fd,NULL,0);
}