51单片机 跑步机控制器设计

在这里插入图片描述


//键盘 
//启动  停止  加速  减速
//紧急   --   升高  降低
//模式   加时  加分  加秒
// --    减时  减分  减秒

//启动就是开启跑步机 灯0打开 
//停止关闭跑步机  灯0关闭
//加速就是加速跑步机  速度越快 灯0越来越亮
//减速就是减速跑步机  速度越慢 灯0越来越暗  距离会根据速度有换算 速度越快距离随时间变化越大

//紧急是紧急停止的意思 其实就是怕停止按键失效 紧急停止会关闭跑步机
//升高 就是升高跑步机坡度  就是灯1越亮 表示越高  实际跑步机会用舵机 和这个一样原理
//降低  就是降低跑步机坡度

//模式 就是进行模式切换的  按一下 进入倒计时模式 再按一下回到正计时模式  倒计时模式下可以设置倒计时时间
//后面这6个按键就是设置倒计时时间的



#include <reg52.h>
#include <intrins.h>
#include "lcd1602.h"

#define uchar	unsigned char
#define uint	unsigned int


sbit	ENA	= P1 ^ 1;       /* 使能 PWM 占空比越大 电机速度越快 接到灯上就是灯会越亮 */
sbit	ENB	= P1 ^ 0;       /* 使能 PWM 占空比越大 电机速度越快 接到灯上就是灯会越亮 */

uchar	pwm_count	= 0;    /* PWM计数 不用管 */
char	ENA_PWM_data	= 1;    /* 0表示占空比0  10表示占空比百分之百 */
char	ENB_PWM_data	= 9;    /* 0表示占空比0  10表示占空比百分之百 */

uchar open = 0;                 /* 是否打开 */

char	rtc_hour	= 0;
char	rtc_min		= 0;
char	rtc_sec		= 0;

char num2 = 0;                  /* 计数 */

uchar time_count_mode = 0;      /* 正计时 */

uint daojishi_shijiana = 0;

void delay( uint z )
{
	uint x;
	while ( z-- )
	{
		for ( x = 125; x > 0; x-- )
			;
	}
}


void init_timer( void )
{
	EA = 1;                                 /* 开总中断 */

	TMOD	= 0x11;
	ET0	= 1;
	TR0	= 1;
	TH0	= (65536 - 50000) / 256;        /* 计数初值重装载 */
	TL0	= (65536 - 50000) % 256;

	ET1	= 1;
	TR1	= 1;
	TH1	= (65536 - 50000) / 256;
	TL1	= (65536 - 50000) % 256;
}


#define GPIO_KEY P3
unsigned char KeyValue = 0xff;
/* 矩阵键盘扫描 电子琴 */
void ScanKey( void )
{
	char a = 0;
	GPIO_KEY = 0x0f;
	if ( GPIO_KEY != 0x0f )         /* 读取按键是否按下 */
	{
		delay( 5 );             /* 延时10ms进行消抖 */
		if ( GPIO_KEY != 0x0f ) /* 再次检测键盘是否按下 */
		{
			/* 测试列 */
			GPIO_KEY = 0X0F;
			switch ( GPIO_KEY )
			{
			case (0X07):
				KeyValue = 0;
				break;
			case (0X0b):
				KeyValue = 1;
				break;
			case (0X0d):
				KeyValue = 2;
				break;
			case (0X0e):
				KeyValue = 3;
				break;
			}
			/* 测试行 */
			GPIO_KEY = 0XF0;
			switch ( GPIO_KEY )
			{
			case (0X70):
				KeyValue = KeyValue;
				break;
			case (0Xb0):
				KeyValue = KeyValue + 4;
				break;
			case (0Xd0):
				KeyValue = KeyValue + 8;
				break;
			case (0Xe0):
				KeyValue = KeyValue + 12;
				break;
			}
			while ( (a < 100) && (GPIO_KEY != 0xf0) ) /* 检测按键松手检测 */
			{
				delay( 10 );
				a++;
			}
		}
	}
}


/*按键处理 */
void KEY_CHULI( void )
{
	uchar map[]={3,7,11,15,2,6,10,14,1,5,9,13,0,4,8,12};
	if (  KeyValue!= 0xff )
	{
		KeyValue=map[KeyValue];
		if ( KeyValue == 0 )
		{
			open = 1;          /* 启动 */
			if ( time_count_mode == 1 )
			{
				/* 倒计时 */
				daojishi_shijiana = rtc_hour * 3600 + rtc_min * 60 + rtc_sec;
			}
		}else if ( KeyValue == 1 )
		{
			open	= 0;                            /* 停止 */
			ENA	= 1;
			
		}else if ( KeyValue == 2 )
		{
			ENA_PWM_data++;                         /* 加速 */
			if ( ENA_PWM_data == 11 )
				ENA_PWM_data = 10;
		}else if ( KeyValue == 3 )
		{
			ENA_PWM_data--;                         /*减速 */
			if ( ENA_PWM_data == 0 )
				ENA_PWM_data = 1;
		}else if ( KeyValue == 4 )
		{
			open	= 0;                            /*紧急停止 */
			
			ENA	= 1;
		}else if ( KeyValue == 6 )
		{
			ENB_PWM_data++;                         /* 升高 */
			if ( ENB_PWM_data == 11 )
				ENB_PWM_data = 10;
		}else if ( KeyValue == 7 )
		{
			ENB_PWM_data--;                         /*降低 */
			if ( ENB_PWM_data == -1 )
				ENB_PWM_data = 0;
		}else if ( KeyValue == 8 )
		{
			/* 切换到倒计时模式 */
			time_count_mode = !time_count_mode;     /* 切换 */
			open		= 0;
			if ( time_count_mode == 0 )
			{
				rtc_hour	= 0;
				rtc_min		= 0;
				rtc_sec		= 0;
			}else{
				rtc_hour	= 0;
				rtc_min		= 10;
				rtc_sec		= 0;
			}
		}

		/* 倒计时下可以设置时间 */
		if ( time_count_mode == 1 )
		{
			if ( KeyValue == 9 )
			{
				/* 加 时 */
				rtc_hour++;
				if ( rtc_hour == 24 )
					rtc_hour = 0;
			}else if ( KeyValue == 10 )
			{
				/* 加 分 */
				rtc_min++;
				if ( rtc_min == 60 )
					rtc_min = 0;
			}else if ( KeyValue == 11 )
			{
				/* 加秒 */
				rtc_sec++;
				if ( rtc_sec == 60 )
					rtc_sec = 0;
			}else if ( KeyValue == 13 )
			{
				/* 减时 */
				rtc_hour--;
				if ( rtc_hour == -1 )
					rtc_hour = 23;
			}else if ( KeyValue == 14 )
			{
				/* 减分 */
				rtc_min--;
				if ( rtc_min == -1 )
					rtc_min = 59;
			}else if ( KeyValue == 15 )
			{
				/* 减秒 */
				rtc_sec--;
				if ( rtc_sec == -1 )
					rtc_sec = 59;
			}
			/* 倒计时 */
				daojishi_shijiana = rtc_hour * 3600 + rtc_min * 60 + rtc_sec;
		}
		KeyValue = 0xff; /* 恢复按键状态 */
	}
}


/* 刷新屏幕显示 */
void update( void )
{
	uint juli = 0;



	/*
	 * 刷新 速度显示  显示在第一排 第一个位置
	 * ENA_PWM_data 就是速度
	 */
	LCD_write_str( 0, 0, "A:" );
	LCD_write_char( 2, 0, '0' + ENA_PWM_data / 10 );
	LCD_write_char( 3, 0, '0' + ENA_PWM_data % 10 );


	/*
	 * 刷新 角度显示  显示在第一排
	 * ENB_PWM_data 就是角度
	 */
	LCD_write_str( 5, 0, "B:" );
	LCD_write_char( 7, 0, '0' + ENB_PWM_data / 10 );
	LCD_write_char( 8, 0, '0' + ENB_PWM_data % 10 );

	/* 模式 */
	LCD_write_char( 10, 0, 'M' );
	LCD_write_char( 11, 0, '0' + time_count_mode ); /* 0就是正计时 1就是倒计时 */
	
	//此时跑步机状态
	LCD_write_char( 13, 0, '0' + open ); /* 0没开 1开着的 */



	/* 刷新时间 */
	LCD_write_char( 0, 1, '0' + rtc_hour / 10 );
	LCD_write_char( 1, 1, '0' + rtc_hour % 10 );
	LCD_write_char( 2, 1, ':' );
	LCD_write_char( 3, 1, '0' + rtc_min / 10 );
	LCD_write_char( 4, 1, '0' + rtc_min % 10 );
	LCD_write_char( 5, 1, ':' );
	LCD_write_char( 6, 1, '0' + rtc_sec / 10 );
	LCD_write_char( 7, 1, '0' + rtc_sec % 10 );

	/* 刷新距离 */
	if ( time_count_mode == 0 )
	{
		juli = (uint)  (rtc_hour * 3600 + rtc_min * 60 + rtc_sec) ;      /* 1s 算走4.5m */
		juli = (uint) (juli*4.5);
	}else{
		juli	= (uint)  (rtc_hour * 3600 + rtc_min * 60 + rtc_sec) ;   /* 1s 算走4.5m */
		juli = (uint) (juli*4.5);
		juli	= (uint) (daojishi_shijiana * 4.5  ) - juli;
	}
	LCD_write_char( 9, 1, '0' + juli / 10000 );
	LCD_write_char( 10, 1, '0' + juli % 10000 / 1000 );
	LCD_write_char( 11, 1, '0' + juli % 1000 / 100 );
	LCD_write_char( 12, 1, '0' + juli % 100 / 10 );
	LCD_write_char( 13, 1, '0' + juli % 10 );
	LCD_write_char( 14, 1, 'm' );
}


/* 主程序 */
void main()
{
	init_timer();
	LCD_init();

	open	= 0;
	ENA	= 1;            /* 关闭PWM */
	ENA_PWM_data	= 5;    /* 0表示占空比0  10表示占空比百分之百 */
  ENB_PWM_data	= 9;    /* 0表示占空比0  10表示占空比百分之百 */


	while ( 1 )
	{
		ScanKey();      /* 得到按键 */
		KEY_CHULI();    /* 处理按键 */
		update();       /* 更新显示 */
	}
}


void Time0( void )
interrupt 1
{
	TH0	= (65536 - 1000) / 256; /* 计数初值重装载 */
	TL0	= (65536 - 1000) % 256;

	/* 启动状态下 */

	pwm_count++;
	if ( pwm_count == 10 )
	{
		pwm_count = 0;
		if ( open == 1 )
		{
			ENA = 0;        /*传动带速度 */
		}
		ENB = 0;                /* 角度 */
	}

	if ( ENA_PWM_data == pwm_count )
	{
		if ( open == 1 )
		{
			ENA = 1;        /*传动带速度 */
		}
	}

	if ( ENB_PWM_data == pwm_count )
	{
		ENB = 1;                /* 角度 */
	}
}


/* 50ms */
void T1_time()
interrupt 3
{
	unsigned int shijian = 0;

	TH1	= (65536 - 50000) / 256;
	TL1	= (65536 - 50000) % 256;

	num2++;
	if ( num2 == 20 )
	{
		num2 = 0;

		/* 正计时 */
		if ( time_count_mode == 0 && open == 1 )
		{
			rtc_sec++;
			if ( rtc_sec == 60 )
			{
				rtc_sec = 0;
				rtc_min++;
				if ( rtc_min == 60 )
				{
					rtc_min = 0;
					rtc_hour++;
					if ( rtc_hour == 24 )
					{
						rtc_hour = 0;
					}
				}
			}
		}

		/* 倒计时 */
		if ( time_count_mode == 1 && open == 1 )
		{
			shijian = rtc_hour * 3600 + rtc_min * 60 + rtc_sec;

			shijian--;
			if ( shijian == 0 )
			{
				open	= 0;
				ENA	= 1; /* 关闭PWM */
				
			}
			rtc_hour	= shijian / 3600;
			rtc_min		= shijian / 60 % 60;
			rtc_sec		= shijian % 60;
		}
	}
}



1602.h



#include <reg52.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
LCD_init();
LCD_write_str(1,1,"2223123");
*/

sbit lcd_rs=P2^4;
sbit lcd_rw=P2^5;
sbit lcd_en=P2^6;

#define DataPort P0

#define RS_CLR lcd_rs=0
#define RS_SET lcd_rs=1

#define RW_CLR lcd_rw=0

#define EN_CLR lcd_en=0
#define EN_SET lcd_en=1



void delay_lcd_ms(unsigned int a) {
	unsigned int i, j;
	for (i = a; i > 0; i--)
		for (j = 100; j > 0; j--)
			;
}
//***********************************************************************
//	显示屏命令写入函数
//***********************************************************************
void LCD_write_com(unsigned char com) 
{	
	RS_CLR;
	RW_CLR;
	EN_SET;
	DataPort = com;                 //命令写入端口
	delay_lcd_ms(5);
	EN_CLR;
}

//***********************************************************************
//	显示屏数据写入函数
//***********************************************************************
void LCD_write_data(unsigned char dataa) 
{
	RS_SET;
	RW_CLR;
	EN_SET;
	DataPort = dataa;                //数据写入端口
	delay_lcd_ms(5);
	EN_CLR;
}



//***********************************************************************
//	显示屏单字符写入函数
//***********************************************************************
void LCD_write_char(unsigned char x,unsigned char y,unsigned char dataa) 
{
	
    if (y == 0) 
    {
    	LCD_write_com(0x80 + x);        //第一行显示
    }
    else 
    {
    	LCD_write_com(0xC0 + x);        //第二行显示
    }
    
    LCD_write_data( dataa);  
}


//***********************************************************************
//	显示屏字符串写入函数
//***********************************************************************
void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s) 
{
	
    if (y == 0) 
    {
    	LCD_write_com(0x80 + x);        //第一行显示
    }
    else 
    {
    	LCD_write_com(0xC0 + x);        //第二行显示
    }
    
    while (*s) 
    {
    	LCD_write_data( *s);
    	s ++;
    }
}


//***********************************************************************
//	显示屏初始化函数
//***********************************************************************
void LCD_init(void) 
{
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	
	
    LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
    LCD_write_com(0x08);		//显示关闭
    delay_lcd_ms(5);
    LCD_write_com(0x01);		//显示清屏
    delay_lcd_ms(5);
    LCD_write_com(0x06);		//显示光标移动设置
    delay_lcd_ms(5);
    LCD_write_com(0x0C);		//显示开及光标设置
    delay_lcd_ms(5);
}

eeprom.h


#include <reg52.h>
#include <intrins.h>


/****************特殊功能寄存器声明****************/
sfr	ISP_DATA	= 0xe2;
sfr	ISP_ADDRH	= 0xe3;
sfr	ISP_ADDRL	= 0xe4;
sfr	ISP_CMD		= 0xe5;
sfr	ISP_TRIG	= 0xe6;
sfr	ISP_CONTR	= 0xe7;


/*
 * STC89C52RC内部EEPROM详细地址表:
 * 第一扇区                   第二扇区                    第三扇区                    第四扇区
 * 起始地址  结束地址   起始地址   结束地址   起始地址   结束地址   起始地址    结束地址
 * 2000h      21FFh       2200h       23FFh      2400h       25FFh       2600h        27FFH
 * 第五扇区                    第六扇区                     第七扇区                    第八扇区
 * 起始地址   结束地址   起始地址   结束地址    起始地址   结束地址   起始地址    结束地址
 * 2800h       29FFh       2A00h      2BFFh        2C00h      2DFFh      2E00h        2FFFh
 *
 *
 * 使用举例
 * cc(0X2000);//擦除第一扇区
 * xcx(0x2002,2);//向地址0x2002写入2
 * duqu=dcx(0x2002);//读取出来
 *
 */


void cc( unsigned int addr );


void xcx( unsigned int addr, char dat );


char dcx( unsigned int addr );


void Q0();


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
*  函数:擦除某一扇区(每个扇区512字节)
*  入口:addr = 某一扇区首地址
*  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void cc( unsigned int addr )
{
/*
 * 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
 * 0x83(晶振<5M)   0x82(晶振<10M)   0x81(晶振<20M)   0x80(晶振<40M)
 */
	ISP_CONTR	= 0x81;
	ISP_CMD		= 0x03;         /* 用户可以对"Data Flash/EEPROM区"进行扇区擦除 */
	ISP_ADDRL	= addr;         /* ISP/IAP操作时的地址寄存器低八位, */
	ISP_ADDRH	= addr >> 8;    /* ISP/IAP操作时的地址寄存器高八位。 */
	EA		= 0;
	ISP_TRIG	= 0x46;         /* 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h, */
	ISP_TRIG	= 0xB9;         /* 再写入B9h,ISP/IAP命令才会生效。 */
	_nop_();

	Q0();                           /* 关闭ISP/IAP */
}


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
*  函数:写一字节
*  入口:addr = 扇区单元地址 , dat = 待写入数据
*  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void xcx( unsigned int addr, char dat )
{
	ISP_CONTR	= 0x81;
	ISP_CMD		= 0x02; /* 用户可以对"Data Flash/EEPROM区"进行字节编程 */
	ISP_ADDRL	= addr;
	ISP_ADDRH	= addr >> 8;
	ISP_DATA	= dat;  /* 数据进ISP_DATA */
	EA		= 0;
	ISP_TRIG	= 0x46;
	ISP_TRIG	= 0xB9;
	_nop_();
	Q0();                   /* 关闭ISP/IAP */
}


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
*  函数:读一字节
*  入口:addr = 扇区单元地址
*  出口:dat  = 读出的数据
*  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
char dcx( unsigned int addr )
{
	char dat;

	ISP_CONTR	= 0x81;
	ISP_CMD		= 0x01; /* 用户可以对"Data Flash/EEPROM区"进行字节读 */
	ISP_ADDRL	= addr;
	ISP_ADDRH	= addr >> 8;
	EA		= 0;
	ISP_TRIG	= 0x46;
	ISP_TRIG	= 0xB9;
	_nop_();
	dat = ISP_DATA;         /* 取出数据 */
	Q0();                   /* 关闭ISP/IAP */
	return(dat);
}


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
*  函数:关闭ISP/IAP操作
*  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void Q0()
{
	ISP_CONTR	= 0;    /* 关闭IAP功能 */
	ISP_CMD		= 0;    /* 待机模式,无ISP操作 */
	ISP_TRIG	= 0;    /* 关闭IAP功能, 清与ISP有关的特殊功能寄存器 */
	EA		= 1;
}


/* 连续写入 10 字节 */
void lianxi_Write( char *pin , unsigned int addr)
{
	char num;
	for ( num = 0; num < 10; num++ )
	{
		xcx( addr + num, *pin ); /* 从0x2010开始读取32个字节 */
		pin++;
	}
}


/* 连续读取 10 个字节 */
void lianxi_Read( char *pin ,unsigned int addr)
{
	char num;
	for ( num = 0; num < 10; num++ )
	{
		*pin = dcx( addr + num ) ; /* 从0x2010开始读取32个字节 */
		pin++;
	}
}



猜你喜欢

转载自blog.csdn.net/x1131230123/article/details/107358867