基于单片机的自行车码表
最近毕业设计中接了别人几个项目,忙完一阵是时候做一些总结。
项目名:基于单片机的自行车码表设计
功能需求: 1可以测量当前的温度和湿度并显示出来。
2时间显示。
3实时速度和行驰里程显示。
4设定里程提醒。
根据功能需求决定硬件:单片机使用STC125A60S2具有足够的资源来进行开发(使用51系列的单片也可行,并且价格更低),显示使用LCD1602,速度使用磁力传感器,温度和湿度使用DHT11传感器。时间计数应该使用外部的时钟芯片(由于没有芯片只能使用单片内部的定时器实现^^误差较大)。提醒声音使用了无源蜂鸣器(PWM波控制).
整体硬件设计图
IO脚定义
#ifndef _CURRENCY_H_ #define _CURRENCY_H_ #include "stc12c5a60s2.h " //currency.h typedef unsigned char unchar; typedef unsigned int unint;sbit Data=P3^5; sbit rs=P2^7; sbit rw=P2^6; sbit e =P2^5; sbit buzzer = P3^4;//蜂鸣器 #endif
主函数部分
/******************************************************************************* * 描述: * * 1602字符型LCD显示演示程序 * * 在第一行显示 里程 时间 * * 在第二行显示 速度 温度 * * * ********************************************************************************/#include <stc12c5a60s2.h> #include "lcd1602.h" #include "DHT11.h" #include "delay.h" #include "currency.h"unchar test[10]; unsigned long time_ms; unsigned long last_time; unsigned long distance_cm; //厘米 unsigned int speed; //百米/时 unsigned int tempr; //0.1度 unsigned int n ; unsigned char tm ; unsigned int distance; bit menu=0; bit clear_flag; unsigned long time_menu;void Timer0Init(void) //10毫秒@12.000MHz {AUXR &= 0x7F; //定时器时钟12T模式TMOD &= 0xF0; //设置定时器模式TMOD |= 0x01; //设置定时器模式TL0 = 0xF0; //设置定时初值TH0 = 0xD8; //设置定时初值TF0 = 0; //清除TF0标志TR0 = 1;ET0 = 1; //定时器0开始计时EA = 1; } //-------------------------------------------------------- //算法实现 //-------------------------------------------------------- void show() {unsigned char c;unsigned char h,m,s;unsigned int time;lcd_pos(0);distance = distance_cm / 10000;c = (distance / 1000) % 10 + '0'; //百位write_data(c); //写入数据c = (distance / 100) % 10 + '0'; //十位 write_data(c);c = (distance / 10) % 10 + '0'; //个位 write_data(c);write_data('.');c = distance % 10 + '0'; //小数一位 write_data(c);//进行位提取write_data('k');write_data ('m');time = time_ms/1000;h = time / 3600;m = (time % 3600) / 60;s = time % 60;lcd_pos(9);c = h % 10 + '0';write_data(c);write_data(':');c = (m / 10) + '0';write_data(c);c = (m % 10) + '0';write_data(c);write_data(':');c = (s / 10) + '0';write_data(c);c = (s % 10) + '0';write_data(c);//时间提取lcd_pos(0x40); //定位第二行c = (speed / 100) % 10 + '0'; //取百位 write_data(c); c = (speed / 10) % 10 + '0'; //取十位 write_data(c);write_data('.');c = speed % 10 + '0'; //取个位 write_data(c);write_data('k');write_data('m');write_data('/');write_data('h');//实时提取 } //开始 void main() {int i;init_1602(); //lcd1602初始化delay_ms(1500); //DHT11上电后要等待1.5S以越过不稳定状态在此期间不能发送任何指令 Timer0Init();IT0=1; //外部中断0下降沿触发EX0=1;IT1=1; //外部中断1下降沿触发EX1=1; //外部中断开启动 distance_cm = 0;time_ms = 0;last_time = 0;tempr = 324;while(1){if((time_ms - last_time) > 5000)speed = 0; P1 = 0xff;if((P1 & 0x02) == 0){distance_cm = 0;time_ms = 0;}if(menu == 0) //菜单0显示 {if(clear_flag==1){ write_com(0x01);clear_flag = 0;}show();if(distance ==15) //单位是百米 {Buzzer_Alert(); }}else if(menu == 1){if(clear_flag==0){ wrire_com(0x01);clear_flag = 1;}ET0 = 0;DHT11_receive();}}}void T0_Interrupt(void) interrupt 1 //3定时器1的中断号 1定时器0的中断号 0外部中断1 2外部中断2 4串口中断 {TL0 = 0xF0; //设置定时初值TH0 = 0xD8; //设置定时初?time_ms += 10; // if(menu) // { // time_menu+= 10; //test: // if(time_menu==10000) // { // menu=0; // time_menu=0; // } // } } //比较重要------------------------------------ void counter(void) interrupt 0 {unsigned int intervel = 0; // static unsigned char cnt = 0;EX0=0;distance_cm+=218; //一圈218厘米cnt++; if(last_time == 0){last_time = time_ms;cnt = 0;}else if(cnt >= 5){intervel = time_ms - last_time;last_time = time_ms;speed = 360 * 5 * 218 / intervel; //实时速度统计if(speed > 350)else cnt = 0;}EX0=1; }void key_menu(void) interrupt 2 {menu=~menu;ET0 = 1; }
LCD1602模块函数
#include "lcd1602.h" #include "currency.h" #include "delay.h" #include "intrins.h"/***********************lcd1602写命令函数************************/ void write_com(unchar com) {e=0;rs=0;rw=0;P0=com;delay_unint(3);e=1;delay_unint(25);e=0; }/***********************lcd1602写数据函数************************/ void write_data(unchar dat) {e=0;rs=1;rw=0;P0=dat;delay_unint(36);e=1;delay_unint(300);e=0; } /***********************lcd1602写数据函数************************/ void write_data_1(unchar dat) {e=0;rs=1;rw=0;P0=dat+48;delay_unint(432);e=1;delay_unint(3600);e=0; }/*********************光标控制***********************/ void lcd1602_guanbiao(unchar open_off,unchar add) {if(open_off == 1) //开光标 {write_com(0x80+add); //将光标移动到秒个位write_com(0x0f); //显示光标并且闪烁 }else {write_com(0x0c); //关光标 } }/***********************lcd1602上显示两位十进制数************************/ void write_sfm2(unchar hang,unchar add,unchar date) {unchar shi,ge;if(hang==1) write_com(0x80+add);elsewrite_com(0x80+0x40+add);shi=date%100/10;ge=date%10; write_data(0x30+shi);write_data(0x30+ge); }/***********************lcd1602上显示这字符函数************************/ void write_string(unchar hang,unchar add,unchar *p) {if(hang==1) write_com(0x80+add);elsewrite_com(0x80+0x40+add);while(1) {if(*p == '\0') break;write_data(*p);p++;delay_unint(600);} }/***********************lcd1602上显示这字符函数************************/ void write_string_1(unchar hang,unchar add,unchar *p) {if(hang==1) write_com(0x80+add);elsewrite_com(0x80+0x40+add);while(1) {if(*p == '\0') break;write_data_1(*p);p++;delay_unint(600);} }/***********************lcd1602初始化设置************************/ void init_1602() {write_com(0x38); // write_com(0x0c);write_com(0x06);delay_unint(12000);//write_string(1,0," Welcome to use "); //write_string(2,0," Bicycle speed ");//lcd1602_guanbiao(1,7+0x40); //开光标 }unchar Lcd1602_ReadBusy() //判断lcd1602是否处于忙的状态,即读忙 {unchar temp;rs=0;rw=1;_nop_();P0=0xff; //读某IO口数据前,先将该口置为1 /*原因:电路中存在的一个普遍的现象:高电平很容易被低电平拉低,而低电平一般不可能被高电平拉高。所以在读数据之前将单片机IO口拉高才不会影响原来数据线上的数据!*/_nop_();e=1;_nop_();temp=P0; //读取此时lcd1602的状态字 _nop_();e=0;return (temp&0x80); //如果忙/*状态字为temp(8位2进制数)的最高位,最高位为1表示禁止读写,为0表示允许读写,即temp&0x80得1表示忙,得0表示不忙*/}void Lcd1602_WriteData(unchar dat) //写数据 { rs=1; //数据rw=0; //写 _nop_();P2=dat;_nop_();e=1;_nop_();_nop_();e=0;_nop_();_nop_(); }void lcd_pos(unchar pos){write_com(pos | 0x80);}
由于DHT11需要比较准确的延时误差在5%
delay.c延时模块
#include "delay.h" #include "intrins.h" #include "DHT11.h" //-------------------------------------------------------- //延时1ms 实际0.99ms //-------------------------------------------------------- void delay_ms(unsigned int x) {while(x--){ unsigned char i, j;_nop_();_nop_();i = 9;j = 120;do{while (--j);} while (--i); } }void delay_unint(unsigned int q) { while(q--); } //-------------------------------------------------------- //延时60s 实际63us //-------------------------------------------------------- void Delay60us() //@12.000MHz {unsigned char i, j;_nop_();_nop_();i = 1;j = 180;do{while (--j);} while (--i); }//-------------------------------------------------------- //延时80s 实际87us //--------------------------------------------------------void Delay80us() //@12.000MHz {unsigned char i, j;_nop_();_nop_();i = 1;j = 255;do{while (--j);} while (--i); }//-------------------------------------------------------- //延时30s 实际31us //--------------------------------------------------------void Delay30us() //@12.000MHz {unsigned char i;i = 87;while (--i); }void Delay50us() //@12.000MHz {unsigned char i, j;_nop_();_nop_();i = 1;j = 145;do{while (--j);} while (--i); }
DHT11.C 温度采集模块
#include "DHT11.h" #include "currency.h" #include "stc12c5a60s2.h" #include "delay.h" #include "lcd1602.h" #include <intrins.h> //------------------------------------ //function:rec_dat数据组清零 //------------------------------------unchar rec_dat[9]; //------------------------------------ //function:DHT11启动 //------------------------------------ void DHT11_start() {Data=1;Delay30us(); Data=0;delay_ms(25); //延时18ms以上Data=1;Delay30us(); }//------------------------------------ //function:DHT11接收一个字节 //------------------------------------ unchar DHT11_rec_byte() //接收一个字节 {unchar i,dat=0;for(i=0;i<8;i++) //从高到低依次接收8位数据 { while(!Data); ////等待50us低电平过去Delay60us(); //延时60us,如果还为高则数据为1,否则为0 dat<<=1; //移位使正确接收8位数据,数据为0时直接移位if(Data==1) //数据为1时,使dat加1来接收数据1dat+=1;while(Data); //等待数据线拉低 } return dat;}//------------------------------------ //function: 接收DHT11的40位的数据 //------------------------------------ void DHT11_receive() //接收40位的数据 {unchar i, R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; DHT11_start();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();if(Data==0){ while(Data==0); //等待拉高Delay80us(); //拉高后延时80us R_H=DHT11_rec_byte(); //接收湿度高八位;R_L=DHT11_rec_byte(); //接收湿度低八位 T_H=DHT11_rec_byte(); //接收温度高八位 T_L=DHT11_rec_byte(); //接收温度低八位revise=DHT11_rec_byte(); //接收校正位Delay30us(); //结束if((R_H+R_L+T_H+T_L)==revise) //校正 {RH=R_H;RL=R_L;TH=T_H;TL=T_L;} /*数据处理,方便显示*/rec_dat[0]='0'+(RH/10);rec_dat[1]='0'+(RH%10);rec_dat[2]='R';rec_dat[3]='H';rec_dat[4]=' ';rec_dat[5]=' ';rec_dat[6]='0'+(TH/10);rec_dat[7]='0'+(TH%10);rec_dat[8]='C';lcd_pos(40); //定位第二行的第一个for(i=0;i<9;i++){write_data(rec_dat[i]);} }}
buzzer,c蜂鸣器模块
#include "buzzer.h" #include "currency.h" #include "delay.h"void Buzzer_Alert() //PWM 500hz {long int i=2000;while(i--){buzzer=~buzzer;delay_ms(1);} }
代码难度不大,具体注释想必有点单片机的基础都可以看懂^^
DHT11的硬件
注:这个上拉电阻主要是普通的单片机的上拉能力不强,当数据进行长距离传输时容易有较大的寄生电容造成RC放电,所以要加上 上拉电阻。短距离不用加也可以。
DHT11的操作比较简单,就是时序操作,没有什么要注意的。
总结:
按键最好要消抖,一般有两种做法,软件消抖和硬件消抖两种方法,在单片机资源足够充裕并且系统对实时性要求不高时,建议使用软件消抖,延时20ms后进行判断。不然利用硬件消抖,一般在按键端接入4.7K电阻加0.1uF的电容,在有时间后加上GPS定位功能。
转载于:https://www.cnblogs.com/Kroner/p/9073651.html
基于单片机的自行车码表相关推荐
- 自行车存放管理系统c语言课程设计,基于51单片机的自行车智能辅助系统设计-(Proteus仿真图+源程序+论文)...
基于单片机的自行车智能辅助系统设计 摘 要 随着科学技术与物联网的发展,推动着智能化产品逐渐从无到有再到快速发展,智能科技逐渐改变社会发展方式,过去很多无法想象的科学技术或者生活方式,现在利用先进和智 ...
- 单片机c语言慧尾灯编码,(参考)基于单片机的智能尾灯开发文档.doc
基于单片机的智能尾灯的设计 摘要 本设计是基于单片机的自行车智能尾灯控制器,该设计为STC89S52单片机做为主控芯片的自行车尾灯控制电路的设计方法,用发光二极管模拟自行车尾灯,按键开关作为转弯等控制 ...
- 基于51单片机自行车码表设计
[毕设课设]基于51单片机自行车码表设计 效果图 Proteus仿真: 功能简介: 文件内容: 程序框架: 网盘链接: 效果图 更多内容请关注@WENJIE电子科技 基于51单片机proteu ...
- 【电路方案】基于单片机智能市电温度控制系统设计-基于单片机RGB颜色智能识别系统设计-基于单片机四路红外遥控开关电路设计-基于单片机自行车自动防盗报警系统设计-基于单片机智能无线病床呼叫系统设计
822基于单片机智能无线病床呼叫系统设计-设计资料下载 硬件构成:单片机+最小系统+LCD1602液晶显示模块+无线收发模块+蜂鸣器模块+LED指示灯模块+按键模块 本设计基于STC89C51/52( ...
- 单片机数码管显示自行车里程c语言,基于51单片机的自行车里程计速度计设计.doc...
信电学院课程设计报告 题目: 基于51单片机的自行车里程计/速度计设计 学生姓名 学 号 班 级 专 业 指导教师 说 明 1. 课程设计文本材料 2. 学生根据指导教师下达的任务书.指导书完成课程设 ...
- 基于51单片机的自行车里程表
电路 51单片机的自行车里程表的硬件主要由51单片机最小系统电路,LCD1602液晶显示模块,霍尔测速模块,电机模块,电位器调速模块,蜂鸣器报警电路,LED指示灯模块,按键模块,DS1302时钟模,A ...
- 基于单片机的压力流量报警器(附代码+仿真+论文)
基于单片机的压力流量报警器(附代码+仿真+论文) **==完整论文+代码+仿真可关注我在主页私我==** 摘要 关键字 第一章绪论 1.1课题背景及其意义 1.2 国内外的研究状况 1.3本文的主要研 ...
- 单片机里程计量设计c语言,基于单片机的出租车计价器的里程计算设计
社会发展的越快,人们的生活质量越好,从以前的走路.骑自行车,再到坐公交车地铁等,到了现在出门"打的",出租车已经成为人们出门的重要代步工具了.因此出租车计价器系统也显得尤为重要.计 ...
- 基于单片机的超市储物柜设计_基于单片机的自动存储柜的设计
金红娟 张娣 王历 摘 要: 隨着科技的日趋发展,智能化产品随处可见,极大地方便了人们的生产生活.在一些综合超市,大型购物商场等一些公共场合,由于人流大,购物的人多,仅靠人工来存储物品速度慢,效率低 ...
- 基于单片机的6位电子时钟
点击链接获取Keil源码与Project Backups仿真图 https://download.csdn.net/download/qq_64505944/87413394 源码获取 摘 要 近年来 ...
最新文章
- 图卷积神经网络分析复杂碳水化合物
- 微信小程序 跳转界面
- JVM_02 类加载器子系统
- 在Spring@Component vs @Repository vs @Service
- Linux 蓝牙读写,实战Linux Bluetooth编程(三) HCI层编程
- Python 创建随机mac地址(单播、组播)
- 蓝盾小火墙补丁_网络安全知识小科普
- 【离散数学】单向连通和弱连通的区别
- 2018年php还是python好_2018年PHP还值得学习吗?
- iphone在jsp显示时间会NAN解决办法
- 如何本地加载live2d模型 离线方式加载看板娘
- 10种微信公众号的推广吸粉方法
- Android实现身份证号码验证
- vba中find方法查找
- 企业运维自动化实战-CSDN公开课-专题视频课程
- 广联达报错access_广联达软件报错问题汇总和解决方案.doc
- 【Vue】图片加载中显示Loading
- google计费接入,Billing结算库支付
- 力扣 704.二分查找
- ...可变形参的使用
热门文章
- Echars 双击Legend 显示自己隐藏其他Legend
- 基于TensorRT和onnxruntime下pytorch的Bert模型加速对比实践
- 饿了么Redis Cluster集群化演进
- 2017 暑期实习校园招聘(Java后台开发方向)面经分享
- 支付宝支付php开发demo下载地址,tp使用支付宝接口demo
- JAVA自学-day11-eclipse工具的使用、API、Object类
- 解决安卓CPU使用率过高问题
- 计算机无法关闭密码保护,Win7密码保护共享关闭不了怎么办?密码保护共享关不掉的解决方法...
- modbusx协议讲解
- 融合泊车占比超过60%,除了德赛西威,还有哪些本土供应商