功能介绍:
0.本系统采用STC89C52作为单片机
1.采用LCD1602来实时显示计步器的数据
2.预留有串口可以自己开发蓝牙功能
3.设计EEPROM可以保存计步的相关数据,断电后下次上电依然可以查询
4.采用DC002作为电源接口可直接输入5V给整个系统供电
5.计步的传感器采用的是加速度传感器ADXL345
原理图:
PCB:
主程序:
#include "main.h"
enum _MODE_DF_ dispMode;
unsigned char setIndex = 0;
char dis0[16]; //数组
bit readAdx = 0; //定时读取adxl345
bit refreshFlag = 0; //定时更新屏幕
unsigned int stepCnt = 0; //累计步数
float distance = 0; //累计距离
float calorie = 0; //累计卡路里
unsigned char statusFlag = 0; //状态
unsigned char isNewFlag = 0; //数据记录
unsigned char saveCnt = 0; //数据记录
void main(void)
{
Init_Timer0(); //定时器0初始化
LCD_Init(); //初始化液晶
DelayMs(20); //延时有助于稳定
LCD_Clear();
EEPROM_Init();
isNewFlag = EEPROM_ReadByte(IS_NEW_ADDR); //读取芯片标志
if (isNewFlag != 0) //如果是新机
{
isNewFlag = 0;
EEPROM_WriteByte(IS_NEW_ADDR, isNewFlag); //将不是新芯片标志写入EEPROM
EmptyData();
}
else
{
saveCnt = EEPROM_ReadByte(SAVECNT_ADDR); //读取存储数量
}
Init_ADXL345(); //清屏
if (Single_Read_ADXL345(0X00) == 0xe5) //读出的数据为0XE5,表示正确
{
DelayMs(5);
}
else
{
DelayMs(3);
}
while (1) //主循环
{
if (readAdx) //定时读取adxl345数据
{
readAdx = 0;
StepCheck(); //检测步数
}
if (refreshFlag)
{
refreshFlag = 0;
if (dispMode == NORMAL)
{
DispNormal();
}
}
KeyScan();
}
}
//步数检测
void StepCheck(void)
{
static unsigned char ErrorNum = 0; //变量定义
static unsigned char NormalNum = 0;
static unsigned char CheckNum = 0; //变量定义
static unsigned char standNum = 0;
static unsigned char sidewaysNum = 0;
static unsigned int remStep = 0;
ReadData_x();
CheckNum++; //检测次数
if ((temp_X < 650) || (abs(temp_Y) > 400)) //查看正常次数
{
LED_STATUS = 0; //呼吸灯
ErrorNum++; //记录次数
standNum++; //竖直状态++
}
else
{
NormalNum++;
sidewaysNum++;
LED_STATUS = 1;
} //呼吸灯//侧着状态++
if ((NormalNum != 0) && (ErrorNum != 0)) // 从角度判断走了一步
{
ErrorNum = 0;
NormalNum = 0;
stepCnt++;
distance = (float)(stepCnt / 2) * 0.45; //计算距离
calorie = distance * 70 * 0.832; //卡路里计算 走路 距离*体重*系数
}
if (CheckNum >= 20)
{
if ((sidewaysNum != 0) && (standNum == 0))
{
statusFlag = 0; //站着状态
}
else if ((sidewaysNum == 0) && (standNum != 0))
{
statusFlag = 1; //躺着状态
}
else if ((sidewaysNum != 0) && (standNum != 0))
{
if ((stepCnt - remStep) >= 6) //跑着 一个周期大于3步
{
statusFlag = 2;
} //跑着状态
else
{
statusFlag = 3;
} //走着状态
remStep = stepCnt; //记录上次步数
}
CheckNum = 0;
sidewaysNum = 0; //清空计数
standNum = 0;
}
}
//正常显示
void DispNormal(void)
{
sprintf(dis0, "S:%04d D:%6.1fm ", stepCnt / 2, distance); //打印
LCD_Write_String(0, 0, dis0); //显示
sprintf(dis0, "%7.2fcal ", calorie); //打印
LCD_Write_String(0, 1, dis0); //显示
if (statusFlag == 0) //站着状态
{
LCD_Write_String(11, 1, "Stand");
}
else if (statusFlag == 1) ////躺着状态
{
LCD_Write_String(11, 1, "Lie ");
}
else if (statusFlag == 2) //跑着状态
{
LCD_Write_String(11, 1, "Run ");
}
else if (statusFlag == 3) //走着状态
{
LCD_Write_String(11, 1, "Walk ");
}
}
//显示选择界面
void DispSelect(unsigned char setIndex)
{
LCD_Write_String(1, 0, "1.Search"); //选项1查询
LCD_Write_String(1, 1, "2.Empty All"); //选项2删除所有
if (setIndex == 1)
{
DispOneChar(0, 0, '>');
DispOneChar(0, 1, ' ');
}
else if (setIndex == 2)
{
DispOneChar(0, 0, ' ');
DispOneChar(0, 1, '>');
}
}
//显示读取步数
void DispReadStep(unsigned char i)
{
unsigned int readStep = 0;
readStep = ReadData(i);
sprintf(dis0, "Data %02d S:%04d", (int)i, readStep); //打印
LCD_Write_String(0, 0, dis0); //显示
}
//存储数据
void SaveData(void)
{
if (saveCnt >= MAXCNT) //最大存储数量
{
LCD_Clear();
LCD_Write_String(0, 0, " Storage Full! "); //显示存储空间已满
DelayMs(200);
DelayMs(200);
DelayMs(200);
DelayMs(200);
}
else
{
EEPROM_WriteByte(START_ADDR + 2*saveCnt, (((stepCnt/2) & 0xFF00) >> 8));
DelayMs(1);
EEPROM_WriteByte(START_ADDR + 2*saveCnt + 1, ((stepCnt/2) & 0x00FF));
DelayMs(1);
saveCnt++;
EEPROM_WriteByte(SAVECNT_ADDR, saveCnt); //将存储数据总数写入EEPROM
DelayMs(1);
}
}
//读取数据
unsigned int ReadData(unsigned char i)
{
unsigned int readStep = 0;
readStep = EEPROM_ReadByte(START_ADDR + 2*i);
DelayMs(1);
readStep = EEPROM_ReadByte(START_ADDR + 2*i + 1) | (readStep << 8);
DelayMs(1);
return readStep;
}
//清空数据
void EmptyData(void)
{
unsigned char i;
saveCnt = 0;
stepCnt = 0;
EEPROM_WriteByte(SAVECNT_ADDR, saveCnt); //将存储数据总数写入EEPROM
DelayMs(1);
for (i = 0; i < MAXCNT; i++)
{
EEPROM_WriteByte(START_ADDR + 2*i, (((stepCnt/2) & 0xFF00) >> 8));
DelayMs(1);
EEPROM_WriteByte(START_ADDR + 2*i + 1, ((stepCnt/2) & 0x00FF));
DelayMs(1);
}
}
//按键扫描
void KeyScan()
{
static char cnt = 0;
if (!KEY_SEARCH) //查询键按下
{
DelayMs(5);
if (!KEY_SEARCH)
{
if (dispMode == NORMAL)
{
LCD_Clear();
dispMode = SELECT;
setIndex = 1;
}
else if (dispMode == SELECT)
{
LCD_Clear();
dispMode = NORMAL;
setIndex = 0;
}
switch (dispMode)
{
case SELECT:
DispSelect(setIndex);
break;
}
}
while (!KEY_SEARCH)
;
}
if (!KEY_ENTER) //确认键按下
{
DelayMs(5);
if (!KEY_ENTER)
{
if (dispMode == SELECT)
{
if (setIndex == 1)
{
LCD_Clear();
dispMode = SEARCH;
cnt = 0;
}
else if (setIndex == 2)
{
LCD_Clear();
LCD_Write_String(0, 0, " Empty All! ");
EmptyData();
DelayMs(200);
DelayMs(200);
DelayMs(200);
DelayMs(200);
LCD_Clear();
dispMode = NORMAL;
}
}
else if (dispMode == SEARCH)
{
LCD_Clear();
dispMode = NORMAL;
}
switch (dispMode)
{
case SELECT:
DispSelect(setIndex);
break;
case SEARCH:
DispReadStep(cnt);
break;
}
}
while (!KEY_ENTER)
;
}
if (!KEY_UP) //上键按下
{
DelayMs(5);
if (!KEY_UP)
{
if (dispMode == NORMAL)
{
LCD_Clear();
sprintf(dis0, "Save %2d Success!", (int)(saveCnt));
LCD_Write_String(0, 0, dis0);
SaveData(); //存储数据
DelayMs(200);
DelayMs(200);
DelayMs(200);
DelayMs(200);
stepCnt = 0; //归零本次数据
distance = 0;
calorie = 0;
}
else if (dispMode == SELECT)
{
setIndex++;
if (setIndex > 3)
{
setIndex = 1;
}
}
else if (dispMode == SEARCH)
{
cnt++;
if (cnt >= MAXCNT)
{
cnt = 0;
}
}
switch (dispMode)
{
case SELECT:
DispSelect(setIndex);
break;
case SEARCH:
DispReadStep(cnt);
break;
}
}
while (!KEY_UP)
;
}
if (!KEY_DOWN) //下键按下
{
DelayMs(5);
if (!KEY_DOWN)
{
if (dispMode == NORMAL)
{
stepCnt = 0; //归零本次数据
distance = 0;
calorie = 0;
}
else if (dispMode == SELECT)
{
setIndex--;
if (setIndex < 1)
{
setIndex = 2;
}
}
else if (dispMode == SEARCH)
{
cnt--;
if (cnt < 0)
{
cnt = MAXCNT - 1;
}
}
switch (dispMode)
{
case SELECT:
DispSelect(setIndex);
break;
case SEARCH:
DispReadStep(cnt);
break;
}
}
while (!KEY_DOWN)
;
}
}
//定时器0初始化
void Init_Timer0(void)
{
TMOD &= 0xF0;
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0 = (65536 - 18432) / 256; //重新赋值 20ms
TL0 = (65536 - 18432) % 256;
EA = 1; //总中断打开
ET0 = 1; //定时器中断打开
TR0 = 1; //定时器开关打开
}
//定时器0中断
void Timer0_isr(void) interrupt 1
{
static unsigned int time_20ms = 0; //定时器计数;
TH0 = (65536 - 18432) / 256; //重新赋值 20ms
TL0 = (65536 - 18432) % 256;
time_20ms++;
if (time_20ms >= 200)
{
time_20ms = 0;
}
if (time_20ms % 10 == 0)
{
refreshFlag = 1;
}
if (time_20ms % 5 == 0)
{
readAdx = 1;
}
}