资讯动态

基于AT89C2051与ST1101的电动自行车速度里程表设计

发布时间:2026/10/17 13:12:05 来源:尧图企业网站定制
简介这份资源是一份面向电子、自动化及单片机课程设计学习者的电动自行车速度与里程表设计方案文档适合作为课设毕设选题参考或嵌入式测速入门案例。方案以AT89C2051单片机与ST1101红外光电传感器为核心通过铝盘过孔产生脉冲信号经零偏置放大器与施密特触发器整形后送入单片机定时器计数再由LED模块交替显示速度与累计里程并借助AT24C02与I2C总线完成里程数据存储。资源包共1个PDF文件约94KB内容涵盖系统概述、硬件电路设计、信号预处理、E2PROM应用、显示模块及软件流程等完整章节配有原理框图和电路图便于读者理解测速与里程计算的整体实现思路。目前已有717人学习下载适合需要快速搭建方案框架、梳理硬件选型与算法逻辑的读者参考借鉴。1. 从机械指针到LED直读这套速度里程表方案到底解决了什么电动自行车骑了三年仪表盘上那根机械指针抖得跟心电图似的里程数全靠猜——这不是个例。市面上大量在跑的电动自行车速度表和里程表还是机械结构靠软轴带动指针用齿轮组累加里程。看起来能用实际上速度显示滞后、里程误差随使用时间越滚越大夜间骑行基本看不清。这套以AT89C2051单片机和ST1101红外光电传感器为核心的速度与里程表设计方案就是冲着这个痛点来的用非接触式光电检测替代机械软轴用单片机算频率替代齿轮计数用6位LED数码管替代指针表盘速度和里程直接数字显示还能在超速时报警。它适合谁做课设毕设的学生需要一套从传感器选型、信号调理、单片机编程到显示驱动的完整链路做小批量电动自行车仪表改装的工程师想评估光电方案替代机械方案的可行性还有带单片机课程的一线教师需要一个能讲清楚“脉冲频率→速度→里程”这条数据流的实战案例。方案本身不复杂但每个环节都有值得抠的细节——铝盘开几个孔、施密特触发器怎么选阈值、E2PROM什么时候写、里程累计怎么防止掉电丢数据。下面按硬件链路、软件逻辑、避坑排查、进阶技巧四块拆开讲。2. 硬件链路拆解从铝盘过孔到LED数码管的信号旅程2.1 脉冲发生源11个过孔和ST1101的配合逻辑整套系统的起点是后轮轴上的铝盘。铝盘与轮子旋转切面平行安装边沿均匀挖出11个圆形过孔留下10个等间距的实体部分。ST1101红外光电传感器固定在铝盘边沿处检测部分对准过孔圆心位置。当铝盘随轮子旋转时红外发光二极管和光电晶体管之间交替出现“有孔”和“无孔”状态——有孔时红外光穿过光电晶体管导通输出低电平无孔时红外光被铝盘挡住输出高电平。这样每转过一个过孔就产生一个脉冲轮子转一圈产生11个脉冲。为什么是11个孔而不是更多或更少孔数直接决定测量精度。孔太少两个过孔之间的弧长太大车轮在低速时可能刚好停在两个孔之间单片机在采样窗口内检测不到脉冲速度显示跳零。孔太多铝盘加工难度上升过孔间距太小容易导致红外光束同时被相邻两个孔之间的实体部分遮挡脉冲波形畸变。11个孔在常见26寸、27.5寸轮径下单孔对应弧长约5到6厘米两秒采样窗口内即使低速骑行也能捕获足够脉冲数。这个数字不是随便定的是精度和加工可行性之间的折中。铝盘材质建议用1.5到2毫米厚铝合金板太薄容易变形导致过孔位置偏移太厚增加转动惯量。过孔直径比红外光束直径大1到2毫米即可一般取3到4毫米。安装时铝盘必须与轮轴同心偏心会导致脉冲间隔不均匀速度显示出现周期性波动。2.2 信号预处理零偏置放大器和DM74LS14整形传感器输出的脉冲信号不能直接进单片机。原因有三个一是信号幅度可能不够ST1101在长距离传输后输出高电平可能衰减到3V以下达不到TTL电平的2.0V阈值二是波形边沿可能变缓铝盘转速低时脉冲上升沿和下降沿不够陡峭三是传输线上可能耦合噪声导致脉冲上出现毛刺。所以需要两级预处理。第一级是零偏置放大器用开关三极管构成。当输入信号为零或负电压时三极管截止输出高电平输入正电压时三极管导通输出电压随输入上升而下降。这个电路的好处是既能放大方波也能放大正弦波输入信号幅度只要大于0.5V就能被有效处理。开关三极管选高频管保证放大器有足够带宽不会把快速变化的脉冲边沿吃掉。第二级是DM74LS14施密特触发器反相器。施密特触发器的核心价值在于它的滞回特性输入电压超过正向阈值VT时输出翻转低于负向阈值VT-时输出才翻回去。只要输入信号幅度大于VT输出端就能得到边沿陡峭、频率相同的矩形脉冲。传输线电容导致的上升沿变缓、阻抗不匹配导致的振荡、电源耦合的噪声经过施密特触发器后都能被整形掉。DM74LS14是六反相器这里只用其中一路输出接到单片机P3.4引脚也就是T0定时器外部计数输入口。注意DM74LS14的VT和VT-由芯片内部电路决定典型值VT约1.7V、VT-约0.9V。如果传感器输出信号经过长线传输后幅度低于1.7V施密特触发器无法翻转单片机就收不到脉冲。这种情况下要么缩短传感器到电路板的距离要么在第一级放大器提高增益。2.3 单片机资源分配T0计数、T1定时、P3口读写的分工AT89C2051是这个方案的核心。它只有20个引脚但资源分配得当完全够用。关键引脚分配如下引脚功能连接对象P3.4T0外部计数输入DM74LS14输出P3.5I2C时钟SCLAT24C02 SCLP3.7I2C数据SDAAT24C02 SDAP1.0-P1.7显示数据/位选MC14511/74LS138P3.0/P3.1串口备用未使用T0工作在计数模式对P3.4引脚上的脉冲下降沿计数。T1工作在定时模式产生固定采样窗口。具体做法是T1设定为50ms中断一次中断服务程序里对一个软件计数器累加累加到40次就是2秒。2秒到达后读取T0计数值这就是两秒内的脉冲数N。然后清零T0重新计数开始下一个采样周期。为什么选2秒作为采样窗口这是测速精度和系统反应时间的折中。窗口太短低速时脉冲数太少计算出的速度分辨率差窗口太长速度变化时显示跟不上骑行者感觉仪表“迟钝”。2秒窗口下假设轮径26寸、铝盘11孔车速20km/h时轮子转速约2.7转/秒两秒内约5.4转对应约59个脉冲。这个脉冲数足够算出精确的速度值。车速降到5km/h时两秒内约15个脉冲仍然可测。再低的速度比如3km/h以下脉冲数少于10个速度显示开始跳变但实际骑行中低于3km/h基本是推行状态不影响使用。2.4 显示与存储MC14511驱动LED和AT24C02存里程显示部分用6位共阴极LED数码管分两组一组显示速度一组显示里程。驱动链路是74LS138位选加MC14511段驱动。74LS138的Y0到Y5分别选通6个数码管的公共端Y6和Y7控制CD4076寄存器来驱动小数点。MC14511把BCD码转换成7段码内部集成锁存器、译码器和驱动器一片顶三片简化了电路。AT24C02是256字节的I2C E2PROM用来存累计里程。为什么不用单片机内部RAM存因为掉电会丢。电动自行车的使用场景是频繁启停每次关钥匙再打开如果里程存在RAM里就归零了。AT24C02的写入寿命约100万次按每天写100次算能用27年足够。地址线A0、A1、A2全部接地器件地址设为000。单片机通过P3.5和P3.7模拟I2C时序写里程时先发写命令收到应答后从内部数据单元取数据写入指定地址读里程时先发读命令收到应答后从AT24C02读出数据供显示。提示AT24C02的写周期典型值5ms最大10ms。连续写入时必须等待上一个写周期完成否则数据会丢。常见做法是写完后延时10ms再发下一个字节或者用应答查询方式判断器件是否就绪。3. 软件逻辑与算法实现脉冲频率怎么变成速度和里程3.1 频率测量模块T0计数加T1定时的组合逻辑频率测量是整个软件的核心。AT89C2051的T0和T1配合方式如下T0配置为计数器模式C/T位设为1对P3.4引脚的外部脉冲下降沿计数计数寄存器是TL0和TH0。T1配置为定时器模式C/T位设为0对内部机器周期计数产生固定时间基准。初始化代码大致如下// AT89C2051 频率测量初始化 // 假设晶振12MHz机器周期1us void timer_init(void) { TMOD 0x15; // T1定时模式16位T0计数模式16位 TH0 0; // T0计数初值清零 TL0 0; TH1 0x3C; // T1初值50ms定时 TL1 0xB0; // 12MHz下50ms 50000us初值65536-50000155360x3CB0 ET0 0; // 关闭T0中断只读计数 ET1 1; // 开启T1中断 EA 1; // 开总中断 TR0 1; // 启动T0计数 TR1 1; // 启动T1定时 } // T1中断服务程序每50ms执行一次 void timer1_isr(void) interrupt 3 { static unsigned char tick 0; TH1 0x3C; // 重装初值 TL1 0xB0; tick; if (tick 40) // 40 * 50ms 2s { tick 0; pulse_count (TH0 8) | TL0; // 读取2秒内脉冲数 TH0 0; // 清零T0开始下一轮 TL0 0; measure_flag 1; // 通知主循环数据就绪 } }这段代码的逻辑是T1每50ms中断一次中断里对tick变量累加累加到40次就是2秒。2秒到达时读取T0的计数值存入pulse_count清零T0置位measure_flag通知主循环。主循环检测到measure_flag后执行速度和里程计算然后清零标志等待下一轮。参数说明晶振频率决定T1初值。12MHz晶振下机器周期1us50ms需要50000个机器周期16位定时器最大值65536初值就是65536减50000等于15536十六进制0x3CB0。如果晶振换成11.0592MHz机器周期约1.085us50ms对应约46080个周期初值要重新算。T0计数模式对外部脉冲计数最高计数频率是晶振频率的1/2412MHz下约500kHz远高于实际脉冲频率不会丢计数。3.2 速度换算从脉冲数到km/h的完整推导拿到2秒内的脉冲数N之后速度计算分四步第一步算铝盘转过的圈数。铝盘每转一圈产生11个脉冲所以圈数等于N除以11。第二步算铝盘圆周走过的距离。铝盘上两个相邻过孔之间的弧长M是已知的11个孔对应11段弧铝盘周长等于11乘以M。铝盘转过的距离等于圈数乘以铝盘周长。第三步算自行车轮子走过的距离。铝盘和轮子同轴角速度相同。轮子周长与铝盘周长的比值等于轮子半径与铝盘半径的比值。设轮子周长C_wheel铝盘周长C_disc则轮子走过距离等于铝盘走过距离乘以C_wheel除以C_disc。第四步除以时间2秒换算成km/h。// 速度计算函数 // 输入pulse_count为2秒内脉冲数 // 输出speed_kmh为速度值单位km/h保留两位小数 void calc_speed(unsigned int pulse_count) { float disc_circum; // 铝盘周长单位mm float wheel_circum; // 轮子周长单位mm float disc_distance; // 铝盘走过距离单位mm float wheel_distance; // 轮子走过距离单位mm float speed_mmps; // 速度单位mm/s // 铝盘周长 11 * 单段弧长M假设M50mm disc_circum 11.0 * 50.0; // 550mm // 轮子周长26寸轮径约2075mm wheel_circum 2075.0; // 铝盘走过距离 (脉冲数/11) * 铝盘周长 disc_distance ((float)pulse_count / 11.0) * disc_circum; // 轮子走过距离 铝盘距离 * (轮子周长/铝盘周长) wheel_distance disc_distance * (wheel_circum / disc_circum); // 速度 距离/时间2秒2000ms speed_mmps wheel_distance / 2000.0; // 换算成km/hmm/s * 3600 / 1000000 speed_kmh speed_mmps * 3.6 / 1000.0; }参数说明单段弧长M由铝盘加工决定需要实测。轮子周长C_wheel根据轮胎规格查表或实测26寸山地车约2075mm27.5寸约2155mm700C约2130mm。这两个参数在代码里定义为常量换车型时只需改这两个值。速度换算中假设2秒内匀速实际骑行中速度波动会导致瞬时误差但2秒窗口的平均速度对骑行者来说已经足够。3.3 里程累计与E2PROM读写掉电不丢数据的实现里程累计的逻辑是每个2秒周期算出轮子走过的距离S1把S1加到当前总里程上然后写入AT24C02。但每个周期都写E2PROM会快速消耗写入寿命而且写周期10ms会阻塞主循环。实际做法是RAM里维护一个里程累加变量每算出S1就加到RAM变量上只有当累计增量超过0.1km时才写入E2PROM一次。这样按每天骑行30km算每天写300次一年约10万次远低于100万次寿命。// 里程累计与存储 // mileage_ram为RAM中的当前里程单位米 // mileage_last_stored为上次存入E2PROM的里程值 void update_mileage(float wheel_distance_mm) { float distance_m; distance_m wheel_distance_mm / 1000.0; // 换算成米 mileage_ram distance_m; // 累计增量超过100米才写E2PROM if ((mileage_ram - mileage_last_stored) 100.0) { e2prom_write_mileage(mileage_ram); mileage_last_stored mileage_ram; } } // I2C写AT24C02写入里程值 // 里程以米为单位用4字节存储 void e2prom_write_mileage(float mileage) { unsigned long m; unsigned char buf[4]; m (unsigned long)mileage; buf[0] (m 24) 0xFF; buf[1] (m 16) 0xFF; buf[2] (m 8) 0xFF; buf[3] m 0xFF; i2c_start(); i2c_send_byte(0xA0); // 器件地址写 i2c_wait_ack(); i2c_send_byte(0x00); // 内部地址0 i2c_wait_ack(); for (unsigned char i 0; i 4; i) { i2c_send_byte(buf[i]); i2c_wait_ack(); } i2c_stop(); delay_ms(10); // 等待写周期完成 }参数说明AT24C02器件地址高7位是1010000加上读写位后写地址是0xA0读地址是0xA1。内部地址0x00到0xFF共256字节里程用4字节存储从地址0x00开始。写入后必须延时10ms等待内部写周期完成否则下一次操作会失败。读取时类似先发写地址和内部地址再发重复起始条件和读地址然后读取4字节。3.4 BCD转换与LED动态扫描6位显示的刷新策略速度和里程都是二进制数LED数码管需要BCD码。转换方法是用除法和取余逐位提取。比如速度值1234表示12.34km/h需要拆成1、2、3、4四个数字。整数部分除以1000得千位余数除以100得百位以此类推。小数部分乘以100后取整再拆。6位数码管采用动态扫描方式74LS138依次选通每一位MC14511输出对应段码。扫描频率要大于50Hz否则人眼会感觉闪烁。每位显示时间约1ms6位一轮6ms刷新率约166Hz足够。扫描在T1中断里做还是主循环里做建议放在T1中断里每50ms中断一次中断里除了计时还执行一轮6位扫描这样显示刷新和计时互不干扰。注意动态扫描时每位点亮时间短峰值电流大。共阴极LED每段电流约5到10mA6位同时只有一位点亮平均电流小但峰值电流可能达到60mA。AT89C2051的I/O口灌电流能力有限建议用74LS138做位选驱动MC14511做段驱动不要直接用单片机I/O口驱动LED。4. 避坑与排查这套方案最容易翻车的五个地方4.1 速度显示跳零或乱跳现象骑行中速度显示偶尔跳到0或者数值剧烈波动。原因最常见的是铝盘过孔位置偏移或传感器安装松动。铝盘偏心导致某些过孔离传感器太远红外光无法有效穿过脉冲丢失。另一个原因是传感器输出信号经过长线传输后幅度衰减到施密特触发器阈值以下部分脉冲无法触发翻转。解决重新校准铝盘同心度用百分表打表确认偏心小于0.5mm。传感器固定支架要加弹垫防松。如果信号衰减缩短传感器到电路板的距离或者在第一级放大器后加一级射极跟随器提高驱动能力。用示波器看DM74LS14输入端的波形确认每个脉冲幅度都超过1.7V。4.2 里程数每次开机归零现象关钥匙再打开累计里程回到零。原因E2PROM写入失败或者读取时序错误。AT24C02的写周期最大10ms如果写完立即断电数据可能没写进去。读取时如果器件地址或内部地址发错读出来的是随机值。解决写入后延时10ms再允许断电或者在电源端加一个大电容保证断电后单片机还能维持10ms供电完成写操作。读取时用示波器看SDA和SCL波形确认起始条件、地址字节、应答位都正确。AT24C02的A0、A1、A2必须接地不能悬空。4.3 低速时速度显示为0现象车速低于5km/h时速度显示0推行时完全没反应。原因2秒采样窗口内脉冲数太少除以11后圈数小于1计算出的距离为0。这是算法本身的限制不是故障。解决如果需要在极低速下显示可以缩短采样窗口到1秒或者改用测量脉冲周期而非频率的方法。但低速显示在实际骑行中意义不大推行时看里程就够了。可以在代码里加一个判断脉冲数小于3时速度显示“0.0”不参与里程累计避免原地抖动导致里程虚增。4.4 LED显示重影或亮度不均现象数码管某些位看起来有重影或者不同位亮度不一致。原因动态扫描时位选和段码切换存在竞争。74LS138的位选信号变化时MC14511的段码还没稳定导致上一位的段码短暂出现在下一位上。另外不同数码管的正向压降有差异同样的段电流下亮度不同。解决在位选切换和段码输出之间加一个小延时或者用锁存器在切换前先关闭所有位选。亮度不均可以给每位串联不同的限流电阻来补偿或者选用同一批次的正向压降一致的数码管。4.5 超速报警误触发现象正常骑行时报警偶尔响或者超速时不报警。原因报警阈值判断用的是瞬时速度而瞬时速度受脉冲计数误差影响有波动。如果阈值设得太接近常用巡航速度波动就会导致误触发。解决报警判断用连续3个采样周期的平均速度而不是单次速度值。阈值加一个回差比如超过25km/h触发报警低于23km/h才解除报警避免在阈值附近反复触发。报警输出可以用单片机某个空闲I/O口驱动蜂鸣器加三极管扩流。5. 进阶技巧让这套方案更接近量产仪表5.1 用脉冲周期法替代频率法提升低速精度频率法在低速时脉冲数少、分辨率差。脉冲周期法是测量两个相邻脉冲之间的时间间隔用T1定时器以微秒级精度计时。速度越低脉冲间隔越长测量精度反而越高。具体做法是T0配置为边沿触发中断每个脉冲下降沿触发中断中断里读取T1计数值并清零这个值就是脉冲周期。速度等于单孔弧长除以脉冲周期。两种方法可以结合高速时用频率法低速时自动切换到周期法。切换阈值设在脉冲数小于10时。这样全速度段都能保持较好精度。5.2 轮径参数在线校准不同车型轮径不同硬编码轮子周长需要改代码重新烧录。可以在AT24C02里留一个区域存轮径参数开机时读取。校准方法是在已知距离的直路上推行比如100米看里程显示值算出比例系数通过串口或按键写入E2PROM。这样一套硬件可以适配多种车型。5.3 掉电保护与数据完整性校验E2PROM存储里程时加CRC校验。每次写入4字节里程数据后再写入1字节校验和。读取时先算校验和与存储值比对不一致说明数据损坏用上一次的有效值。另外可以在E2PROM里存两份里程地址0x00和0x10各一份读取时取较大的那个防止写入过程中断电导致数据回退。5.4 显示刷新与计算任务的时序隔离主循环里做速度计算和里程累计T1中断里做显示扫描和计时。两者共享的变量比如pulse_count、speed_kmh要加volatile修饰防止编译器优化导致读取到旧值。计算任务执行时间要短避免影响中断响应。如果计算量大可以把计算拆成多个小步骤每个主循环周期执行一步。从那以后我每次做带E2PROM存储的项目都强制走一遍“写入-断电-上电-读取”的完整验证流程不看到数据正确恢复不往下走。这套速度里程表的方案不复杂但存储和信号调理这两个环节最容易埋雷提前验证比事后排查省事得多。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑