基于51单片机的计步器(步数,存储) 具体要求如下: 1、利用震动传感器实现计步功能的模拟; 2、可以记录行走的步数,可以显示记录的步数; 3、通过按键实现归零功能,可以存储历史数据,并断电不丢失; 4、通过按键实现历史记录的查看。 包含: 仿真、程序、原理图、流程图

硬件选型直接用了SW-18015P震动传感器,这货灵敏度够高但容易神经质。为了稳定,我在传感器输出端接了个10kΩ上拉电阻,信号线直连P3.2外部中断口。显示模块用四位共阳数码管,驱动方式选了三极管扩流+74HC595级联,节省IO口的同时亮度也够用。

存储方案纠结半天,最后用了AT24C02这个I2C的EEPROM。焊接时特别注意了A0-A2地址线接地,这样器件地址就是0xA0。不过后来调试发现,51的普通IO口模拟I2C时序得调延迟,太快了会丢数据。

主程序里最关键的震动中断服务程序长这样:

void EX0_ISR() interrupt 0
{
    static uint last_time = 0;
    if(TMR0 - last_time > 20) // 20ms防抖
    {
        step_count++;
        update_eeprom = 1;
    }
    last_time = TMR0;
}

这里用定时器0的计数值做时间戳判断,比delay循环靠谱多了。注意中断标志位的清除是硬件自动完成的,不用手动操作。

基于51单片机的计步器(步数,存储) 具体要求如下: 1、利用震动传感器实现计步功能的模拟; 2、可以记录行走的步数,可以显示记录的步数; 3、通过按键实现归零功能,可以存储历史数据,并断电不丢失; 4、通过按键实现历史记录的查看。 包含: 仿真、程序、原理图、流程图

数据存储策略采用环形缓冲区,每次计步时除了更新当前步数,还会把整点数据存进EEPROM。这里有个坑:AT24C02的页写入周期是5ms,连续写必须隔开时间。我的解决办法是设立写入队列:

void save_to_eeprom()
{
    static uint8_t save_ptr = 0;
    AT24C02_Write(SAVE_BASE + save_ptr*2, step_count >> 8);
    AT24C02_Write(SAVE_BASE + save_ptr*2 +1, step_count & 0xFF);
    save_ptr = (save_ptr +1) % 10; // 存10组历史数据
}

每次只存2字节数据,通过移位操作拆分高低字节。历史记录查看时用了个取巧的方法——长按功能键时切换显示模式:

if(key_hold_time > 1000) // 长按1秒
{
    display_mode = (display_mode +1) % 3;
    load_history(display_mode);
}

数码管动态扫描函数里根据display_mode变量决定显示当前步数还是历史数据。消隐处理必须做好,否则会有残影,这里用了P0=0xFF在切换位选前清空段选。

实测发现传感器误触发的问题还是存在,后来在硬件上加了个100nF电容并联在传感器输出端,软件端加了二级滤波:

if(sensor_counter > 3) // 连续三次检测到高电平才计数
{
    sensor_valid = 1;
    sensor_counter = 0;
}

现在晃动桌子也不会乱计数了。整个项目最费时间的其实是EEPROM数据的掉电保存验证,反复拔插电源十几次确认数据不丢失,建议调试时用可调电源模拟断电更方便。

完整代码里用了状态机结构处理按键扫描和显示切换,中断服务程序尽量精简。注意51的XRAM空间有限,历史数据数组不要开太大。最后在Proteus里仿真时,记得给传感器信号加随机脉冲测试稳定性。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐