找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1643|回复: 0
收起左侧

51单片机+LCD2004组成两路测速程序与Proteus仿真图

[复制链接]
ID:579397 发表于 2022-3-26 02:13 | 显示全部楼层 |阅读模式
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
1.png
51hei.png
2.png

单片机源程序如下:
  1. #include <intrins.h>                                        //引用程序目录的相对路径中的头文件
  2. #include <reg52.h>                                                //引用编译器的类库路径里面的头文件

  3. #define LCD P2                                //LCD2004数据接口

  4. sbit RS=P1^2;                        //设置RS引脚接口,RS=0,指令寄存器;RS=1,数据寄存器
  5. sbit RW=P1^1;                        //设置R/W引脚接口,R/W=0,写;R/W=1,读
  6. sbit E=P1^0;                        //设置E引脚接口,E允许信号

  7. unsigned char RPM_R[]="000";                        //右电机转速,H整型转换为字符型,定义数组长度。
  8. unsigned char RPM_L[]="000";                        //左电机转速,H整型转换为字符型,定义数组长度。
  9. unsigned char V_R[]="000";                        //右电机时速,H整型转换为字符型,定义数组长度。
  10. unsigned char V_L[]="000";                        //左电机时速,H整型转换为字符型,定义数组长度。

  11. unsigned int rpm_r=0;                        //初始化右电机转速
  12. unsigned int rpm_l=0;                        //初始化左电机转速
  13. unsigned int v_r=0;                        //初始化右电机时速
  14. unsigned int v_l=0;                        //初始化左电机时速

  15. unsigned int D=770;                //直径

  16. unsigned char cnt=0;                //中断次数倍数,50ms为单位,若20倍,组成1秒
  17. unsigned char flag=0;                //时钟标志位

  18. /******************************
  19.                 LCD忙检测函数子程序
  20. ******************************/
  21. void CheckBusy(void)
  22.         {
  23.                 unsigned int nTimeOut=0;
  24.                 RS=0;
  25.                 RW=1;
  26.                 E=0;
  27.                 E=1;
  28.                 while((LCD&0x80)&&(++nTimeOut !=0));
  29.                 E=0;
  30.                 RS=0;
  31.                 RW=1;
  32.         }
  33.         
  34. /******************************
  35.                 LCD发送命令或数据子程序
  36. ******************************/
  37. void SendCmdorData(unsigned char byCmdorData,bit DI)
  38.         {
  39.                 CheckBusy();
  40.                 RS=DI;                        //为寄存器选择脚,高电平时选择数据寄存器、低电平时选择指令寄存器
  41.                 RW=0;                        //为读、写信号线,低电平时进行写操作
  42.                 E=0;                        //E端为使能端,当E端由高电平跳变为低电平时,液晶模块执行命令
  43.                 LCD=byCmdorData;                        //送数据
  44.                 _nop_();                        //空操作,给硬件反应时间
  45.                 _nop_();                        //空操作,给硬件反应时间
  46.                 E=1;
  47.                 _nop_();                        //空操作,给硬件反应时间
  48.                 _nop_();                        //空操作,给硬件反应时间
  49.                 E=0;                        //E引脚要有一个下降沿,才能把数据线上数据,命令送入1602
  50.                 RW=1;                        //为读、写信号线,高电平时进行读操作
  51.                 RS=0;                        //为寄存器选择脚,低电平时选择指令寄存器
  52.         }

  53. /******************************
  54.                 延时1毫秒
  55. ******************************/        
  56. void Delay(unsigned int nDelay)
  57.         {
  58.                 unsigned int i;
  59.                 for(;nDelay>0;nDelay--)
  60.                 {
  61.                         for(i=124;i>0;i--);
  62.                 }
  63.         }

  64. /******************************
  65.                 LCD初始化子程序
  66. ******************************/        
  67. void Init(void)
  68.         {
  69.                 SendCmdorData(0x38,0);                        //写命令,设置16*2显示,5*7点阵,8位数据接口
  70.                 Delay(50);                        //50ms延时,给硬件反应时间
  71.                 SendCmdorData(0x01,0);                        //写命令,显示清屏:1、数据指针清零 2、所有显示清零
  72.                 Delay(50);                        //50ms延时,给硬件反应时间
  73.                 SendCmdorData(0x06,0);                        //写命令,当读或写一个字符后地址指针加一,且光标加一
  74.                 Delay(50);                        //50ms延时,给硬件反应时间
  75.                 SendCmdorData(0x0c,0);                        //写命令,开显示、不显示光标、光标不显示
  76.                 Delay(50);                        //50ms延时,给硬件反应时间
  77.         }

  78. /******************************
  79.                 地址转换子程序
  80.                 x为行号 y为列号
  81. ******************************/        
  82. void SetAddress(unsigned char x,y)
  83.         {
  84.                 unsigned char byAddress;
  85.                 switch(x)
  86.                         {
  87.                         case 1:byAddress=0x80+y;break;                        //第一行首地址
  88.                         case 2:byAddress=0xC0+y;break;                        //第二行首地址
  89.                         case 3:byAddress=0x94+y;break;                        //第三行首地址
  90.                         case 4:byAddress=0xD4+y;break;                        //第四行首地址
  91.                         default:break;                        //default就是如果没有符合的case就执行它,default并不是必须的.
  92.                         }                                 
  93.                         SendCmdorData(byAddress,0);                        //执行发送指令子程序
  94.         }

  95. /******************************
  96.                 发送字符串到LCD子程序
  97. ******************************/        
  98. void PutString(unsigned char x,y,unsigned char *pData)
  99.         {
  100.                 SetAddress(x,y);                        //执行地址转换子程序
  101.                 while(*pData !='\0')                                                //表示显示内容不为空时,执行循环体的代码段,
  102.                         {
  103.                                 SendCmdorData(*pData++,1);                        //发送命令子程序,*就是声明他的类型,是一个指向整型数据的指针
  104.                         }
  105.         }

  106. /******************************
  107.         4位数的H整型转换为字符型,        加48为转ASCII。
  108.         *就是声明他的类型,是一个指向整型数据的指针
  109. ******************************/        
  110. void Inttochar4(unsigned int a,unsigned char *chx)
  111.         {        
  112.                 chx[0]=a/1000+48;                        //高电平千位
  113.                 chx[1]=(a/100)%10+48;                        //高电平百位
  114.                 chx[2]=(a/10)%10+48;                        //高电平十位
  115.                 chx[3]=a%10+48;                        //高电平个位
  116.                 }

  117. /******************************
  118.         3位数的H整型转换为字符型,加48为转ASCII。
  119.         *就是声明他的类型,是一个指向整型数据的指针
  120. ******************************/               
  121. void Inttochar3(unsigned int a,unsigned char *chx)
  122.         {        
  123.                 chx[0]=a/100+48;                        //百分数百位
  124.                 chx[1]=(a/10)%10+48;                        //百分数十位
  125.                 chx[2]=a%10+48;                        //百分数个位
  126.                 }

  127. /******************************
  128.                 LCD数据显示子程序
  129. ******************************/               
  130. void Display(void)
  131.         {
  132.                 Inttochar3(rpm_r,(unsigned char *)RPM_R);                        //右电机转速,H整型转换为字符型。*就是声明他的类型,是一个指向整型数据的指针               
  133.                 Inttochar3(rpm_l,(unsigned char *)RPM_L);                        //左电机转速,H整型转换为字符型。*就是声明他的类型,是一个指向整型数据的指针               
  134.                 Inttochar3(v_r,(unsigned char *)V_R);                        //右电机速度,H整型转换为字符型。*就是声明他的类型,是一个指向整型数据的指针               
  135.                 Inttochar3(v_l,(unsigned char *)V_L);                        //左电机速度,H整型转换为字符型。*就是声明他的类型,是一个指向整型数据的指针
  136.                 PutString(1,4,"R:");                        //字体,2字节        
  137.                 PutString(1,7,RPM_R);                        //RPM_R为右电机转速的ASCII数组,3字节        
  138.                 PutString(1,11,"r/min");                        //字体,5字节                                
  139.                 PutString(2,4,"L:");                        //字体,2字节
  140.                 PutString(2,7,RPM_L);                        //RPM_L为左电机转速的ASCII数组,3字节        
  141.                 PutString(2,11,"r/min");                        //字体,5字节                                       
  142.                 PutString(3,4,"R:");                        //字体,2字节
  143.                 PutString(3,7,V_R);                        //V_R为右电机速度的ASCII数组,3字节        
  144.                 PutString(3,11,"km/h");                        //字体,4字节                                                
  145.                 PutString(4,4,"L:");                        //字体,2字节
  146.                 PutString(4,7,V_L);                        //V_L为左电机速度的ASCII数组,3字节        
  147.                 PutString(4,11,"km/h");                        //字体,4字节
  148.                 }

  149. /******************************
  150.                 单片机初始化
  151. ******************************/
  152. void Initial()
  153.         {
  154.                 TMOD=0x55;                //定时器T0、T1工作于计数器模式1;解释:C/T=1时为计数功能:加1计数器对来自输入引脚T0(P3.4)和T1(P3.5)的外信号脉冲进行计数;M1=0、M0=1,方式1:16位定时器/计数器
  155.                 RCAP2H=(65536-50000)/256;                //定时/计数器2陷阱寄存器高字节,50000次溢出一次产生中断
  156.                 RCAP2L=(65536-50000)%256;                //定时/计数器2陷阱寄存器低字节,50ms中断
  157.                 ET2=1;                //打开定时器中断
  158.                 TR2=1;                //打开定时器开关
  159.                 EA=1;                //打开总中断
  160.                 TR0=1;                //打开定时器开关
  161.                 TR1=1;                //打开定时器开关
  162.         }

  163. /******************************
  164.                 主程序
  165. ******************************/               
  166. void main()
  167.         {
  168.                 Init();                //LCD初始化子程序
  169.                 Initial();                //单片机初始化
  170.                 while(1)
  171.                         {
  172.                                 TH0=0;                //定时器T0高八位的初值
  173.                                 TL0=0;                //定时器T0低八位的初值
  174.                                 TH1=0;                //定时器T1高八位的初值
  175.                                 TL1=0;                //定时器T1低八位的初值
  176.                                 flag=0;                //时钟标志位
  177.                                 while(flag==0);                // 时间未满等待
  178.                                 rpm_r=(TH0*256+TL0)*60/20;                //计算转速,乘以60秒,除以每周产生20个脉冲,单位为r/min                                
  179.                                 v_r=D*3.14*(TH0*256+TL0)/20*3.6/1000;                //v=2π*R*n,线速度为v,单位为m/s,转速为n,单位为r/s,1m/s=3.6km/h
  180.                                 rpm_l=(TH1*256+TL1)*60/20;                //计算转速,除以每周产生20个脉冲,单位为r/s
  181.                                 v_l=D*3.14*(TH1*256+TL1)/20*3.6/1000;                //v=2π*R*n,线速度为v,单位为m/s,转速为n,单位为r/s,1m/s=3.6km/h
  182.                                 Display();
  183.                         }
  184.         }

  185. /******************************
  186.                 中断0(P3.2),C1接收个数累加
  187. ******************************/        
  188. void time2() interrupt 5//定时器T2中断服务程序
  189.         {
  190.                 TF2=0;                //定时器2溢出标志位,注意!定时器2必须由软件对溢出标志位清零,硬件不能清零,这里与定时器0和定时器1不同。
  191.                 cnt++;                //中断次数倍数,50ms为单位
  192.                 if(cnt==20)                //中断20次,每次50ms秒,累加1s。
  193.                         {
  194.                                 flag=1;                //时钟标志位
  195.                                 cnt=0;                //中断次数倍数
  196.                         }
  197.         }
复制代码

Keil代码下载:
OPG测速1.rar (84.35 KB, 下载次数: 21)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表