
c展开代码//键盘 
//启动  停止  加速  减速
//紧急   --   升高  降低
//模式   加时  加分  加秒
// --    减时  减分  减秒
//启动就是开启跑步机 灯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
c展开代码#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
c展开代码#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++;
 }
}


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!