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 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!